Précédent   Forum des professionnels en informatique > Autres langages > Algorithmes > Contribuez
Contribuez Proposez vos articles, cours, tutoriels, FAQ, sources, etc.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Actualité déjà publiée
 
Outils de la discussion
Publicité
'
Vieux 26/04/2007, 23h14   #1
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Par défaut [Image] Détecteur de Harris pour ImageJ

Continuons avec l'extraction des points caracteristiques. Apres les contours (Canny), passons maintenant aux coins avec Harris.

Le detecteur de Harris est un detecteur assez simple qui permet d'extraire les "coins" des contours. Les points récupérés sont souvent utilisés dans les algorithmes de reconnaissance de forme.



plus d'info: http://en.wikipedia.org/wiki/Corner_detection

Code Java :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
 
import ij.IJ;
import ij.ImagePlus;
import ij.gui.GenericDialog;
import ij.plugin.filter.PlugInFilter;
import ij.process.ByteProcessor;
import ij.process.ImageProcessor;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
 
/**
 * Harris Corner Detector
 * 
 * @author Xavier Philippeau
 *
 */
public class Harris_ implements PlugInFilter {
 
	// corners list
	List<int[]> corners = new ArrayList<int[]>();
 
	// halfwindow size (integration, kernels)
	private int halfwindow = 0;
 
	// variance of gaussians
	private double gaussiansigma = 0;
 
	// corner filtering
	private int minDistance = 0;
	private int minMeasure = 0;
 
	// Gradient kernel
	GradientVector gradient = new GradientVector();
 
	//	 About...
	private void showAbout() {
		IJ.showMessage("Harris...","Harris Corner Detector by Pseudocode");
	}
 
	public int setup(String arg, ImagePlus imp) {
 
		// about...
		if (arg.equals("about")) {
			showAbout(); 
			return DONE;
		}
 
		// else...
		if (imp==null) return DONE;
 
		// Configuration dialog.
		GenericDialog gd = new GenericDialog("Parameters");
		gd.addNumericField("Half-Window size",1,0);
		gd.addNumericField("Gaussian sigma",1.4,1);
		gd.addNumericField("Min Harris measure for corners",10,0);
		gd.addNumericField("Min distance between corners",8,0);
 
		int  halfwindow = 0;
		double gaussiansigma = 0;
		int minMeasure = 0;
		int minDistance = 0;
 
		while(true) {
			gd.showDialog();
			if ( gd.wasCanceled() )	return DONE;
 
			halfwindow     = (int) gd.getNextNumber();
			gaussiansigma  = (double) gd.getNextNumber();
			minMeasure     = (int) gd.getNextNumber();
			minDistance    = (int) gd.getNextNumber();
 
			if (halfwindow<=0) continue;
			if (gaussiansigma<=0) continue;
			if (minMeasure<0) continue;
			if (minDistance<0) continue;
			break;
		}
		gd.dispose();
 
		this.halfwindow = halfwindow;
		this.gaussiansigma = gaussiansigma;
		this.minMeasure = minMeasure;
		this.minDistance = minDistance;
 
		return PlugInFilter.DOES_8G;
	}
 
	public void run(ImageProcessor ip) {
 
		// ImageProcessor -> ByteProcessor conversion
		ByteProcessor bp = new ByteProcessor(ip.getWidth(),ip.getHeight());
		for (int y = 0; y < ip.getHeight(); y++) {
			for (int x = 0; x < ip.getWidth(); x++) {
				bp.set(x,y,ip.getPixel(x,y));
			}
		}
 
		// canny filter
		ByteProcessor newbp = filter( bp, this.minMeasure, this.minDistance );
 
		// ByteProcessor -> ImageProcessor conversion
		ImageProcessor out = new ByteProcessor(ip.getWidth(),ip.getHeight());
		for (int y = 0; y < ip.getHeight(); y++) {
			for (int x = 0; x < ip.getWidth(); x++) {
				out.set(x,y,newbp.get(x,y));
			}
		}
		ImagePlus newImg = new ImagePlus("Canny Filter Result", out);
		newImg.show();
 
	}
 
	// -------------------------------------------------------------------------
 
	/**
	 * Gaussian window function
	 * 
	 * @param x x coordinates
	 * @param y y coordinates
	 * @param sigma2 variance
	 * @return value of the function
	 */
	private double gaussian(double x, double y, double sigma2) {
		double t = (x*x+y*y)/(2*sigma2);
		double u = 1.0/(2*Math.PI*sigma2);
		double e = u*Math.exp( -t );
		return e;
	}
 
	/**
	 * compute harris measure for a pixel
	 * 
	 * @param c Image map
	 * @param x x coord of the computation
	 * @param y y coord of the computation
	 * @return harris measure 
	 */
	private double harrisMeasure(ByteProcessor c, int x, int y) {
		double m00=0, m01=0, m10=0, m11=0;
 
		// Harris estimator
		// ----------------
		//
		// k = det(A) - lambda * trace(A)^2
		//
		// Where A is the second-moment matrix 
		//
		//           | Lx²(x+dx,y+dy)    Lx.Ly(x+dx,y+dy) |
		// A =  Sum  |                                    | * Gaussian(dx,dy)
		//     dx,dy | Lx.Ly(x+dx,y+dy)  Ly²(x+dx,y+dy)   |
		//
		// and lambda = 0.06  (totaly empirical :-)
 
		for(int dy=-halfwindow;dy<=halfwindow;dy++) {
			for(int dx=-halfwindow;dx<=halfwindow;dx++) {
				int xk = x + dx;
				int yk = y + dy;
				if (xk<0 || xk>=c.getWidth()) continue;
				if (yk<0 || yk>=c.getHeight()) continue;
 
				// gradient value
				double[] g = gradient.getVector(c,xk,yk);
				double gx = g[0];
				double gy = g[1];
 
				// gaussian window
				double gw = gaussian(dx,dy,gaussiansigma);
 
				// second-moment matrix elements
				m00 += gx * gx * gw;
				m01 += gx * gy * gw;
				m10 = m01;
				m11 += gy * gy * gw;
			}
		}
 
		// Harris corner measure 
		double harris = m00*m11 - m01*m10 - 0.06*(m00+m11)*(m00+m11);
 
		// scaled down
		return harris/(256*256);
	}
 
