/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
* http://www.geo-solutions.it/
* Copyright 2014 GeoSolutions
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package it.geosolutions.jaiext.mosaic;
import it.geosolutions.jaiext.range.Range;
import java.awt.RenderingHints;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.util.List;
import javax.media.jai.JAI;
import javax.media.jai.OperationDescriptorImpl;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.ROI;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.MosaicType;
import javax.media.jai.registry.RenderedRegistryMode;
/**
* This class is very similar to the Mosaic operation because it returns a
* composition of various images of the same type (same bands and same
* dataType). This mosaic implementation has two main differences from the
* first:
* <ul>
* <li>It doesn't support the threshold weight type.</li>
* <li>It handles source no data values.</li>
* </ul>
* This new behavior can be summarized with this code:
* <ul>
* <li>Overlay mode</li>
*
* <pre>
* // s[i][x][y] = pixel value for the source i
* // d[x][y] = pixel value of the destination
* d[x][y] = destinationNoData;
* for (int i=0; i< sources.length(); i++) {
* if (!SourceNoDataRange[i].contains(s[i][x][y]) {
* d[x][y] = s[i][x][y];
* break;
* }
* }
* </pre>
*
* <li>Blend mode. The destination pixel is calculated as a combination of all
* the source pixel in the same position.</li>
*
* <pre>
* // s[i][x][y] = pixel value for the source i
* // w[i][x][y] = weigthed value of the destination
* w[i][x][y] = 0;
* for (int i=0; i< sources.length(); i++) {
* if (!SourceNoDataRange[i].contains(s[i][x][y]) {
* w[i][x][y] = 1;
* }
* }
*
* </pre>
*
* </ul>
* <p>
* The operation parameters are:
* <ul>
* <li>A Java Bean used for storing image data, ROI and alpha channel if
* present, and no data Range.</li>
* <li>The type of operation executed(Overlay or Blend) .</li>
* <li>The destination no data value used if all the pixel source in the same
* location are no data.</li>
* </ul>
* </p>
* <p>
* The no data support is provided using the <code>Range</code> class in the
* JAI-EXT package.
* </p>
* <p>
* In this Mosaic implementation the no data support has been added for
* geospatial images mosaic elaborations. In that images the there could be
* different type of nodata and a simple thresholding operation couldn't be
* enough for avoiding image artifacts.
* <p>
* The ROI and alpha mosaic type are equal to those of the classic MosaicOp.
*
* @see MosaicOpImage
*/
public class MosaicDescriptor extends OperationDescriptorImpl {
/** serialVersionUID */
private static final long serialVersionUID = 2718297230579888333L;
/**
* The resource strings that indicates the global name, local name, vendor,
* a simple operation description, the documentation URL, the version
* number and a simple description of the operation parameters.
*/
private static final String[][] resources = {
{ "GlobalName", "Mosaic" },
{ "LocalName", "Mosaic" },
{ "Vendor", "it.geosolutions.jaiext" },
{
"Description",
"A different mosaic operation which supports noData and doesn't supports threshold" },
{ "DocURL", "wiki github non already available" },
{ "Version", "1.0" },
{ "arg0Desc", "Mosaic Type" },
{ "arg1Desc", "The source Alpha bands" },
{ "arg2Desc", "The source ROIs" },
{ "arg3Desc", "Thresholds used for the mosaic" },
{ "arg4Desc", "Background values" },
{ "arg5Desc", "No data Values" }
};
/** The parameter class. Used for the constructor. */
private static final Class[] paramClasses = {
javax.media.jai.operator.MosaicType.class,
javax.media.jai.PlanarImage[].class,
javax.media.jai.ROI[].class,
double[][].class,
double[].class,
it.geosolutions.jaiext.range.Range[].class,
};
/** The parameter name list. Used for the constructor. */
private static final String[] paramNames = {
"mosaicType",
"sourceAlpha",
"sourceROI",
"sourceThreshold",
"backgroundValues",
"nodata"
};
/** The parameter values. Used for the constructor. */
private static final Object[] paramDefaults = {
javax.media.jai.operator.MosaicDescriptor.MOSAIC_TYPE_OVERLAY,
null,
null,
new double[][] {{1.0}},
new double[] {0.0},
null };
/** Constructor. */
public MosaicDescriptor() {
super(resources, new String[] { RenderedRegistryMode.MODE_NAME }, 0,
paramNames, paramClasses, paramDefaults, null);
}
/** Check if the Renderable mode is supported */
public boolean isRenderableSupported() {
return false;
}
/**
* RenderedOp creation method that takes all the parameters, passes them to the
* ParameterBlockJAI and then call the JAI create method for the mosaic
* operation with no data support.
*
* @param sources The RenderdImage source array used for the operation.
* @param mosaicType This field sets which type of mosaic operation must be
* executed.
* @param sourceAlpha source alpha bands
* @param sourceROI source ROI
* @param sourceThreshold source thresholds
* @param backgroundValues This value fills the image pixels that contain no
* data.
* @param nodata array of NoData {@link Range} used for checking nodata values
* @param renderingHints This value sets the rendering hints for the operation.
* @return A RenderedOp that performs the mosaic operation with no data support.
*/
public static RenderedOp create(RenderedImage[] sources,
MosaicType mosaicType,
PlanarImage[] sourceAlpha,
ROI[] sourceROI,
double[][] sourceThreshold,
double[] backgroundValues,
Range[] nodata,
RenderingHints renderingHints) {
ParameterBlockJAI pb = new ParameterBlockJAI("Mosaic", RenderedRegistryMode.MODE_NAME);
// All the source images are added to the parameter block.
int numSources = sources.length;
for (int i = 0; i < numSources; i++) {
pb.addSource(sources[i]);
}
// Then the parameters are passed to the parameterblockJAI.
pb.setParameter("mosaicType", mosaicType);
pb.setParameter("sourceAlpha", sourceAlpha);
pb.setParameter("sourceROI", sourceROI);
pb.setParameter("sourceThreshold", sourceThreshold);
pb.setParameter("backgroundValues", backgroundValues);
pb.setParameter("nodata", nodata);
// JAI operation performed.
return JAI.create("Mosaic", pb, renderingHints);
}
}