1 /*
2  * $RCSfile: HistogramDescriptor.java,v $
3  *
4  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Use is subject to license terms.
7  *
8  * $Revision: 1.1 $
9  * $Date: 2005/02/11 04:57:36 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.mediax.jai.operator;
13 import java.awt.RenderingHints;
14 import java.awt.image.RenderedImage;
15 import java.awt.image.renderable.ParameterBlock;
16 import com.lightcrafts.mediax.jai.JAI;
17 import com.lightcrafts.mediax.jai.OperationDescriptorImpl;
18 import com.lightcrafts.mediax.jai.ParameterBlockJAI;
19 import com.lightcrafts.mediax.jai.ROI;
20 import com.lightcrafts.mediax.jai.RenderedOp;
21 import com.lightcrafts.mediax.jai.registry.RenderedRegistryMode;
22 
23 /**
24  * This <code>OperationDescriptor</code> defines the "Histogram"
25  * operation.
26  *
27  * <p> A histogram of an image is represented by a list of "bins"
28  * where each bin is the total number of pixel samples of the image
29  * whose values lie within a given range.  This data are encapulated
30  * in the <code>com.lightcrafts.mediax.jai.Histogram</code> object, and may be
31  * retrieved by calling the <code>getProperty</code> method on this
32  * operator with "<i>histogram</i>" as the property name.
33  *
34  * <p> At a request for the histogram property, this operator scans
35  * the specific region of the source image, generates the pixel count
36  * data, and returns an instance of the <code>Histogram</code> class
37  * where the data are stored.  The source image's pixels are unchanged
38  * by this operator.
39  *
40  * <p> The region-of-interest (ROI), within which the pixels are counted,
41  * does not have to be a rectangle.  It may be <code>null</code>, in
42  * which case the entire image is scanned to accumulate the histogram.
43  *
44  * <p> The set of pixels scanned may be further reduced by specifying
45  * the "xPeriod" and "yPeriod" parameters that represent the sampling
46  * rate along the two axis.  These variables may not be less than 1.
47  * If they are not set, the default value of 1 is used so that every
48  * pixel within the ROI is counted.
49  *
50  * <p> The three arguments, <code>numBins</code>, <code>lowValue</code>,
51  * and <code>highValue</code>, define the type of the histogram to be
52  * generated.  Please see the <code>Histogram</code> specification for
53  * their detailed descriptions.  The three arrays must either have an
54  * array length of 1, in which case the same value is applied to all
55  * bands of the source image, or an array length that equals to the
56  * number of bands of the source image, in which case each value is
57  * applied to its corresponding band.  The <code>numBins</code> must
58  * all be greater than 0, and each <code>lowValue</code> must be less
59  * than its corresponding <code>highValue</code>.  Note that the default
60  * values of these three parameters are specific to the case wherein
61  * the image data are of type <code>byte</code>.  For other image data
62  * types the values of these parameters should be supplied explicitely.
63  *
64  * <p><table border=1>
65  * <caption>Resource List</caption>
66  * <tr><th>Name</th>        <th>Value</th></tr>
67  * <tr><td>GlobalName</td>  <td>Histogram</td></tr>
68  * <tr><td>LocalName</td>   <td>Histogram</td></tr>
69  * <tr><td>Vendor</td>      <td>com.lightcrafts.media.jai</td></tr>
70  * <tr><td>Description</td> <td>Generates a histogram based on the pixel values
71  *                              within a specific region of an image.</td></tr>
72  * <tr><td>DocURL</td>      <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/HistogramDescriptor.html</td></tr>
73  * <tr><td>Version</td>     <td>1.1</td></tr>
74  * <tr><td>arg0Desc</td>    <td>The region of the image to be scanned.</td></tr>
75  * <tr><td>arg1Desc</td>    <td>The horizontal sampling rate;
76  *                              may not be less than 1.</td></tr>
77  * <tr><td>arg2Desc</td>    <td>The vertical sampling rate;
78  *                              may not be less than 1.</td></tr>
79  * <tr><td>arg3Desc</td>    <td>The number of bins for each band.</td></tr>
80  * <tr><td>arg4Desc</td>    <td>The lowest inclusive pixel value to be
81  *                              checked for each band.</td></tr>
82  * <tr><td>arg5Desc</td>    <td>The highest exclusive pixel value to be
83  *                              checked for each band.</td></tr>
84  * </table></p>
85  *
86  * <p><table border=1>
87  * <caption>Parameter List</caption>
88  * <tr><th>Name</th>      <th>Class Type</th>
89  *                        <th>Default Value</th></tr>
90  * <tr><td>roi</td>       <td>com.lightcrafts.mediax.jai.ROI</td>
91  *                        <td>null</td>
92  * <tr><td>xPeriod</td>   <td>java.lang.Integer</td>
93  *                        <td>1</td>
94  * <tr><td>yPeriod</td>   <td>java.lang.Integer</td>
95  *                        <td>1</td>
96  * <tr><td>numBins</td>   <td>int[]</td>
97  *                        <td>{256}</td>
98  * <tr><td>lowValue</td>  <td>double[]</td>
99  *                        <td>{0.0}</td>
100  * <tr><td>highValue</td> <td>double[]</td>
101  *                        <td>{256.0}</td>
102  * </table></p>
103  *
104  * @see com.lightcrafts.mediax.jai.Histogram
105  * @see com.lightcrafts.mediax.jai.ROI
106  * @see com.lightcrafts.mediax.jai.OperationDescriptor
107  */
108 public class HistogramDescriptor extends OperationDescriptorImpl {
109 
110     /**
111      * The resource strings that provide the general documentation
112      * and specify the parameter list for this operation.
113      */
114     private static final String[][] resources = {
115         {"GlobalName",  "Histogram"},
116         {"LocalName",   "Histogram"},
117         {"Vendor",      "com.lightcrafts.media.jai"},
118         {"Description", JaiI18N.getString("HistogramDescriptor0")},
119         {"DocURL",      "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/HistogramDescriptor.html"},
120         {"Version",     JaiI18N.getString("DescriptorVersion2")},
121         {"arg0Desc",    JaiI18N.getString("HistogramDescriptor1")},
122         {"arg1Desc",    JaiI18N.getString("HistogramDescriptor2")},
123         {"arg2Desc",    JaiI18N.getString("HistogramDescriptor3")},
124         {"arg3Desc",    JaiI18N.getString("HistogramDescriptor4")},
125         {"arg4Desc",    JaiI18N.getString("HistogramDescriptor5")},
126         {"arg5Desc",    JaiI18N.getString("HistogramDescriptor6")}
127     };
128 
129     /** The parameter name list for this operation. */
130     private static final String[] paramNames = {
131         "roi",
132         "xPeriod",
133         "yPeriod",
134         "numBins",
135         "lowValue",
136         "highValue"
137     };
138 
139     /** The parameter class list for this operation. */
140     private static final Class[] paramClasses = {
141         com.lightcrafts.mediax.jai.ROI.class,
142         java.lang.Integer.class,
143         java.lang.Integer.class,
144         int[].class,
145         double[].class,
146         double[].class
147     };
148 
149     /** The parameter default value list for this operation. */
150     private static final Object[] paramDefaults = {
151         null,
152         new Integer(1),
153         new Integer(1),
154         new int[] {256},
155         new double[] {0.0},
156         new double[] {256.0}
157     };
158 
159     /** Constructor. */
HistogramDescriptor()160     public HistogramDescriptor() {
161         super(resources, 1, paramClasses, paramNames, paramDefaults);
162     }
163 
164     /**
165      * Returns the minimum legal value of a specified numeric parameter
166      * for this operation.
167      */
getParamMinValue(int index)168     public Number getParamMinValue(int index) {
169         switch (index) {
170         case 1:
171         case 2:
172             return new Integer(1);
173         case 0:
174         case 3:
175         case 4:
176         case 5:
177             return null;
178         default:
179             throw new ArrayIndexOutOfBoundsException();
180         }
181     }
182 
183     /**
184      * Returns <code>true</code> if this operation is capable of handling
185      * the input parameters.
186      *
187      * <p> In addition to the default validations done in the super class,
188      * this method verifies that each element of <code>numBins</code> is
189      * greater than 0, and each <code>lowValue</code> is less than its
190      * corresponding <code>highValue</code>.
191      *
192      * @throws IllegalArgumentException  If <code>args</code> is <code>null</code>.
193      * @throws IllegalArgumentException  If <code>msg</code> is <code>null</code>
194      *         and the validation fails.
195      */
validateParameters(ParameterBlock args, StringBuffer msg)196     protected boolean validateParameters(ParameterBlock args,
197                                          StringBuffer msg) {
198 
199         if ( args == null || msg == null ) {
200             throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
201         }
202 
203         if (!super.validateParameters(args, msg)) {
204             return false;
205         }
206 
207         int[] numBins = (int[])args.getObjectParameter(3);
208         double[] lowValue = (double[])args.getObjectParameter(4);
209         double[] highValue = (double[])args.getObjectParameter(5);
210 
211         int l1 = numBins.length;
212         int l2 = lowValue.length;
213         int l3 = highValue.length;
214 
215         int length = Math.max(l1, Math.max(l2, l3));
216 
217         for (int i = 0; i < length; i++) {
218             if (i < l1 && numBins[i] <= 0) {
219                 msg.append(getName() + " " +
220                        JaiI18N.getString("HistogramDescriptor7"));
221                 return false;
222             }
223 
224             double l = i < l2 ? lowValue[i] : lowValue[0];
225             double h = i < l3 ? highValue[i] : highValue[0];
226 
227             if (l >= h) {
228                 msg.append(getName() + " " +
229                        JaiI18N.getString("HistogramDescriptor8"));
230                 return false;
231             }
232         }
233 
234         return true;
235     }
236 
237 
238     /**
239      * Generates a histogram based on the pixel values within a specific region of an image.
240      *
241      * <p>Creates a <code>ParameterBlockJAI</code> from all
242      * supplied arguments except <code>hints</code> and invokes
243      * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
244      *
245      * @see JAI
246      * @see ParameterBlockJAI
247      * @see RenderedOp
248      *
249      * @param source0 <code>RenderedImage</code> source 0.
250      * @param roi The region of the image to be scanned.
251      * May be <code>null</code>.
252      * @param xPeriod The horizontal sampling rate; may not be less than 1.
253      * May be <code>null</code>.
254      * @param yPeriod The vertical sampling rate; may not be less than 1.
255      * May be <code>null</code>.
256      * @param numBins The number of bins for each band.
257      * May be <code>null</code>.
258      * @param lowValue The lowest inclusive pixel value to be checked for each band.
259      * May be <code>null</code>.
260      * @param highValue The highest exclusive pixel value to be checked for each band.
261      * May be <code>null</code>.
262      * @param hints The <code>RenderingHints</code> to use.
263      * May be <code>null</code>.
264      * @return The <code>RenderedOp</code> destination.
265      * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
266      */
267     public static RenderedOp create(RenderedImage source0,
268                                     ROI roi,
269                                     Integer xPeriod,
270                                     Integer yPeriod,
271                                     int[] numBins,
272                                     double[] lowValue,
273                                     double[] highValue,
274                                     RenderingHints hints)  {
275         ParameterBlockJAI pb =
276             new ParameterBlockJAI("Histogram",
277                                   RenderedRegistryMode.MODE_NAME);
278 
279         pb.setSource("source0", source0);
280 
281         pb.setParameter("roi", roi);
282         pb.setParameter("xPeriod", xPeriod);
283         pb.setParameter("yPeriod", yPeriod);
284         pb.setParameter("numBins", numBins);
285         pb.setParameter("lowValue", lowValue);
286         pb.setParameter("highValue", highValue);
287 
288         return JAI.create("Histogram", pb, hints);
289     }
290 }
291