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 package org.openimaj.image.processing.edges;
32
33 import org.openimaj.image.DisplayUtilities;
34 import org.openimaj.image.FImage;
35 import org.openimaj.image.analysis.algorithm.EdgeDirectionCoherenceVector;
36 import org.openimaj.image.processor.SinglebandImageProcessor;
37
38
39
40
41
42
43
44
45
46
47
48
49 @Deprecated
50 public class CannyEdgeDetector2 implements SinglebandImageProcessor<Float, FImage>
51 {
52 private boolean complete;
53
54
55 private int threshold = 128;
56
57
58 private int hystThresh1 = 50;
59
60
61 private int hystThresh2 = 230;
62
63
64 private int kernelSize = 15;
65
66 final float ORIENT_SCALE = 40F;
67 private int height;
68 private int width;
69 private int picsize;
70 private float[] data;
71 private int derivative_mag[];
72 private float magnitude[];
73 private float orientation[];
74 private FImage sourceImage;
75 private FImage edgeImage;
76
77
78
79
80 public CannyEdgeDetector2()
81 {
82 complete = false;
83 }
84
85
86
87
88 public boolean isImageReady()
89 {
90 return complete;
91 }
92
93
94
95
96
97
98 @Override
99 public void processImage(FImage image)
100 {
101 complete = false;
102
103 final int widGaussianKernel = kernelSize;
104 final int threshold = this.threshold;
105 final int threshold1 = hystThresh1;
106 final int threshold2 = hystThresh2;
107
108 if (threshold < 0 || threshold > 255)
109 {
110 throw new IllegalArgumentException("The value of the threshold " +
111 "is out of its valid range.");
112 }
113
114 if (widGaussianKernel < 3 || widGaussianKernel > 40)
115 {
116 throw new IllegalArgumentException("The value of the widGaussianKernel " +
117 "is out of its valid range.");
118 }
119
120 width = image.getWidth();
121 height = image.getHeight();
122 picsize = width * height;
123 sourceImage = image;
124
125 data = new float[picsize];
126 magnitude = new float[picsize];
127 orientation = new float[picsize];
128
129 final float f = 1.0F;
130 canny_core(f, widGaussianKernel);
131 thresholding_tracker(threshold1, threshold2);
132
133 for (int i = 0; i < picsize; i++)
134 if (data[i] > threshold)
135 data[i] = 1;
136 else
137 data[i] = -1;
138
139 edgeImage = new FImage(data, width, height).normalise();
140 data = null;
141
142 complete = true;
143
144 image.internalAssign(edgeImage);
145 }
146
147
148
149
150
151
152
153
154 protected void display(int[] data)
155 {
156 final FImage tmp = new FImage(width, height);
157 for (int r = 0; r < height; r++)
158 for (int c = 0; c < width; c++)
159 tmp.pixels[r][c] = data[c + r * width] / 255f;
160 DisplayUtilities.display(tmp);
161 }
162
163
164
165
166
167
168
169
170 protected void display(float[] data)
171 {
172 final FImage tmp = new FImage(width, height);
173 for (int r = 0; r < height; r++)
174 for (int c = 0; c < width; c++)
175 tmp.pixels[r][c] = data[c + r * width] / 255f;
176 DisplayUtilities.display(tmp);
177 }
178
179
180
181
182
183 private void canny_core(float f, int i)
184 {
185 derivative_mag = new int[picsize];
186 final float af4[] = new float[i];
187 final float af5[] = new float[i];
188 final float af6[] = new float[i];
189
190 data = sourceImage.clone().multiply(255.0f).getFloatPixelVector();
191 int k4 = 0;
192 do {
193 if (k4 >= i)
194 break;
195 final float f1 = gaussian(k4, f);
196 if (f1 <= 0.005F && k4 >= 2)
197 break;
198 final float f2 = gaussian(k4 - 0.5F, f);
199 final float f3 = gaussian(k4 + 0.5F, f);
200 final float f4 = gaussian(k4, f * 0.5F);
201 af4[k4] = (f1 + f2 + f3) / 3F / (6.283185F * f * f);
202 af5[k4] = f3 - f2;
203 af6[k4] = 1.6F * f4 - f1;
204 k4++;
205 } while (true);
206
207 final int j = k4;
208 float af[] = new float[picsize];
209 float af1[] = new float[picsize];
210 int j1 = width - (j - 1);
211 int l = width * (j - 1);
212 int i1 = width * (height - (j - 1));
213 for (int l4 = j - 1; l4 < j1; l4++) {
214 for (int l5 = l; l5 < i1; l5 += width) {
215 final int k1 = l4 + l5;
216 float f8 = data[k1] * af4[0];
217 float f10 = f8;
218 int l6 = 1;
219 int k7 = k1 - width;
220 for (int i8 = k1 + width; l6 < j; i8 += width) {
221 f8 += af4[l6] * (data[k7] + data[i8]);
222 f10 += af4[l6] * (data[k1 - l6] + data[k1 + l6]);
223 l6++;
224 k7 -= width;
225 }
226
227 af[k1] = f8;
228 af1[k1] = f10;
229 }
230
231 }
232
233 float af2[] = new float[picsize];
234 for (int i5 = j - 1; i5 < j1; i5++) {
235 for (int i6 = l; i6 < i1; i6 += width) {
236 float f9 = 0.0F;
237 final int l1 = i5 + i6;
238 for (int i7 = 1; i7 < j; i7++)
239 f9 += af5[i7] * (af[l1 - i7] - af[l1 + i7]);
240
241 af2[l1] = f9;
242 }
243
244 }
245
246 af = null;
247 float af3[] = new float[picsize];
248 for (int j5 = k4; j5 < width - k4; j5++) {
249 for (int j6 = l; j6 < i1; j6 += width) {
250 float f11 = 0.0F;
251 final int i2 = j5 + j6;
252 int j7 = 1;
253 for (int l7 = width; j7 < j; l7 += width) {
254 f11 += af5[j7] * (af1[i2 - l7] - af1[i2 + l7]);
255 j7++;
256 }
257
258 af3[i2] = f11;
259 }
260
261 }
262
263
264
265 af1 = null;
266 j1 = width - j;
267 l = width * j;
268 i1 = width * (height - j);
269 for (int k5 = j; k5 < j1; k5++) {
270 for (int k6 = l; k6 < i1; k6 += width) {
271 final int j2 = k5 + k6;
272 final int k2 = j2 - width;
273 final int l2 = j2 + width;
274 final int i3 = j2 - 1;
275 final int j3 = j2 + 1;
276 final int k3 = k2 - 1;
277 final int l3 = k2 + 1;
278 final int i4 = l2 - 1;
279 final int j4 = l2 + 1;
280 final float f6 = af2[j2];
281 final float f7 = af3[j2];
282 final float f12 = hypotenuse(f6, f7);
283 final int k = (int) (f12 * 20D);
284 derivative_mag[j2] = k >= 256 ? 255 : k;
285 final float f13 = hypotenuse(af2[k2], af3[k2]);
286 final float f14 = hypotenuse(af2[l2], af3[l2]);
287 final float f15 = hypotenuse(af2[i3], af3[i3]);
288 final float f16 = hypotenuse(af2[j3], af3[j3]);
289 final float f18 = hypotenuse(af2[l3], af3[l3]);
290 final float f20 = hypotenuse(af2[j4], af3[j4]);
291 final float f19 = hypotenuse(af2[i4], af3[i4]);
292 final float f17 = hypotenuse(af2[k3], af3[k3]);
293 float f5;
294 if (f6 * f7 <= 0
295 ? Math.abs(f6) >= Math.abs(f7)
296 ? (f5 = Math.abs(f6 * f12))
297 >= Math.abs(f7 * f18 - (f6 + f7) * f16)
298 && f5
299 > Math.abs(f7 * f19 - (f6 + f7) * f15) : (
300 f5 = Math.abs(f7 * f12))
301 >= Math.abs(f6 * f18 - (f7 + f6) * f13)
302 && f5
303 > Math.abs(f6 * f19 - (f7 + f6) * f14) : Math.abs(f6)
304 >= Math.abs(f7)
305 ? (f5 = Math.abs(f6 * f12))
306 >= Math.abs(f7 * f20 + (f6 - f7) * f16)
307 && f5
308 > Math.abs(f7 * f17 + (f6 - f7) * f15) : (
309 f5 = Math.abs(f7 * f12))
310 >= Math.abs(f6 * f20 + (f7 - f6) * f14)
311 && f5 > Math.abs(f6 * f17 + (f7 - f6) * f13))
312 {
313 magnitude[j2] = derivative_mag[j2];
314 orientation[j2] = (float) Math.toDegrees(
315 Math.atan2(f7, f6));
316 }
317 }
318
319 }
320
321 derivative_mag = null;
322 af2 = null;
323 af3 = null;
324 }
325
326
327
328
329
330
331
332
333
334
335
336 private float hypotenuse(float f, float f1)
337 {
338 if (f == 0.0F && f1 == 0.0F)
339 return 0.0F;
340 else
341 return (float) Math.sqrt(f * f + f1 * f1);
342 }
343
344 private float gaussian(float f, float f1) {
345 return (float) Math.exp((-f * f) / (2 * f1 * f1));
346 }
347
348 private void thresholding_tracker(int i, int j) {
349 for (int k = 0; k < picsize; k++)
350 data[k] = 0;
351
352 for (int l = 0; l < width; l++) {
353 for (int i1 = 0; i1 < height; i1++)
354 if (magnitude[l + width * i1] >= i)
355 follow(l, i1, j);
356
357 }
358
359 }
360
361
362
363
364
365
366
367 private boolean follow(int i, int j, int k)
368 {
369 int j1 = i + 1;
370 int k1 = i - 1;
371 int l1 = j + 1;
372 int i2 = j - 1;
373 final int j2 = i + j * width;
374 if (l1 >= height)
375 l1 = height - 1;
376 if (i2 < 0)
377 i2 = 0;
378 if (j1 >= width)
379 j1 = width - 1;
380 if (k1 < 0)
381 k1 = 0;
382 if (data[j2] == 0) {
383 data[j2] = magnitude[j2];
384 boolean flag = false;
385 int l = k1;
386 do {
387 if (l > j1)
388 break;
389 int i1 = i2;
390 do {
391 if (i1 > l1)
392 break;
393 final int k2 = l + i1 * width;
394 if ((i1 != j || l != i)
395 && magnitude[k2] >= k
396 && follow(l, i1, k))
397 {
398 flag = true;
399 break;
400 }
401 i1++;
402 } while (true);
403 if (!flag)
404 break;
405 l++;
406 } while (true);
407 return true;
408 } else {
409 return false;
410 }
411 }
412
413
414
415
416 public void setSourceImage(FImage image)
417 {
418 sourceImage = image;
419 }
420
421
422
423
424 public FImage getEdgeImage()
425 {
426 return edgeImage;
427 }
428
429
430
431
432 public float[] getMagnitude()
433 {
434 return magnitude;
435 }
436
437
438
439
440 public float[] getOrientation()
441 {
442 return orientation;
443 }
444
445
446
447
448
449
450 public int getThreshold()
451 {
452 return threshold;
453 }
454
455
456
457
458
459
460
461
462 public void setThreshold(int threshold)
463 {
464 this.threshold = threshold;
465 }
466
467
468
469
470
471
472 public int getHystThresh1()
473 {
474 return hystThresh1;
475 }
476
477
478
479
480
481
482
483 public void setHystThresh1(int hystThresh1)
484 {
485 this.hystThresh1 = hystThresh1;
486 }
487
488
489
490
491
492
493 public int getHystThresh2()
494 {
495 return hystThresh2;
496 }
497
498
499
500
501
502
503
504 public void setHystThresh2(int hystThresh2)
505 {
506 this.hystThresh2 = hystThresh2;
507 }
508
509
510
511
512
513
514 public int getKernelSize()
515 {
516 return kernelSize;
517 }
518
519
520
521
522
523
524
525 public void setKernelSize(int kernelSize)
526 {
527 this.kernelSize = kernelSize;
528 }
529 }