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