"Fossies" - the Fresh Open Source Software Archive 
Member "scikit-image-0.19.3/skimage/transform/tests/test_hough_transform.py" (12 Jun 2022, 19722 Bytes) of package /linux/misc/scikit-image-0.19.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
1 import numpy as np
2 import pytest
3 from numpy.testing import assert_almost_equal, assert_equal
4
5 from skimage import data, transform
6 from skimage._shared.testing import test_parallel
7 from skimage.draw import circle_perimeter, ellipse_perimeter, line
8
9
10 @test_parallel()
11 def test_hough_line():
12 # Generate a test image
13 img = np.zeros((100, 150), dtype=int)
14 rr, cc = line(60, 130, 80, 10)
15 img[rr, cc] = 1
16
17 out, angles, d = transform.hough_line(img)
18
19 y, x = np.where(out == out.max())
20 dist = d[y[0]]
21 theta = angles[x[0]]
22
23 assert_almost_equal(dist, 80.0, 1)
24 assert_almost_equal(theta, 1.41, 1)
25
26
27 def test_hough_line_angles():
28 img = np.zeros((10, 10))
29 img[0, 0] = 1
30
31 out, angles, d = transform.hough_line(img, np.linspace(0, 360, 10))
32
33 assert_equal(len(angles), 10)
34
35
36 def test_hough_line_bad_input():
37 img = np.zeros(100)
38 img[10] = 1
39
40 # Expected error, img must be 2D
41 with pytest.raises(ValueError):
42 transform.hough_line(img, np.linspace(0, 360, 10))
43
44
45 def test_probabilistic_hough():
46 # Generate a test image
47 img = np.zeros((100, 100), dtype=int)
48 for i in range(25, 75):
49 img[100 - i, i] = 100
50 img[i, i] = 100
51
52 # decrease default theta sampling because similar orientations may confuse
53 # as mentioned in article of Galambos et al
54 theta = np.linspace(0, np.pi, 45)
55 lines = transform.probabilistic_hough_line(
56 img, threshold=10, line_length=10, line_gap=1, theta=theta)
57 # sort the lines according to the x-axis
58 sorted_lines = []
59 for ln in lines:
60 ln = list(ln)
61 ln.sort(key=lambda x: x[0])
62 sorted_lines.append(ln)
63
64 assert([(25, 75), (74, 26)] in sorted_lines)
65 assert([(25, 25), (74, 74)] in sorted_lines)
66
67 # Execute with default theta
68 transform.probabilistic_hough_line(img, line_length=10, line_gap=3)
69
70
71 def test_probabilistic_hough_seed():
72 # Load image that is likely to give a randomly varying number of lines
73 image = data.checkerboard()
74
75 # Use constant seed to ensure a deterministic output
76 lines = transform.probabilistic_hough_line(image, threshold=50,
77 line_length=50, line_gap=1,
78 seed=41537233)
79 assert len(lines) == 56
80
81
82 def test_probabilistic_hough_bad_input():
83 img = np.zeros(100)
84 img[10] = 1
85
86 # Expected error, img must be 2D
87 with pytest.raises(ValueError):
88 transform.probabilistic_hough_line(img)
89
90
91 def test_hough_line_peaks():
92 img = np.zeros((100, 150), dtype=int)
93 rr, cc = line(60, 130, 80, 10)
94 img[rr, cc] = 1
95
96 out, angles, d = transform.hough_line(img)
97
98 out, theta, dist = transform.hough_line_peaks(out, angles, d)
99
100 assert_equal(len(dist), 1)
101 assert_almost_equal(dist[0], 81.0, 1)
102 assert_almost_equal(theta[0], 1.41, 1)
103
104
105 def test_hough_line_peaks_ordered():
106 # Regression test per PR #1421
107 testim = np.zeros((256, 64), dtype=bool)
108
109 testim[50:100, 20] = True
110 testim[20:225, 25] = True
111 testim[15:35, 50] = True
112 testim[1:-1, 58] = True
113
114 hough_space, angles, dists = transform.hough_line(testim)
115
116 hspace, _, _ = transform.hough_line_peaks(hough_space, angles, dists)
117 assert hspace[0] > hspace[1]
118
119
120 def test_hough_line_peaks_single_line():
121 # Regression test for gh-6187, gh-4129
122
123 # create an empty test image
124 img = np.zeros((100, 100), dtype=bool)
125 # draw a horizontal line into our test image
126 img[30, :] = 1
127
128 hough_space, angles, dist = transform.hough_line(img)
129
130 best_h_space, best_angles, best_dist = transform.hough_line_peaks(
131 hough_space, angles, dist
132 )
133 assert len(best_angles) == 1
134 assert len(best_dist) == 1
135 expected_angle = -np.pi / 2
136 expected_dist = -30
137 assert abs(best_angles[0] - expected_angle) < 0.01
138 assert abs(best_dist[0] - expected_dist) < 0.01
139
140
141 def test_hough_line_peaks_dist():
142 img = np.zeros((100, 100), dtype=bool)
143 img[:, 30] = True
144 img[:, 40] = True
145 hspace, angles, dists = transform.hough_line(img)
146 assert len(transform.hough_line_peaks(hspace, angles, dists,
147 min_distance=5)[0]) == 2
148 assert len(transform.hough_line_peaks(hspace, angles, dists,
149 min_distance=15)[0]) == 1
150
151
152 def test_hough_line_peaks_angle():
153 check_hough_line_peaks_angle()
154
155
156 def check_hough_line_peaks_angle():
157 img = np.zeros((100, 100), dtype=bool)
158 img[:, 0] = True
159 img[0, :] = True
160
161 hspace, angles, dists = transform.hough_line(img)
162 assert len(transform.hough_line_peaks(hspace, angles, dists,
163 min_angle=45)[0]) == 2
164 assert len(transform.hough_line_peaks(hspace, angles, dists,
165 min_angle=90)[0]) == 1
166
167 theta = np.linspace(0, np.pi, 100)
168 hspace, angles, dists = transform.hough_line(img, theta)
169 assert len(transform.hough_line_peaks(hspace, angles, dists,
170 min_angle=45)[0]) == 2
171 assert len(transform.hough_line_peaks(hspace, angles, dists,
172 min_angle=90)[0]) == 1
173
174 theta = np.linspace(np.pi / 3, 4. / 3 * np.pi, 100)
175 hspace, angles, dists = transform.hough_line(img, theta)
176 assert len(transform.hough_line_peaks(hspace, angles, dists,
177 min_angle=45)[0]) == 2
178 assert len(transform.hough_line_peaks(hspace, angles, dists,
179 min_angle=90)[0]) == 1
180
181
182 def test_hough_line_peaks_num():
183 img = np.zeros((100, 100), dtype=bool)
184 img[:, 30] = True
185 img[:, 40] = True
186 hspace, angles, dists = transform.hough_line(img)
187 assert len(transform.hough_line_peaks(hspace, angles, dists,
188 min_distance=0, min_angle=0,
189 num_peaks=1)[0]) == 1
190
191
192 def test_hough_line_peaks_zero_input():
193 # Test to make sure empty input doesn't cause a failure
194 img = np.zeros((100, 100), dtype='uint8')
195 theta = np.linspace(0, np.pi, 100)
196 hspace, angles, dists = transform.hough_line(img, theta)
197 h, a, d = transform.hough_line_peaks(hspace, angles, dists)
198 assert_equal(a, np.array([]))
199
200
201 def test_hough_line_peaks_single_angle():
202 # Regression test for gh-4814
203 # This code snippet used to raise an IndexError
204 img = np.random.random((100, 100))
205 tested_angles = np.array([np.pi / 2])
206 h, theta, d = transform.hough_line(img, theta=tested_angles)
207 accum, angles, dists = transform.hough_line_peaks(h, theta, d, threshold=2)
208
209
210 @test_parallel()
211 def test_hough_circle():
212 # Prepare picture
213 img = np.zeros((120, 100), dtype=int)
214 radius = 20
215 x_0, y_0 = (99, 50)
216 y, x = circle_perimeter(y_0, x_0, radius)
217 img[x, y] = 1
218
219 out1 = transform.hough_circle(img, radius)
220 out2 = transform.hough_circle(img, [radius])
221 assert_equal(out1, out2)
222 out = transform.hough_circle(img, np.array([radius], dtype=np.intp))
223 assert_equal(out, out1)
224 x, y = np.where(out[0] == out[0].max())
225 assert_equal(x[0], x_0)
226 assert_equal(y[0], y_0)
227
228
229 def test_hough_circle_extended():
230 # Prepare picture
231 # The circle center is outside the image
232 img = np.zeros((100, 100), dtype=int)
233 radius = 20
234 x_0, y_0 = (-5, 50)
235 y, x = circle_perimeter(y_0, x_0, radius)
236 img[x[np.where(x > 0)], y[np.where(x > 0)]] = 1
237
238 out = transform.hough_circle(img, np.array([radius], dtype=np.intp),
239 full_output=True)
240
241 x, y = np.where(out[0] == out[0].max())
242 # Offset for x_0, y_0
243 assert_equal(x[0], x_0 + radius)
244 assert_equal(y[0], y_0 + radius)
245
246
247 def test_hough_circle_peaks():
248 x_0, y_0, rad_0 = (99, 50, 20)
249 img = np.zeros((120, 100), dtype=int)
250 y, x = circle_perimeter(y_0, x_0, rad_0)
251 img[x, y] = 1
252
253 x_1, y_1, rad_1 = (49, 60, 30)
254 y, x = circle_perimeter(y_1, x_1, rad_1)
255 img[x, y] = 1
256
257 radii = [rad_0, rad_1]
258 hspaces = transform.hough_circle(img, radii)
259 out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=1,
260 min_ydistance=1, threshold=None,
261 num_peaks=np.inf,
262 total_num_peaks=np.inf)
263 s = np.argsort(out[3]) # sort by radii
264 assert_equal(out[1][s], np.array([y_0, y_1]))
265 assert_equal(out[2][s], np.array([x_0, x_1]))
266 assert_equal(out[3][s], np.array([rad_0, rad_1]))
267
268
269 def test_hough_circle_peaks_total_peak():
270 img = np.zeros((120, 100), dtype=int)
271
272 x_0, y_0, rad_0 = (99, 50, 20)
273 y, x = circle_perimeter(y_0, x_0, rad_0)
274 img[x, y] = 1
275
276 x_1, y_1, rad_1 = (49, 60, 30)
277 y, x = circle_perimeter(y_1, x_1, rad_1)
278 img[x, y] = 1
279
280 radii = [rad_0, rad_1]
281 hspaces = transform.hough_circle(img, radii)
282 out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=1,
283 min_ydistance=1, threshold=None,
284 num_peaks=np.inf, total_num_peaks=1)
285 assert_equal(out[1][0], np.array([y_1, ]))
286 assert_equal(out[2][0], np.array([x_1, ]))
287 assert_equal(out[3][0], np.array([rad_1, ]))
288
289
290 def test_hough_circle_peaks_min_distance():
291 x_0, y_0, rad_0 = (50, 50, 20)
292 img = np.zeros((120, 100), dtype=int)
293 y, x = circle_perimeter(y_0, x_0, rad_0)
294 img[x, y] = 1
295
296 x_1, y_1, rad_1 = (60, 60, 30)
297 y, x = circle_perimeter(y_1, x_1, rad_1)
298 # Add noise and create an imperfect circle to lower the peak in Hough space
299 y[::2] += 1
300 x[::2] += 1
301 img[x, y] = 1
302
303 x_2, y_2, rad_2 = (70, 70, 20)
304 y, x = circle_perimeter(y_2, x_2, rad_2)
305 # Add noise and create an imperfect circle to lower the peak in Hough space
306 y[::2] += 1
307 x[::2] += 1
308 img[x, y] = 1
309
310 radii = [rad_0, rad_1, rad_2]
311 hspaces = transform.hough_circle(img, radii)
312 out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=15,
313 min_ydistance=15, threshold=None,
314 num_peaks=np.inf,
315 total_num_peaks=np.inf,
316 normalize=True)
317
318 # The second circle is too close to the first one
319 # and has a weaker peak in Hough space due to imperfectness.
320 # Therefore it got removed.
321 assert_equal(out[1], np.array([y_0, y_2]))
322 assert_equal(out[2], np.array([x_0, x_2]))
323 assert_equal(out[3], np.array([rad_0, rad_2]))
324
325
326 def test_hough_circle_peaks_total_peak_and_min_distance():
327 img = np.zeros((120, 120), dtype=int)
328 cx = cy = [40, 50, 60, 70, 80]
329 radii = range(20, 30, 2)
330 for i in range(len(cx)):
331 y, x = circle_perimeter(cy[i], cx[i], radii[i])
332 img[x, y] = 1
333
334 hspaces = transform.hough_circle(img, radii)
335 out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=15,
336 min_ydistance=15, threshold=None,
337 num_peaks=np.inf,
338 total_num_peaks=2,
339 normalize=True)
340
341 # 2nd (4th) circle is removed as it is close to 1st (3rd) oneself.
342 # 5th is removed as total_num_peaks = 2
343 assert_equal(out[1], np.array(cy[:4:2]))
344 assert_equal(out[2], np.array(cx[:4:2]))
345 assert_equal(out[3], np.array(radii[:4:2]))
346
347
348 def test_hough_circle_peaks_normalize():
349 x_0, y_0, rad_0 = (50, 50, 20)
350 img = np.zeros((120, 100), dtype=int)
351 y, x = circle_perimeter(y_0, x_0, rad_0)
352 img[x, y] = 1
353
354 x_1, y_1, rad_1 = (60, 60, 30)
355 y, x = circle_perimeter(y_1, x_1, rad_1)
356 img[x, y] = 1
357
358 radii = [rad_0, rad_1]
359 hspaces = transform.hough_circle(img, radii)
360 out = transform.hough_circle_peaks(hspaces, radii, min_xdistance=15,
361 min_ydistance=15, threshold=None,
362 num_peaks=np.inf,
363 total_num_peaks=np.inf,
364 normalize=False)
365
366 # Two perfect circles are close but the second one is bigger.
367 # Therefore, it is picked due to its high peak.
368 assert_equal(out[1], np.array([y_1]))
369 assert_equal(out[2], np.array([x_1]))
370 assert_equal(out[3], np.array([rad_1]))
371
372
373 def test_hough_ellipse_zero_angle():
374 img = np.zeros((25, 25), dtype=int)
375 rx = 6
376 ry = 8
377 x0 = 12
378 y0 = 15
379 angle = 0
380 rr, cc = ellipse_perimeter(y0, x0, ry, rx)
381 img[rr, cc] = 1
382 result = transform.hough_ellipse(img, threshold=9)
383 best = result[-1]
384 assert_equal(best[1], y0)
385 assert_equal(best[2], x0)
386 assert_almost_equal(best[3], ry, decimal=1)
387 assert_almost_equal(best[4], rx, decimal=1)
388 assert_equal(best[5], angle)
389 # Check if I re-draw the ellipse, points are the same!
390 # ie check API compatibility between hough_ellipse and ellipse_perimeter
391 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
392 orientation=best[5])
393 assert_equal(rr, rr2)
394 assert_equal(cc, cc2)
395
396
397 def test_hough_ellipse_non_zero_posangle1():
398 # ry > rx, angle in [0:pi/2]
399 img = np.zeros((30, 24), dtype=int)
400 rx = 6
401 ry = 12
402 x0 = 10
403 y0 = 15
404 angle = np.pi / 1.35
405 rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
406 img[rr, cc] = 1
407 result = transform.hough_ellipse(img, threshold=15, accuracy=3)
408 result.sort(order='accumulator')
409 best = result[-1]
410 assert_almost_equal(best[1] / 100., y0 / 100., decimal=1)
411 assert_almost_equal(best[2] / 100., x0 / 100., decimal=1)
412 assert_almost_equal(best[3] / 10., ry / 10., decimal=1)
413 assert_almost_equal(best[4] / 100., rx / 100., decimal=1)
414 assert_almost_equal(best[5], angle, decimal=1)
415 # Check if I re-draw the ellipse, points are the same!
416 # ie check API compatibility between hough_ellipse and ellipse_perimeter
417 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
418 orientation=best[5])
419 assert_equal(rr, rr2)
420 assert_equal(cc, cc2)
421
422
423 def test_hough_ellipse_non_zero_posangle2():
424 # ry < rx, angle in [0:pi/2]
425 img = np.zeros((30, 24), dtype=int)
426 rx = 12
427 ry = 6
428 x0 = 10
429 y0 = 15
430 angle = np.pi / 1.35
431 rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
432 img[rr, cc] = 1
433 result = transform.hough_ellipse(img, threshold=15, accuracy=3)
434 result.sort(order='accumulator')
435 best = result[-1]
436 assert_almost_equal(best[1] / 100., y0 / 100., decimal=1)
437 assert_almost_equal(best[2] / 100., x0 / 100., decimal=1)
438 assert_almost_equal(best[3] / 10., ry / 10., decimal=1)
439 assert_almost_equal(best[4] / 100., rx / 100., decimal=1)
440 assert_almost_equal(best[5], angle, decimal=1)
441 # Check if I re-draw the ellipse, points are the same!
442 # ie check API compatibility between hough_ellipse and ellipse_perimeter
443 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
444 orientation=best[5])
445 assert_equal(rr, rr2)
446 assert_equal(cc, cc2)
447
448
449 def test_hough_ellipse_non_zero_posangle3():
450 # ry < rx, angle in [pi/2:pi]
451 img = np.zeros((30, 24), dtype=int)
452 rx = 12
453 ry = 6
454 x0 = 10
455 y0 = 15
456 angle = np.pi / 1.35 + np.pi / 2.
457 rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
458 img[rr, cc] = 1
459 result = transform.hough_ellipse(img, threshold=15, accuracy=3)
460 result.sort(order='accumulator')
461 best = result[-1]
462 # Check if I re-draw the ellipse, points are the same!
463 # ie check API compatibility between hough_ellipse and ellipse_perimeter
464 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
465 orientation=best[5])
466 assert_equal(rr, rr2)
467 assert_equal(cc, cc2)
468
469
470 def test_hough_ellipse_non_zero_posangle4():
471 # ry < rx, angle in [pi:3pi/4]
472 img = np.zeros((30, 24), dtype=int)
473 rx = 12
474 ry = 6
475 x0 = 10
476 y0 = 15
477 angle = np.pi / 1.35 + np.pi
478 rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
479 img[rr, cc] = 1
480 result = transform.hough_ellipse(img, threshold=15, accuracy=3)
481 result.sort(order='accumulator')
482 best = result[-1]
483 # Check if I re-draw the ellipse, points are the same!
484 # ie check API compatibility between hough_ellipse and ellipse_perimeter
485 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
486 orientation=best[5])
487 assert_equal(rr, rr2)
488 assert_equal(cc, cc2)
489
490
491 def test_hough_ellipse_non_zero_negangle1():
492 # ry > rx, angle in [0:-pi/2]
493 img = np.zeros((30, 24), dtype=int)
494 rx = 6
495 ry = 12
496 x0 = 10
497 y0 = 15
498 angle = - np.pi / 1.35
499 rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
500 img[rr, cc] = 1
501 result = transform.hough_ellipse(img, threshold=15, accuracy=3)
502 result.sort(order='accumulator')
503 best = result[-1]
504 # Check if I re-draw the ellipse, points are the same!
505 # ie check API compatibility between hough_ellipse and ellipse_perimeter
506 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
507 orientation=best[5])
508 assert_equal(rr, rr2)
509 assert_equal(cc, cc2)
510
511
512 def test_hough_ellipse_non_zero_negangle2():
513 # ry < rx, angle in [0:-pi/2]
514 img = np.zeros((30, 24), dtype=int)
515 rx = 12
516 ry = 6
517 x0 = 10
518 y0 = 15
519 angle = - np.pi / 1.35
520 rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
521 img[rr, cc] = 1
522 result = transform.hough_ellipse(img, threshold=15, accuracy=3)
523 result.sort(order='accumulator')
524 best = result[-1]
525 # Check if I re-draw the ellipse, points are the same!
526 # ie check API compatibility between hough_ellipse and ellipse_perimeter
527 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
528 orientation=best[5])
529 assert_equal(rr, rr2)
530 assert_equal(cc, cc2)
531
532
533 def test_hough_ellipse_non_zero_negangle3():
534 # ry < rx, angle in [-pi/2:-pi]
535 img = np.zeros((30, 24), dtype=int)
536 rx = 12
537 ry = 6
538 x0 = 10
539 y0 = 15
540 angle = - np.pi / 1.35 - np.pi / 2.
541 rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
542 img[rr, cc] = 1
543 result = transform.hough_ellipse(img, threshold=15, accuracy=3)
544 result.sort(order='accumulator')
545 best = result[-1]
546 # Check if I re-draw the ellipse, points are the same!
547 # ie check API compatibility between hough_ellipse and ellipse_perimeter
548 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
549 orientation=best[5])
550 assert_equal(rr, rr2)
551 assert_equal(cc, cc2)
552
553
554 def test_hough_ellipse_non_zero_negangle4():
555 # ry < rx, angle in [-pi:-3pi/4]
556 img = np.zeros((30, 24), dtype=int)
557 rx = 12
558 ry = 6
559 x0 = 10
560 y0 = 15
561 angle = - np.pi / 1.35 - np.pi
562 rr, cc = ellipse_perimeter(y0, x0, ry, rx, orientation=angle)
563 img[rr, cc] = 1
564 result = transform.hough_ellipse(img, threshold=15, accuracy=3)
565 result.sort(order='accumulator')
566 best = result[-1]
567 # Check if I re-draw the ellipse, points are the same!
568 # ie check API compatibility between hough_ellipse and ellipse_perimeter
569 rr2, cc2 = ellipse_perimeter(y0, x0, int(best[3]), int(best[4]),
570 orientation=best[5])
571 assert_equal(rr, rr2)
572 assert_equal(cc, cc2)
573
574
575 def test_hough_ellipse_all_black_img():
576 assert(transform.hough_ellipse(np.zeros((100, 100))).shape == (0, 6))