// Catalano Imaging Library
// The Catalano Framework
//
// Copyright © Diego Catalano, 2012-2016
// diego.catalano at live.com
//
// Copyright © Max Bügler, 2010-2013
// max at maxbuegler.eu
//
//    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;
import Catalano.Math.Functions.Gabor;
import Catalano.Math.Functions.Gabor.Config;

/**
 * Gabor Filter.
 * 
 *  In image processing, a Gabor filter, named after Dennis Gabor, is a linear filter used for edge detection.
 * Frequency and orientation representations of Gabor filters are similar to those of the human visual system,
 * and they have been found to be particularly appropriate for texture representation and discrimination.
 * In the spatial domain, a 2D Gabor filter is a Gaussian kernel function modulated by a sinusoidal plane wave. 
 * 
 * @see http://en.wikipedia.org/wiki/Gabor_filter
 * @author Diego Catalano
 */
public class GaborFilter implements IApplyInPlace{
    
    // Size of kernel
    private int size = 3;
    
    // Wavelength
    private double lambda = 4.0;
    
    // Orientation
    private double theta = 0.6;
    
    // Phase offset
    private double psi = 1.0;
    
    // Gaussian variance
    private double sigma = 2.0;
    
    // Aspect ratio
    private double gamma = 0.3;
    private Gabor.Config config = Gabor.Config.Imaginary;
    private boolean signed = false;

    /**
     * Get size of Gabor kernel.
     * @return Size.
     */
    public int getSize() {
        return size;
    }

    /**
     * Set size of Gabor kernel.
     * @param size Size.
     */
    public void setSize(int size) {
        this.size = size;
    }

    /**
     * Get Wavelength (Lambda).
     * @return Lambda value.
     */
    public double getWavelength() {
        return lambda;
    }

    /**
     * Set Wavelength (Lambda).
     * @param lambda Lambda value.
     */
    public void setWavelength(double lambda) {
        this.lambda = lambda;
    }

    /**
     * Get Orientation (Theta).
     * @return Theta value.
     */
    public double getOrientation() {
        return theta;
    }

    /**
     * Set Orientation (Theta).
     * @param theta Theta value.
     */
    public void setOrientation(double theta) {
        this.theta = theta;
    }

    /**
     * Get Phase offset (Psi).
     * @return Phi value.
     */
    public double getPhaseOffset() {
        return psi;
    }

    /**
     * Set Phase offset (Psi).
     * @param phi 
     */
    public void setPhaseOffset(double psi) {
        this.psi = psi;
    }

    /**
     * Get Gaussian variance (Sigma).
     * @return Sigma value.
     */
    public double getGaussianVar() {
        return sigma;
    }

    /**
     * Set Gaussian variance (Sigma).
     * @param sigma Sigma value.
     */
    public void setGaussianVar(double sigma) {
        this.sigma = sigma;
    }

    /**
     * Get Aspect ratio (Gamma).
     * @return gamma.
     */
    public double getAspectRatio() {
        return gamma;
    }

    /**
     * Set Aspect ratio (Gamma).
     * @param gamma Gamma.
     */
    public void setAspectRatio(double gamma) {
        this.gamma = gamma;
    }

    /**
     * Get Gabor function configuration.
     * @return Configuration.
     */
    public Config getConfig() {
        return config;
    }

    /**
     * Set Gabor function configuration.
     * @param config Configuration.
     */
    public void setConfig(Config config) {
        this.config = config;
    }

    /**
     * Verify if the image is signed.
     * @return True if the image is signed, otherwise false.
     */
    public boolean isSigned() {
        return signed;
    }

    /**
     * Set signed image.
     * If true, image will be converted to RGB.
     * @param signed True for signed image, false for grayscale image.
     */
    public void setSigned(boolean signed) {
        this.signed = signed;
    }

    /**
     * Initializes a new instance of the GaborFilterFinal class.
     */
    public GaborFilter() {}

    /**
     * Initializes a new instance of the GaborFilterFinal class.
     * @param wavelength Wavelength.
     */
    public GaborFilter(double wavelength) {
        this.lambda = wavelength;
    }

    /**
     * Initializes a new instance of the GaborFilterFinal class.
     * @param wavelength Wavelength.
     * @param orientation Orientation.
     */
    public GaborFilter(double wavelength, double orientation) {
        this.lambda = wavelength;
        this.theta = orientation;
    }

    /**
     * Initializes a new instance of the GaborFilterFinal class.
     * @param wavelength Wavelength.
     * @param orientation Orientation.
     * @param phaseOffset Phase offset.
     */
    public GaborFilter(double wavelength, double orientation, double phaseOffset) {
        this.lambda = wavelength;
        this.theta = orientation;
        this.psi = phaseOffset;
    }

