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