	/**
	 * return the the measure at pixel (x,y) if the pixel is a spatial Maxima, else return -1
	 * 
	 * @param c original image 
	 * @param x x coordinates of pixel
	 * @param y y coordinates of pixel
	 * @return the measure if the pixel is a spatial Maxima, else -1
	 */
	private double spatialMaximaofHarrisMeasure(ByteProcessor c, int x, int y) {
		int n=8;
		int[] dx = new int[] {-1,0,1,1,1,0,-1,-1};
		int[] dy = new int[] {-1,-1,-1,0,1,1,1,0};
		double w =  harrisMeasure(c,x,y);
		for(int i=0;i<n;i++) {
			double wk = harrisMeasure(c,x+dx[i],y+dy[i]);
			if (wk>=w) return -1;
		}
		return w;
	}
 
	/**
	 * Perfom Harris Corner Detection
	 * 
	 * @param c Image map
	 * @param tilesize size of a tile 
	 * @param nmbmax max number of corner to keep
	 * @return filtered image map
	 */
	public ByteProcessor filter(ByteProcessor c, int minMeasure, int minDistance) {
		int width = c.getWidth();
		int height = c.getHeight();
 
		// copy of the original image (at little darker)
		ByteProcessor c2 = new ByteProcessor(width,height);
		for (int y=0; y<height; y++)
			for (int x=0; x<width; x++)
				c2.set(x,y,(int)(c.get(x,y)*0.80));
 
		// for each tile in the image
		for (int y=0; y<height; y++) {
			for (int x=0; x<width; x++) {
				// harris measure
				int h = (int)spatialMaximaofHarrisMeasure(c, x, y);
 
				// add the corner to the list
				if (h>=minMeasure) corners.add( new int[]{x,y,h} );
			}
		}
 
		// remove corners to close to each other (keep the highest measure)
		Iterator<int[]> iter = corners.iterator();
		while(iter.hasNext()) {
			int[] p = iter.next();
			for(int[] n:corners) {
				if (n==p) continue;
				int dist = (int)Math.sqrt( (p[0]-n[0])*(p[0]-n[0])+(p[1]-n[1])*(p[1]-n[1]) );
				if( dist>minDistance) continue;
				if (n[2]<p[2]) continue;
				iter.remove();
				break;
			}
		}
 
		// Display corners over the image (cross)
		for (int[] p:corners) {
			for (int dx=-2; dx<=2; dx++) {
				if (p[0]+dx<0 || p[0]+dx>=width) continue;
				c2.set(p[0]+dx,p[1],255);
			}
			for (int dy=-2; dy<=2; dy++) {
				if (p[1]+dy<0 || p[1]+dy>=height) continue;
				c2.set(p[0],p[1]+dy,255);
			}
			//System.out.println("corner found at: "+p[0]+","+p[1]+" ("+p[2]+")");
		}		
 
		return c2;
	}
 
	public class GradientVector {
 
		int halfwindow = 1; // 3x3 kernel
		double sigma2 = 1.4;
 
		double[][] kernelGx = new double[2*halfwindow+1][2*halfwindow+1];
		double[][] kernelGy = new double[2*halfwindow+1][2*halfwindow+1];
 
		// Constructor
		public GradientVector() {
			for(int y=-halfwindow;y<=halfwindow;y++) {
				for(int x=-halfwindow;x<=halfwindow;x++) {
					kernelGx[halfwindow+y][halfwindow+x] = Gx(x, y);
					kernelGy[halfwindow+y][halfwindow+x] = Gy(x, y);
				}
			}
		}
 
		// Kernel functions (gaussian 1st order partial derivatives)
		private double Gx(int x, int y) {
			double t = (x*x+y*y)/(2*sigma2);
			double d2t = -x / sigma2;
			double e = d2t * Math.exp( -t );
			return e;
		}
 
		private double Gy(int x, int y) {
			double t = (x*x+y*y)/(2*sigma2);
			double d2t = -y / sigma2;
			double e = d2t * Math.exp( -t );
			return e;
		}
 
		// return the Gradient Vector for pixel(x,y) 
		public double[] getVector(ByteProcessor c, int x, int y) {
			double gx=0, gy=0;
			for(int dy=-halfwindow;dy<=halfwindow;dy++) {
				for(int dx=-halfwindow;dx<=halfwindow;dx++) {
					int xk = x + dx;
					int yk = y + dy;
					double vk = c.getPixel(xk,yk); // <-- value of the pixel
					gx += kernelGx[halfwindow-dy][halfwindow-dx] * vk;
					gy += kernelGy[halfwindow-dy][halfwindow-dx] * vk;
				}
			}
 
			double[] gradientVector = new double[] { gx, gy };
 
			return gradientVector;
		}	
	}
}

Vous trouverez une version "stand-alone" de ce code au Post #14

Et également une version sous forme de Plugin pour l'application de Millie ici -> HarrisDetectionPlugin.jar
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/04/2007, 15h24   #2
Membre chevronné
 
Avatar de parp1
 
Inscription : mai 2005
Messages : 818
Détails du profil
Informations personnelles :
Âge : 28
Localisation : France, Calvados (Basse Normandie)

Informations forums :
Inscription : mai 2005
Messages : 818
Points : 692
Points : 692
Bien joué, moi je l'avais implémenté en Python pour faire un suivi de point sur un film de prothèse. C'est assez robuste, faut il choisir le bon seuil pour avoir les points les plus robuste !

Bravo encore
__________________
Dis moi qui tu suis, je te dirais qui je Hais!
Heureux est l'étudiant, qui comme la rivière suit son cours sans sortir de son lit

Mon premier Tutoriel

You are safe in Parp1City .... (AC DC)
Ensemble luttons contre le chômage de parp1City!



A 80% des cas je résouts mon problème en rédigeant une nouvelle discussion, du coup je ne poste que 20% de mes problèmes...
parp1 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/04/2007, 16h47   #3
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Citation:
Envoyé par parp1
Bien joué, moi je l'avais implémenté en Python pour faire un suivi de point sur un film de prothèse. C'est assez robuste, faut il choisir le bon seuil pour avoir les points les plus robuste !

Bravo encore
Merci. Je n'ai pas vraiment de merite. Cet algo est largement connu, je n'ai fait que le réecrire en Java.

En fait, a l'instar de millie, je fais un peu de menage dans mes archives de code. J'en profite pour remettre au propre et poster les algos usuels.
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/04/2007, 17h15   #4
Membre chevronné
 
Avatar de parp1
 
Inscription : mai 2005
Messages : 818
Détails du profil
Informations personnelles :
Âge : 28
Localisation : France, Calvados (Basse Normandie)

