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