# Harris Corner Detection



## JavaNurd (11. Apr 2012)

Hallo zusammen,
weis nicht ob das wirklich hier reinpasst, aber ich fand hier noch am ehesten.
Wir sollen in unserer Informatik Vorlesung den Harris Corner Detection Algorithmus implementieren.
So weit so gut hab eigentlich auch vermutlich alles (zumindest augenscheinlich) richtig implementiert, nur findet er nicht nur die Ecken sondern auch die Kanten.
Habe das Problem auch schon gefunden nur kann ich es nicht lösen:
Die Corner Response Funktion findet auch für Kanten große Werte und nicht nur für Ecken(zum Teil für Kanten sogar größere)...

Vllt hat einer von euch ja ne Idee,
würde mir sehr helfen.
Hier mal der Code:


```
public static BufferedImage eckenFinder(BufferedImage source) {
HarrisCornerDetektor hcd = new HarrisCornerDetektor(source);
hcd.paintCorners(hcd.getGoodCorners(hcd.getCorners()));
return source;
	}
```
und Hier die eigentliche Funktion:

```
public class HarrisCornerDetektor {

	BufferedImage source;

	Vector<Corner> ecken = new Vector<Corner>();
	double alpha = 0.25;
	double schwellwert_unten = 10000;
	double[][] x_diff_kernel = { { -1, 0, 1 }, { -1, 0, 1 }, { -1, 0, 1 } };
	double[][] y_diff_kernel = { { -1, -1, -1 }, { 0, 0, 0 }, { 1, 1, 1 } };

	HarrisCornerDetektor(BufferedImage source) {
		this.source = source;

		try {
			alpha = Double.parseDouble(JOptionPane
					.showInputDialog("Bitte alpha eingeben"
							+ "\n(Nur Werte zwischen 0..0.25)"));
			if (alpha <= 0.01)
				alpha = 0.01;
			if (alpha >= 0.25)
				alpha = 0.25;

		} catch (NumberFormatException exp) {
			JOptionPane.showMessageDialog(null,
					"Bitte nur zulässige Werte eingeben");
		}

	}

	public Vector<Corner> getCorners() {

		// Parameter i_x²,i_y²,i__xy
		double[][] a_arr = new double[source.getWidth()][source.getHeight()];
		double[][] b_arr = new double[source.getWidth()][source.getHeight()];
		double[][] c_arr = new double[source.getWidth()][source.getHeight()];
		double[][] a_arr_gl = new double[source.getWidth()][source.getHeight()];
		double[][] b_arr_gl = new double[source.getWidth()][source.getHeight()];
		double[][] c_arr_gl = new double[source.getWidth()][source.getHeight()];
		double i_x, i_y;

		// Fuelle i_x²,i_y²,i__xy
		for (int i = 1; i < source.getWidth() - 1; i++)
			for (int j = 1; j < source.getHeight() - 1; j++) {
				i_x = getI_X(i, j);
				i_y = getI_Y(i, j);
				a_arr[i][j] = Math.pow(i_x, 2);
				b_arr[i][j] = Math.pow(i_y, 2);
				c_arr[i][j] = i_x * i_y;

			}

		// Gausglättung
		double[][] gaus_kernel = new double[3][3];
		double normgaus = 0;
		for (int k = -1; k < 2; k++)
			for (int l = -1; l < 2; l++) {
				gaus_kernel[k + 1][l + 1] = MyBufferedImageManip
						.gausFunktion2D(k, l, Math.sqrt(2));
				normgaus += gaus_kernel[k + 1][l + 1];
			}

		for (int k = -1; k < 2; k++)
			for (int l = -1; l < 2; l++)
				gaus_kernel[k + 1][l + 1] /= normgaus;

		for (int i = 1; i < source.getWidth() - 1; i++)
			for (int j = 1; j < source.getHeight() - 1; j++) {
				for (int k = -1; k < 2; k++)
					for (int l = -1; l < 2; l++) {
						a_arr_gl[i][j] += a_arr[i + k][j + l]
								* gaus_kernel[k + 1][l + 1];
						b_arr_gl[i][j] += a_arr[i + k][j + l]
								* gaus_kernel[k + 1][l + 1];
						c_arr_gl[i][j] += a_arr[i + k][j + l]
								* gaus_kernel[k + 1][l + 1];
					}
			}

		// Ecken finden
		for (int i = 1; i < source.getWidth() - 1; i++)
			for (int j = 1; j < source.getHeight() - 1; j++) {
				double val = this.CornerResponseFunktion(a_arr[i][j],
						b_arr[i][j], c_arr[i][j], alpha);
				val = Math.abs(val);

				if (val > schwellwert_unten) { // &val <schwellwert_oben){
					ecken.add(new Corner(i, j, val));
				}
			}
		System.out.println(ecken.size());
		System.out.println("fertig gesucht");

		return ecken;

	}

	public Corner[] getGoodCorners(Vector<Corner> ecken) {
		Corner[] eckenArr = this.sortCorners(ecken);

		for (int i = 0; i < eckenArr.length; i++) {

			if (eckenArr[i] != null) {
				int a_loc_x = eckenArr[i].x;
				int a_loc_y = eckenArr[i].y;

				for (int j = i + 1; j < eckenArr.length; j++) {
					if (eckenArr[j] != null) {
						int b_loc_x = eckenArr[j].x;
						int b_loc_y = eckenArr[j].y;

						if (Math.abs(a_loc_x - b_loc_x) < 5)
							if (Math.abs(a_loc_y - b_loc_y) < 5)
								eckenArr[j] = null;
					}
				}
			}
		}
		int anz_good = 0;
		for (int i = 0; i < eckenArr.length; i++)
			if (eckenArr[i] != null)
				anz_good++;
		Corner[] goodEckenArr = new Corner[anz_good];

		System.out.println(anz_good);
		int j = 0;
		for (int i = 0; i < eckenArr.length; i++)
			if (eckenArr[i] != null) {
				goodEckenArr[j++] = eckenArr[i];
				System.out.println(j + ". " + eckenArr[i].getResponseValue());
			}
		return goodEckenArr;
	}

	public void paintCorners(Corner[] good_Ecken) {
		Graphics2D g = source.createGraphics();

		for (int i = 0; i < good_Ecken.length; i++) {
			int a_log_height = good_Ecken[i].x;
			int a_log_width = good_Ecken[i].y;
			g.setColor(Color.RED);
			g.drawLine(a_log_height - 3, a_log_width, a_log_height + 3,
					a_log_width);
			g.drawLine(a_log_height, a_log_width - 3, a_log_height,
					a_log_width + 3);

		}
		System.out.println("fertig gemalt");

	}

	/*
	 * Interne Hilfsmethoden zur Berechnung der Ecken
	 */

	private double getI_X(int x, int y) {
		double diff = 0;

		for (int i = -1; i < 2; i++)
			for (int j = -1; j < 2; j++) {
				int grauwert = (new Color(source.getRGB(x + i, y + j)))
						.getGreen();

				diff += grauwert * x_diff_kernel[i + 1][j + 1];
			}

		return diff;

	}

	private double getI_Y(int x, int y) {
		double diff = 0;

		for (int i = -1; i < 2; i++)
			for (int j = -1; j < 2; j++) {

				int grauwert = (new Color(source.getRGB(x + i, y + j)))
						.getGreen();

				diff += grauwert * y_diff_kernel[i + 1][j + 1];
			}

		return diff;

	}

	private double CornerResponseFunktion(double a, double b, double c,
			double alpha) {

		return (a * b - Math.pow(c, 2)) - alpha * Math.pow((a + b), 2);
	}

	private Corner[] sortCorners(Vector<Corner> ecken) {
		Corner[] eckenArr = new Corner[ecken.size()];

		for (int i = 0; i < eckenArr.length; i++) {
			eckenArr[i] = ecken.elementAt(i);

		}

		Arrays.sort(eckenArr);
		System.out.println(eckenArr.length);
		System.out.println("Fertig sortiert");
		return eckenArr;

	}

}

class Corner implements Comparable {
	private double responseValue = 0;
	int x = 0;
	int y = 0;

	Corner(int x, int y, double responseValue) {
		this.x = x;
		this.y = y;
		this.responseValue = responseValue;
	}

	public int compareTo(Object and) {
		Corner andere = (Corner) and;

		if (this.responseValue > andere.responseValue)
			return 1;
		else if (this.responseValue == andere.responseValue)
			return 0;
		else
			return -1;
	}

	public double getResponseValue() {
		return responseValue;
	}

}
```