Informations forums :
Inscription : mai 2005
Messages : 818
Points : 692
Points : 692
Dès lors ou tu passes du temps a faire quelque chose, et que tu mets en ligne tu as du merite, ce que je veux dire par la... tu pourrais te faire ta petite ToolBox pour le traitement d'image, mais non tu en fait profité les copains.
__________________
Dis moi qui tu suis, je te dirais qui je Hais!
Heureux est l'étudiant, qui comme la rivière suit son cours sans sortir de son lit

Mon premier Tutoriel

You are safe in Parp1City .... (AC DC)
Ensemble luttons contre le chômage de parp1City!



A 80% des cas je résouts mon problème en rédigeant une nouvelle discussion, du coup je ne poste que 20% de mes problèmes...
parp1 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/05/2007, 19h30   #5
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Nouvelle version du filtre:

- utilisation d'une fenetre gaussienne lors du calcul de la matrice de harris (second-moment).
- recherche du maxima local de la mesure de Harris (8 pixels voisins)
- filtrage des points trop proche ou ayant une mesure trop faible

Bref de meilleurs résultats, au detriment des perfs (la recherche du maxima local implique de calculer 9 mesures)
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/06/2007, 00h01   #6
Invité de passage
 
Inscription : mai 2007
Messages : 28
Détails du profil
Informations forums :
Inscription : mai 2007
Messages : 28
Points : 2
Points : 2
y a t'il une version C++ de cet algorithme?
kruskal21 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/06/2007, 10h22   #7
Rédacteur/Modérateur
 
Avatar de millie
 
Inscription : juin 2006
Messages : 6 929
Détails du profil
Informations personnelles :
Localisation : Luxembourg

Informations forums :
Inscription : juin 2006
Messages : 6 929
Points : 6 714
Points : 6 714
Citation:
Envoyé par kruskal21
y a t'il une version C++ de cet algorithme?
En vérité, avoir une version C++ ne veut pas dire grand chose. Il est nécessaire de spécifier la bibliothèque que tu utilises pour traiter tes images.

De plus, la discussion est ici et pas dans le domaine Java car le code permet assez facilement (cela dit, ça peut prendre un peu de temps), en connaissant un peu Java, de pouvoir le transcrire dans le langage et la bibliothèque de ton choix.
__________________
Je ne répondrai à aucune question technique en privé
millie est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/06/2007, 13h23   #8
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Citation:
Envoyé par kruskal21
y a t'il une version C++ de cet algorithme?
Faut demander gentiment à Millie de le porter dans la MillieLib...
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/05/2008, 23h10   #9
Membre du Club
 
Étudiant
Inscription : décembre 2006
Messages : 175
Détails du profil
Informations personnelles :
Âge : 25
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2006
Messages : 175
Points : 69
Points : 69
Par défaut re

Annule et remplace :

Voici maintenant mon lanceur :

Code :
1
2
3
4
5
6
7
8
		String filename = "baboon.jpg";

		ImagePlus ipl = new ImagePlus(filename);
		ImageProcessor ipr = ipl.getProcessor();
		Harris_ harris = new Harris_();
		harris.setup("", ipl);
		harris.run(ipr);
j'avais pas saisi le fait de mettre un harris.setup pour que cela fonctionne.
Maintenant c'est bon ! Sinon l'argument 1 de setup() est facultatif ??

Bonne soirée
Methode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/05/2008, 10h24   #10
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Citation:
Envoyé par Methode Voir le message
j'avais pas saisi le fait de mettre un harris.setup pour que cela fonctionne.
Maintenant c'est bon ! Sinon l'argument 1 de setup() est facultatif ??
Le classe présentée ici est un PLUGIN pour ImageJ. Elle n'est pas conçue pour être appelable depuis un main(), mais pour être utilisée par le programme executable "ImageJ" qui se charge d'appeler les methodes de l'interface "setup()" et "run()"

Cela dit, il est possible de recupérer le code des autres methodes.
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/06/2008, 11h38   #11
Membre du Club
 
Étudiant
Inscription : décembre 2006
Messages : 175
Détails du profil
Informations personnelles :
Âge : 25
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2006
Messages : 175
Points : 69
Points : 69
Par défaut mon code harris

Bonjour,

J'ai tenté de faire ma propre implémentation du détecteur de Harris.
Cependant sur une image entière le temps de calcul est très long et les résultats pas très probants...

Quelqu'un saurait-il dire ce qui ne vas vraiment pas ?

Pour le faire fonctionner :
- API Jama (Java Matrix)
- API JAI
nécessaires...

Deux classes :
- ImageNM.java
- Harris.java (classe main[])

Code java :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
 
package imageprocessing;
 
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
 
import Jama.Matrix;
import Jama.SingularValueDecomposition;
 
public class Harris {
 
	private static ImageNM img = new ImageNM("lena_b&w.jpg");
	private static int minDistance = 2;
	private static int nbpts = 8;
 
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
 
		int width = img.getWidth();
		int height = img.getHeight();
		int size = height * width;
 
		// Conversion niveaux de gris
		img.convert2GrayLevel();		
 
		// Calcul des gradients de Sobel X et Y : on obtient les images Ix et Iy
		PlanarImage img_sobx = img.SobelX();
		PlanarImage img_soby = img.SobelY();
 
		// Calcul des images Ixx Iyy et Ixy
		PlanarImage sobxx = JAI.create("multiply", img_sobx, img_sobx);
		PlanarImage sobyy = JAI.create("multiply", img_soby, img_soby);
		PlanarImage sobxy = JAI.create("multiply", img_sobx, img_soby);
 
		ImageNM img_sobxx = new ImageNM(sobxx);
		ImageNM img_sobyy = new ImageNM(sobyy);
		ImageNM img_sobxy = new ImageNM(sobxy);
 
		// Lissage des images Ixx Iyy Ixy par un noyau gaussien
		PlanarImage gimg_sobxx = img_sobxx.convolveByGaussian();
		PlanarImage gimg_sobyy = img_sobyy.convolveByGaussian();
		PlanarImage gimg_sobxy = img_sobxy.convolveByGaussian();
 
		double[] A = new double[3];
		double[] B = new double[3];
		double[] C = new double[3];
 
