1 /* Copyright (C) 2005-2011 Fabio Riccardi */
2 
3 /*
4  * $RCSfile: BandCombineOpImage.java,v $
5  *
6  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
7  *
8  * Use is subject to license terms.
9  *
10  * $Revision: 1.1 $
11  * $Date: 2005/02/11 04:56:15 $
12  * $State: Exp $
13  */
14 package com.lightcrafts.jai.opimage;
15 
16 import java.awt.Rectangle;
17 import java.awt.image.DataBuffer;
18 import java.awt.image.Raster;
19 import java.awt.image.RenderedImage;
20 import java.awt.image.WritableRaster;
21 import java.util.Map;
22 import com.lightcrafts.mediax.jai.ImageLayout;
23 import com.lightcrafts.mediax.jai.PointOpImage;
24 import com.lightcrafts.mediax.jai.RasterAccessor;
25 import com.lightcrafts.mediax.jai.RasterFormatTag;
26 import com.lightcrafts.mediax.jai.RasterFactory;
27 import com.lightcrafts.media.jai.util.ImageUtil;
28 import com.lightcrafts.media.jai.util.JDKWorkarounds;
29 
30 /**
31  * An <code>OpImage</code> implementing the "BandCombine" operation.
32  *
33  * <p>This <code>OpImage</code> performs the arbitrary interband
34  * linear combination of an image using the specified matrix.  The
35  * width of the matrix must be one larger that the number of bands
36  * in the source image.  The height of the matrix must be equal to
37  * the number of bands in the destination image.  Because the matrix
38  * can be of arbitrary size, this function can be used to produce
39  * a destination image with a different number of bands from the
40  * source image.
41  * <p>The destination image is formed by performing a matrix-
42  * multiply operation between the bands of the source image and
43  * the specified matrix.  The extra column of values is a constant
44  * that is added after the matrix-multiply operation takes place.
45  *
46  * @see com.lightcrafts.mediax.jai.operator.BandCombineDescriptor
47  * @see LCBandCombineCRIF
48  *
49  *
50  * @since EA3
51  */
52 final class LCBandCombineOpImage extends PointOpImage {
53 
54     private double[][] matrix;
55 
56     /**
57      * Constructor.
58      *
59      * @param source       The source image.
60      * @param layout       The destination image layout.
61      * @param matrix       The matrix of values used to perform the
62      *                     linear combination.
63      */
LCBandCombineOpImage(RenderedImage source, Map config, ImageLayout layout, double[][] matrix)64     public LCBandCombineOpImage(RenderedImage source,
65                               Map config,
66                               ImageLayout layout,
67                               double[][] matrix) {
68         super(source, layout, config, true);
69 
70         this.matrix = matrix;
71 
72         int numBands = matrix.length;  // matrix height is dst numBands
73         if (getSampleModel().getNumBands() != numBands) {
74             sampleModel = RasterFactory.createComponentSampleModel(sampleModel,
75                                   sampleModel.getDataType(),
76                                   tileWidth, tileHeight, numBands);
77 
78             if(colorModel != null &&
79                !JDKWorkarounds.areCompatibleDataModels(sampleModel,
80                                                        colorModel)) {
81                 colorModel = ImageUtil.getCompatibleColorModel(sampleModel,
82                                                                config);
83             }
84         }
85     }
86 
87     /**
88      * Performs linear combination of source image with matrix
89      *
90      * @param sources   Cobbled sources, guaranteed to provide all the
91      *                  source data necessary for computing the rectangle.
92      * @param dest      The tile containing the rectangle to be computed.
93      * @param destRect  The rectangle within the tile to be computed.
94      */
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)95     protected void computeRect(Raster[] sources,
96                                WritableRaster dest,
97                                Rectangle destRect) {
98         // Retrieve format tags.
99         RasterFormatTag[] formatTags = getFormatTags();
100 
101         RasterAccessor s = new RasterAccessor(sources[0], destRect,
102                                               formatTags[0],
103                                               getSourceImage(0).getColorModel());
104         RasterAccessor d = new RasterAccessor(dest, destRect,
105                                               formatTags[1], getColorModel());
106 
107         switch (d.getDataType()) {
108         case DataBuffer.TYPE_BYTE:
109             computeRectByte(s, d);
110             break;
111         case DataBuffer.TYPE_USHORT:
112             computeRectUShort(s, d);
113             break;
114         case DataBuffer.TYPE_SHORT:
115             computeRectShort(s, d);
116             break;
117         case DataBuffer.TYPE_INT:
118             computeRectInt(s, d);
119             break;
120         case DataBuffer.TYPE_FLOAT:
121             computeRectFloat(s, d);
122             break;
123         case DataBuffer.TYPE_DOUBLE:
124             computeRectDouble(s, d);
125             break;
126         }
127 
128         if (d.isDataCopy()) {
129             d.clampDataArrays();
130             d.copyDataToRaster();
131         }
132     }
133 
computeRectByte(RasterAccessor src, RasterAccessor dst)134     private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
135         int sLineStride = src.getScanlineStride();
136         int sPixelStride = src.getPixelStride();
137         int sbands = src.getNumBands();
138         int[] sBandOffsets = src.getBandOffsets();
139         byte[][] sData = src.getByteDataArrays();
140 
141         int dwidth = dst.getWidth();
142         int dheight = dst.getHeight();
143         int dbands = dst.getNumBands();
144         int dLineStride = dst.getScanlineStride();
145         int dPixelStride = dst.getPixelStride();
146         int[] dBandOffsets = dst.getBandOffsets();
147         byte[][] dData = dst.getByteDataArrays();
148 
149         if (sbands > 1 && sPixelStride > 1 && (dbands == 1 || (dbands > 1 && dPixelStride > 1))) {
150             byte[] ddData = dData[0];
151             byte[] ssData = sData[0];
152 
153             int rows = matrix.length;
154             int cols = matrix[0].length;
155             int sortedMatrix[][] = new int[rows][cols];
156 
157             int[] bandOffsets = src.getOffsetsForBands();
158 
159             int minBandOffset = sBandOffsets[0];
160             for (int i = 0; i < rows; i++) {
161                 for (int j = 0; j < cols - 1; j++) {
162                     sortedMatrix[i][j] = (int) (matrix[i][j < cols - 1 ? bandOffsets[j] : j] * 0x100 + 0.5);
163                     if (j < cols - 1)
164                         minBandOffset = sBandOffsets[j] < minBandOffset ? sBandOffsets[j] : minBandOffset;
165                 }
166             }
167 
168             int sso = minBandOffset, dso = 0;
169 
170             if (sbands == 3 && dbands == 3) {
171                 for (int h = 0; h < dheight; h++) {
172                     int spo = sso;
173                     int dpo = dso;
174 
175                     for (int w = 0; w < dwidth; w++) {
176                         int[] mat = sortedMatrix[0];
177                         int sum = mat[0] * (int) (ssData[spo + 0] & 0xFF) +
178                                   mat[1] * (int) (ssData[spo + 1] & 0xFF) +
179                                   mat[2] * (int) (ssData[spo + 2] & 0xFF);
180                         ddData[dpo + dBandOffsets[0]] = ImageUtil.clampByte(sum / 0x100 + mat[3]);
181 
182                         mat = sortedMatrix[1];
183                         sum = mat[0] * (int) (ssData[spo + 0] & 0xFF) +
184                               mat[1] * (int) (ssData[spo + 1] & 0xFF) +
185                               mat[2] * (int) (ssData[spo + 2] & 0xFF);
186                         ddData[dpo + dBandOffsets[1]] = ImageUtil.clampByte(sum / 0x100 + mat[3]);
187 
188                         mat = sortedMatrix[2];
189                         sum = mat[0] * (int) (ssData[spo + 0] & 0xFF) +
190                               mat[1] * (int) (ssData[spo + 1] & 0xFF) +
191                               mat[2] * (int) (ssData[spo + 2] & 0xFF);
192                         ddData[dpo + dBandOffsets[2]] = ImageUtil.clampByte(sum / 0x100 + mat[3]);
193 
194                         spo += sPixelStride;
195                         dpo += dPixelStride;
196                     }
197 
198                     sso += sLineStride;
199                     dso += dLineStride;
200                 }
201             } else if (sbands == 3 && dbands == 1) {
202                 for (int h = 0; h < dheight; h++) {
203                     int spo = sso;
204                     int dpo = dso;
205 
206                     for (int w = 0; w < dwidth; w++) {
207                         int[] mat = sortedMatrix[0];
208                         int sum = mat[0] * (int) (ssData[spo + 0] & 0xFF) +
209                                   mat[1] * (int) (ssData[spo + 1] & 0xFF) +
210                                   mat[2] * (int) (ssData[spo + 2] & 0xFF);
211                         ddData[dpo + dBandOffsets[0]] = ImageUtil.clampByte(sum / 0x100 + mat[3]);
212 
213                         spo += sPixelStride;
214                         dpo += dPixelStride;
215                     }
216 
217                     sso += sLineStride;
218                     dso += dLineStride;
219                 }
220             } else {
221                 for (int h = 0; h < dheight; h++) {
222                     int spo = sso;
223                     int dpo = dso;
224 
225                     for (int w = 0; w < dwidth; w++) {
226                         for (int b = 0; b < dbands; b++) {
227                             int sum = 0;
228                             int[] mat = sortedMatrix[b];
229 
230                             for (int k = 0; k < sbands; k++ ) {
231                                 sum += (mat[k] * (int)(ssData[spo+k] & 0xFF)) / 0x100;
232                             }
233 
234                             ddData[dpo+dBandOffsets[b]] = ImageUtil.clampByte(sum + mat[sbands]);
235                         }
236                         spo += sPixelStride;
237                         dpo += dPixelStride;
238                     }
239 
240                     sso += sLineStride;
241                     dso += dLineStride;
242                 }
243             }
244         } else {
245             int rows = matrix.length;
246             int cols = matrix[0].length;
247             int intMatrix[][] = new int[rows][cols];
248 
249             for (int i = 0; i < rows; i++) {
250                 for (int j = 0; j < cols - 1; j++) {
251                     intMatrix[i][j] = (int) (matrix[i][j] * 0x100 + 0.5);
252                 }
253             }
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                         int sum = 0;
264                         int[] mat = intMatrix[b];
265 
266                         for (int k = 0; k < sbands; k++) {
267                             sum += (mat[k] * (int) (sData[k][spo + sBandOffsets[k]] & 0xFF)) / 0x100;
268                         }
269 
270                         dData[b][dpo + dBandOffsets[b]] = ImageUtil.clampByte(sum + mat[sbands]);
271                     }
272 
273                     spo += sPixelStride;
274                     dpo += dPixelStride;
275                 }
276 
277                 sso += sLineStride;
278                 dso += dLineStride;
279             }
280         }
281     }
282 
283     private void computeRectUShort(RasterAccessor src, RasterAccessor dst) {
284         int sLineStride = src.getScanlineStride();
285         int sPixelStride = src.getPixelStride();
286         int sbands = src.getNumBands();
287         int[] sBandOffsets = src.getBandOffsets();
288         short[][] sData = src.getShortDataArrays();
289 
290         int dwidth = dst.getWidth();
291         int dheight = dst.getHeight();
292         int dbands = dst.getNumBands();
293         int dLineStride = dst.getScanlineStride();
294         int dPixelStride = dst.getPixelStride();
295         int[] dBandOffsets = dst.getBandOffsets();
296         short[][] dData = dst.getShortDataArrays();
297 
298         if (sbands > 1 && sPixelStride > 1 && (dbands == 1 || (dbands > 1 && dPixelStride > 1))) {
299             short[] ddData = dData[0];
300             short[] ssData = sData[0];
301 
302             int rows = matrix.length;
303             int cols = matrix[0].length;
304             int sortedMatrix[][] = new int[rows][cols];
305 
306             int minBandOffset = sBandOffsets[0];
307             for (int i = 0; i < rows; i++) {
308                 for (int j = 0; j < cols - 1; j++) {
309                     sortedMatrix[i][j] = (int) (matrix[i][j < cols - 1 ? sBandOffsets[j] : j] * 0x10000 + 0.5);
310                     if (j < cols - 1)
311                         minBandOffset = sBandOffsets[j] < minBandOffset ? sBandOffsets[j] : minBandOffset;
312                 }
313             }
314 
315             int sso = minBandOffset, dso = 0;
316 
317             if (sbands == 3 && dbands == 3) {
318                 for (int h = 0; h < dheight; h++) {
319                     int spo = sso;
320                     int dpo = dso;
321 
322                     for (int w = 0; w < dwidth; w++) {
323                         int[] mat = sortedMatrix[0];
324                         long sum = mat[0] * (long) (ssData[spo + 0] & 0xFFFF) +
325                                    mat[1] * (long) (ssData[spo + 1] & 0xFFFF) +
326                                    mat[2] * (long) (ssData[spo + 2] & 0xFFFF);
327                         ddData[dpo + dBandOffsets[0]] = ImageUtil.clampUShort((int) (sum / 0x10000 + mat[3]));
328 
329                         mat = sortedMatrix[1];
330                         sum = mat[0] * (long) (ssData[spo + 0] & 0xFFFF) +
331                               mat[1] * (long) (ssData[spo + 1] & 0xFFFF) +
332                               mat[2] * (long) (ssData[spo + 2] & 0xFFFF);
333                         ddData[dpo + dBandOffsets[1]] = ImageUtil.clampUShort((int) (sum / 0x10000 + mat[3]));
334 
335                         mat = sortedMatrix[2];
336                         sum = mat[0] * (long) (ssData[spo + 0] & 0xFFFF) +
337                               mat[1] * (long) (ssData[spo + 1] & 0xFFFF) +
338                               mat[2] * (long) (ssData[spo + 2] & 0xFFFF);
339                         ddData[dpo + dBandOffsets[2]] = ImageUtil.clampUShort((int) (sum / 0x10000 + mat[3]));
340 
341                         spo += sPixelStride;
342                         dpo += dPixelStride;
343                     }
344 
345                     sso += sLineStride;
346                     dso += dLineStride;
347                 }
348             } else if (sbands == 3 && dbands == 1) {
349                 for (int h = 0; h < dheight; h++) {
350                     int spo = sso;
351                     int dpo = dso;
352 
353                     for (int w = 0; w < dwidth; w++) {
354                         int[] mat = sortedMatrix[0];
355                         long sum = mat[0] * (long) (ssData[spo + 0] & 0xFFFF) +
356                                    mat[1] * (long) (ssData[spo + 1] & 0xFFFF) +
357                                    mat[2] * (long) (ssData[spo + 2] & 0xFFFF);
358                         ddData[dpo + dBandOffsets[0]] = ImageUtil.clampUShort((int) (sum / 0x10000 + mat[3]));
359 
360                         spo += sPixelStride;
361                         dpo += dPixelStride;
362                     }
363 
364                     sso += sLineStride;
365                     dso += dLineStride;
366                 }
367             } else {
368                 for (int h = 0; h < dheight; h++) {
369                     int spo = sso;
370                     int dpo = dso;
371 
372                     for (int w = 0; w < dwidth; w++) {
373                         for (int b = 0; b < dbands; b++) {
374                             long sum = 0;
375                             int[] mat = sortedMatrix[b];
376 
377                             for (int k = 0; k < sbands; k++ ) {
378                                 sum += (mat[k] * (long)(ssData[spo+k] & 0xFFFF)) / 0x10000;
379                             }
380 
381                             ddData[dpo+dBandOffsets[b]] = ImageUtil.clampUShort((int) (sum + mat[sbands]));
382                         }
383                         spo += sPixelStride;
384                         dpo += dPixelStride;
385                     }
386 
387                     sso += sLineStride;
388                     dso += dLineStride;
389                 }
390             }
391         } else {
392             int rows = matrix.length;
393             int cols = matrix[0].length;
394             int intMatrix[][] = new int[rows][cols];
395 
396             for (int i = 0; i < rows; i++) {
397                 for (int j = 0; j < cols - 1; j++) {
398                     intMatrix[i][j] = (int) (matrix[i][j] * 0x10000 + 0.5);
399                 }
400             }
401 
402             int sso = 0, dso = 0;
403 
404             for (int h = 0; h < dheight; h++) {
405                 int spo = sso;
406                 int dpo = dso;
407 
408                 for (int w = 0; w < dwidth; w++) {
409                     for (int b = 0; b < dbands; b++) {
410                         long sum = 0;
411                         int[] mat = intMatrix[b];
412 
413                         for (int k = 0; k < sbands; k++ ) {
414                             sum += (mat[k] * (long) (sData[k][spo+sBandOffsets[k]] & 0xFFFF)) / 0x10000;
415                         }
416 
417                         dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampUShort((int) (sum + mat[sbands]));
418                     }
419 
420                     spo += sPixelStride;
421                     dpo += dPixelStride;
422                 }
423 
424                 sso += sLineStride;
425                 dso += dLineStride;
426             }
427         }
428     }
429 
430     private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
431         int sLineStride = src.getScanlineStride();
432         int sPixelStride = src.getPixelStride();
433         int sbands = src.getNumBands();
434         int[] sBandOffsets = src.getBandOffsets();
435         short[][] sData = src.getShortDataArrays();
436 
437         int dwidth = dst.getWidth();
438         int dheight = dst.getHeight();
439         int dbands = dst.getNumBands();
440         int dLineStride = dst.getScanlineStride();
441         int dPixelStride = dst.getPixelStride();
442         int[] dBandOffsets = dst.getBandOffsets();
443         short[][] dData = dst.getShortDataArrays();
444 
445         int sso = 0, dso = 0;
446 
447         for (int h = 0; h < dheight; h++) {
448             int spo = sso;
449             int dpo = dso;
450 
451             for (int w = 0; w < dwidth; w++) {
452                 for (int b = 0; b < dbands; b++) {
453                     double sum = 0.0F;
454                     double[] mat = matrix[b];
455 
456                     for (int k = 0; k < sbands; k++ ) {
457                         sum += mat[k] * sData[k][spo+sBandOffsets[k]];
458                     }
459 
460                     dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampUShort((int) (sum + mat[sbands]));
461                 }
462 
463                 spo += sPixelStride;
464                 dpo += dPixelStride;
465             }
466 
467             sso += sLineStride;
468             dso += dLineStride;
469         }
470 
471     }
472 
473     private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
474         int sLineStride = src.getScanlineStride();
475         int sPixelStride = src.getPixelStride();
476         int sbands = src.getNumBands();
477         int[] sBandOffsets = src.getBandOffsets();
478         int[][] sData = src.getIntDataArrays();
479 
480         int dwidth = dst.getWidth();
481         int dheight = dst.getHeight();
482         int dbands = dst.getNumBands();
483         int dLineStride = dst.getScanlineStride();
484         int dPixelStride = dst.getPixelStride();
485         int[] dBandOffsets = dst.getBandOffsets();
486         int[][] dData = dst.getIntDataArrays();
487 
488         int sso = 0, dso = 0;
489 
490         for (int h = 0; h < dheight; h++) {
491             int spo = sso;
492             int dpo = dso;
493 
494             for (int w = 0; w < dwidth; w++) {
495                 for (int b = 0; b < dbands; b++) {
496                     double sum = 0.0F;
497                     double[] mat = matrix[b];
498 
499                     for (int k = 0; k < sbands; k++ ) {
500                         sum += mat[k] * sData[k][spo+sBandOffsets[k]];
501                     }
502 
503                     dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampRoundInt(sum + mat[sbands]);
504                 }
505 
506                 spo += sPixelStride;
507                 dpo += dPixelStride;
508             }
509 
510             sso += sLineStride;
511             dso += dLineStride;
512         }
513     }
514 
515     private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
516         int sLineStride = src.getScanlineStride();
517         int sPixelStride = src.getPixelStride();
518         int sbands = src.getNumBands();
519         int[] sBandOffsets = src.getBandOffsets();
520         float[][] sData = src.getFloatDataArrays();
521 
522         int dwidth = dst.getWidth();
523         int dheight = dst.getHeight();
524         int dbands = dst.getNumBands();
525         int dLineStride = dst.getScanlineStride();
526         int dPixelStride = dst.getPixelStride();
527         int[] dBandOffsets = dst.getBandOffsets();
528         float[][] dData = dst.getFloatDataArrays();
529 
530         int sso = 0, dso = 0;
531 
532         for (int h = 0; h < dheight; h++) {
533             int spo = sso;
534             int dpo = dso;
535 
536             for (int w = 0; w < dwidth; w++) {
537                 for (int b = 0; b < dbands; b++) {
538                     double sum = 0.0F;
539                     double[] mat = matrix[b];
540 
541                     for (int k = 0; k < sbands; k++ ) {
542                         sum += mat[k] * sData[k][spo+sBandOffsets[k]];
543                     }
544 
545                     dData[b][dpo+dBandOffsets[b]] = (float) (sum + mat[sbands]);
546                 }
547 
548                 spo += sPixelStride;
549                 dpo += dPixelStride;
550             }
551 
552             sso += sLineStride;
553             dso += dLineStride;
554         }
555     }
556 
557     private void computeRectDouble(RasterAccessor src, RasterAccessor dst) {
558         int sLineStride = src.getScanlineStride();
559         int sPixelStride = src.getPixelStride();
560         int sbands = src.getNumBands();
561         int[] sBandOffsets = src.getBandOffsets();
562         double[][] sData = src.getDoubleDataArrays();
563 
564         int dwidth = dst.getWidth();
565         int dheight = dst.getHeight();
566         int dbands = dst.getNumBands();
567         int dLineStride = dst.getScanlineStride();
568         int dPixelStride = dst.getPixelStride();
569         int[] dBandOffsets = dst.getBandOffsets();
570         double[][] dData = dst.getDoubleDataArrays();
571 
572         int sso = 0, dso = 0;
573 
574         for (int h = 0; h < dheight; h++) {
575             int spo = sso;
576             int dpo = dso;
577 
578             for (int w = 0; w < dwidth; w++) {
579                 for (int b = 0; b < dbands; b++) {
580                     double sum = 0.0D;
581                     double[] mat = matrix[b];
582 
583                     for (int k = 0; k < sbands; k++ ) {
584                         sum += mat[k] * sData[k][spo+sBandOffsets[k]];
585                     }
586 
587                     dData[b][dpo+dBandOffsets[b]] = sum + mat[sbands];
588                 }
589 
590                 spo += sPixelStride;
591                 dpo += dPixelStride;
592             }
593 
594             sso += sLineStride;
595             dso += dLineStride;
596         }
597     }
598 }
599