----------



## Marco13 (11. Apr 2012)

Ist so durch draufschauen natürlich schwierig bis unmöglich nachzuvollziehen. Wenn man sich in Harris einlesen würde, könnte man sich vielleicht erschließen, ob es bei

```
a_arr_gl[i][j] += a_arr[i + k][j + l]
                                * gaus_kernel[k + 1][l + 1];
                        b_arr_gl[i][j] += a_arr[i + k][j + l]
                                * gaus_kernel[k + 1][l + 1];
                        c_arr_gl[i][j] += a_arr[i + k][j + l]
                                * gaus_kernel[k + 1][l + 1];
```
nicht 
a += a * ...
b += b * ...
c += c * ...
lauten sollte - so sieht's erstmal nur komisch aus  Aber wenn man es testen könnte, würde sich vielleicht jemand finden, der das tun würde....


----------



## Spacerat (12. Apr 2012)

Vllt. hilft das hier ja weiter: http://www.imagingbook.com/fileadmin/de/java1/ch08.zip

Quelle: Burger/Burge: Digitale Bildverarbeitung Prog. D.1


----------



## JavaNurd (14. Apr 2012)

Danke für die Antworten,
hat irgendwie alles nicht so richtig funktioniert aber die Implementierung von Burger/Burge ist echt gut danke


----------

