Sie sind auf Seite 1von 6

1 namespace Accord.

Imaging
2 {
3 using System.Collections.Generic;
4 using System.Drawing;
5 using System.Drawing.Imaging;
6 using AForge.Imaging;
7 using AForge.Imaging.Filters;
8 using AForge;
9
10
11 public class HarrisCornersDetector : ICornersDetector
12 {
13
14 private float k = 0.04f;
15 private float threshold = 1000f;
16 private double sigma = 1.4;
17 private int r = 3;
18
19
20 /// <summary>
21 /// Harris parameter k. Default value is 0.04.
22 /// </summary>
23 public float K
24 {
25 get { return k; }
26 set { k = value; }
27 }
28
29 /// <summary>
30 /// Harris threshold. Default value is 1000.
31 /// </summary>
32 public float Threshold
33 {
34 get { return threshold; }
35 set { threshold = value; }
36 }
37
38 /// <summary>
39 /// Gaussian smoothing sigma. Default value is 1.4.
40 /// </summary>
41 public double Sigma
42 {
43 get { return sigma; }
44 set { sigma = value; }
45 }
46
47 /// <summary>
48 /// Non-maximum suppression window radius. Default value is 3.
49 /// </summary>
50 public int Suppression
51 {
52 get { return r; }
53 set { r = value; }
54 }
55
56
57
58 /// <summary>
59 /// Initializes a new instance of the <see cref="HarrisCornersDetector"/>
class.
60 /// </summary>
61 public HarrisCornersDetector()
62 {
63 }
64
65 /// <summary>
66 /// Initializes a new instance of the <see cref="HarrisCornersDetector"/>
class.
67 /// </summary>
68 public HarrisCornersDetector(float k)
69 : this()
70 {
71 this.k = k;
72 }
73
74 /// <summary>
75 /// Initializes a new instance of the <see cref="HarrisCornersDetector"/>
class.
76 /// </summary>
77 public HarrisCornersDetector(float k, float threshold)
78 : this()
79 {
80 this.k = k;
81 this.threshold = threshold;
82 }
83
84 /// <summary>
85 /// Initializes a new instance of the <see cref="HarrisCornersDetector"/>
class.
86 /// </summary>
87 public HarrisCornersDetector(float k, float threshold, double sigma)
88 : this()
89 {
90 this.k = k;
91 this.threshold = threshold;
92 this.sigma = sigma;
93 }
94
95
96
97 /// <summary>
98 /// Process image looking for corners.
99 /// </summary>
100 ///
101 /// <param name="image">Source image data to process.</param>
102 ///
103 /// <returns>Returns list of found corners (X-Y coordinates).</returns>
104 ///
105 /// <exception cref="UnsupportedImageFormatException">
106 /// The source image has incorrect pixel format.
107 /// </exception>
108 ///
109 public List<IntPoint> ProcessImage(UnmanagedImage image)
110 {
111 // check image format
112 if (
113 (image.PixelFormat != PixelFormat.Format8bppIndexed) &&
114 (image.PixelFormat != PixelFormat.Format24bppRgb) &&
115 (image.PixelFormat != PixelFormat.Format32bppRgb) &&
116 (image.PixelFormat != PixelFormat.Format32bppArgb)
117 )
118 {
119 throw new UnsupportedImageFormatException("Unsupported pixel format
of the source image.");
120 }
121
122 // make sure we have grayscale image
123 UnmanagedImage grayImage = null;
124
125 if (image.PixelFormat == PixelFormat.Format8bppIndexed)
126 {
127 grayImage = image;
128 }
129 else
130 {
131 // create temporary grayscale image
132 grayImage = Grayscale.CommonAlgorithms.BT709.Apply(image);
133 }
134
135
136 // get source image size
137 int width = grayImage.Width;
138 int height = grayImage.Height;
139 int stride = grayImage.Stride;
140 int offset = stride - width;
141
142
143
144 // 1. Calculate partial differences
145 UnmanagedImage diffx = UnmanagedImage.Create(width, height,
PixelFormat.Format8bppIndexed);
146 UnmanagedImage diffy = UnmanagedImage.Create(width, height,
PixelFormat.Format8bppIndexed);
147 UnmanagedImage diffxy = UnmanagedImage.Create(width, height,
PixelFormat.Format8bppIndexed);
148
149 unsafe
150 {
151 // Compute dx and dy
152 byte* src = (byte*)grayImage.ImageData.ToPointer();
153 byte* dx = (byte*)diffx.ImageData.ToPointer();
154 byte* dy = (byte*)diffy.ImageData.ToPointer();
155 byte* dxy = (byte*)diffxy.ImageData.ToPointer();
156
157 // for each line
158 for (int y = 0; y < height; y++)
159 {
160 // for each pixel
161 for (int x = 0; x < width; x++, src++, dx++, dy++)
162 {
163 // TODO: Place those verifications
164 // outside the innermost loop
165 if (x == 0 || x == width - 1 ||
166 y == 0 || y == height - 1)
167 {
168 *dx = *dy = 0; continue;
169 }
170
171 int h = -(src[-stride - 1] + src[-1] + src[stride - 1]) +
172 (src[-stride + 1] + src[+1] + src[stride + 1]);
173 *dx = (byte)(h > 255 ? 255 : h < 0 ? 0 : h);
174
175 int v = -(src[-stride - 1] + src[-stride] + src[-stride +
1]) +
176 (src[+stride - 1] + src[+stride] + src[+stride + 1]);
177 *dy = (byte)(v > 255 ? 255 : v < 0 ? 0 : v);
178 }
179 src += offset;
180 dx += offset;
181 dy += offset;
182 }
183
184
185 // Compute dxy
186 dx = (byte*)diffx.ImageData.ToPointer();
187 dxy = (byte*)diffxy.ImageData.ToPointer();
188
189 // for each line
190 for (int y = 0; y < height; y++)
191 {
192 // for each pixel
193 for (int x = 0; x < width; x++, dx++, dxy++)
194 {
195 if (x == 0 || x == width - 1 ||
196 y == 0 || y == height - 1)
197 {
198 *dxy = 0; continue;
199 }
200
201 int v = -(dx[-stride - 1] + dx[-stride] + dx[-stride + 1]) +
202 (dx[+stride - 1] + dx[+stride] + dx[+stride + 1]);
203 *dxy = (byte)(v > 255 ? 255 : v < 0 ? 0 : v);
204 }
205 dx += offset;
206 dxy += offset;
207 }
208 }
209
210
211 // 2. Smooth the diff images
212 if (sigma > 0.0)
213 {
214 GaussianBlur blur = new GaussianBlur(sigma);
215 blur.ApplyInPlace(diffx);
216 blur.ApplyInPlace(diffy);
217 blur.ApplyInPlace(diffxy);
218 }
219
220
221 // 3. Compute Harris Corner Response
222 float[,] H = new float[height, width];
223
224 unsafe
225 {
226 byte* ptrA = (byte*)diffx.ImageData.ToPointer();
227 byte* ptrB = (byte*)diffy.ImageData.ToPointer();
228 byte* ptrC = (byte*)diffxy.ImageData.ToPointer();
229 float M, A, B, C;
230
231 for (int y = 0; y < height; y++)
232 {
233 for (int x = 0; x < width; x++)
234 {
235 A = *(ptrA++);
236 B = *(ptrB++);
237 C = *(ptrC++);
238
239 // Harris corner measure
240 M = (A * B - C * C) - (k * ((A + B) * (A + B)));
241
242 if (M > threshold)
243 H[y, x] = M;
244 else H[y, x] = 0;
245 }
246
247 ptrA += offset;
248 ptrB += offset;
249 ptrC += offset;
250 }
251 }
252
253
254 // Free resources
255 diffx.Dispose();
256 diffy.Dispose();
257 diffxy.Dispose();
258
259 if (image.PixelFormat != PixelFormat.Format8bppIndexed)
260 grayImage.Dispose();
261
262
263 // 4. Suppress non-maximum points
264 List<IntPoint> cornersList = new List<IntPoint>();
265
266 // for each row
267 for (int y = r, maxY = height - r; y < maxY; y++)
268 {
269 // for each pixel
270 for (int x = r, maxX = width - r; x < maxX; x++)
271 {
272 float currentValue = H[y, x];
273
274 // for each windows' row
275 for (int i = -r; (currentValue != 0) && (i <= r); i++)
276 {
277 // for each windows' pixel
278 for (int j = -r; j <= r; j++)
279 {
280 if (H[y + i, x + j] > currentValue)
281 {
282 currentValue = 0;
283 break;
284 }
285 }
286 }
287
288 // check if this point is really interesting
289 if (currentValue != 0)
290 {
291 cornersList.Add(new IntPoint(x, y));
292 }
293 }
294 }
295
296
297 return cornersList;
298 }
299
300 /// <summary>
301 /// Process image looking for corners.
302 /// </summary>
303 ///
304 /// <param name="imageData">Source image data to process.</param>
305 ///
306 /// <returns>Returns list of found corners (X-Y coordinates).</returns>
307 ///
308 /// <exception cref="UnsupportedImageFormatException">
309 /// The source image has incorrect pixel format.
310 /// </exception>
311 ///
312 public List<IntPoint> ProcessImage(BitmapData imageData)
313 {
314 return ProcessImage(new UnmanagedImage(imageData));
315 }
316
317 /// <summary>
318 /// Process image looking for corners.
319 /// </summary>
320 ///
321 /// <param name="image">Source image data to process.</param>
322 ///
323 /// <returns>Returns list of found corners (X-Y coordinates).</returns>
324 ///
325 /// <exception cref="UnsupportedImageFormatException">
326 /// The source image has incorrect pixel format.
327 /// </exception>
328 ///
329 public List<IntPoint> ProcessImage(Bitmap image)
330 {
331 // check image format
332 if (
333 (image.PixelFormat != PixelFormat.Format8bppIndexed) &&
334 (image.PixelFormat != PixelFormat.Format24bppRgb) &&
335 (image.PixelFormat != PixelFormat.Format32bppRgb) &&
336 (image.PixelFormat != PixelFormat.Format32bppArgb)
337 )
338 {
339 throw new UnsupportedImageFormatException("Unsupported pixel format
of the source");
340 }
341
342 // lock source image
343 BitmapData imageData = image.LockBits(
344 new Rectangle(0, 0, image.Width, image.Height),
345 ImageLockMode.ReadOnly, image.PixelFormat);
346
347 List<IntPoint> corners;
348
349 try
350 {
351 // process the image
352 corners = ProcessImage(new UnmanagedImage(imageData));
353 }
354 finally
355 {
356 // unlock image
357 image.UnlockBits(imageData);
358 }
359
360 return corners;
361 }
362
363 }
364 }

Das könnte Ihnen auch gefallen