		double[] Trace = new double[size];
		double[] Det = new double[size];
		double[] R = new double[size];
 
 
		// Calcul des coins de harris pour chaque pixel
		for (int i = 0; i < width; i++) {
			for (int j = 0; j < height; j++) {
				gimg_sobxx.getData().getPixel(i, j, A);
				gimg_sobyy.getData().getPixel(i, j, B);
				gimg_sobxy.getData().getPixel(i, j, C);
 
				double[][] data = { { A[0], C[0] }, { C[0], B[0] } };
 
				Matrix M = new Matrix(data);
				SingularValueDecomposition singularvalues = M.svd();
				double[] singularvaluetab = singularvalues.getSingularValues();
 
				Trace[j * width + i] = singularvaluetab[0]
						+ singularvaluetab[1];
				Det[j * width + i] = singularvaluetab[0] * singularvaluetab[1];
				R[j * width + i] = Det[j * width + i] - 0.06
						* Math.pow((Trace[j * width + i]), 2);
 
			}
		}
 
		double[] nb = new double[8];
		List<Rmark> listR = new ArrayList<Rmark>();
 
		// Extraction des maxima locaux pour chaque pixel
		for (int i = 0; i < R.length; i++) {
 
			nb[0] = getNeighbours(R, i, -1, 1);
			nb[1] = getNeighbours(R, i, 0, 1);
			nb[2] = getNeighbours(R, i, 1, 1);
			nb[3] = getNeighbours(R, i, -1, 0);
			nb[4] = getNeighbours(R, i, 1, 0);
			nb[5] = getNeighbours(R, i, -1, -1);
			nb[6] = getNeighbours(R, i, 0, -1);
			nb[7] = getNeighbours(R, i, 1, -1);
 
			boolean added = false;
			for (int j = 0; j < nb.length; j++) {
				if ((R[i] > nb[j]) && (R[i] > 0) && !added){
					listR.add(new Rmark(R[i],i%width,i/width));
					added = true;
				}
 
			}
 
		}
 
		// tri les mesures de harris dans l'ordre décroissant
		java.util.Collections.sort(listR, java.util.Collections.reverseOrder());
 
		// Supprime les coins trop proches (répétabilité)
		Iterator&lt;Rmark> iter = listR.iterator();
		while(iter.hasNext()){
			Rmark rmark = iter.next();
			for(Rmark rmark2 : listR){
				if((rmark.i==rmark2.i)&&(rmark.j==rmark2.j)) continue;
				int dist = (int)Math.sqrt((rmark.i-rmark2.i)*(rmark.i-rmark2.i)+(rmark.j-rmark2.j)*(rmark.j-rmark2.j));
				if(dist>minDistance) continue;
				if(rmark2.interest<rmark.interest) continue;
				iter.remove();
				break;
			}	
		}
 
		// sélectionne les nbpts les plus représentatifs d'un coin
		List<Rmark> sorted_selected_RList = new ArrayList<Rmark>();	
		sorted_selected_RList = listR.subList(0, nbpts);	
 
		// Affiche des croix '+' sur l'image
		PlanarImage pimg= img.getImage();
 
		BufferedImage bimg = pimg.getAsBufferedImage();
		Graphics2D g2d = bimg.createGraphics();
 
		g2d.setColor(new Color(255,0,0));
		for (Rmark rmark : sorted_selected_RList) {
			int x=rmark.i;
			int y=rmark.j;
 
			g2d.drawLine(x-2,y,x+2,y);
			g2d.drawLine(x,y-2,x,y+2);
		}
 
		ImageNM tempimg = new ImageNM(bimg);
		tempimg.displayImage();
 
		System.out.println(sorted_selected_RList.toString());
 
	}
 
 
	private static double getNeighbours(double[] src1d, int i, int ox, int oy) {
		int x, y;
		double result;
 
		x = (i % img.getWidth()) + ox; // d_w and d_h are assumed to be set
											// to the
		y = (i / img.getWidth()) + oy; // width and height of scr1d
 
		if ((x < 0) || (x >= img.getWidth()) || (y < 0)
				|| (y >= img.getHeight())) {
			result = 0;// (int) (Math.random()*src1d.length);
		} else {
			result = src1d[y * img.getWidth() + x];// & 0x000000ff;
		}
		return result;
	}
 
	static class Rmark implements Comparable<Rmark>{
		double interest;
		int i,j;
 
		public Rmark(double interest,int i, int j) {
			this.interest = interest;
			this.i = i;
			this.j = j;
		}
 
		public int compareTo(Rmark o) {
			return (int)Math.round(interest-o.interest);
		}
 
		public String toString(){
			return "coord : ("+i+" ,"+j+")"; 
		}
 
 
	}
 
 
 
}

et la classe ImageNM :

Code java :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
 
package imageprocessing;
 
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import java.io.IOException;
 
import javax.media.jai.JAI;
import javax.media.jai.KernelJAI;
import javax.media.jai.PlanarImage;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
 
import com.sun.media.jai.widget.DisplayJAI;
 
public class ImageNM {
 
	private PlanarImage image;
 
	private String imagename;
 
	private int width, height;
 
	private int size;
 
	private ColorModel cm;
 
