1 /* Copyright (C) 2005-2011 Fabio Riccardi */ 2 3 package com.lightcrafts.jai.opimage; 4 5 import java.awt.Rectangle; 6 import java.awt.image.DataBuffer; 7 import java.awt.image.Raster; 8 import java.awt.image.RenderedImage; 9 import java.awt.image.WritableRaster; 10 import com.lightcrafts.mediax.jai.AreaOpImage; 11 import com.lightcrafts.mediax.jai.BorderExtender; 12 import com.lightcrafts.mediax.jai.ImageLayout; 13 import com.lightcrafts.mediax.jai.RasterAccessor; 14 import com.lightcrafts.mediax.jai.RasterFormatTag; 15 16 import java.util.Map; 17 18 /** 19 * An OpImage class to perform separable convolve on a source image. 20 */ 21 final class BilateralFilterOpImage2 extends AreaOpImage { 22 private int wr; /* window radius */ 23 private int ws; /* window size */ 24 private float kernel[], scale_r, elut[]; 25 SQR(double x)26 private static double SQR(double x) { 27 return x * x; 28 } 29 BilateralFilterOpImage2(RenderedImage source, BorderExtender extender, Map config, ImageLayout layout, float sigma_d, float sigma_r)30 public BilateralFilterOpImage2(RenderedImage source, 31 BorderExtender extender, 32 Map config, 33 ImageLayout layout, 34 float sigma_d, float sigma_r) { 35 super(source, 36 layout, 37 config, 38 true, 39 extender, 40 (int) Math.ceil(sigma_d * 2), 41 (int) Math.ceil(sigma_d * 2), 42 (int) Math.ceil(sigma_d * 2), 43 (int) Math.ceil(sigma_d * 2)); 44 45 wr = (int) Math.ceil(sigma_d * 2); /* window radius */ 46 ws = 2 * wr + 1; /* window size */ 47 48 kernel = new float[ws]; 49 50 kernel = new float[ws]; 51 for (int i = -wr; i <= wr; i++) 52 kernel[wr + i] = (float) (256 / (2 * SQR(sigma_d)) * i * i + 0.25); 53 scale_r = (float) (256 / (2 * SQR(sigma_r))); 54 elut = new float[0x1000]; 55 for (int i = 0; i < 0x1000; i++) 56 elut[i] = (float) Math.exp(-i / 256.0); 57 58 } 59 60 /** 61 * Performs convolution on a specified rectangle. The sources are 62 * cobbled. 63 * 64 * @param sources an array of source Rasters, guaranteed to provide all 65 * necessary source data for computing the output. 66 * @param dest a WritableRaster tile containing the area to be computed. 67 * @param destRect the rectangle within dest to be processed. 68 */ computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)69 protected void computeRect(Raster[] sources, 70 WritableRaster dest, 71 Rectangle destRect) { 72 // Retrieve format tags. 73 RasterFormatTag[] formatTags = getFormatTags(); 74 75 Raster source = sources[0]; 76 Rectangle srcRect = mapDestRect(destRect, 0); 77 78 79 RasterAccessor srcAccessor = 80 new RasterAccessor(source, srcRect, formatTags[0], 81 getSourceImage(0).getColorModel()); 82 RasterAccessor dstAccessor = 83 new RasterAccessor(dest, destRect, formatTags[1], 84 this.getColorModel()); 85 86 switch (dstAccessor.getDataType()) { 87 case DataBuffer.TYPE_USHORT: 88 ushortLoop(srcAccessor, dstAccessor); 89 break; 90 91 default: 92 } 93 94 // If the RasterAccessor object set up a temporary buffer for the 95 // op to write to, tell the RasterAccessor to write that data 96 // to the raster no that we're done with it. 97 if (dstAccessor.isDataCopy()) { 98 dstAccessor.clampDataArrays(); 99 dstAccessor.copyDataToRaster(); 100 } 101 } 102 ushortLoop(RasterAccessor src, RasterAccessor dst)103 protected void ushortLoop(RasterAccessor src, 104 RasterAccessor dst) { 105 int dwidth = dst.getWidth(); 106 int dheight = dst.getHeight(); 107 108 short dstDataArrays[][] = dst.getShortDataArrays(); 109 int dstBandOffsets[] = dst.getBandOffsets(); 110 int dstPixelStride = dst.getPixelStride(); 111 int dstScanlineStride = dst.getScanlineStride(); 112 113 short srcDataArrays[][] = src.getShortDataArrays(); 114 int srcBandOffsets[] = src.getBandOffsets(); 115 int srcPixelStride = src.getPixelStride(); 116 int srcScanlineStride = src.getScanlineStride(); 117 float tmpBuffer[][] = new float[3][ws * dwidth]; 118 int tmpBufferSize = ws * dwidth; 119 120 short dstData[] = dstDataArrays[0]; 121 short srcData[] = srcDataArrays[0]; 122 int srcScanlineOffset = srcBandOffsets[0]; 123 int dstScanlineOffset = dstBandOffsets[0]; 124 125 int revolver = 0; 126 int kvRevolver = 0; // to match kernel vValues 127 for (int j = 0; j < ws - 1; j++) { 128 int srcPixelOffset = srcScanlineOffset; 129 130 for (int i = 0; i < dwidth; i++) { 131 int imageOffset = srcPixelOffset; 132 float sa = 0, sb = 0, ss = 0; 133 int g0 = srcData[wr + imageOffset + 1] & 0xffff; 134 int a0 = g0 - (srcData[wr + imageOffset] & 0xffff); 135 int b0 = g0 - (srcData[wr + imageOffset + 2] & 0xffff); 136 for (int v = 0; v < ws; v++) { 137 int g = srcData[imageOffset + 1] & 0xffff; 138 int a = g - (srcData[imageOffset] & 0xffff); 139 int b = g - (srcData[imageOffset + 2] & 0xffff); 140 141 int sep = ((int) ((SQR(a - a0) + SQR(b - b0)) * scale_r + kernel[wr] + kernel[v])) / 0x10000; 142 if (sep < 0x1000) { 143 float exp = elut[sep]; 144 sa += exp * a; 145 sb += exp * b; 146 ss += exp; 147 } 148 imageOffset += srcPixelStride; 149 } 150 tmpBuffer[0][revolver + i] = g0; 151 tmpBuffer[1][revolver + i] = sa/ss; 152 tmpBuffer[2][revolver + i] = sb/ss; 153 154 srcPixelOffset += srcPixelStride; 155 } 156 revolver += dwidth; 157 srcScanlineOffset += srcScanlineStride; 158 } 159 160 // srcScanlineStride already bumped by 161 // ws-1*scanlineStride 162 163 for (int j = 0; j < dheight; j++) { 164 int srcPixelOffset = srcScanlineOffset; 165 int dstPixelOffset = dstScanlineOffset; 166 167 for (int i = 0; i < dwidth; i++) { 168 int imageOffset = srcPixelOffset; 169 float sa = 0, sb = 0, ss = 0; 170 float g0 = srcData[wr + imageOffset + 1] & 0xffff; 171 float a0 = g0 - (srcData[wr + imageOffset] & 0xffff); 172 float b0 = g0 - (srcData[wr + imageOffset + 2] & 0xffff); 173 for (int v = 0; v < ws; v++) { 174 float g = srcData[imageOffset + 1] & 0xffff; 175 float a = g - (srcData[imageOffset] & 0xffff); 176 float b = g - (srcData[imageOffset + 2] & 0xffff); 177 178 int sep = ((int) ((SQR(a - a0) + SQR(b - b0)) * scale_r + kernel[wr] + kernel[v])) / 0x10000; 179 if (sep < 0x1000) { 180 float exp = elut[sep]; 181 sa += exp * a; 182 sb += exp * b; 183 ss += exp; 184 } 185 imageOffset += srcPixelStride; 186 } 187 tmpBuffer[0][revolver + i] = g0; 188 tmpBuffer[1][revolver + i] = sa/ss; 189 tmpBuffer[2][revolver + i] = sb/ss; 190 191 int bb = kvRevolver + i; 192 sa = sb = ss = 0; 193 194 int idx0 = bb; 195 for (int m = 0; m < wr; m++) { 196 idx0 += dwidth; 197 if (idx0 >= tmpBufferSize) idx0 -= tmpBufferSize; 198 } 199 g0 = tmpBuffer[0][idx0]; 200 a0 = tmpBuffer[1][idx0]; 201 b0 = tmpBuffer[2][idx0]; 202 203 for (int aa = 0; aa < ws; aa++) { 204 float a = tmpBuffer[1][bb]; 205 float b = tmpBuffer[2][bb]; 206 int sep = ((int) ((SQR(a - a0) + SQR(b - b0)) * scale_r + kernel[wr] + kernel[aa])) / 0x10000; 207 if (sep < 0x1000) { 208 float exp = elut[sep]; 209 sa += exp * a; 210 sb += exp * b; 211 ss += exp; 212 } 213 bb += dwidth; 214 if (bb >= tmpBufferSize) bb -= tmpBufferSize; 215 } 216 217 int g = (int) g0; 218 int r = g - (int) (sa / ss); 219 int b = g - (int) (sb / ss); 220 221 dstData[dstPixelOffset+0] = (short) (0xffff & (r < 0 ? 0 : r > 0xffff ? 0xffff : r)); 222 dstData[dstPixelOffset+1] = (short) (0xffff & g); 223 dstData[dstPixelOffset+2] = (short) (0xffff & (b < 0 ? 0 : b > 0xffff ? 0xffff : b)); 224 225 srcPixelOffset += srcPixelStride; 226 dstPixelOffset += dstPixelStride; 227 } 228 revolver += dwidth; 229 if (revolver == tmpBufferSize) { 230 revolver = 0; 231 } 232 kvRevolver += dwidth; 233 if (kvRevolver == tmpBufferSize) { 234 kvRevolver = 0; 235 } 236 srcScanlineOffset += srcScanlineStride; 237 dstScanlineOffset += dstScanlineStride; 238 } 239 } 240 } 241