// Catalano Imaging Library
// The Catalano Framework
//
// Copyright © Diego Catalano, 2012-2016
// diego.catalano at live.com
//
// Copyright © César Souza, 2009-2013
// cesarsouza at gmail.com
//
// 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.Corners;
import Catalano.Core.ArraysUtil;
import Catalano.Core.IntPoint;
import Catalano.Imaging.FastBitmap;
import Catalano.Math.Constants;
import java.util.ArrayList;
import java.util.List;
/**
* Harris Corners Detector.
* @author Diego Catalano
*/
public class HarrisCornersDetector implements ICornersDetector{
public enum HarrisCornerMeasure {Harris, Noble};
HarrisCornerMeasure algo;
// Harris parameters
private HarrisCornerMeasure measure = HarrisCornerMeasure.Harris;
private float k = 0.04f;
private float threshold = 20000f;
// Non-maximum suppression parameters
private int suppression = 3;
// Gaussian smoothing parameters
private double sigma = 1.2;
private float[] kernel;
private int size = 7;
/**
* Gets the measure to use when detecting corners.
* @return Measure.
*/
public HarrisCornerMeasure getMeasure() {
return measure;
}
/**
* Sets the measure to use when detecting corners.
* @param measure Measure.
*/
public void setMeasure(HarrisCornerMeasure measure) {
this.measure = measure;
}
/**
* Gets Non-maximum suppression window radius. Default value is 3.
* @return Non-maximum suppression window radius.
*/
public int getSuppression() {
return suppression;
}
/**
* Sets Non-maximum suppression window radius. Default value is 3.
* @param suppression Non-maximum suppression window radius.
*/
public void setSuppression(int suppression) {
this.suppression = suppression;
}
/**
* Gets Harris parameter k. Default value is 0.04.
* @return Harris parameter.
*/
public float getK() {
return k;
}
/**
* Sets Harris parameter k. Default value is 0.04.
* @param k Harris parameter.
*/
public void setK(float k) {
this.k = k;
}
/**
* Get Harris threshold. Default value is 20000.
* @return Harris threshold.
*/
public float getThreshold() {
return threshold;
}
/**
* Set Harris threshold. Default value is 20000.
* @param threshold Harris threshold.
*/
public void setThreshold(float threshold) {
this.threshold = threshold;
}
/**
* Get Gaussian smoothing sigma. Default value is 1.2.
* @return Gaussian smoothing.
*/
public double getSigma() {
return sigma;
}
/**
* Set Gaussian smoothing sigma. Default value is 1.2.
* @param sigma Gaussian smoothing.
*/
public void setSigma(double sigma) {
this.sigma = sigma;
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
*/
public HarrisCornersDetector() {
init(HarrisCornerMeasure.Harris, k, threshold, sigma, suppression, size);
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
* @param k Harris parameter.
*/
public HarrisCornersDetector(float k){
init(HarrisCornerMeasure.Harris, k, threshold, sigma, suppression, size);
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
* @param k Harris parameter.
* @param threshold Harris threshold.
*/
public HarrisCornersDetector(float k, float threshold){
init(HarrisCornerMeasure.Harris, k, threshold, sigma, suppression, size);
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
* @param k Harris parameter.
* @param threshold Harris threshold.
* @param sigma Gaussian smoothing.
*/
public HarrisCornersDetector(float k, float threshold, double sigma){
init(HarrisCornerMeasure.Harris, k, threshold, sigma, suppression, size);
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
* @param k Harris parameter.
* @param threshold Harris threshold.
* @param sigma Gaussian smoothing.
* @param suppression Non-maximum suppression window radius.
*/
public HarrisCornersDetector(float k, float threshold, double sigma, int suppression){
init(HarrisCornerMeasure.Harris, k, threshold, sigma, suppression, size);
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
* @param measure Measure to use when detecting corners.
* @param threshold Harris threshold.
* @param sigma Gaussian smoothing.
* @param suppression Non-maximum suppression window radius.
*/
public HarrisCornersDetector(HarrisCornerMeasure measure, float threshold, double sigma, int suppression){
init(measure, k, threshold, sigma, suppression, size);
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
* @param measure Measure to use when detecting corners.
* @param threshold Harris threshold.
* @param sigma Gaussian smoothing.
*/
public HarrisCornersDetector(HarrisCornerMeasure measure, float threshold, double sigma){
init(measure, k, threshold, sigma, suppression, size);
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
* @param measure Measure to use when detecting corners.
* @param threshold Harris threshold.
*/
public HarrisCornersDetector(HarrisCornerMeasure measure, float threshold){
init(measure, k, threshold, sigma, suppression, size);
}
/**
* Initializes a new instance of the HarrisCornersDetector class.
* @param measure Measure to use when detecting corners.
*/
public HarrisCornersDetector(HarrisCornerMeasure measure){
init(measure, k, threshold, sigma, suppression, size);
}
private void init(HarrisCornerMeasure measure, float k, float threshold, double sigma, int suppression, int size){
this.measure = measure;
this.threshold = threshold;
this.k = k;
this.suppression = suppression;
this.sigma = sigma;
this.size = size;
createGaussian();
}
private void createGaussian(){
double[] kernel = new Catalano.Math.Functions.Gaussian(sigma).Kernel1D(size);
this.kernel = ArraysUtil.toFloat(kernel);
}
@Override
public List ProcessImage(FastBitmap fastBitmap) {
FastBitmap gray;
if (fastBitmap.isGrayscale())
{
gray = fastBitmap;
}
else{
gray = new FastBitmap(fastBitmap);
gray.toGrayscale();
}
int width = gray.getWidth();
int height = gray.getHeight();
// 1. Calculate partial differences
float[][] diffx = new float[height][width];
float[][] diffy = new float[height][width];
float[][] diffxy = new float[height][width];
for (int i = 1; i < height - 1; i++) {
for (int j = 1; j < width - 1; j++) {
int p1 = gray.getGray(i - 1, j + 1);
int p2 = gray.getGray(i, j + 1);
int p3 = gray.getGray(i + 1, j + 1);
int p4 = gray.getGray(i - 1, j - 1);
int p5 = gray.getGray(i, j - 1);
int p6 = gray.getGray(i + 1, j - 1);
int p7 = gray.getGray(i + 1, j);
int p8 = gray.getGray(i - 1, j);
float h = ((p1 + p2 + p3) - (p4 + p5 + p6)) * 0.166666667f;
float v = ((p6 + p7 + p3) - (p4 + p8 + p1)) * 0.166666667f;
diffx[i][j] = h * h;
diffy[i][j] = v * v;
diffxy[i][j] = h * v;
}
}
// 2. Smooth the diff images
if (sigma > 0.0)
{
float[][] temp = new float[height][width];
// Convolve with Gaussian kernel
convolve(diffx, temp, kernel);
convolve(diffy, temp, kernel);
convolve(diffxy, temp, kernel);
}
// 3. Compute Harris Corner Response Map
float[][] map = new float[height][width];
float M, A, B, C;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
A = diffx[i][j];
B = diffy[i][j];
C = diffxy[i][j];
if (measure == HarrisCornerMeasure.Harris){
M = (A * B - C * C) - (k * ((A + B) * (A + B)));
}
else{
M = (A * B - C * C) / (A + B + Constants.SingleEpsilon);
}
if (M > threshold)
map[i][j] = M;
}
}
// 4. Suppress non-maximum points
ArrayList cornersList = new ArrayList();
for (int x = suppression, maxX = height - suppression; x < maxX; x++) {
for (int y = suppression, maxY = width - suppression; y < maxY; y++) {
float currentValue = map[x][y];
// for each windows' row
for (int i = -suppression; (currentValue != 0) && (i <= suppression); i++) {
// for each windows' pixel
for (int j = -suppression; j <= suppression; j++) {
if (map[x + i][y + j] > currentValue){
currentValue = 0;
break;
}
}
}
// check if this point is really interesting
if (currentValue != 0){
cornersList.add(new IntPoint(x, y));
}
}
}
return cornersList;
}
/**
* Convolution with decomposed 1D kernel.
* @param image Original image.
* @param temp Temporary image.
* @param kernel Kernel.
*/
private void convolve(float[][] image, float[][] temp, float[] kernel){
int width = image[0].length;
int height = image.length;
int radius = kernel.length / 2;
for (int x = 0; x < height; x++){
for (int y = radius; y < width - radius; y++){
float v = 0;
for (int k = 0; k < kernel.length; k++){
v += image[x][y + k - radius] * kernel[k];
}
temp[x][y] = v;
}
}
for (int y = 0; y < width; y++)
{
for (int x = radius; x < height - radius; x++)
{
float v = 0;
for (int k = 0; k < kernel.length; k++){
v += temp[x + k - radius][y] * kernel[k];
}
image[x][y] = v;
}
}
}
}
Ads help maintain this website.