	public ImageNM(File imagefileHandle) {
		try {
			this.imagename = imagefileHandle.getCanonicalPath();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			image = readImage(imagename);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		width = image.getWidth();
		height = image.getHeight();
		size = width * height;
	}
 
	public ImageNM(String filename) {
		imagename = filename;
		try {
			image = readImage(filename);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		width = image.getWidth();
		height = image.getHeight();
		size = width * height;
	}
 
	public ImageNM(BufferedImage imbuf) {
		imagename = "temp";
 
		// 1st solution BufferedImage --> PlanarImage
		// ParameterBlock pb = new ParameterBlock();
		// pb.add(imbuf);
		//
		// image = (PlanarImage) JAI.create("awtImage", pb);
 
		// 2nd solution BufferedImage --> PlanarImage
		image = PlanarImage.wrapRenderedImage(imbuf);
		width = imbuf.getWidth();
		height = imbuf.getHeight();
		size = width * height;
	}
 
	public ImageNM(PlanarImage plimage, String plimagename) {
		imagename = plimagename;
		image = plimage;
		width = plimage.getWidth();
		height = plimage.getHeight();
		size = width * height;
	}
 
	public ImageNM(PlanarImage plimage) {
		imagename = "temp";
		image = plimage;
		width = plimage.getWidth();
		height = plimage.getHeight();
		size = width * height;
	}
 
	public PlanarImage readImage(String filename) throws IOException {
		PlanarImage image = JAI.create("fileload", filename);
		return image;
	}
 
	public void writeImage(PlanarImage imageout, String nameout) {
		JAI.create("filestore", imageout, nameout);
	}
 
	public void displayImage() {
 
		JFrame frame = new JFrame("Image " + imagename);
		frame.setSize(width, height);
 
		Container contentPane = frame.getContentPane();
		contentPane.setLayout(new BorderLayout());
		DisplayJAI dj = new DisplayJAI(image);
		contentPane.add(new JScrollPane(dj), BorderLayout.CENTER);
 
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
 
 
	public int[] getPixel(int x, int y) {
		int[] pixel = new int[image.getNumBands()];
		image.getData().getPixel(x, y, pixel);
		return pixel;
	}
 
	public int[] getGrayPixels(int x, int y, int w, int h) {
 
		Raster raster = image.getData();
 
		if (raster.getNumBands() == 3) {
			PlanarImage grayImage = convert2GrayLevel();
			Raster rastergray = grayImage.getData();
			int[] pixels = new int[(w - x) * (h - y)];
 
			rastergray.getPixels(x, y, w, h, pixels);
 
			return pixels;
		} else {
			int[] graypixels = new int[(w - x) * (h - y)];
			raster.getPixels(x, y, w, h, graypixels);
			return graypixels;
		}
 
	}
 
 
	public int[] getRGBPixels(int x, int y, int w, int h) {
 
		Raster raster = image.getData();
 
		if (raster.getNumBands() == 1) {
			return getGrayPixels(x,y,w,h);
		} else {
			int pixels[][] = new int[raster.getNumBands()][(w - x) * (h - y)];
			// added
			int rgbpixels[] = new int[(w - x) * (h - y)];
 
			for (int i = 0; i < raster.getNumBands(); i++) {
				raster.getSamples(x, y, w, h, i, pixels[i]);
			}
 
			for (int i = 0; i < (w - x) * (h - y); i++) {
				rgbpixels[i] = (pixels[0][i] << 16) | (pixels[1][i] << 8)
						| (pixels[2][i]);
			}
 
			return rgbpixels;
		}
	}
 
	public PlanarImage blurImage() {
 
		float[] kernelData = { 1.0F / 14.0F, 2.0F / 14.0F, 1.0F / 14.0F,
				2.0F / 14.0F, 2.0F / 14.0F, 2.0F / 14.0F, 1.0F / 14.0F,
				2.0F / 14.0F, 1.0F / 14.0F };
 
		KernelJAI kernel = new KernelJAI(3, 3, kernelData);
		PlanarImage result = JAI.create("convolve", image, kernel);
		return result;
	}
 
	public PlanarImage convolveByMoyen3x3() {
 
		float[] kernelData = { 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F };
 
		KernelJAI kernel = new KernelJAI(3, 3, kernelData);
		PlanarImage result = JAI.create("convolve", image, kernel);
		return result;
	}
 
 
	public PlanarImage convolveByGaussian() {
 
		float[] kernelData = { 0.7F / 256F, 3.3F / 256F, 5.5F / 256F,
				3.3F / 256F, 0.7F / 256F, 3.3F / 256F, 15.0F / 256F,
				24.7F / 256F, 15F / 256F, 3.3F / 256F, 5.5F / 256F,
				24.7F / 256F, 40.7F / 256F, 24.7F / 256F, 5.5F / 256F,
				3.3F / 256F, 15.0F / 256F, 24.7F / 256F, 15F / 256F,
				3.3F / 256F, 0.7F / 256F, 3.3F / 256F, 5.5F / 256F,
				3.3F / 256F, 0.7F / 256F };
 
		KernelJAI kernel = new KernelJAI(5, 5, kernelData);
		PlanarImage result = JAI.create("convolve", image, kernel);
		return result;
	}
 
	public PlanarImage convolveByLaplacian() {
 
		float[] kernelData = { 0.0F, -1.0F, 0.0F, -1.0F, 4.0F, -1.0F, 0.0F,
				-1.0F, 0.0F };
 
		KernelJAI kernel = new KernelJAI(3, 3, kernelData);
		PlanarImage result = JAI.create("convolve", image, kernel);
		return result;
	}
 
 
	 /**
     * Filtre de SobelX
     * @return l'image modifi&#65533;e
     */
    public PlanarImage SobelX()
    {	    	
 
    	float data_v[] = new float[]
    	                    		{
    	               			   1.0F ,  1.414F , 1.0F ,
    	                            0.0F ,   0.0F   ,  0.0F ,
    	                            1.0F ,   1.414F ,  1.0F
    	                           }; 
 
    	//KernelJAI kernel = new KernelJAI(3, 3, 1, 1, data_v);
    	KernelJAI kernel = new KernelJAI(3,3,data_v);
    	PlanarImage result = JAI.create("convolve", image, kernel);
        return result;
    }
 
    /**
     * Filtre de SobelY
     * @return l'image modifi&#65533;e
     */
    public PlanarImage SobelY()
    {	    	
 
    	float data_h[] = new float[]
       	           				{
       	           				1.0F  , 0.0F , -1.0F,
       	           				1.414F, 0.0F , -1.414F,
       	           				1.0F  , 0.0F , -1.0F
       	};
 
    	//KernelJAI kernel = new KernelJAI(3, 3, 1, 1, data_v);
    	KernelJAI kernel = new KernelJAI(3,3,data_h);
    	PlanarImage result = JAI.create("convolve", image, kernel);
        return result;
    }
 
 
	public PlanarImage edgesByRoberts() {
 
		float[] data_h = {0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, -1.0F,
				0.0F };
 
		float[] data_v = {0.0F, 0.0F, 0.0F, 0.0F, -1.0F, 1.0F, 0.0F, 0.0F,
				1.0F };
 
		KernelJAI kern_h = new KernelJAI(3,3,data_h);
     	KernelJAI kern_v = new KernelJAI(3,3,data_v);
		PlanarImage result = JAI.create("gradientmagnitude", image, kern_h, kern_v);
		return result;
	}
 
	public PlanarImage edgesByPrewitt() {
 
		float[] data_h = {-1.0F, 0.0F, 1.0F, -1.0F, 0.0F, 1.0F, -1.0F, 0.0F,
				1.0F };
 
		float[] data_v = {-1.0F, -1.0F, -1.0F, 0.0F, 0.0F, 0.0F, 1.0F, 1.0F,
				1.0F };
 
		KernelJAI kern_h = new KernelJAI(3,3,data_h);
     	KernelJAI kern_v = new KernelJAI(3,3,data_v);
		PlanarImage result = JAI.create("gradientmagnitude", image, kern_h, kern_v);
		return result;
	}
 
 
	/**
     * Filtre de SobelXY
     * @return l'image modifiée
     */
    public PlanarImage edgesBySobel()
    {
 
    	float data_h[] = new float[]
    	           				{
    	           				1.0F  , 0.0F , -1.0F,
    	           				1.414F, 0.0F , -1.414F,
    	           				1.0F  , 0.0F , -1.0F
    	};
 
     	float data_v[] = new float[]
     		{
			1.0F ,  1.414F , 1.0F ,
             0.0F ,   0.0F   ,  0.0F ,
             1.0F ,   1.414F ,  1.0F
            };
 
		KernelJAI kern_h = new KernelJAI(3,3,data_h);
     	KernelJAI kern_v = new KernelJAI(3,3,data_v);
		//operation de detection de contour
 		PlanarImage result ;
        return result = (PlanarImage)JAI.create("gradientmagnitude",image, kern_h, kern_v);
    }
 
 
	public PlanarImage convert2GrayLevel() {
 
		Raster raster = image.getData();
 
		if (raster.getNumBands() == 3) {
		double[][] matrix = { { 0.114, 0.587, 0.299, 0.0 } };
 
		// Create the ParameterBlock.
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(image);
		pb.add(matrix);
 
		// Perform the convolution
		PlanarImage result = (PlanarImage) JAI.create("bandcombine", pb, null);
		return result;
		}
		else{
			throw new IllegalArgumentException("Image # bands <> 3");
		}	
 
	}
 
	public int getHeight() {
		return height;
	}
 
	public PlanarImage getImage() {
		return image;
	}
 
	public String getImagename() {
		return imagename;
	}
 
	public int getWidth() {
		return width;
	}
 
	public static void main(String[] args) {
 
		ImageNM image = new ImageNM("lena_b&w.jpg");
		image.displayImage();
		ImageNM imageconvolved = new ImageNM(image.edgesByPrewitt());
		imageconvolved.displayImage();
 
	}
 
}
Methode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/06/2008, 11h51   #12
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Code java :
1
2
3
4
 
Matrix M = new Matrix(data);
SingularValueDecomposition singularvalues = M.svd();
double[] singularvaluetab = singularvalues.getSingularValues();

Dans le detecteur de Harris, on n'a pas besoin de cherchers les valeurs propres de la matrice. On calcule la courbure (R, Determinant et Trace) en utilisant les elements de la matrice M.
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/06/2008, 12h18   #13
Membre du Club
 
Étudiant
Inscription : décembre 2006
Messages : 175
Détails du profil
Informations personnelles :
Âge : 25
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2006
Messages : 175
Points : 69
Points : 69
Par défaut re

Ok je vais changer ça.

Cependant cela ne devrait pas tellement influencer les résultats (je ne sais si tu as tester le prog?) puisque :

Trace(M) = λ1+ λ2 = M1,1 + M2,2
Déterminant(M) = λ1λ2 = M1,1*M2,2 – M1,2*M2,1

R = Déterminant(M) – k(Trace(M))^2

Merci à toi
Methode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/06/2008, 12h34   #14
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Le résultat sans doute pas, mais la vitesse surement...

J'en profite pour poster une version "stand-alone" du filtre, qui précalcule les valeurs filtrés des derivées F*Lx², F*Ly² et F*Lxy pour accelerer le temps de traitement (au detriment de la mémoire).

Code java :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
 
/**
 * Harris Corner Detector
 * 		
 *  k = det(A) - k * trace(A)^2
 * 
 *  Where A is the second-moment matrix 
 * 
 *            | Lx²(x+dx,y+dy)    Lx.Ly(x+dx,y+dy) |
 *  A =  Sum  |                                    | * Gaussian(dx,dy)
 *      dx,dy | Lx.Ly(x+dx,y+dy)  Ly²(x+dx,y+dy)   |
 * 
 *  and k = a/(1+a)^2, 
 *  
 *  where "a" is the mininmum ratio between the two eigenvalues
 *  for a point to be considered as a corner.
 *  
 * @author Xavier Philippeau
 */
public class HarrisFast  {
 
	// corner class
	class Corner {
		int x,y; // corner position
		float h; // harris measure
		public Corner(int x, int y, float h) {
			this.x=x; this.y=y; this.h=h;
		}
	}
 
	// corners list
	List<Corner> corners = new ArrayList<Corner>();
 
	// image
	private int[][] image;
	int width,height;
 
	// precomputed values of the derivatives
	private float[][] Lx2,Ly2,Lxy;
 
	/**
	 *  Constructor
	 */
	public HarrisFast(int[][] image, int width, int height) {
		this.image = image;
		this.width = width;
		this.height = height;
	}
 
	/**
	 * Gaussian function
	 */
	private double gaussian(double x, double y, double sigma) {
		double sigma2 = sigma*sigma;
		double t = (x*x+y*y)/(2*sigma2);
		double u = 1.0/(2*Math.PI*sigma2);
		double e = u*Math.exp( -t );
		return e;
	}
 
	/**
	 * Sobel gradient 3x3
	 */
	private float[] sobel(int x, int y) {
		int v00=0,v01=0,v02=0,v10=0,v12=0,v20=0,v21=0,v22=0;
 
		int x0 = x-1, x1 = x, x2 = x+1;
		int y0 = y-1, y1 = y, y2 = y+1;
		if (x0<0) x0=0;
		if (y0<0) y0=0;
		if (x2>=width) x2=width-1;
		if (y2>=height) y2=height-1;
 
		v00=image[x0][y0]; v10=image[x1][y0]; v20=image[x2][y0];
		v01=image[x0][y1];                    v21=image[x2][y1];
		v02=image[x0][y2]; v12=image[x1][y2]; v22=image[x2][y2];
 
		float sx = ((v20+2*v21+v22)-(v00+2*v01+v02))/(4*255f);
		float sy = ((v02+2*v12+v22)-(v00+2*v10+v20))/(4*255f);
		return new float[] {sx,sy};
	}
 
 
	/**
	 * Compute the 3 arrays Ix, Iy and Ixy
	 */
	private void computeDerivatives(double sigma){
		this.Lx2 = new float[width][height];
		this.Ly2 = new float[width][height];
		this.Lxy = new float[width][height];
 
		// gradient values: Gx,Gy
		float[][][] grad = new float[width][height][];
		for (int y=0; y<height; y++)
			for (int x=0; x<width; x++)
				grad[x][y] = sobel(x,y);
 
		// precompute the coefficients of the gaussian filter
		int radius = (int)(2*sigma);
		int window = 1+2*radius;
		float[][] gaussian = new float[window][window];
		for(int j=-radius;j<=radius;j++)
			for(int i=-radius;i<=radius;i++)
				gaussian[i+radius][j+radius]=(float)gaussian(i,j,sigma);
 
		// Convolve gradient with gaussian filter:
		//
		// Ix2 = (F) * (Gx^2)
		// Iy2 = (F) * (Gy^2)
		// Ixy = (F) * (Gx.Gy)
		//
		for (int y=0; y<height; y++) {
			for (int x=0; x<width; x++) {
 
				for(int dy=-radius;dy<=radius;dy++) {
					for(int dx=-radius;dx<=radius;dx++) {
						int xk = x + dx;
						int yk = y + dy;
						if (xk<0 || xk>=width) continue;
						if (yk<0 || yk>=height) continue;
 
						// gaussian weight
						double gw = gaussian[dx+radius][dy+radius];
 
						// convolution
						this.Lx2[x][y]+=gw*grad[xk][yk][0]*grad[xk][yk][0];
						this.Ly2[x][y]+=gw*grad[xk][yk][1]*grad[xk][yk][1];
						this.Lxy[x][y]+=gw*grad[xk][yk][0]*grad[xk][yk][1];
					}
				}
			}
		}
	}
 
	/**
	 * compute harris measure for a pixel
	 */
	private float harrisMeasure(int x, int y, float k) {
		// matrix elements (normalized)
		float m00 = this.Lx2[x][y]; 
		float m01 = this.Lxy[x][y];
		float m10 = this.Lxy[x][y];
		float m11 = this.Ly2[x][y];
 
		// Harris corner measure = det(M)-k.trace(M)^2
		return m00*m11 - m01*m10 - k*(m00+m11)*(m00+m11);
	}
 
	/**
	 * return true if the measure at pixel (x,y) is a local spatial Maxima
	 */
	private boolean isSpatialMaxima(float[][] hmap, int x, int y) {
		int n=8;
		int[] dx = new int[] {-1,0,1,1,1,0,-1,-1};
		int[] dy = new int[] {-1,-1,-1,0,1,1,1,0};
		double w =  hmap[x][y];
		for(int i=0;i<n;i++) {
			double wk = hmap[x+dx[i]][y+dy[i]];
			if (wk>=w) return false;
		}
		return true;
	}
 
	/**
	 * compute the Harris measure for each pixel of the image
	 */
	private float[][] computeHarrisMap(double k) {
 
		// Harris measure map
		float[][] harrismap = new float[width][height];
 
		// for each pixel in the image
		for (int y=0; y<height; y++) {
			for (int x=0; x<width; x++) {
				// compute the harris measure
				double h =  harrisMeasure(x,y,(float)k);
				if (h<=0) continue;
				// log scale
				h = 255 * Math.log(1+h) / Math.log(1+255);
				// store
				harrismap[x][y]=(float)h;
			}
		}
 
		return harrismap;
	}
 
	/**
	 * Perfom the Harris Corner Detection
	 * 
	 * @param sigma gaussian filter parameter 
	 * @param k parameter of the harris measure formula
	 * @param minDistance minimum distance between corners
	 * @return the orginal image marked with cross sign at each corner
	 */
	public int[][] filter(double sigma, double k, int minDistance) {
 
		// precompute derivatives
		computeDerivatives(sigma);
 
		// Harris measure map
		float[][] harrismap = computeHarrisMap(k);
 
		// for each pixel in the harrismap 
		for (int y=1; y<height-1; y++) {
			for (int x=1; x<width-1; x++) {
				// thresholding : harris measure > epsilon
				float h = harrismap[x][y];
				if (h<=1E-3) continue;
				// keep only a local maxima
				if (!isSpatialMaxima(harrismap, x, y)) continue;
				// add the corner to the list
				corners.add( new Corner(x,y,h) );
			}
		}
 
		System.out.println(corners.size()+" potential corners found.");
 
		// remove corners to close to each other (keep the highest measure)
		Iterator<Corner> iter = corners.iterator();
		while(iter.hasNext()) {
			Corner p = iter.next();
			for(Corner n:corners) {
				if (n==p) continue;
				int dist = (int)Math.sqrt( (p.x-n.x)*(p.x-n.x)+(p.y-n.y)*(p.y-n.y) );
				if(dist>minDistance) continue;
				if (n.h<p.h) continue;
				iter.remove();
				break;
			}
		}
 
		// output
		int[][] output =new int[width][height];
		for (int y=0; y<height; y++)
			for (int x=0; x<width; x++)
				output[x][y]=(int)(image[x][y]*0.75); // original image (darker)
 
		// for each corner
		for (Corner p:corners) {
			// add the cross sign over the image
			for (int dt=-3; dt<=3; dt++) {
				if (p.x+dt>=0 && p.x+dt<width ) output[p.x+dt][p.y]=255;
				if (p.y+dt>=0 && p.y+dt<height) output[p.x][p.y+dt]=255;
			}
			System.out.println("corner found at: "+p.x+","+p.y+" ("+p.h+")");
		}		
		System.out.println(corners.size()+" corners found.");
 
		return output;
	}
}

Pour l'utiliser:
Code java :
1
2
3
4
5
6
7
8
9
10
11
12
 
int[][] input = ... // tableau 2D [x][y] contenant l'image en niveau de gris (0-255)
int width     = ... // largeur de l'image
int height    = ... // hauteur de l'image
 
int sigma   = 1.2;  // parametre du filtre gaussien
int k       = 0.06; // parametre de la formule de la mesure
int spacing = 8;    // distance minimum entre 2 coins
 
int[][] output = new HarrisFast(img,width,height).filter(sigma,k,spacing);
 
// output[][] : image d'entrée avec les coins marqués par des croix
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/07/2008, 23h55   #15
Invité de passage
 
Inscription : juillet 2008
Messages : 4
Détails du profil
Informations forums :
Inscription : juillet 2008
Messages : 4
Points : 1
Points : 1
Bonjour,

j'essaye désespérément de savoir de quoi est capable un détecteur de Harris, et surtout si je vais pouvoir l'utiliser pour mon projet. Voilà j'y connais pas grand chose en "computer vision" et j'aimerais trouver un algo qui puisse me donner les coordonnées de formes géométriques simples (rectangles).
Naïvement je pense que le détecteur de Harris est la solution à mon pb.

Voilà donc je tente d'utiliser votre implémentation, mais le résultat qu'il me sort n'est pas très cohérent. Mon niveau en graphic avec java est assez faible, je débute, donc je dois surement passer de mauvaise ressource à Fast Harris.

Toutes remarques bienvenues !
Merci

Code Java :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 
		Image sourceImage;
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		sourceImage = toolkit.getImage("E:\\Workspace\\tmp\\test-corners.png");
 
 
		int[][] input; // tableau 2D [x][y] contenant l'image en niveau de gris (0-255)
		int width; // largeur de l'image
		int height; // hauteur de l'image
 
		int window  = 3;   // taille du filtre gaussien
		double sigma   = 1.2; // parametre du filtre gaussien
		int min     = 32;  // courbure minimum pour un coin
		int spacing = 8;   // distance minimum entre 2 coins
 
		PixelGrabber grabber = new PixelGrabber(sourceImage, 0, 0, -1, -1, false);
		grabber.startGrabbing();
		if (grabber.grabPixels()) {
			boolean isGrey = isGreyscaleImage(grabber);
            width = grabber.getWidth();
            height = grabber.getHeight();
            byte[] data = (byte[]) grabber.getPixels();
            input = new int[width][height];
 
            for (int x=0; x < width; x++)
    		{
    			for (int y=0; y < height; y++)
    			{
    				int offset = x*height + y;
    				byte val = data[offset];
    				if (val == -1){
    					input[x][y] = (int)255;
    				}else{
    					input[x][y] = (int) val;
    				}
    			}
    		}
 
            int[][] output = new HarrisFast(input,width,height).filter(window,sigma,min,spacing);
 
            int[] outData = new int[width * height];
            for (int x=0; x < width; x++)
    		{
    			for (int y=0; y < height; y++)
    			{
    				int offset = x*height + y;
    				int val = output[x][y];
    				if (val == 255){
    					outData[offset] = -1;
    				}else{
    					outData[offset] = val;
    				}
    			}
    		}
 
            BufferedImage out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            out.setRGB(0, 0, width, height, outData, 0, width);
            File file = new File("E:\\Workspace\\tmp\\out-harris.png");
            ImageIO.write(out, "png", file);
dmanu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/08/2008, 15h26   #16
Membre du Club
 
Étudiant
Inscription : décembre 2006
Messages : 175
Détails du profil
Informations personnelles :
Âge : 25
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2006
Messages : 175
Points : 69
Points : 69
Par défaut facteur*1000

Pour revenir sur le détecteur de Harris dans le code de pseudocode.
A quoi sert le coef multiplicateur * 1000 lors du calcul des coefficients gaussiens ?
Methode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/08/2008, 15h47   #17
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Citation:
Envoyé par Methode Voir le message
Pour revenir sur le détecteur de Harris dans le code de pseudocode.
A quoi sert le coef multiplicateur * 1000 lors du calcul des coefficients gaussiens ?
Hum... au départ je dirais que c'etait pour stocker les valeurs sur des "int" et pas des "double" pour accelerer les calculs. Mais comme grad[][] est un double, ca n'a plus aucun interet.
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/08/2008, 17h27   #18
Membre du Club
 
Étudiant
Inscription : décembre 2006
Messages : 175
Détails du profil
Informations personnelles :
Âge : 25
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Étudiant

Informations forums :
Inscription : décembre 2006
Messages : 175
Points : 69
Points : 69
Par défaut re

oki... merci
Methode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/01/2009, 12h19   #19
Invité de passage
 
Inscription : janvier 2009
Messages : 1
Détails du profil
Informations forums :
Inscription : janvier 2009
Messages : 1
Points : 1
Points : 1
Par défaut comment limiter le nombre de corners

merci pour le code , personnellement je l'ai tester et ça marche convenablement. Le seul problème que j'ai rencontré c'est comment fixer un seuil maximal pour le nombre de coins sachant que dans votre code le paramètre nmbmax est écrit dans le commentaire mais pas utilisé dans la méthode filtre .Donc je vous demande comment procéder pour limiter le nombre de coin à seuil donné.
/**
* Perfom Harris Corner Detection
*
* @param c Image map
* @param tilesize size of a tile
* @param nmbmax max number of corner to keep
* @return filtered image map
*/
public ByteProcessor filter(ByteProcessor c, int minMeasure, int minDistance)
tarek.z est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/01/2009, 19h56   #20
Rédacteur/Modérateur
 
Avatar de pseudocode
 
Homme Xavier Philippeau
Architecte système
Inscription : décembre 2006
Messages : 9 424
Détails du profil
Informations personnelles :
Nom : Homme Xavier Philippeau
Âge : 39
Localisation : France, Hérault (Languedoc Roussillon)

Informations professionnelles :
Activité : Architecte système
Secteur : Industrie

Informations forums :
Inscription : décembre 2006
Messages : 9 424
Points : 14 133
Points : 14 133
Citation:
Envoyé par tarek.z Voir le message
merci pour le code , personnellement je l'ai tester et ça marche convenablement. Le seul problème que j'ai rencontré c'est comment fixer un seuil maximal pour le nombre de coins sachant que dans votre code le paramètre nmbmax est écrit dans le commentaire mais pas utilisé dans la méthode filtre .Donc je vous demande comment procéder pour limiter le nombre de coin à seuil donné.
Oups. Eclipse ne remet pas encore la javadoc a jour automatiquement.

1. Je vous suggère d'utiliser/adapter le code du post#14 qui est une version un peu plus "optimisée" des calculs.

2. Une méthode qui marche pas mal, c'est d'utiliser un seuil en pourcentage. Pour cela on calcule toutes les mesures de Harris, on normalise et font un simple test de dépassement.

C'est la méthode qui est utilisée dans MillieGUI :

HarrisFastDetectionOperator.java


La normalisation entre 0 et 100 (en échelle Log et qui pourrait être optimisée ):
Code java :
1
2
3
4
5
6
7
8
// rescale measures in 0-100
for (int y=0; y<this.height; y++) {
	for (int x=0; x<this.width; x++) {
		double h=harrismap[x][y];
		if (h<0) h=0; else h = 100 * Math.log(1+h) / Math.log(1+max);
		harrismap[x][y]=h;
	}
}

Le test de dépassement:
Code java :
1
2
3
4
5
6
7
8
9
10
// for each pixel in the hmap, keep the local maxima
for (int y=1; y<this.height-1; y++) {
	for (int x=1; x<this.width-1; x++) {
		double h = harrismap[x][y];
		if (h<this.minMeasure) continue;
		if (!isSpatialMaxima(harrismap, (int)x, (int)y)) continue;
		// add the corner to the list
		getCorner(canal).add( new Corner(x,y,h) );
	}
}
__________________
ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.
pseudocode est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Actualité déjà publiée
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 02h12.


 
 
 
 
Partenaires

Hébergement Web