// Catalano Imaging Library
// The Catalano Framework
//
// Copyright © Diego Catalano, 2012-2016
// diego.catalano at live.com
//
// Copyright © Wayne Rasband, 2010
// wsr at nih.gov
//
//    This library is free software; you can redistribute it and/or
//    modify it under the terms of the GNU Lesser General Public
//    License as published by the Free Software Foundation; either
//    version 2.1 of the License, or (at your option) any later version.
//
//    This library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//    Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public
//    License along with this library; if not, write to the Free Software
//    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//

package Catalano.Imaging.Filters;

import Catalano.Imaging.FastBitmap;
import Catalano.Imaging.IApplyInPlace;

/**
 * Kuwahara filter is able to apply smoothing on the image while preserving the edges.
 * @author Diego Catalano
 */
public class Kuwahara implements IApplyInPlace{
    
    private int windowSize = 5;

    /**
     * Initialize a new instance of the Kuwahara class.
     * Default window size is 5x5;
     */
    public Kuwahara() {}

    /**
     * Initialize a new instance of the Kuwahara class.
     * @param windowSize Window size.
     */
    public Kuwahara(int windowSize) {
        this.windowSize = Math.max(windowSize, 5);
    }

    @Override
    public void applyInPlace(FastBitmap fastBitmap) {
        
        int width = fastBitmap.getWidth();
        int height = fastBitmap.getHeight();
        int size2 = (windowSize+1)/2;
        int offset = (windowSize-1)/2;
        
        FastBitmap copy = new FastBitmap(fastBitmap);
        
        if (fastBitmap.isRGB()) {
            int width2 = width+offset;
            int height2 = height+offset;
            float[][][] mean = new float[width2][height2][3];
            float[][][] variance = new float[width2][height2][3];
            double sumR, sum2R;
            double sumG, sum2G;
            double sumB, sum2B;
            int n, r,g,b, xbase, ybase;
            for (int y1=0-offset; y1<0+height; y1++) {
                for (int x1=0-offset; x1<0+width; x1++) {
                    sumR=sumG=sumB=0;
                    sum2R=sum2G=sum2B=0;
                    n=0;
                    for (int x2=x1; x2 0 && x2 < width && y2 > 0 && y2 < height){
                                r = copy.getRed(y2, x2);
                                g = copy.getGreen(y2, x2);
                                b = copy.getBlue(y2, x2);
                                
                                sumR += r;
                                sum2R += r*r;
                                
                                sumG += g;
                                sum2G += g*g;
                                
                                sumB += b;
                                sum2B += b*b;
                                
                                n++;
                            }
                            else{
                                n++;
                            }
                        }
                    }
                    mean[x1+offset][y1+offset][0] = (float)(sumR/n);
                    mean[x1+offset][y1+offset][1] = (float)(sumG/n);
                    mean[x1+offset][y1+offset][2] = (float)(sumB/n);
                    
                    variance[x1+offset][y1+offset][0] = (float)(sum2R-sumR*sumR/n);
                    variance[x1+offset][y1+offset][1] = (float)(sum2G-sumG*sumG/n);
                    variance[x1+offset][y1+offset][2] = (float)(sum2B-sumB*sumB/n);
                }
            }
            
            int xbase2=0, ybase2=0;
            float var, min;
            for (int y1=0; y1<0+height; y1++) {
                for (int x1=0; x1<0+width; x1++) {
                    
                    //Red channel
                    min = Float.MAX_VALUE;
                    xbase = x1; ybase=y1;
                    var = variance[xbase][ybase][0];
                    if (var 0 && x2 < width && y2 > 0 && y2 < height){
                                v = copy.getGray(y2, x2);
                                sum += v;
                                sum2 += v*v;
                                n++;
                            }
                            else{
                                v = 0;
                                sum += v;
                                sum2 += v*v;
                                n++;
                            }
                        }
                    }
                    mean[x1+offset][y1+offset] = (float)(sum/n);
                    variance[x1+offset][y1+offset] = (float)(sum2-sum*sum/n);
                }
            }
            
            int xbase2=0, ybase2=0;
            float var, min;
            for (int y1=0; y1<0+height; y1++) {
                for (int x1=0; x1<0+width; x1++) {
                    min = Float.MAX_VALUE;
                    xbase = x1; ybase=y1;
                    var = variance[xbase][ybase];
                    if (var 

Ads help maintain this website.