1 /* Copyright (C) 2005-2011 Fabio Riccardi */ 2 /* Copyright (C) 2016 Masahiro Kitagawa */ 3 4 package com.lightcrafts.jai.opimage; 5 6 import java.awt.*; 7 import java.awt.color.ColorSpace; 8 import java.awt.image.*; 9 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 public final class FastBilateralFilterOpImage extends AreaOpImage { 19 private final float sigma_d; 20 private final float sigma_r; 21 22 private static final BorderExtender copyExtender = BorderExtender.createInstance(BorderExtender.BORDER_COPY); 23 24 private static final float transform[] = new float[0x10000]; 25 26 static { 27 for (int i = 0; i < 0x10000; i++) { 28 float x = i / (float) 0x10000; 29 transform[i] = (float) (Math.log1p(x)/Math.log(2) + 1.5 * Math.exp(-10*x) * Math.pow(x, 0.7)); 30 } 31 } 32 fblLayout(RenderedImage source)33 private static ImageLayout fblLayout(RenderedImage source) { 34 35 class TwoComponentsColorSpace extends ColorSpace { 36 37 private TwoComponentsColorSpace() { 38 super(ColorSpace.TYPE_2CLR, 2); 39 } 40 41 @Override 42 public float[] toRGB(float[] colorvalue) { 43 if(colorvalue.length < 2) 44 throw new ArrayIndexOutOfBoundsException("colorvalue.length < 2"); 45 return colorvalue; 46 } 47 48 @Override 49 public float[] fromRGB(float[] rgbvalue) { 50 if(rgbvalue.length < 2) 51 throw new ArrayIndexOutOfBoundsException("rgbvalue.length < 3"); 52 return new float[] {rgbvalue[0], rgbvalue[1]}; 53 } 54 55 @Override 56 public float[] toCIEXYZ(float[] colorvalue) { 57 if(colorvalue.length < 2) 58 throw new ArrayIndexOutOfBoundsException("colorvalue.length < 2"); 59 return colorvalue; 60 } 61 62 @Override 63 public float[] fromCIEXYZ(float[] xyzvalue) { 64 if(xyzvalue.length < 2) 65 throw new ArrayIndexOutOfBoundsException("xyzvalue.length < 3"); 66 return new float[] {xyzvalue[0], xyzvalue[1]}; 67 } 68 } 69 70 // SampleModel sm = new ComponentSampleModel(DataBuffer.TYPE_USHORT, source.getWidth(), source.getHeight(), 2, 2*source.getWidth(), new int[]{0, 2}); 71 72 ColorModel cm = new ComponentColorModel(new TwoComponentsColorSpace(), 73 false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); 74 SampleModel sm = cm.createCompatibleSampleModel(source.getWidth(), source.getHeight()); 75 76 return new ImageLayout(source.getMinX(), source.getMinY(), 77 source.getWidth(), source.getHeight(), 78 source.getTileGridXOffset(), source.getTileGridYOffset(), 79 source.getTileWidth(), source.getTileHeight(), 80 sm, cm); 81 } 82 FastBilateralFilterOpImage(RenderedImage source, Map config, float sigma_d, float sigma_r)83 public FastBilateralFilterOpImage(RenderedImage source, Map config, float sigma_d, float sigma_r) { 84 super(source, 85 fblLayout(source), 86 config, 87 true, 88 copyExtender, 89 (int) (2*Math.ceil(sigma_d)), 90 (int) (2*Math.ceil(sigma_d)), 91 (int) (2*Math.ceil(sigma_d)), 92 (int) (2*Math.ceil(sigma_d))); 93 94 this.sigma_d = sigma_d; 95 this.sigma_r = sigma_r; 96 } 97 computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)98 protected void computeRect(Raster[] sources, 99 WritableRaster dest, 100 Rectangle destRect) { 101 // Retrieve format tags. 102 RasterFormatTag[] formatTags = getFormatTags(); 103 104 Raster source = sources[0]; 105 Rectangle srcRect = mapDestRect(destRect, 0); 106 107 RasterAccessor srcAccessor = 108 new RasterAccessor(source, srcRect, formatTags[0], 109 getSourceImage(0).getColorModel()); 110 RasterAccessor dstAccessor = 111 new RasterAccessor(dest, destRect, formatTags[1], 112 this.getColorModel()); 113 114 switch (dstAccessor.getDataType()) { 115 case DataBuffer.TYPE_USHORT: 116 ushortLoop(srcAccessor, dstAccessor); 117 break; 118 default: 119 } 120 121 // If the RasterAccessor object set up a temporary buffer for the 122 // op to write to, tell the RasterAccessor to write that data 123 // to the raster no that we're done with it. 124 if (dstAccessor.isDataCopy()) { 125 dstAccessor.clampDataArrays(); 126 dstAccessor.copyDataToRaster(); 127 } 128 } 129 ushortLoop(RasterAccessor src, RasterAccessor dst)130 protected void ushortLoop(RasterAccessor src, RasterAccessor dst) { 131 int swidth = src.getWidth(); 132 int sheight = src.getHeight(); 133 134 short dstDataArrays[][] = dst.getShortDataArrays(); 135 int dstBandOffsets[] = dst.getBandOffsets(); 136 int dstScanlineStride = dst.getScanlineStride(); 137 138 short srcDataArrays[][] = src.getShortDataArrays(); 139 int srcBandOffsets[] = src.getBandOffsets(); 140 int srcScanlineStride = src.getScanlineStride(); 141 142 short dstData[] = dstDataArrays[0]; 143 short srcData[] = srcDataArrays[0]; 144 145 if (src.getNumBands() == 1) 146 fastBilateralFilterMono(srcData, dstData, 147 sigma_d, sigma_r, 148 swidth, sheight, 149 src.getPixelStride(), dst.getPixelStride(), 150 srcBandOffsets[0], dstBandOffsets[0], 151 srcScanlineStride, dstScanlineStride, 152 transform); 153 // else if (luminosity) 154 // bilateralFilterLuma(srcData, dstData, 155 // wr, ws, scale_r, kernel, 156 // swidth, sheight, 157 // srcBandOffsets[0], srcBandOffsets[1], srcBandOffsets[2], 158 // dstBandOffsets[0], dstBandOffsets[1], dstBandOffsets[2], 159 // srcScanlineStride, dstScanlineStride); 160 else 161 fastBilateralFilterChroma(srcData, dstData, 162 sigma_d, sigma_r, 163 swidth, sheight, 164 src.getPixelStride(), dst.getPixelStride(), 165 srcBandOffsets[0], srcBandOffsets[1], srcBandOffsets[2], 166 dstBandOffsets[0], dstBandOffsets[1], dstBandOffsets[2], 167 srcScanlineStride, dstScanlineStride); 168 } 169 fastBilateralFilterMono(short srcData[], short destData[], float sigma_s, float sigma_r, int width, int height, int srcPixelStride, int destPixelStride, int srcOffset, int destOffset, int srcLineStride, int destLineStride, float transform[])170 static native void fastBilateralFilterMono(short srcData[], short destData[], 171 float sigma_s, float sigma_r, 172 int width, int height, 173 int srcPixelStride, int destPixelStride, 174 int srcOffset, int destOffset, 175 int srcLineStride, int destLineStride, 176 float transform[]); 177 fastBilateralFilterChroma(short srcData[], short destData[], float sigma_s, float sigma_r, int width, int height, int srcPixelStride, int destPixelStride, int srcROffset, int srcGOffset, int srcBOffset, int destROffset, int destGOffset, int destBOffset, int srcLineStride, int destLineStride)178 static native void fastBilateralFilterChroma(short srcData[], short destData[], 179 float sigma_s, float sigma_r, 180 int width, int height, 181 int srcPixelStride, int destPixelStride, 182 int srcROffset, int srcGOffset, int srcBOffset, 183 int destROffset, int destGOffset, int destBOffset, 184 int srcLineStride, int destLineStride); 185 fastBilateralFilterColor(short srcData[], short destData[], float sigma_s, float sigma_r, int width, int height, int srcPixelStride, int destPixelStride, int srcROffset, int srcGOffset, int srcBOffset, int destROffset, int destGOffset, int destBOffset, int srcLineStride, int destLineStride)186 static native void fastBilateralFilterColor(short srcData[], short destData[], 187 float sigma_s, float sigma_r, 188 int width, int height, 189 int srcPixelStride, int destPixelStride, 190 int srcROffset, int srcGOffset, int srcBOffset, 191 int destROffset, int destGOffset, int destBOffset, 192 int srcLineStride, int destLineStride); 193 } 194