001: /*
002: * @(#) $Header: /cvs/jai-operators/src/tests/ca/forklabs/media/jai/opimage/KMeansOpImageTest.java,v 1.2 2007/09/07 18:13:36 forklabs Exp $
003: *
004: * Copyright (C) 2006 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.opimage;
022:
023: import java.awt.Rectangle;
024: import java.awt.image.Raster;
025: import java.awt.image.RenderedImage;
026: import java.awt.image.WritableRaster;
027: import java.util.Arrays;
028: import junit.framework.TestCase;
029: import ca.forklabs.media.jai.RasterAdapter;
030: import ca.forklabs.media.jai.operator.KMeansDescriptor;
031:
032: /**
033: * Class {@code KMeansOpImageTest} tests class {@link KMeansOpImage}.
034: *
035: * @author <a href="mailto:forklabs at dev.java.net?subject=ca.forklabs.media.jai.opimage.KMeansOpImageTest">Daniel Léonard</a>
036: * @version $Revision: 1.2 $
037: */
038: @SuppressWarnings("nls")
039: public class KMeansOpImageTest extends TestCase {
040:
041: //---------------------------
042: // Constructors
043: //---------------------------
044:
045: /**
046: * Constructor.
047: * @param name the name of this test.
048: */
049: public KMeansOpImageTest(String name) {
050: super (name);
051: }
052:
053: //---------------------------
054: // Test methods
055: //---------------------------
056:
057: /**
058: * Tests that four different centers are found. Due to the random nature of
059: * this test, it might fail to select four distinct centers - re-run the
060: * test if this is the case.
061: */
062: public void testInitializeCenters() {
063: int[][] pixels = new int[][] {
064: { 1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 3, 3, 4, 4, },
065: { 5, 5, 6, 6, 5, 5, 6, 6, 7, 7, 8, 8, 7, 7, 8, 8, }, };
066: int cols = 4;
067: int rows = 4;
068: RenderedImage image = RasterAdapter.buildIntImage(pixels, cols,
069: rows);
070:
071: int clusters = 4;
072: KMeansDescriptor.EvaluationFunction function = new KMeansDescriptor.ColorEvaluationFunction();
073: int iterations = 100;
074: int[][] color_map = new int[][] { { 2, }, { 4, }, { 6, },
075: { 8, } };
076: KMeansOpImage op_image = new KMeansOpImage(image, clusters,
077: function, iterations, color_map, null, null);
078:
079: Raster raster = image.getData();
080: Rectangle bounds = new Rectangle(0, 0, 4, 4);
081: double[][] centers = op_image.initializeCenters(raster, bounds,
082: function);
083:
084: // the centers are also sorted before being delivered
085: assertTrue(Arrays
086: .equals(new double[] { 1.0, 5.0, }, centers[0]));
087: assertTrue(Arrays
088: .equals(new double[] { 2.0, 6.0, }, centers[1]));
089: assertTrue(Arrays
090: .equals(new double[] { 3.0, 7.0, }, centers[2]));
091: assertTrue(Arrays
092: .equals(new double[] { 4.0, 8.0, }, centers[3]));
093: }
094:
095: /**
096: * Test method
097: * {@link KMeansOpImage#calculateSquareDistances(double[], double[][], double[])}.
098: */
099: public void testCalculateSquareDistances() {
100: int[][] pixels = new int[][] {
101: { 1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 3, 3, 4, 4, },
102: { 5, 5, 6, 6, 5, 5, 6, 6, 7, 7, 8, 8, 7, 7, 8, 8, }, };
103: int cols = 4;
104: int rows = 4;
105: RenderedImage image = RasterAdapter.buildIntImage(pixels, cols,
106: rows);
107:
108: int clusters = 4;
109: KMeansDescriptor.EvaluationFunction function = new KMeansDescriptor.ColorEvaluationFunction();
110: int iterations = 100;
111: int[][] color_map = new int[][] { { 2, }, { 4, }, { 6, },
112: { 8, }, };
113: KMeansOpImage op_image = new KMeansOpImage(image, clusters,
114: function, iterations, color_map, null, null);
115:
116: double[] pixel = new double[] { 0.0, 0.0, };
117: double[][] centers = new double[][] { { 3.0, 4.0, },
118: { -3.0, 4.0, }, { 3.0, -4.0, }, { -3.0, -4.0, }, };
119: double[] distances = new double[4];
120: op_image.calculateSquareDistances(pixel, centers, distances);
121:
122: for (double distance : distances) {
123: assertEquals(25.0, distance, 10e-6);
124: }
125: }
126:
127: /**
128: * Test method {@link KMeansOpImage#findClosestCenter(double[])}.
129: */
130: public void testFindClosestCenter() {
131: int[][] pixels = new int[][] {
132: { 1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 3, 3, 4, 4, },
133: { 5, 5, 6, 6, 5, 5, 6, 6, 7, 7, 8, 8, 7, 7, 8, 8, }, };
134: int cols = 4;
135: int rows = 4;
136: RenderedImage image = RasterAdapter.buildIntImage(pixels, cols,
137: rows);
138:
139: int clusters = 4;
140: KMeansDescriptor.EvaluationFunction function = new KMeansDescriptor.ColorEvaluationFunction();
141: int iterations = 100;
142: int[][] color_map = new int[][] { { 2, }, { 4, }, { 6, }, };
143: KMeansOpImage op_image = new KMeansOpImage(image, clusters,
144: function, iterations, color_map, null, null);
145:
146: double[] distances = new double[] { 2.0, 1.0, 0.0, };
147: int index = op_image.findClosestCenter(distances);
148: assertEquals(2, index);
149: }
150:
151: /**
152: * Test the overall algorithm with predefined centers.
153: */
154: public void testComputeImage() {
155: int[][] pixels = new int[][] { { 1, 2, 3, 4, 5, 6, 7, 8, 9, }, };
156: int cols = 3;
157: int rows = 3;
158: RenderedImage image = RasterAdapter.buildIntImage(pixels, cols,
159: rows);
160: Raster[] sources = new Raster[] { image.getData(), };
161:
162: WritableRaster sink = RasterAdapter.buildIntImage(pixels, cols,
163: rows).getData().createCompatibleWritableRaster();
164:
165: int clusters = 3;
166: KMeansDescriptor.EvaluationFunction function = new KMeansDescriptor.ColorEvaluationFunction();
167: int iterations = 5;
168: int[][] color_map = new int[][] { { 2, }, { 4, }, { 6, }, };
169: KMeansOpImage op_image = new KMeansOpImage(image, clusters,
170: function, iterations, color_map, null, null) {
171: @Override
172: @SuppressWarnings("hiding")
173: protected double[][] initializeCenters(Raster source,
174: Rectangle bounds,
175: KMeansDescriptor.EvaluationFunction function) {
176: double[][] centers = new double[][] { { 1.0, },
177: { 2.0, }, { 9.0, }, };
178: return centers;
179: }
180: };
181:
182: // with initial centers [[9.0], [2.0], [1.0]]
183: // it gives image
184: // [2.0] [2.0] [4.0]
185: // [4.0] [4.0] [6.0]
186: // [6.0] [6.0] [6.0]
187:
188: op_image.computeImage(sources, sink, new Rectangle(0, 0, 3, 3));
189:
190: assertEquals(2, sink.getPixel(0, 0, new int[1])[0]);
191: assertEquals(2, sink.getPixel(1, 0, new int[1])[0]);
192: assertEquals(4, sink.getPixel(2, 0, new int[1])[0]);
193: assertEquals(4, sink.getPixel(0, 1, new int[1])[0]);
194: assertEquals(4, sink.getPixel(1, 1, new int[1])[0]);
195: assertEquals(6, sink.getPixel(2, 1, new int[1])[0]);
196: assertEquals(6, sink.getPixel(0, 2, new int[1])[0]);
197: assertEquals(6, sink.getPixel(1, 2, new int[1])[0]);
198: assertEquals(6, sink.getPixel(2, 2, new int[1])[0]);
199: }
200:
201: //---------------------------
202: // Class methods
203: //---------------------------
204:
205: /**
206: * Runs only this test.
207: * @param args ignored.
208: */
209: public static void main(String... args) {
210: junit.swingui.TestRunner.run(KMeansOpImageTest.class);
211: }
212:
213: }
214:
215: /*
216: * $Log: KMeansOpImageTest.java,v $
217: * Revision 1.2 2007/09/07 18:13:36 forklabs
218: * Refactored K-Means to add a new parameter, the evaluation function.
219: *
220: * Revision 1.1 2007/08/16 21:26:43 forklabs
221: * Operator kmeans.
222: *
223: */
|