001: /*
002: * @(#) $Header: /cvs/jai-operators/src/tests/ca/forklabs/media/jai/operator/KMeansDescriptorTest.java,v 1.2 2007/09/07 18:13:36 forklabs Exp $
003: *
004: * Copyright (C) 2007 DIRO Daniel Léonard
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: */
020:
021: package ca.forklabs.media.jai.operator;
022:
023: import java.awt.image.Raster;
024: import java.awt.image.RenderedImage;
025: import java.awt.image.renderable.ParameterBlock;
026: import java.util.Arrays;
027: import java.util.Iterator;
028: import java.util.Locale;
029: import javax.media.jai.JAI;
030: import javax.media.jai.RenderedOp;
031: import javax.media.jai.registry.RenderedRegistryMode;
032: import junit.framework.AssertionFailedError;
033: import junit.framework.TestCase;
034: import ca.forklabs.media.jai.RasterAdapter;
035: import ca.forklabs.media.jai.operator.KMeansDescriptor;
036:
037: /**
038: * Class {@code KMeansDescriptorTest} tests class {@link KMeansDescriptor}.
039: *
040: * @author <a href="mailto:forklabs at dev.java.net?subject=ca.forklabs.media.jai.operator.KMeansDescriptorTest">Daniel Léonard</a>
041: * @version $Revision: 1.2 $
042: */
043: @SuppressWarnings("nls")
044: public class KMeansDescriptorTest extends TestCase {
045:
046: //---------------------------
047: // Constructors
048: //---------------------------
049:
050: /**
051: * Constructor.
052: * @param name the name of this test.
053: */
054: public KMeansDescriptorTest(String name) {
055: super (name);
056: }
057:
058: //---------------------------
059: // Test methods
060: //---------------------------
061:
062: /**
063: * Tests that the default color map is well constructed.
064: */
065: public void testCreateDefaultColorMap() {
066: int clusters = 5;
067: int bands = 6;
068:
069: KMeansDescriptor descriptor = new KMeansDescriptor();
070: int[][] color_map = descriptor.createDefaultColorMap(clusters,
071: bands);
072:
073: assertEquals(clusters, color_map.length);
074: for (int c = 0; c < color_map.length; c++) {
075: int[] map = color_map[c];
076: assertEquals(bands, map.length);
077: for (int b = 0; b < map.length; b++) {
078: assertEquals(c, map[b]);
079: }
080: }
081: }
082:
083: /**
084: * Tests the error catching in
085: * {@link AutoRescaleDescriptor#validateParameters(String, ParameterBlock, StringBuffer)}
086: */
087: public void testValidateBadParameters() {
088: Locale locale = Locale.getDefault();
089: Locale.setDefault(Locale.ENGLISH);
090: try {
091: KMeansDescriptor descriptor = new KMeansDescriptor();
092:
093: RenderedImage source = RasterAdapter.buildIntImage(
094: new int[][] { { 1, 2, 3, 4 }, }, 2, 2);
095:
096: String mode = RenderedRegistryMode.MODE_NAME;
097:
098: KMeansDescriptor.EvaluationFunction function = null;
099: int clusters, iterations;
100:
101: {
102: // test negative cluster
103: clusters = -1;
104: ParameterBlock pb = new ParameterBlock().addSource(
105: source).add(clusters);
106: StringBuffer sb = new StringBuffer();
107:
108: boolean got = descriptor.validateParameters(mode, pb,
109: sb);
110: assertFalse(got);
111: }
112:
113: clusters = 2;
114:
115: {
116: // test negative iterations
117: iterations = -1;
118:
119: ParameterBlock pb = new ParameterBlock().addSource(
120: source).add(clusters).add(function).add(
121: iterations);
122: StringBuffer sb = new StringBuffer();
123:
124: boolean got = descriptor.validateParameters(mode, pb,
125: sb);
126: assertFalse(got);
127: }
128:
129: iterations = 2;
130:
131: {
132: // color map too long
133: int[][] color_map = new int[3][1];
134:
135: ParameterBlock pb = new ParameterBlock().addSource(
136: source).add(clusters).add(function).add(
137: iterations).add(color_map);
138: StringBuffer sb = new StringBuffer();
139:
140: boolean got = descriptor.validateParameters(mode, pb,
141: sb);
142: assertFalse(got);
143: assertEquals(
144: "The number of colors in the color map (3) do not match the number of clusters (2)",
145: sb.toString());
146: }
147:
148: {
149: // color map too short
150: int[][] color_map = new int[1][1];
151:
152: ParameterBlock pb = new ParameterBlock().addSource(
153: source).add(clusters).add(function).add(
154: iterations).add(color_map);
155: StringBuffer sb = new StringBuffer();
156:
157: boolean got = descriptor.validateParameters(mode, pb,
158: sb);
159: assertFalse(got);
160: assertEquals(
161: "The number of colors in the color map (1) do not match the number of clusters (2)",
162: sb.toString());
163: }
164:
165: {
166: // irregular color map
167: int[][] color_map = new int[][] { { 1, }, { 2, 3, }, };
168:
169: ParameterBlock pb = new ParameterBlock().addSource(
170: source).add(clusters).add(function).add(
171: iterations).add(color_map);
172: StringBuffer sb = new StringBuffer();
173:
174: boolean got = descriptor.validateParameters(mode, pb,
175: sb);
176: assertFalse(got);
177: assertEquals(
178: "One color in the color map contain 1 bands, another contains 2",
179: sb.toString());
180: }
181:
182: {
183: // too few bands
184: int[][] color_map = new int[2][0];
185:
186: ParameterBlock pb = new ParameterBlock().addSource(
187: source).add(clusters).add(function).add(
188: iterations).add(color_map);
189: StringBuffer sb = new StringBuffer();
190:
191: boolean got = descriptor.validateParameters(mode, pb,
192: sb);
193: assertFalse(got);
194: assertEquals(
195: "The number of bands in the color map (0) do not match the number of bands (1) in the image",
196: sb.toString());
197: }
198:
199: {
200: // too many bands
201: int[][] color_map = new int[2][2];
202:
203: ParameterBlock pb = new ParameterBlock().addSource(
204: source).add(clusters).add(function).add(
205: iterations).add(color_map);
206: StringBuffer sb = new StringBuffer();
207:
208: boolean got = descriptor.validateParameters(mode, pb,
209: sb);
210: assertFalse(got);
211: assertEquals(
212: "The number of bands in the color map (2) do not match the number of bands (1) in the image",
213: sb.toString());
214: }
215: } finally {
216: Locale.setDefault(locale);
217: }
218: }
219:
220: /**
221: * Tests that the operator work when called by JAI.
222: */
223: @SuppressWarnings("boxing")
224: public void testCreateRendered() {
225: int[][] pixels = new int[][] { { 1, 2, 3, 4, 5, 6, 7, 8, 9, }, };
226: int cols = 3;
227: int rows = 3;
228: RenderedImage source = RasterAdapter.buildIntImage(pixels,
229: cols, rows);
230:
231: int clusters = 3;
232: KMeansDescriptor.EvaluationFunction function = null;
233: int iterations = 100;
234: int[][] color_map = new int[][] { { 2, }, { 4, }, { 6, }, };
235: RenderedOp image = KMeansDescriptor.create(source, clusters,
236: function, iterations, color_map, null);
237:
238: Raster raster = image.getData();
239:
240: Iterator<Integer> iter = Arrays.asList(2, 4, 6).iterator();
241: int expected = iter.next();
242: for (int r = 0; r < rows; r++) {
243: for (int c = 0; c < cols; c++) {
244: int pixel = raster.getPixel(c, r, new int[1])[0];
245: if (expected != pixel) {
246: expected = iter.next();
247: if (expected != pixel) {
248: throw new AssertionFailedError("Expected "
249: + expected + " but got " + pixel);
250: }
251: }
252: }
253: }
254: }
255:
256: /**
257: * Tests that the operator work when called by JAI.
258: */
259: @SuppressWarnings("boxing")
260: public void testJAICreate() {
261: int[][] pixels = new int[][] { { 1, 2, 3, 4, 5, 6, 7, 8, 9, }, };
262: int cols = 3;
263: int rows = 3;
264: RenderedImage source = RasterAdapter.buildIntImage(pixels,
265: cols, rows);
266:
267: int clusters = 3;
268: RenderedOp image = JAI.create("kmeans", new ParameterBlock()
269: .addSource(source).add(clusters));
270:
271: Raster raster = image.getData();
272:
273: Iterator<Integer> iter = Arrays.asList(0, 1, 2).iterator();
274: int expected = iter.next();
275: for (int r = 0; r < rows; r++) {
276: for (int c = 0; c < cols; c++) {
277: int pixel = raster.getPixel(c, r, new int[1])[0];
278: if (expected != pixel) {
279: expected = iter.next();
280: if (expected != pixel) {
281: throw new AssertionFailedError("Expected "
282: + expected + " but got " + pixel);
283: }
284: }
285: }
286: }
287: }
288:
289: /**
290: * Tests the English messages.
291: */
292: public void testEnglishMessages() {
293: Locale locale = Locale.getDefault();
294: Locale.setDefault(Locale.ENGLISH);
295:
296: try {
297: String[] expected = new String[] {
298: "K-means algorithm",
299: "The number of clusters",
300: "The evaluation function (optional)",
301: "The maximum number of iteration (optional)",
302: "A new color map (optional)",
303: "The number of colors in the color map (2) do not match the number of clusters (1)",
304: "One color in the color map contain 1 bands, another contains 2",
305: "The number of bands in the color map (4) do not match the number of bands (5) in the image", };
306:
307: KMeansDescriptor descriptor = new KMeansDescriptor();
308: String[] got = new String[] {
309: KMeansDescriptor.getDescription(),
310: KMeansDescriptor.getArg0Description(),
311: KMeansDescriptor.getArg1Description(),
312: KMeansDescriptor.getArg2Description(),
313: KMeansDescriptor.getArg3Description(),
314: descriptor.getClustersDoNotMatchErrorMessage(1, 2),
315: descriptor.getColorMapNotRectangularErrorMessage(1,
316: 2),
317: descriptor.getBandsDoNotMatchErrorMessage(5, 4), };
318:
319: assertEquals(expected.length, got.length);
320:
321: for (int i = 0; i < expected.length; i++) {
322: assertEquals("[" + i + "]", expected[i], got[i]);
323: }
324: } finally {
325: Locale.setDefault(locale);
326: }
327: }
328:
329: /**
330: * Tests the French messages.
331: */
332: public void testFrenchMessages() {
333: Locale locale = Locale.getDefault();
334: Locale.setDefault(Locale.FRENCH);
335:
336: try {
337: String[] expected = new String[] {
338: "Algorithme des k-moyennes",
339: "Le nombre de partitions",
340: "La fonction d'évaluation (optionel)",
341: "Le nombre maximal d'itérations (optionel)",
342: "Les couleurs pour les partitions (optionel)",
343: "Le nombre de couleur dans la table de couleur (2) ne correspond pas au nombre de segments (1)",
344: "Une couleur de la table de couleur contient 1 bandes, une autre en contient 2",
345: "Le nombre de bandes dans la table de couleur (4) ne correspond pas au nombre de bandes (5) dans l'image", };
346:
347: KMeansDescriptor descriptor = new KMeansDescriptor();
348: String[] got = new String[] {
349: KMeansDescriptor.getDescription(),
350: KMeansDescriptor.getArg0Description(),
351: KMeansDescriptor.getArg1Description(),
352: KMeansDescriptor.getArg2Description(),
353: KMeansDescriptor.getArg3Description(),
354: descriptor.getClustersDoNotMatchErrorMessage(1, 2),
355: descriptor.getColorMapNotRectangularErrorMessage(1,
356: 2),
357: descriptor.getBandsDoNotMatchErrorMessage(5, 4), };
358:
359: assertEquals(expected.length, got.length);
360:
361: for (int i = 0; i < expected.length; i++) {
362: assertEquals("[" + i + "]", expected[i], got[i]);
363: }
364: } finally {
365: Locale.setDefault(locale);
366: }
367: }
368:
369: //---------------------------
370: // Class methods
371: //---------------------------
372:
373: /**
374: * Runs only this test.
375: * @param args ignored.
376: */
377: public static void main(String... args) {
378: junit.swingui.TestRunner.run(KMeansDescriptorTest.class);
379: }
380:
381: }
382:
383: /*
384: * $Log: KMeansDescriptorTest.java,v $
385: * Revision 1.2 2007/09/07 18:13:36 forklabs
386: * Refactored K-Means to add a new parameter, the evaluation function.
387: *
388: * Revision 1.1 2007/08/16 21:26:43 forklabs
389: * Operator kmeans.
390: *
391: */
|