1 package com.lightcrafts.jai.opimage;
2 
3 /**
4  * Copyright (C) 2010 Light Crafts, Inc.
5  * Author: fabio
6  * 12/22/10 @ 11:20 AM
7  */
8 
9 import com.lightcrafts.image.color.ColorScience;
10 import com.lightcrafts.mediax.jai.*;
11 
12 import java.awt.*;
13 import java.awt.image.DataBuffer;
14 import java.awt.image.Raster;
15 import java.awt.image.RenderedImage;
16 import java.awt.image.WritableRaster;
17 import java.util.Map;
18 
19 public final class BilateralFilterRGBOpImage extends AreaOpImage {
20 
21     private final int y_wr, c_wr; /* window radius */
22     private final int y_ws, c_ws; /* window size */
23     private final float y_kernel[], c_kernel[], y_scale_r, c_scale_r;
24     private final float rgb_to_yst[], yst_to_rgb[];
25 
SQR(float s)26     private static float SQR(float s) { return s * s; }
27 
border(float y_sigma_d, float c_sigma_d)28     private static int border(float y_sigma_d, float c_sigma_d) {
29         return (int) Math.max(Math.ceil(y_sigma_d), Math.ceil(c_sigma_d));
30     }
31 
BilateralFilterRGBOpImage(RenderedImage source, BorderExtender extender, Map config, ImageLayout layout, float y_sigma_d, float y_sigma_r, float c_sigma_d, float c_sigma_r)32     public BilateralFilterRGBOpImage(RenderedImage source,
33                                      BorderExtender extender,
34                                      Map config,
35                                      ImageLayout layout,
36                                      float y_sigma_d, float y_sigma_r, float c_sigma_d, float c_sigma_r) {
37         super(source,
38               layout,
39               config,
40               true,
41               extender,
42               border(y_sigma_d, c_sigma_d),
43               border(y_sigma_d, c_sigma_d),
44               border(y_sigma_d, c_sigma_d),
45               border(y_sigma_d, c_sigma_d));
46 
47         y_wr = (int) Math.ceil(y_sigma_d);   /* window radius */
48         y_ws = 2 * y_wr + 1;		 /* window size */
49 
50         y_kernel = new float[y_ws];
51         for (int i = -y_wr; i <= y_wr; i++)
52             y_kernel[y_wr+i] = (float) (1 / (2 * SQR(y_sigma_d)) * i * i + 0.25);
53         y_scale_r = 1 / (2 * SQR(y_sigma_r));
54 
55         c_wr = (int) Math.ceil(c_sigma_d);   /* window radius */
56         c_ws = 2 * c_wr + 1;		 /* window size */
57 
58         c_kernel = new float[c_ws];
59         for (int i = -c_wr; i <= c_wr; i++)
60             c_kernel[c_wr+i] = (float) (1 / (2 * SQR(c_sigma_d)) * i * i + 0.25);
61         c_scale_r = 1 / (2 * SQR(c_sigma_r));
62 
63         ColorScience.LinearTransform transform = new ColorScience.YST();
64 
65         double[][] rgb2yst = transform.fromRGB(DataBuffer.TYPE_FLOAT);
66         rgb_to_yst = new float[9];
67         for (int i = 0; i < 3; i++)
68             for (int j = 0; j < 3; j++)
69                 rgb_to_yst[3*i+j] = (float) rgb2yst[i][j];
70 
71         double[][] yst2rgb = transform.toRGB(DataBuffer.TYPE_FLOAT);
72         yst_to_rgb = new float[9];
73         for (int i = 0; i < 3; i++)
74             for (int j = 0; j < 3; j++)
75                 yst_to_rgb[3*i+j] = (float) yst2rgb[i][j];
76     }
77 
78     /**
79      * Performs convolution on a specified rectangle. The sources are
80      * cobbled.
81      *
82      * @param sources an array of source Rasters, guaranteed to provide all
83      *                necessary source data for computing the output.
84      * @param dest a WritableRaster tile containing the area to be computed.
85      * @param destRect the rectangle within dest to be processed.
86      */
computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)87     protected void computeRect(Raster[] sources,
88                                WritableRaster dest,
89                                Rectangle destRect) {
90         // Retrieve format tags.
91         RasterFormatTag[] formatTags = getFormatTags();
92 
93         Raster source = sources[0];
94         Rectangle srcRect = mapDestRect(destRect, 0);
95 
96         RasterAccessor srcAccessor =
97                 new RasterAccessor(source, srcRect, formatTags[0],
98                                    getSourceImage(0).getColorModel());
99         RasterAccessor dstAccessor =
100                 new RasterAccessor(dest, destRect, formatTags[1],
101                                    this.getColorModel());
102 
103         switch (dstAccessor.getDataType()) {
104         case DataBuffer.TYPE_USHORT:
105             ushortLoop(srcAccessor, dstAccessor);
106             break;
107         default:
108         }
109 
110         // If the RasterAccessor object set up a temporary buffer for the
111         // op to write to, tell the RasterAccessor to write that data
112         // to the raster no that we're done with it.
113         if (dstAccessor.isDataCopy()) {
114             dstAccessor.clampDataArrays();
115             dstAccessor.copyDataToRaster();
116         }
117     }
118 
ushortLoop(RasterAccessor src, RasterAccessor dst)119     protected void ushortLoop(RasterAccessor src, RasterAccessor dst) {
120         int swidth = src.getWidth();
121         int sheight = src.getHeight();
122 
123         short dstDataArrays[][] = dst.getShortDataArrays();
124         int dstBandOffsets[] = dst.getBandOffsets();
125         int dstScanlineStride = dst.getScanlineStride();
126 
127         short srcDataArrays[][] = src.getShortDataArrays();
128         int srcBandOffsets[] = src.getBandOffsets();
129         int srcScanlineStride = src.getScanlineStride();
130 
131         short dstData[] = dstDataArrays[0];
132         short srcData[] = srcDataArrays[0];
133 
134         if (src.getNumBands() == 3)
135             bilateralFilterRGB(srcData, dstData,
136                     y_wr, c_wr, y_ws, c_ws,
137                     4 * y_scale_r, 4 * c_scale_r,
138                     y_kernel, c_kernel,
139                     rgb_to_yst, yst_to_rgb,
140                     swidth, sheight,
141                     srcBandOffsets[0], srcBandOffsets[1], srcBandOffsets[2],
142                     dstBandOffsets[0], dstBandOffsets[1], dstBandOffsets[2],
143                     srcScanlineStride, dstScanlineStride);
144     }
145 
bilateralFilterRGB(short srcData[], short destData[], int y_wr, int c_wr, int y_ws, int c_ws, float y_scale_r, float c_scale_r, float y_kernel[], float c_kernel[], float rgb_to_yst[], float yst_to_rgb[], int width, int height, int srcROffset, int srcGOffset, int srcBOffset, int destROffset, int destGOffset, int destBOffset, int srcLineStride, int destLineStride)146     static native void bilateralFilterRGB(short srcData[], short destData[],
147                                     int y_wr, int c_wr, int y_ws, int c_ws,
148                                     float y_scale_r, float c_scale_r,
149                                     float y_kernel[], float c_kernel[],
150                                     float rgb_to_yst[], float yst_to_rgb[],
151                                     int width, int height,
152                                     int srcROffset, int srcGOffset, int srcBOffset,
153                                     int destROffset, int destGOffset, int destBOffset,
154                                     int srcLineStride, int destLineStride);
155 }
156