1 /* Copyright (C) 2005-2011 Fabio Riccardi */ 2 3 /* 4 * $RCSfile: SeparableConvolveOpImage.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:43 $ 12 * $State: Exp $ 13 */ 14 package com.lightcrafts.jai.opimage; 15 import java.awt.Rectangle; 16 import java.awt.image.DataBuffer; 17 import java.awt.image.Raster; 18 import java.awt.image.RenderedImage; 19 import java.awt.image.WritableRaster; 20 import com.lightcrafts.mediax.jai.AreaOpImage; 21 import com.lightcrafts.mediax.jai.BorderExtender; 22 import com.lightcrafts.mediax.jai.ImageLayout; 23 import com.lightcrafts.mediax.jai.RasterAccessor; 24 import com.lightcrafts.mediax.jai.RasterFormatTag; 25 import com.lightcrafts.mediax.jai.KernelJAI; 26 import java.util.Map; 27 // import com.lightcrafts.media.jai.test.OpImageTester; 28 29 /** 30 * An OpImage class to perform separable convolve on a source image. 31 * 32 * 33 */ 34 final class LCSeparableConvolveOpImage extends AreaOpImage { 35 36 static { 37 System.loadLibrary("JAI"); 38 } 39 40 protected KernelJAI kernel; 41 protected int kw, kh, kx, ky; 42 43 private float hValues[]; 44 private float vValues[]; 45 46 /** 47 * Creates a SeparableConvoveOpImage on the source 48 * with the given pre-rotated kernel. The image dimensions are 49 * derived the source image. The tile grid layout, SampleModel, and 50 * ColorModel may optionally be specified by an ImageLayout 51 * object. 52 * 53 * @param source a RenderedImage. 54 * @param extender a BorderExtender, or null. 55 * @param layout an ImageLayout optionally containing the tile grid layout, 56 * SampleModel, and ColorModel, or null. 57 * @param kernel a pre-rotated convolution kernel 58 */ LCSeparableConvolveOpImage(RenderedImage source, BorderExtender extender, Map config, ImageLayout layout, KernelJAI kernel)59 public LCSeparableConvolveOpImage(RenderedImage source, 60 BorderExtender extender, 61 Map config, 62 ImageLayout layout, 63 KernelJAI kernel) { 64 super(source, 65 layout, 66 config, 67 true, 68 extender, 69 kernel.getLeftPadding(), 70 kernel.getRightPadding(), 71 kernel.getTopPadding(), 72 kernel.getBottomPadding()); 73 74 this.kernel = kernel; 75 kw = kernel.getWidth(); 76 kh = kernel.getHeight(); 77 kx = kernel.getXOrigin(); 78 ky = kernel.getYOrigin(); 79 80 hValues = kernel.getHorizontalKernelData(); 81 82 vValues = kernel.getVerticalKernelData(); 83 } 84 85 /** 86 * Performs convolution on a specified rectangle. The sources are 87 * cobbled. 88 * 89 * @param sources an array of source Rasters, guaranteed to provide all 90 * necessary source data for computing the output. 91 * @param dest a WritableRaster tile containing the area to be computed. 92 * @param destRect the rectangle within dest to be processed. 93 */ computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)94 protected void computeRect(Raster[] sources, 95 WritableRaster dest, 96 Rectangle destRect) { 97 // Retrieve format tags. 98 RasterFormatTag[] formatTags = getFormatTags(); 99 100 Raster source = sources[0]; 101 Rectangle srcRect = mapDestRect(destRect, 0); 102 103 104 RasterAccessor srcAccessor = 105 new RasterAccessor(source, srcRect, formatTags[0], 106 getSourceImage(0).getColorModel()); 107 RasterAccessor dstAccessor = 108 new RasterAccessor(dest, destRect, formatTags[1], 109 this.getColorModel()); 110 111 switch (dstAccessor.getDataType()) { 112 case DataBuffer.TYPE_BYTE: 113 byteLoop(srcAccessor, dstAccessor); 114 break; 115 case DataBuffer.TYPE_INT: 116 intLoop(srcAccessor, dstAccessor); 117 break; 118 case DataBuffer.TYPE_SHORT: 119 shortLoop(srcAccessor, dstAccessor); 120 break; 121 case DataBuffer.TYPE_USHORT: 122 ushortLoop(srcAccessor, dstAccessor); 123 break; 124 case DataBuffer.TYPE_FLOAT: 125 floatLoop(srcAccessor, dstAccessor); 126 break; 127 case DataBuffer.TYPE_DOUBLE: 128 doubleLoop(srcAccessor, dstAccessor); 129 break; 130 131 default: 132 } 133 134 // If the RasterAccessor object set up a temporary buffer for the 135 // op to write to, tell the RasterAccessor to write that data 136 // to the raster no that we're done with it. 137 if (dstAccessor.isDataCopy()) { 138 dstAccessor.clampDataArrays(); 139 dstAccessor.copyDataToRaster(); 140 } 141 } 142 143 private final boolean INTERLEAVED3OPT = true; 144 byteLoop(RasterAccessor src, RasterAccessor dst)145 protected void byteLoop(RasterAccessor src, 146 RasterAccessor dst) { 147 int dwidth = dst.getWidth(); 148 int dheight = dst.getHeight(); 149 int dnumBands = dst.getNumBands(); 150 151 byte dstDataArrays[][] = dst.getByteDataArrays(); 152 int dstBandOffsets[] = dst.getBandOffsets(); 153 int dstPixelStride = dst.getPixelStride(); 154 int dstScanlineStride = dst.getScanlineStride(); 155 156 byte srcDataArrays[][] = src.getByteDataArrays(); 157 int srcBandOffsets[] = src.getBandOffsets(); 158 int srcPixelStride = src.getPixelStride(); 159 int srcScanlineStride = src.getScanlineStride(); 160 161 if (INTERLEAVED3OPT && dstPixelStride == 3 && dstPixelStride == srcPixelStride) { 162 int band0 = 0; 163 for (int k = 1; k < dnumBands; k++) 164 if (dstBandOffsets[k] < dstBandOffsets[band0]) 165 band0 = k; 166 167 byte dstData[] = dstDataArrays[band0]; 168 byte srcData[] = srcDataArrays[band0]; 169 int srcScanlineOffset = srcBandOffsets[band0]; 170 int dstScanlineOffset = dstBandOffsets[band0]; 171 172 Convolutions.cInterleaved3ByteLoop(srcData, dstData, 173 srcScanlineOffset, dstScanlineOffset, 174 srcScanlineStride, dstScanlineStride, 175 dheight, dwidth, kw, kh, hValues, vValues); 176 } else 177 for (int k = 0; k < dnumBands; k++) { 178 byte dstData[] = dstDataArrays[k]; 179 byte srcData[] = srcDataArrays[k]; 180 int srcScanlineOffset = srcBandOffsets[k]; 181 int dstScanlineOffset = dstBandOffsets[k]; 182 183 Convolutions.cByteLoop(srcData, dstData, 184 srcScanlineOffset, dstScanlineOffset, 185 srcScanlineStride, dstScanlineStride, 186 srcPixelStride, dstPixelStride, 187 dheight, dwidth, kw, kh, hValues, vValues); 188 } 189 } 190 191 192 shortLoop(RasterAccessor src, RasterAccessor dst)193 protected void shortLoop(RasterAccessor src, 194 RasterAccessor dst) { 195 int dwidth = dst.getWidth(); 196 int dheight = dst.getHeight(); 197 int dnumBands = dst.getNumBands(); 198 199 short dstDataArrays[][] = dst.getShortDataArrays(); 200 int dstBandOffsets[] = dst.getBandOffsets(); 201 int dstPixelStride = dst.getPixelStride(); 202 int dstScanlineStride = dst.getScanlineStride(); 203 204 short srcDataArrays[][] = src.getShortDataArrays(); 205 int srcBandOffsets[] = src.getBandOffsets(); 206 int srcPixelStride = src.getPixelStride(); 207 int srcScanlineStride = src.getScanlineStride(); 208 209 if (INTERLEAVED3OPT && dstPixelStride == 3 && dstPixelStride == srcPixelStride) { 210 int band0 = 0; 211 for (int k = 1; k < dnumBands; k++) 212 if (dstBandOffsets[k] < dstBandOffsets[band0]) 213 band0 = k; 214 215 short dstData[] = dstDataArrays[band0]; 216 short srcData[] = srcDataArrays[band0]; 217 int srcScanlineOffset = srcBandOffsets[band0]; 218 int dstScanlineOffset = dstBandOffsets[band0]; 219 220 Convolutions.cInterleaved3ShortLoop(srcData, dstData, 221 srcScanlineOffset, dstScanlineOffset, 222 srcScanlineStride, dstScanlineStride, 223 dheight, dwidth, kw, kh, hValues, vValues); 224 } else 225 for (int k = 0; k < dnumBands; k++) { 226 short dstData[] = dstDataArrays[k]; 227 short srcData[] = srcDataArrays[k]; 228 int srcScanlineOffset = srcBandOffsets[k]; 229 int dstScanlineOffset = dstBandOffsets[k]; 230 231 Convolutions.cShortLoop(srcData, dstData, 232 srcScanlineOffset, dstScanlineOffset, 233 srcScanlineStride, dstScanlineStride, 234 srcPixelStride, dstPixelStride, 235 dheight, dwidth, kw, kh, hValues, vValues); 236 } 237 238 239 } 240 ushortLoop(RasterAccessor src, RasterAccessor dst)241 protected void ushortLoop(RasterAccessor src, 242 RasterAccessor dst) { 243 int dwidth = dst.getWidth(); 244 int dheight = dst.getHeight(); 245 int dnumBands = dst.getNumBands(); 246 247 short dstDataArrays[][] = dst.getShortDataArrays(); 248 int dstBandOffsets[] = dst.getBandOffsets(); 249 int dstPixelStride = dst.getPixelStride(); 250 int dstScanlineStride = dst.getScanlineStride(); 251 252 short srcDataArrays[][] = src.getShortDataArrays(); 253 int srcBandOffsets[] = src.getBandOffsets(); 254 int srcPixelStride = src.getPixelStride(); 255 int srcScanlineStride = src.getScanlineStride(); 256 257 if (INTERLEAVED3OPT && dstPixelStride == 3 && dstPixelStride == srcPixelStride) { 258 int band0 = 0; 259 for (int k = 1; k < dnumBands; k++) 260 if (dstBandOffsets[k] < dstBandOffsets[band0]) 261 band0 = k; 262 263 short dstData[] = dstDataArrays[band0]; 264 short srcData[] = srcDataArrays[band0]; 265 int srcScanlineOffset = srcBandOffsets[band0]; 266 int dstScanlineOffset = dstBandOffsets[band0]; 267 268 Convolutions.cInterleaved3UShortLoop(srcData, dstData, 269 srcScanlineOffset, dstScanlineOffset, 270 srcScanlineStride, dstScanlineStride, 271 dheight, dwidth, kw, kh, hValues, vValues); 272 } else 273 for (int k = 0; k < dnumBands; k++) { 274 short dstData[] = dstDataArrays[k]; 275 short srcData[] = srcDataArrays[k]; 276 int srcScanlineOffset = srcBandOffsets[k]; 277 int dstScanlineOffset = dstBandOffsets[k]; 278 279 Convolutions.cUShortLoop(srcData, dstData, 280 srcScanlineOffset, dstScanlineOffset, 281 srcScanlineStride, dstScanlineStride, 282 srcPixelStride, dstPixelStride, 283 dheight, dwidth, kw, kh, hValues, vValues); 284 } 285 } 286 intLoop(RasterAccessor src, RasterAccessor dst)287 protected void intLoop(RasterAccessor src, 288 RasterAccessor dst) { 289 int dwidth = dst.getWidth(); 290 int dheight = dst.getHeight(); 291 int dnumBands = dst.getNumBands(); 292 293 int dstDataArrays[][] = dst.getIntDataArrays(); 294 int dstBandOffsets[] = dst.getBandOffsets(); 295 int dstPixelStride = dst.getPixelStride(); 296 int dstScanlineStride = dst.getScanlineStride(); 297 298 int srcDataArrays[][] = src.getIntDataArrays(); 299 int srcBandOffsets[] = src.getBandOffsets(); 300 int srcPixelStride = src.getPixelStride(); 301 int srcScanlineStride = src.getScanlineStride(); 302 303 if (INTERLEAVED3OPT && dstPixelStride == 3 && dstPixelStride == srcPixelStride) { 304 int band0 = 0; 305 for (int k = 1; k < dnumBands; k++) 306 if (dstBandOffsets[k] < dstBandOffsets[band0]) 307 band0 = k; 308 309 int dstData[] = dstDataArrays[band0]; 310 int srcData[] = srcDataArrays[band0]; 311 int srcScanlineOffset = srcBandOffsets[band0]; 312 int dstScanlineOffset = dstBandOffsets[band0]; 313 314 Convolutions.cInterleaved3IntLoop(srcData, dstData, 315 srcScanlineOffset, dstScanlineOffset, 316 srcScanlineStride, dstScanlineStride, 317 dheight, dwidth, kw, kh, hValues, vValues); 318 } else 319 for (int k = 0; k < dnumBands; k++) { 320 int dstData[] = dstDataArrays[k]; 321 int srcData[] = srcDataArrays[k]; 322 int srcScanlineOffset = srcBandOffsets[k]; 323 int dstScanlineOffset = dstBandOffsets[k]; 324 325 Convolutions.cIntLoop(srcData, dstData, 326 srcScanlineOffset, dstScanlineOffset, 327 srcScanlineStride, dstScanlineStride, 328 srcPixelStride, dstPixelStride, 329 dheight, dwidth, kw, kh, hValues, vValues); 330 } 331 332 } 333 floatLoop(RasterAccessor src, RasterAccessor dst)334 protected void floatLoop(RasterAccessor src, 335 RasterAccessor dst) { 336 int dwidth = dst.getWidth(); 337 int dheight = dst.getHeight(); 338 int dnumBands = dst.getNumBands(); 339 340 float dstDataArrays[][] = dst.getFloatDataArrays(); 341 int dstBandOffsets[] = dst.getBandOffsets(); 342 int dstPixelStride = dst.getPixelStride(); 343 int dstScanlineStride = dst.getScanlineStride(); 344 345 float srcDataArrays[][] = src.getFloatDataArrays(); 346 int srcBandOffsets[] = src.getBandOffsets(); 347 int srcPixelStride = src.getPixelStride(); 348 int srcScanlineStride = src.getScanlineStride(); 349 350 for (int k = 0; k < dnumBands; k++) { 351 float dstData[] = dstDataArrays[k]; 352 float srcData[] = srcDataArrays[k]; 353 int srcScanlineOffset = srcBandOffsets[k]; 354 int dstScanlineOffset = dstBandOffsets[k]; 355 356 Convolutions.cFloatLoop(srcData, dstData, 357 srcScanlineOffset, dstScanlineOffset, 358 srcScanlineStride, dstScanlineStride, 359 srcPixelStride, dstPixelStride, 360 dheight, dwidth, kw, kh, hValues, vValues); 361 } 362 } 363 doubleLoop(RasterAccessor src, RasterAccessor dst)364 protected void doubleLoop(RasterAccessor src, 365 RasterAccessor dst) { 366 int dwidth = dst.getWidth(); 367 int dheight = dst.getHeight(); 368 int dnumBands = dst.getNumBands(); 369 370 double dstDataArrays[][] = dst.getDoubleDataArrays(); 371 int dstBandOffsets[] = dst.getBandOffsets(); 372 int dstPixelStride = dst.getPixelStride(); 373 int dstScanlineStride = dst.getScanlineStride(); 374 375 double srcDataArrays[][] = src.getDoubleDataArrays(); 376 int srcBandOffsets[] = src.getBandOffsets(); 377 int srcPixelStride = src.getPixelStride(); 378 int srcScanlineStride = src.getScanlineStride(); 379 380 for (int k = 0; k < dnumBands; k++) { 381 double dstData[] = dstDataArrays[k]; 382 double srcData[] = srcDataArrays[k]; 383 int srcScanlineOffset = srcBandOffsets[k]; 384 int dstScanlineOffset = dstBandOffsets[k]; 385 386 Convolutions.cDoubleLoop(srcData, dstData, 387 srcScanlineOffset, dstScanlineOffset, 388 srcScanlineStride, dstScanlineStride, 389 srcPixelStride, dstPixelStride, 390 dheight, dwidth, kw, kh, hValues, vValues); 391 } 392 } 393 394 // public static OpImage createTestImage(OpImageTester oit) { 395 // float data[] = {0.05f,0.10f,0.05f, 396 // 0.10f,0.20f,0.10f, 397 // 0.05f,0.10f,0.05f}; 398 // KernelJAI kJAI = new KernelJAI(3,3,1,1,data); 399 // return new SeparableConvolveOpImage(oit.getSource(), null, null, 400 // new ImageLayout(oit.getSource()), 401 // kJAI); 402 // } 403 404 // public static void main(String args[]) { 405 // String classname = "com.lightcrafts.media.jai.opimage.SeparableConvolveOpImage"; 406 // OpImageTester.performDiagnostics(classname,args); 407 // } 408 } 409