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