    /**
     * Initializes a new instance of the GaborFilterFinal class.
     * @param wavelength Wavelength.
     * @param orientation Orientation.
     * @param phaseOffset Phase offset.
     * @param gaussianVar Gaussian variance.
     */
    public GaborFilter(double wavelength, double orientation, double phaseOffset, double gaussianVar) {
        this.lambda = wavelength;
        this.theta = orientation;
        this.psi = phaseOffset;
        this.sigma = gaussianVar;
    }

    /**
     * Initializes a new instance of the GaborFilterFinal class.
     * @param wavelength Wavelength.
     * @param orientation Orientation.
     * @param phaseOffset Phase offset.
     * @param gaussianVar Gaussian variance.
     * @param aspectRatio Aspect ratio.
     */
    public GaborFilter(double wavelength, double orientation, double phaseOffset, double gaussianVar, double aspectRatio) {
        this.lambda = wavelength;
        this.theta = orientation;
        this.psi = phaseOffset;
        this.sigma = gaussianVar;
        this.gamma = aspectRatio;
    }
    
    /**
     * Initializes a new instance of the GaborFilterFinal class.
     * @param wavelength Wavelength.
     * @param orientation Orientation.
     * @param phaseOffset Phase offset.
     * @param gaussianVar Gaussian variance.
     * @param aspectRatio Aspect ratio.
     * @param config Gabor configuration.
     */
    public GaborFilter(double wavelength, double orientation, double phaseOffset, double gaussianVar, double aspectRatio, Gabor.Config config) {
        this.lambda = wavelength;
        this.theta = orientation;
        this.psi = phaseOffset;
        this.sigma = gaussianVar;
        this.gamma = aspectRatio;
        this.config = config;
    }

    @Override
    public void applyInPlace(FastBitmap fastBitmap) {
        
        double[][] gaborKernel;
        int width = fastBitmap.getWidth();
        int height = fastBitmap.getHeight();
        
        if (fastBitmap.isGrayscale()){
            
            gaborKernel = Gabor.Kernel2D(size, lambda, theta, psi, sigma, gamma, config);
            int[][] gaborResponse = applyGabor(fastBitmap, gaborKernel);
            int maxG = Integer.MIN_VALUE;
            int minG = Integer.MAX_VALUE;
            
            if (isSigned()){
                fastBitmap.toRGB();

                // Gets max and min gray value.
                for (int i = 0; i < gaborResponse.length; i++) {
                    for (int j = 0; j < gaborResponse[0].length; j++) {
                        int gray = gaborResponse[i][j];
                        if (gray > maxG && gray > 0) maxG = gray;
                        if (gray < minG && gray < 0) minG = gray;
                    }
                }

                for (int i = 0; i < height; i++) {
                    for (int j = 0; j < width; j++) {
                        
                        int g = (int)Math.round((255*(double)(gaborResponse[i][j] / (double)maxG)));
                        if (gaborResponse[i][j] < 0){
                            g = (int)Math.round((255*(double)(gaborResponse[i][j] / (double)minG)));
                        }
                        if (gaborResponse[i][j] > 0)
                            fastBitmap.setRGB(i, j, g, 0, 0);
                        else
                            fastBitmap.setRGB(i, j, 0, 0, g);
                    }
                }
            }
            else{

                // Gets max and min gray value.
                for (int i = 0; i < gaborResponse.length; i++) {
                    for (int j = 0; j < gaborResponse[0].length; j++) {
                        int gray = gaborResponse[i][j];
                        if (gray > maxG) maxG = gray;
                        if (gray < minG) minG = gray;
                    }
                }

                for (int i = 0; i < height; i++) {
                    for (int j = 0; j < width; j++) {
                        int g = (int)Math.round((255*(double)(gaborResponse[i][j] - minG))/(maxG - minG));
                        fastBitmap.setGray(i, j, g);
                    }
                }
            }
        }
        else{
            try {
                throw new IllegalArgumentException("Gabor filter only works with grayscale images.");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * Apply Gabor 
     * @param fastBitmap Image to be processed.
     * @param gaborKernel Gabor kernel.
     * @return Gabor response.
     */
    private int[][] applyGabor(FastBitmap fastBitmap, double[][] gaborKernel){
        
        int height = fastBitmap.getHeight();
        int width = fastBitmap.getWidth();
        
        int xmax=(int)Math.floor(gaborKernel.length / 2.0);
        int ymax=(int)Math.floor(gaborKernel[0].length / 2.0);
        int[][] gaborResponse = new int[height][width];
        
        for (int x=0; x < height;x++){
            for (int y=0; y < width;y++){
                double sum = 0;
                for (int xf = -xmax; xf <= xmax; xf++){
                    for (int yf = -ymax; yf <= ymax; yf++){
                        if (x-xf >= 0 && x-xf < height && y-yf >= 0 && y-yf < width){
                            int value = fastBitmap.getGray(x - xf, y - yf);
                            sum += gaborKernel[xf + xmax][yf + ymax] * value;
                        }
                    }
                }
                gaborResponse[x][y] = (int)Math.round(sum);
            }
        }
        return gaborResponse;
    }
}
 

Ads help maintain this website.