1 /*
2  * $RCSfile: BandCombineOpImage.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:56:15 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.media.jai.opimage;
13 import java.awt.Rectangle;
14 import java.awt.image.DataBuffer;
15 import java.awt.image.Raster;
16 import java.awt.image.RenderedImage;
17 import java.awt.image.WritableRaster;
18 import java.util.Collection;
19 import java.util.LinkedList;
20 import java.util.Map;
21 import java.util.concurrent.Callable;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Executors;
24 
25 import com.lightcrafts.mediax.jai.ImageLayout;
26 import com.lightcrafts.mediax.jai.PointOpImage;
27 import com.lightcrafts.mediax.jai.RasterAccessor;
28 import com.lightcrafts.mediax.jai.RasterFormatTag;
29 import com.lightcrafts.mediax.jai.RasterFactory;
30 import com.lightcrafts.media.jai.util.ImageUtil;
31 import com.lightcrafts.media.jai.util.JDKWorkarounds;
32 
33 /**
34  * An <code>OpImage</code> implementing the "BandCombine" operation.
35  *
36  * <p>This <code>OpImage</code> performs the arbitrary interband
37  * linear combination of an image using the specified matrix.  The
38  * width of the matrix must be one larger that the number of bands
39  * in the source image.  The height of the matrix must be equal to
40  * the number of bands in the destination image.  Because the matrix
41  * can be of arbitrary size, this function can be used to produce
42  * a destination image with a different number of bands from the
43  * source image.
44  * <p>The destination image is formed by performing a matrix-
45  * multiply operation between the bands of the source image and
46  * the specified matrix.  The extra column of values is a constant
47  * that is added after the matrix-multiply operation takes place.
48  *
49  * @see com.lightcrafts.mediax.jai.operator.BandCombineDescriptor
50  * @see BandCombineCRIF
51  *
52  *
53  * @since EA3
54  */
55 final class BandCombineOpImage extends PointOpImage {
56 
57     static final int numProc = Runtime.getRuntime().availableProcessors();
58 
59     private double[][] matrix;
60 
61     /**
62      * Constructor.
63      *
64      * @param source       The source image.
65      * @param layout       The destination image layout.
66      * @param matrix       The matrix of values used to perform the
67      *                     linear combination.
68      */
BandCombineOpImage(RenderedImage source, Map config, ImageLayout layout, double[][] matrix)69     public BandCombineOpImage(RenderedImage source,
70                               Map config,
71                               ImageLayout layout,
72                               double[][] matrix) {
73         super(source, layout, config, true);
74 
75         this.matrix = matrix;
76 
77         int numBands = matrix.length;  // matrix height is dst numBands
78         if (getSampleModel().getNumBands() != numBands) {
79             sampleModel = RasterFactory.createComponentSampleModel(sampleModel,
80                                   sampleModel.getDataType(),
81                                   tileWidth, tileHeight, numBands);
82 
83             if(colorModel != null &&
84                !JDKWorkarounds.areCompatibleDataModels(sampleModel,
85                                                        colorModel)) {
86                 colorModel = ImageUtil.getCompatibleColorModel(sampleModel,
87                                                                config);
88             }
89         }
90     }
91 
92     /**
93      * Performs linear combination of source image with matrix
94      *
95      * @param sources   Cobbled sources, guaranteed to provide all the
96      *                  source data necessary for computing the rectangle.
97      * @param dest      The tile containing the rectangle to be computed.
98      * @param destRect  The rectangle within the tile to be computed.
99      */
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)100     protected void computeRect(Raster[] sources,
101                                WritableRaster dest,
102                                Rectangle destRect) {
103         // Retrieve format tags.
104         RasterFormatTag[] formatTags = getFormatTags();
105 
106         RasterAccessor s = new RasterAccessor(sources[0], destRect,
107                                               formatTags[0],
108                                               getSourceImage(0).getColorModel());
109         RasterAccessor d = new RasterAccessor(dest, destRect,
110                                               formatTags[1], getColorModel());
111 
112         switch (d.getDataType()) {
113         case DataBuffer.TYPE_BYTE:
114             computeRectByte(s, d);
115             break;
116         case DataBuffer.TYPE_USHORT:
117             computeRectUShort(s, d);
118             break;
119         case DataBuffer.TYPE_SHORT:
120             computeRectShort(s, d);
121             break;
122         case DataBuffer.TYPE_INT:
123             computeRectInt(s, d);
124             break;
125         case DataBuffer.TYPE_FLOAT:
126             computeRectFloat(s, d);
127             break;
128         case DataBuffer.TYPE_DOUBLE:
129             computeRectDouble(s, d);
130             break;
131         }
132 
133         if (d.isDataCopy()) {
134             d.clampDataArrays();
135             d.copyDataToRaster();
136         }
137     }
138 
computeRectByte(RasterAccessor src, RasterAccessor dst)139     private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
140         int sLineStride = src.getScanlineStride();
141         int sPixelStride = src.getPixelStride();
142         int sbands = src.getNumBands();
143         int[] sBandOffsets = src.getBandOffsets();
144         byte[][] sData = src.getByteDataArrays();
145 
146         int dwidth = dst.getWidth();
147         int dheight = dst.getHeight();
148         int dbands = dst.getNumBands();
149         int dLineStride = dst.getScanlineStride();
150         int dPixelStride = dst.getPixelStride();
151         int[] dBandOffsets = dst.getBandOffsets();
152         byte[][] dData = dst.getByteDataArrays();
153 
154         int sso = 0, dso = 0;
155 
156         for (int h = 0; h < dheight; h++) {
157             int spo = sso;
158             int dpo = dso;
159 
160             for (int w = 0; w < dwidth; w++) {
161                 for (int b = 0; b < dbands; b++) {
162                     float sum = 0.0F;
163                     double[] mat = matrix[b];
164 
165                     for (int k = 0; k < sbands; k++ ) {
166                         sum += (float)mat[k] *
167                                (float)(sData[k][spo+sBandOffsets[k]] & 0xFF);
168                     }
169 
170                     dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampRoundByte(sum + (float)mat[sbands]);
171                 }
172 
173                 spo += sPixelStride;
174                 dpo += dPixelStride;
175             }
176 
177             sso += sLineStride;
178             dso += dLineStride;
179         }
180     }
181 
computeRectUShort(RasterAccessor src, RasterAccessor dst)182     private void computeRectUShort(RasterAccessor src, RasterAccessor dst) {
183         final int sLineStride = src.getScanlineStride();
184         final int sPixelStride = src.getPixelStride();
185         final int sbands = src.getNumBands();
186         final int[] sBandOffsets = src.getBandOffsets();
187         final short[][] sData = src.getShortDataArrays();
188 
189         final int dwidth = dst.getWidth();
190         final int dheight = dst.getHeight();
191         final int dbands = dst.getNumBands();
192         final int dLineStride = dst.getScanlineStride();
193         final int dPixelStride = dst.getPixelStride();
194         final int[] dBandOffsets = dst.getBandOffsets();
195         final short[][] dData = dst.getShortDataArrays();
196 
197         int sso = 0, dso = 0;
198 
199         ExecutorService threadPool = Executors.newFixedThreadPool(numProc);
200         Collection<Callable<Void>> processes = new LinkedList<Callable<Void>>();
201         for (int h = 0; h < dheight; h++) {
202             final int sso_f = sso;
203             final int dso_f = dso;
204             processes.add(new Callable<Void>() {
205                 @Override
206                 public Void call() {
207                     int spo = sso_f;
208                     int dpo = dso_f;
209 
210                     for (int w = 0; w < dwidth; w++) {
211                         for (int b = 0; b < dbands; b++) {
212                             float sum = 0.0F;
213                             double[] mat = matrix[b];
214 
215                             for (int k = 0; k < sbands; k++) {
216                                 sum += (float) mat[k] *
217                                        (float) (sData[k][spo + sBandOffsets[k]] & 0xFFFF);
218                             }
219                             dData[b][dpo + dBandOffsets[b]] =
220                                     ImageUtil.clampRoundUShort(sum + (float) matrix[b][sbands]);
221                         }
222                         spo += sPixelStride;
223                         dpo += dPixelStride;
224                     }
225                     return null;
226                 }
227             });
228             sso += sLineStride;
229             dso += dLineStride;
230         }
231         try {
232             threadPool.invokeAll(processes);
233         } catch (InterruptedException e) {
234             throw new RuntimeException(e);
235         } finally {
236             threadPool.shutdown();
237         }
238     }
239 
computeRectShort(RasterAccessor src, RasterAccessor dst)240     private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
241         int sLineStride = src.getScanlineStride();
242         int sPixelStride = src.getPixelStride();
243         int sbands = src.getNumBands();
244         int[] sBandOffsets = src.getBandOffsets();
245         short[][] sData = src.getShortDataArrays();
246 
247         int dwidth = dst.getWidth();
248         int dheight = dst.getHeight();
249         int dbands = dst.getNumBands();
250         int dLineStride = dst.getScanlineStride();
251         int dPixelStride = dst.getPixelStride();
252         int[] dBandOffsets = dst.getBandOffsets();
253         short[][] dData = dst.getShortDataArrays();
254 
255         int sso = 0, dso = 0;
256 
257         for (int h = 0; h < dheight; h++) {
258             int spo = sso;
259             int dpo = dso;
260 
261             for (int w = 0; w < dwidth; w++) {
262                 for (int b = 0; b < dbands; b++) {
263                     float sum = 0.0F;
264                     double[] mat = matrix[b];
265 
266                     for (int k = 0; k < sbands; k++ ) {
267                         sum += (float)mat[k] *
268                                (float)(sData[k][spo+sBandOffsets[k]]);
269                     }
270 
271                     dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampRoundUShort(sum + (float)matrix[b][sbands]);
272                 }
273 
274                 spo += sPixelStride;
275                 dpo += dPixelStride;
276             }
277 
278             sso += sLineStride;
279             dso += dLineStride;
280         }
281 
282     }
283 
computeRectInt(RasterAccessor src, RasterAccessor dst)284     private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
285         int sLineStride = src.getScanlineStride();
286         int sPixelStride = src.getPixelStride();
287         int sbands = src.getNumBands();
288         int[] sBandOffsets = src.getBandOffsets();
289         int[][] sData = src.getIntDataArrays();
290 
291         int dwidth = dst.getWidth();
292         int dheight = dst.getHeight();
293         int dbands = dst.getNumBands();
294         int dLineStride = dst.getScanlineStride();
295         int dPixelStride = dst.getPixelStride();
296         int[] dBandOffsets = dst.getBandOffsets();
297         int[][] dData = dst.getIntDataArrays();
298 
299         int sso = 0, dso = 0;
300 
301         for (int h = 0; h < dheight; h++) {
302             int spo = sso;
303             int dpo = dso;
304 
305             for (int w = 0; w < dwidth; w++) {
306                 for (int b = 0; b < dbands; b++) {
307                     float sum = 0.0F;
308                     double[] mat = matrix[b];
309 
310                     for (int k = 0; k < sbands; k++ ) {
311                         sum += (float)mat[k] *
312                                (float)(sData[k][spo+sBandOffsets[k]]);
313                     }
314 
315                     dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampRoundInt(sum + (float)matrix[b][sbands]);
316                 }
317 
318                 spo += sPixelStride;
319                 dpo += dPixelStride;
320             }
321 
322             sso += sLineStride;
323             dso += dLineStride;
324         }
325     }
326 
computeRectFloat(RasterAccessor src, RasterAccessor dst)327     private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
328         int sLineStride = src.getScanlineStride();
329         int sPixelStride = src.getPixelStride();
330         int sbands = src.getNumBands();
331         int[] sBandOffsets = src.getBandOffsets();
332         float[][] sData = src.getFloatDataArrays();
333 
334         int dwidth = dst.getWidth();
335         int dheight = dst.getHeight();
336         int dbands = dst.getNumBands();
337         int dLineStride = dst.getScanlineStride();
338         int dPixelStride = dst.getPixelStride();
339         int[] dBandOffsets = dst.getBandOffsets();
340         float[][] dData = dst.getFloatDataArrays();
341 
342         int sso = 0, dso = 0;
343 
344         for (int h = 0; h < dheight; h++) {
345             int spo = sso;
346             int dpo = dso;
347 
348             for (int w = 0; w < dwidth; w++) {
349                 for (int b = 0; b < dbands; b++) {
350                     float sum = 0.0F;
351                     double[] mat = matrix[b];
352 
353                     for (int k = 0; k < sbands; k++ ) {
354                         sum += (float)mat[k] * sData[k][spo+sBandOffsets[k]];
355                     }
356 
357                     dData[b][dpo+dBandOffsets[b]] = sum + (float)matrix[b][sbands];
358                 }
359 
360                 spo += sPixelStride;
361                 dpo += dPixelStride;
362             }
363 
364             sso += sLineStride;
365             dso += dLineStride;
366         }
367     }
368 
computeRectDouble(RasterAccessor src, RasterAccessor dst)369     private void computeRectDouble(RasterAccessor src, RasterAccessor dst) {
370         int sLineStride = src.getScanlineStride();
371         int sPixelStride = src.getPixelStride();
372         int sbands = src.getNumBands();
373         int[] sBandOffsets = src.getBandOffsets();
374         double[][] sData = src.getDoubleDataArrays();
375 
376         int dwidth = dst.getWidth();
377         int dheight = dst.getHeight();
378         int dbands = dst.getNumBands();
379         int dLineStride = dst.getScanlineStride();
380         int dPixelStride = dst.getPixelStride();
381         int[] dBandOffsets = dst.getBandOffsets();
382         double[][] dData = dst.getDoubleDataArrays();
383 
384         int sso = 0, dso = 0;
385 
386         for (int h = 0; h < dheight; h++) {
387             int spo = sso;
388             int dpo = dso;
389 
390             for (int w = 0; w < dwidth; w++) {
391                 for (int b = 0; b < dbands; b++) {
392                     double sum = 0.0D;
393                     double[] mat = matrix[b];
394 
395                     for (int k = 0; k < sbands; k++ ) {
396                         sum += mat[k] * sData[k][spo+sBandOffsets[k]];
397                     }
398 
399                     dData[b][dpo+dBandOffsets[b]] = sum + matrix[b][sbands];
400                 }
401 
402                 spo += sPixelStride;
403                 dpo += dPixelStride;
404             }
405 
406             sso += sLineStride;
407             dso += dLineStride;
408         }
409     }
410 }
411