001: /*
002: * $RCSfile: ExtremaDescriptor.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:35 $
010: * $State: Exp $
011: */
012: package javax.media.jai.operator;
013:
014: import java.awt.RenderingHints;
015: import java.awt.image.RenderedImage;
016: import java.awt.image.renderable.ParameterBlock;
017: import javax.media.jai.JAI;
018: import javax.media.jai.OperationDescriptorImpl;
019: import javax.media.jai.ParameterBlockJAI;
020: import javax.media.jai.ROI;
021: import javax.media.jai.RenderedOp;
022: import javax.media.jai.registry.RenderedRegistryMode;
023:
024: /**
025: * An <code>OperationDescriptor</code> describing the "Extrema" operation.
026: *
027: * <p> The Extrema operation scans a specific region of a rendered
028: * image and finds the maximum and minimum pixel values for each band
029: * within that region of the image. The image data pass through this
030: * operation unchanged.
031: *
032: * <p> The region-wise maximum and minimum pixel values may be obtained
033: * as properties. Calling the <code>getProperty</code> method on this
034: * operation with "extrema" as the property name retrieves both the
035: * region-wise maximum and minimum pixel values. Calling it with
036: * "maximum" as the property name retrieves the region-wise maximum
037: * pixel value, and with "minimum" as the property name retrieves the
038: * region-wise minimum pixel value. The return value for "extrema" has
039: * type <code>double[2][#bands]</code>, and those for "maximum"
040: * and "minimum" have type <code>double[#bands]</code>.
041: *
042: * <p> The region of interest (ROI) does not have to be a rectangle.
043: * It may be <code>null</code>, in which case the entire image is
044: * scanned to find the image-wise maximum and minimum pixel values
045: * for each band.
046: *
047: * <p> The set of pixels scanned may be further reduced by
048: * specifying the "xPeriod" and "yPeriod" parameters that represent
049: * the sampling rate along each axis. These variables may not be
050: * less than 1. However, they may be <code>null</code>, in which
051: * case the sampling rate is set to 1; that is, every pixel in the
052: * ROI is processed.
053: *
054: * <p> The <code>Boolean</code> parameter "saveLocations" indicates whether
055: * the locations of the extrema will be computed. If <code>TRUE</code>, the
056: * locations are computed and stored in the properties "minLocations" and
057: * "maxLocations" in the form of lists of run length codes. Each run length
058: * code is stored as a three-entry integer array <code>(xStart, yStart,
059: * length)</code>. Because the statistics are implemented on the
060: * low-resolution image, this <code>length</code> is defined on the image
061: * coordinate system of the low-resolution image. Thus, the run length code
062: * above means the pixels <code>(xStart, yStart), (xStart + xPeriod, yStart),
063: * ..., (xStart + (length - 1) * xPeriod, yStart) </code> of the original
064: * image have a value of the maximum or minimum, depending on whether this
065: * run exists in the property "maxLocations" or "minLocations". The run length
066: * code is row-based, thus the run doesn't wrap on the image boundaries.
067: * Runs are not guaranteed to be maximal, e.g. a run that crosses tile
068: * boundaries might be broken at the boundary into multiple runs. The order
069: * of the runs is not guaranteed.
070: *
071: * <p> The value objects of the properties "minLocations" and "maxLocations"
072: * are arrays of <code>java.util.List</code>. Each array entry contains
073: * the minimum/maximum locations of one band. The elements in
074: * a list can be accessed using the iterator of
075: * the <code>java.util.List</code>. For example, the sample code below
076: * demonstrates how to retrieve the minimum locations of the first band:
077: * <pre>
078: * List minLocations = ((List[])extremaOp.getProperty("minLocations"))[0];
079: * Iterator iter = minLocations.iterator();
080: * while(iter.hasNext()) {
081: * int[] runLength = (int[])iter.next();
082: * int xStart = runLength[0];
083: * int yStart = runLength[1];
084: * int length = runLength[2];
085: * }
086: * </pre>
087: *
088: * <p> In the implementation of this operator, the proper use of the parameter
089: * "saveLocations" also helps to keep the efficiency of the operator in the
090: * common case: when only the extremal values are computed.
091: *
092: * <p> The parameter "maxRuns" is the maximum number of run length codes that
093: * the user would like to store. It is defined to reduce memory
094: * consumption on very large images. If the parameter "saveLocations" is
095: * <code>FALSE</code>, this parameter will be ignored. If this parameter is
096: * equal to <code> Integer.MAX_VALUE</code>, all the locations will be saved.
097: *
098: * <p><table border=1>
099: * <caption>Resource List</caption>
100: * <tr><th>Name</th> <th>Value</th></tr>
101: * <tr><td>GlobalName</td> <td>Extrema</td></tr>
102: * <tr><td>LocalName</td> <td>Extrema</td></tr>
103: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
104: * <tr><td>Description</td> <td>Finds the maximum and minimum pixel value
105: * in each band of an image.</td></tr>
106: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/ExtremaDescriptor.html</td></tr>
107: * <tr><td>Version</td> <td>1.0</td></tr>
108: * <tr><td>arg0Desc</td> <td>The region of the image to scan.</td></tr>
109: * <tr><td>arg1Desc</td> <td>The horizontal sampling rate,
110: * may not be less than 1.</td></tr>
111: * <tr><td>arg2Desc</td> <td>The vertical sampling rate,
112: * may not be less than 1.</td></tr>
113: * <tr><td>arg3Desc</td> <td>Whether to store extrema locations.</td></tr>
114: * <tr><td>arg4Desc</td> <td>Maximum number of run length codes to store.</td></tr>
115: * </table></p>
116: *
117: * <p><table border=1>
118: * <caption>Parameter List</caption>
119: * <tr><th>Name</th> <th>Class Type</th>
120: * <th>Default Value</th></tr>
121: * <tr><td>roi</td> <td>javax.media.jai.ROI</td>
122: * <td>null</td>
123: * <tr><td>xPeriod</td> <td>java.lang.Integer</td>
124: * <td>1</td>
125: * <tr><td>yPeriod</td> <td>java.lang.Integer</td>
126: * <td>1</td>
127: * <tr><td>saveLocations</td> <td>java.lang.Boolean</td>
128: * <td>Boolean.FALSE</td>
129: * <tr><td>maxRuns</td> <td>java.lang.Integer</td>
130: * <td>1</td>
131: * </table></p>
132: *
133: * @see javax.media.jai.OperationDescriptor
134: */
135: public class ExtremaDescriptor extends OperationDescriptorImpl {
136:
137: /**
138: * The resource strings that provide the general documentation
139: * and specify the parameter list for this operation.
140: */
141: private static final String[][] resources = {
142: { "GlobalName", "Extrema" },
143: { "LocalName", "Extrema" },
144: { "Vendor", "com.sun.media.jai" },
145: { "Description", JaiI18N.getString("ExtremaDescriptor0") },
146: {
147: "DocURL",
148: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/ExtremaDescriptor.html" },
149: { "Version", JaiI18N.getString("DescriptorVersion") },
150: { "arg0Desc", JaiI18N.getString("ExtremaDescriptor1") },
151: { "arg1Desc", JaiI18N.getString("ExtremaDescriptor2") },
152: { "arg2Desc", JaiI18N.getString("ExtremaDescriptor3") },
153: { "arg3Desc", JaiI18N.getString("ExtremaDescriptor4") },
154: { "arg4Desc", JaiI18N.getString("ExtremaDescriptor5") } };
155:
156: /** The parameter name list for this operation. */
157: private static final String[] paramNames = { "roi", "xPeriod",
158: "yPeriod", "saveLocations", "maxRuns" };
159:
160: /** The parameter class list for this operation. */
161: private static final Class[] paramClasses = {
162: javax.media.jai.ROI.class, java.lang.Integer.class,
163: java.lang.Integer.class, java.lang.Boolean.class,
164: java.lang.Integer.class };
165:
166: /** The parameter default value list for this operation. */
167: private static final Object[] paramDefaults = { null,
168: new Integer(1), new Integer(1), Boolean.FALSE,
169: new Integer(1) };
170:
171: /** Constructor. */
172: public ExtremaDescriptor() {
173: super (resources, 1, paramClasses, paramNames, paramDefaults);
174: }
175:
176: /**
177: * Returns the minimum legal value of a specified numeric parameter
178: * for this operation.
179: */
180: public Number getParamMinValue(int index) {
181: if (index == 0 || index == 3) {
182: return null;
183: } else if (index == 1 || index == 2 || index == 4) {
184: return new Integer(1);
185: } else {
186: throw new ArrayIndexOutOfBoundsException();
187: }
188: }
189:
190: /**
191: * Finds the maximum and minimum pixel value in each band of an image.
192: *
193: * <p>Creates a <code>ParameterBlockJAI</code> from all
194: * supplied arguments except <code>hints</code> and invokes
195: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
196: *
197: * @see JAI
198: * @see ParameterBlockJAI
199: * @see RenderedOp
200: *
201: * @param source0 <code>RenderedImage</code> source 0.
202: * @param roi The region of the image to scan.
203: * May be <code>null</code>.
204: * @param xPeriod The horizontal sampling rate, may not be less than 1.
205: * May be <code>null</code>.
206: * @param yPeriod The vertical sampling rate, may not be less than 1.
207: * May be <code>null</code>.
208: * @param saveLocations Whether to store extrema locations.
209: * May be <code>null</code>.
210: * @param maxRuns Maximum number of run length codes to store.
211: * May be <code>null</code>.
212: * @param hints The <code>RenderingHints</code> to use.
213: * May be <code>null</code>.
214: * @return The <code>RenderedOp</code> destination.
215: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
216: */
217: public static RenderedOp create(RenderedImage source0, ROI roi,
218: Integer xPeriod, Integer yPeriod, Boolean saveLocations,
219: Integer maxRuns, RenderingHints hints) {
220: ParameterBlockJAI pb = new ParameterBlockJAI("Extrema",
221: RenderedRegistryMode.MODE_NAME);
222:
223: pb.setSource("source0", source0);
224:
225: pb.setParameter("roi", roi);
226: pb.setParameter("xPeriod", xPeriod);
227: pb.setParameter("yPeriod", yPeriod);
228: pb.setParameter("saveLocations", saveLocations);
229: pb.setParameter("maxRuns", maxRuns);
230:
231: return JAI.create("Extrema", pb, hints);
232: }
233: }
|