All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jaitools.media.jai.maskedconvolve.MaskedConvolveDescriptor Maven / Gradle / Ivy

Go to download

Provides a single jar containing all JAI-tools modules which you can use instead of including individual modules in your project. Note: It does not include the Jiffle scripting language or Jiffle image operator.

The newest version!
/*
 * Copyright 2009 Michael Bedward
 * 
 * This file is part of jai-tools.
 *
 * jai-tools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 *
 * jai-tools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public 
 * License along with jai-tools.  If not, see .
 * 
 */

package jaitools.media.jai.maskedconvolve;

import java.awt.RenderingHints;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.JAI;
import javax.media.jai.KernelJAI;
import javax.media.jai.OperationDescriptorImpl;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.ROI;
import javax.media.jai.RenderedOp;
import javax.media.jai.registry.RenderedRegistryMode;

/**
 * An {@code OperationDescriptor} describing the "MaskedConvolve" operation.
 * This is a variant of JAI's {@code convolve} operator which constrains the
 * convolution to pixels that are included in an {@link ROI}. 
 * 

* Two masking options are provided: *

    *
  • source masking, in which the ROI is used * to constrain which source image pixels contribute to the kernel calculation; *
  • destination masking in which the ROI constrains the positioning of * the convolution kernel such that destination image value will be 0 if a source * pixel is not contained in the ROI. *
The two options may be used together. If neither masking option * is required it is prefereable to use the "Convolve" operator for faster processing. *

* If there is no convolution result for a destination image pixel, either because it * was not included in a destination mask or had no kernel values included in a * source mask, it will be set to a flag value. This can be set using the {@code nilValue} * parameter (default is 0). * @param minCells the minimum number of non-zero kernel cells that be positioned over * unmasked source image cells for convolution to be performed for the target cell; * any of the following are accepted:

    *
  1. "ANY" (case-insensitive) (or the constant {@linkplain #MIN_CELLS_ANY}); * this is the default *
  2. "ALL" (case-insensitive) (or the constant {@linkplain #MIN_CELLS_ALL}); *
  3. a {@code Number} with value between one and the number of non-zero kernel * cells (inclusive) *
  4. a {@code String} representing a numeric value *
* * Example of use: *

 * RenderedImage img = ...
 * 
 * float[] kernelData = new float[]{  // for neighbourhood sum
 *      0, 0, 1, 0, 0,
 *      0, 1, 1, 1, 0,
 *      1, 1, 1, 1, 1,
 *      0, 1, 1, 1, 0,
 *      0, 0, 1, 0, 0,
 * };
 *       
 * KernelJAI kernel = new KernelJAI(5, 5, kernelData);
 * ROI roi = new ROI(img, thresholdValue);
 * 
 * ParameterBlockJAI pb = new ParameterBlockJAI("maskedconvolve");
 * pb.setSource("source0", op0);
 * pb.setParameter("kernel", kernel);
 * pb.setParameter("roi", roi);
 * pb.setParameter("nilValue", Integer.valueOf(-1));
 * 
 * // no need to set masksource and maskdest params if we want to
 * // use their default values (TRUE)
 * 
 * BorderExtender extender = BorderExtender.createInstance(BorderExtender.BORDER_ZERO);
 * RenderingHints hints = new RenderingHints(JAI.KEY_BORDER_EXTENDER, extender);
 *
 * RenderedOp dest = JAI.create("maskedconvolve", pb, hints);
 *
* * @see * ConvolveDescriptor * * @author Michael Bedward * @since 1.0 * @version $Id: MaskedConvolveDescriptor.java 1383 2011-02-10 11:22:29Z michael.bedward $ */ public class MaskedConvolveDescriptor extends OperationDescriptorImpl { /** * Constant that can be used for the minCells parameter to specify * convolution will be performed for a terget cell if any non-zero kernel * cells overlap with unmasked source image cells. This is the default * parameter value. */ public static final String MIN_CELLS_ANY = "ANY"; /** * Constant that can be used for the minCells parameter to require * all non-zero kernel cells to overlap with unmasked source image * cells for convolution to be performed for a terget cell */ public static final String MIN_CELLS_ALL = "ALL"; /** Default value for nilValue parameter (0) */ public static final Number DEFAULT_NIL_VALUE = Integer.valueOf(0); static final int KERNEL_ARG = 0; static final int ROI_ARG = 1; static final int MASKSRC_ARG = 2; static final int MASKDEST_ARG = 3; static final int NIL_VALUE_ARG = 4; static final int MIN_CELLS_ARG = 5; private static final String[] paramNames = { "kernel", "roi", "maskSource", "maskDest", "nilValue", "minCells" }; private static final Class[] paramClasses = { javax.media.jai.KernelJAI.class, javax.media.jai.ROI.class, Boolean.class, Boolean.class, Number.class, Object.class }; private static final Object[] paramDefaults = { NO_PARAMETER_DEFAULT, NO_PARAMETER_DEFAULT, Boolean.TRUE, Boolean.TRUE, DEFAULT_NIL_VALUE, MIN_CELLS_ANY }; /** Constructor. */ public MaskedConvolveDescriptor() { super(new String[][]{ {"GlobalName", "MaskedConvolve"}, {"LocalName", "MaskedConvolve"}, {"Vendor", "jaitools.media.jai"}, {"Description", "Convolve a rendered image masked by an associated ROI"}, {"DocURL", "http://code.google.com/p/jai-tools/"}, {"Version", "1.0.0"}, {"arg0Desc", paramNames[0] + " - a JAI Kernel object"}, {"arg1Desc", paramNames[1] + " - an ROI object which must have the same " + "pixel bounds as the source iamge"}, {"arg2Desc", paramNames[2] + " (Boolean, default=true):" + "if TRUE (default) only the values of source pixels where" + "roi.contains is true contribute to the convolution"}, {"arg3Desc", paramNames[3] + " (Boolean): " + "if TRUE (default) convolution is only performed" + "for pixels where roi.contains is true"}, {"arg4Desc", paramNames[4] + " (Number): " + "the value to write to the destination image for pixels where " + "there is no convolution result"}, {"arg5Desc", paramNames[5] + " (String or Number, default=MIN_CELLS_ANY):" + "the minimum number of non-zero kernel cells that must overlap" + "unmasked source image cells for convolution to be performed"} }, new String[]{RenderedRegistryMode.MODE_NAME}, // supported modes 1, // number of sources paramNames, paramClasses, paramDefaults, null // valid values (none defined) ); } /** * Constructs a {@link ParameterBlockJAI} and * invokes {@code JAI.create("maskedconvolve", params) }. *

* Note: with this method only integer values can be passed for the {@code minCells} * argument. To use the Strings "ANY" or "ALL" or the constants described in the class docs * use the {@code JAI.create} method with a parameter block rather than this method. * * @param source0 the image to be convolved * * @param kernel convolution kernel * * @param roi the roi controlling convolution (must have the same pixel bounds * as the source image) * * @param maskSource if TRUE only the values of source pixels where * {@code roi.contains} is true contribute to the convolution * * @param maskDest if TRUE convolution is only performed for pixels where * {@code roi.contains} is true * * @param nilValue value to write to the destination image for pixels where * there is no convolution result * * @param minCells the minimum number of non-zero kernel cells that be positioned over * unmasked source image cells for convolution to be performed for the target cell * * @param hints useful for specifying a border extender; may be null * * @return the RenderedOp destination * @throws IllegalArgumentException if any args are null */ public static RenderedOp create( RenderedImage source0, KernelJAI kernel, ROI roi, Boolean maskSource, Boolean maskDest, Number nilValue, int minCells, RenderingHints hints) { ParameterBlockJAI pb = new ParameterBlockJAI("MaskedConvolve", RenderedRegistryMode.MODE_NAME); pb.setSource("source0", source0); pb.setParameter(paramNames[KERNEL_ARG], kernel); pb.setParameter(paramNames[ROI_ARG], roi); pb.setParameter(paramNames[MASKSRC_ARG], maskSource); pb.setParameter(paramNames[MASKDEST_ARG], maskDest); pb.setParameter(paramNames[NIL_VALUE_ARG], nilValue); pb.setParameter(paramNames[MIN_CELLS_ARG], Integer.valueOf(minCells)); return JAI.create("MaskedConvolve", pb, hints); } @Override protected boolean validateParameters(String modeName, ParameterBlock pb, StringBuffer msg) { final String minCellsErrorMsg = "minCells must be ANY, ALL or a numeric value" + " between 1 and the number of non-zero kernel cells"; boolean ok = super.validateParameters(modeName, pb, msg); if (ok) { KernelJAI kernel = (KernelJAI) pb.getObjectParameter(KERNEL_ARG); Object minCells = pb.getObjectParameter(MIN_CELLS_ARG); int minCellsValue = parseMinCells(minCells, kernel); if (minCellsValue >= 1) { pb.set(Integer.valueOf(minCellsValue), MIN_CELLS_ARG); } else { msg.append(minCellsErrorMsg); ok = false; } } return ok; } /** * Attempt to parse the Object value of the minCells parameter. * * @param minCells Object from the parameter block * * @param numActiveKernelCells upper limit on the numeric value * * @return the parsed value as an int or -1 if parsing failed or the * parsed value was out of range */ private int parseMinCells(Object minCells, KernelJAI kernel) { int value = -1; int numActiveKernelCells = numActiveKernelCells(kernel); if (minCells instanceof String) { /* * First try to parse it as a String */ String s = (String) minCells; if (s.trim().equalsIgnoreCase(MaskedConvolveDescriptor.MIN_CELLS_ALL)) { value = numActiveKernelCells; } if (s.trim().equalsIgnoreCase(MaskedConvolveDescriptor.MIN_CELLS_ANY)) { value = 1; } if (value < 0) { /* * Try it as the String value of a number */ try { int n = Double.valueOf(s).intValue(); if (n > 0 && n <= numActiveKernelCells) { value = n; } } catch (NumberFormatException ex) { // do nothing } } /* * Try it as a Number object */ } else if (minCells instanceof Number) { int n = ((Number) minCells).intValue(); if (n > 0 && n <= numActiveKernelCells) { value = n; } } else { /* * Don't know what it is but we don't like it ! */ } return value; } /** * Counts the number of active cells (those with non-zero values) in the kernel. * A round-off tolerance of 1.0e-6 is used. * * @param kernel the kernel * * @return the number of non-zero cells */ private int numActiveKernelCells(KernelJAI kernel) { final float TOL = 1.0e-6F; float[] data = kernel.getKernelData(); int n = 0; for (float cellValue : data) { if (Math.abs(cellValue) > TOL) { n++ ; } } return n; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy