IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Contribution Image : Détecteur de Harris pour ImageJ
Par Xavier Philippeau

Le , par pseudocode

45PARTAGES

1  0 
Continuons avec l'extraction des points caractéristiques. Après les contours (Canny), passons maintenant aux coins avec Harris.

Le détecteur de Harris est un détecteur 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 : Sélectionner tout
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&nbsp;:-) 
  
		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

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de pseudocode
Rédacteur https://www.developpez.com
Le 22/06/2011 à 17:11
Citation Envoyé par azertyuio Voir le message
aah d'accord donc je dois ajouter un test si la valeur est négative je la détecte pas !!
c'est à dire pour toutes les valeurs de R (la matrice de mesure de Harris) si la valeurs est négative je ne la détecte pas.
c'est ça ?
C'est ca.

- Si la valeur est négative, c'est un bord => on ne marque pas le pixel
- Si la valeur est nulle (ou très faible), c'est une zone homogène => on ne marque pas le pixel
- Si la valeur est positive, c'est un coin => on marque le pixel !
1  0 
Avatar de parp1
Membre éclairé https://www.developpez.com
Le 27/04/2007 à 15:24
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
0  0 
Avatar de pseudocode
Rédacteur https://www.developpez.com
Le 27/04/2007 à 16:47
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.
0  0 
Avatar de parp1
Membre éclairé https://www.developpez.com
Le 27/04/2007 à 17:15
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.
0  0 
Avatar de pseudocode
Rédacteur https://www.developpez.com
Le 10/05/2007 à 19:30
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)
0  0 
Avatar de kruskal21
Membre à l'essai https://www.developpez.com
Le 02/06/2007 à 0:01
y a t'il une version C++ de cet algorithme?
0  0 
Avatar de millie
Rédacteur https://www.developpez.com
Le 02/06/2007 à 10:22
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.
0  0 
Avatar de pseudocode
Rédacteur https://www.developpez.com
Le 02/06/2007 à 13:23
Citation Envoyé par kruskal21
y a t'il une version C++ de cet algorithme?
Faut demander gentiment à Millie de le porter dans la MillieLib...
0  0 
Avatar de Methode
Membre régulier https://www.developpez.com
Le 12/05/2008 à 23:10
Annule et remplace :

Voici maintenant mon lanceur :

Code : Sélectionner tout
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
0  0 
Avatar de pseudocode
Rédacteur https://www.developpez.com
Le 13/05/2008 à 10:24
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.
0  0