/*
* This file is part of the JFeatureLib project: https://github.com/locked-fg/JFeatureLib
* JFeatureLib is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* JFeatureLib 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JFeatureLib; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* You are kindly asked to refer to the papers of the according authors which
* should be mentioned in the Javadocs of the respective classes as well as the
* JFeatureLib project itself.
*
* Hints how to cite the projects can be found at
* https://github.com/locked-fg/JFeatureLib/wiki/Citation
*/
package de.lmu.ifi.dbs.jfeaturelib.utils;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
/**
* Class that calculates gradients from a given image.
*
* The image is convolved with masks (default = sobel) in x and y in order to
* create the derivates. Afterwards, the gradient orientation and length is
* computed for each pixel.
*
* If the task is just to create a derivation of the image
* {@link DerivativeImage} might be more useful.
*
* @author graf
* @see DerivativeImage
*/
public class GradientImage implements GradientSource {
/**
* The kernel mask used for derivation in x-direction
*/
private int[] kernelX = {1, 0, -1, 2, 0, -2, 1, 0, -1};
/**
* The kernel mask used for derivation in y-direction
*/
private int[] kernelY = {1, 2, 1, 0, 0, 0, -1, -2, -1};
/**
* The processor describing the length of the gradients.
*/
private FloatProcessor length = null;
/**
* The processor describing the orientation of the gradients in [0, Pi[.
*/
private FloatProcessor theta = null;
@Override
public void setIp(ImageProcessor ip) {
ip = ip.convertToFloat();
/*
* ipX and ipY are temporary processors for the derivations. This of
* course consumes quite some memory. A more optimal yet less
* transparent solution would be to use the length and theta processors
* for derivation AND for the final result at once.
*/
FloatProcessor ipX = (FloatProcessor) ip.duplicate();
FloatProcessor ipY = (FloatProcessor) ip.duplicate();
ipX.convolve3x3(kernelX);
ipY.convolve3x3(kernelY);
length = new FloatProcessor(ip.getWidth(), ip.getHeight());
theta = new FloatProcessor(ip.getWidth(), ip.getHeight());
final int max = ip.getWidth() * ip.getHeight();
float dx, dy;
float thetaValue;
for (int i = 0; i < max; i++) {
dx = ipX.getf(i);
dy = ipY.getf(i);
if (dx != 0 || dy != 0) {
length.setf(i, (float) Math.sqrt(dx * dx + dy * dy));
thetaValue = (float) (Math.atan2(dy, dx) + Math.PI);
thetaValue %= Math.PI;
theta.setf(i, thetaValue);
}
}
}
/**
* Returns the angle of the gradient in the area [0, PI[.
*
* @param x x-cooridnate in pixel space
* @param y y-cooridnate in pixel space
* @return angle of gradient [0,pi[
*/
@Override
public double getTheta(int x, int y) {
return theta.getf(x, y);
}
/**
* return the length of the gradient vector at the specified position
*
* @param x x-cooridnate in pixel space
* @param y y-cooridnate in pixel space
* @return length of gradient
*/
@Override
public double getLength(int x, int y) {
return length.getf(x, y);
}
//<editor-fold defaultstate="collapsed" desc="getters & setters">
public int[] getKernelX() {
return kernelX;
}
public void setKernelX(int[] kernelX) {
this.kernelX = kernelX;
}
public int[] getKernelY() {
return kernelY;
}
public void setKernelY(int[] kernelY) {
this.kernelY = kernelY;
}
//</editor-fold>
}