08_edge_detection.py

Download
python 340 lines 9.1 KB
  1"""
  208. ์—ฃ์ง€ ๊ฒ€์ถœ
  3- Sobel, Scharr ํ•„ํ„ฐ
  4- Laplacian
  5- Canny ์—ฃ์ง€ ๊ฒ€์ถœ
  6"""
  7
  8import cv2
  9import numpy as np
 10
 11
 12def create_test_image():
 13    """ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ ์ƒ์„ฑ"""
 14    img = np.zeros((300, 400), dtype=np.uint8)
 15    img[:] = 200
 16
 17    # ์‚ฌ๊ฐํ˜•
 18    cv2.rectangle(img, (50, 50), (150, 150), 50, -1)
 19
 20    # ์›
 21    cv2.circle(img, (300, 150), 60, 80, -1)
 22
 23    # ์‚ผ๊ฐํ˜•
 24    pts = np.array([[200, 250], [150, 290], [250, 290]], np.int32)
 25    cv2.fillPoly(img, [pts], 100)
 26
 27    # ํ…์ŠคํŠธ
 28    cv2.putText(img, 'EDGE', (100, 270), cv2.FONT_HERSHEY_SIMPLEX, 0.8, 30, 2)
 29
 30    return img
 31
 32
 33def sobel_demo():
 34    """Sobel ํ•„ํ„ฐ ๋ฐ๋ชจ"""
 35    print("=" * 50)
 36    print("Sobel ํ•„ํ„ฐ")
 37    print("=" * 50)
 38
 39    img = create_test_image()
 40
 41    # Sobel ํ•„ํ„ฐ (x ๋ฐฉํ–ฅ)
 42    sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
 43
 44    # Sobel ํ•„ํ„ฐ (y ๋ฐฉํ–ฅ)
 45    sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
 46
 47    # ์ ˆ๋Œ€๊ฐ’ ๋ฐ 8๋น„ํŠธ ๋ณ€ํ™˜
 48    sobel_x_abs = cv2.convertScaleAbs(sobel_x)
 49    sobel_y_abs = cv2.convertScaleAbs(sobel_y)
 50
 51    # x, y ํ•ฉ์„ฑ
 52    sobel_combined = cv2.addWeighted(sobel_x_abs, 0.5, sobel_y_abs, 0.5, 0)
 53
 54    # ํฌ๊ธฐ ๊ณ„์‚ฐ (์ •ํ™•ํ•œ ๋ฐฉ๋ฒ•)
 55    sobel_magnitude = np.sqrt(sobel_x**2 + sobel_y**2)
 56    sobel_magnitude = np.uint8(np.clip(sobel_magnitude, 0, 255))
 57
 58    print("Sobel ํ•„ํ„ฐ:")
 59    print("  - 1์ฐจ ๋ฏธ๋ถ„ ๊ธฐ๋ฐ˜ ์—ฃ์ง€ ๊ฒ€์ถœ")
 60    print("  - x ๋ฐฉํ–ฅ: ์ˆ˜์ง ์—ฃ์ง€ ๊ฒ€์ถœ")
 61    print("  - y ๋ฐฉํ–ฅ: ์ˆ˜ํ‰ ์—ฃ์ง€ ๊ฒ€์ถœ")
 62    print("  - ksize: ์ปค๋„ ํฌ๊ธฐ (3, 5, 7)")
 63
 64    cv2.imwrite('edge_original.jpg', img)
 65    cv2.imwrite('sobel_x.jpg', sobel_x_abs)
 66    cv2.imwrite('sobel_y.jpg', sobel_y_abs)
 67    cv2.imwrite('sobel_combined.jpg', sobel_combined)
 68    cv2.imwrite('sobel_magnitude.jpg', sobel_magnitude)
 69
 70
 71def scharr_demo():
 72    """Scharr ํ•„ํ„ฐ ๋ฐ๋ชจ"""
 73    print("\n" + "=" * 50)
 74    print("Scharr ํ•„ํ„ฐ")
 75    print("=" * 50)
 76
 77    img = create_test_image()
 78
 79    # Scharr ํ•„ํ„ฐ (Sobel๋ณด๋‹ค ์ •ํ™•)
 80    scharr_x = cv2.Scharr(img, cv2.CV_64F, 1, 0)
 81    scharr_y = cv2.Scharr(img, cv2.CV_64F, 0, 1)
 82
 83    scharr_x_abs = cv2.convertScaleAbs(scharr_x)
 84    scharr_y_abs = cv2.convertScaleAbs(scharr_y)
 85
 86    scharr_combined = cv2.addWeighted(scharr_x_abs, 0.5, scharr_y_abs, 0.5, 0)
 87
 88    print("Scharr ํ•„ํ„ฐ:")
 89    print("  - Sobel์˜ ๊ฐœ์„  ๋ฒ„์ „")
 90    print("  - 3x3 ์ปค๋„๋งŒ ์ง€์›")
 91    print("  - ๋” ์ •ํ™•ํ•œ ๊ทธ๋ž˜๋””์–ธํŠธ ๊ณ„์‚ฐ")
 92    print("  - Sobel(ksize=-1)๊ณผ ๋™์ผ")
 93
 94    cv2.imwrite('scharr_x.jpg', scharr_x_abs)
 95    cv2.imwrite('scharr_y.jpg', scharr_y_abs)
 96    cv2.imwrite('scharr_combined.jpg', scharr_combined)
 97
 98
 99def laplacian_demo():
100    """Laplacian ํ•„ํ„ฐ ๋ฐ๋ชจ"""
101    print("\n" + "=" * 50)
102    print("Laplacian ํ•„ํ„ฐ")
103    print("=" * 50)
104
105    img = create_test_image()
106
107    # ๋…ธ์ด์ฆˆ์— ๋ฏผ๊ฐํ•˜๋ฏ€๋กœ ๋ธ”๋Ÿฌ ์ ์šฉ
108    blurred = cv2.GaussianBlur(img, (3, 3), 0)
109
110    # Laplacian ํ•„ํ„ฐ
111    laplacian = cv2.Laplacian(blurred, cv2.CV_64F)
112    laplacian_abs = cv2.convertScaleAbs(laplacian)
113
114    # ์ปค๋„ ํฌ๊ธฐ ๋ณ€ํ™”
115    lap_k1 = cv2.Laplacian(blurred, cv2.CV_64F, ksize=1)
116    lap_k3 = cv2.Laplacian(blurred, cv2.CV_64F, ksize=3)
117    lap_k5 = cv2.Laplacian(blurred, cv2.CV_64F, ksize=5)
118
119    print("Laplacian ํ•„ํ„ฐ:")
120    print("  - 2์ฐจ ๋ฏธ๋ถ„ ๊ธฐ๋ฐ˜ ์—ฃ์ง€ ๊ฒ€์ถœ")
121    print("  - ๋ชจ๋“  ๋ฐฉํ–ฅ์˜ ์—ฃ์ง€ ํ•œ ๋ฒˆ์— ๊ฒ€์ถœ")
122    print("  - ๋…ธ์ด์ฆˆ์— ๋ฏผ๊ฐ โ†’ ๋ธ”๋Ÿฌ ํ•„์š”")
123
124    cv2.imwrite('laplacian.jpg', laplacian_abs)
125    cv2.imwrite('laplacian_k1.jpg', cv2.convertScaleAbs(lap_k1))
126    cv2.imwrite('laplacian_k3.jpg', cv2.convertScaleAbs(lap_k3))
127    cv2.imwrite('laplacian_k5.jpg', cv2.convertScaleAbs(lap_k5))
128
129
130def canny_demo():
131    """Canny ์—ฃ์ง€ ๊ฒ€์ถœ ๋ฐ๋ชจ"""
132    print("\n" + "=" * 50)
133    print("Canny ์—ฃ์ง€ ๊ฒ€์ถœ")
134    print("=" * 50)
135
136    img = create_test_image()
137
138    # Canny ์—ฃ์ง€ ๊ฒ€์ถœ
139    # threshold1: ๋‚ฎ์€ ์ž„๊ณ„๊ฐ’
140    # threshold2: ๋†’์€ ์ž„๊ณ„๊ฐ’
141    canny_50_150 = cv2.Canny(img, 50, 150)
142    canny_100_200 = cv2.Canny(img, 100, 200)
143    canny_30_100 = cv2.Canny(img, 30, 100)
144
145    print("Canny ์—ฃ์ง€ ๊ฒ€์ถœ ๋‹จ๊ณ„:")
146    print("  1. ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ๋กœ ๋…ธ์ด์ฆˆ ์ œ๊ฑฐ")
147    print("  2. Sobel๋กœ ๊ทธ๋ž˜๋””์–ธํŠธ ๊ณ„์‚ฐ")
148    print("  3. ๋น„์ตœ๋Œ€ ์–ต์ œ (Non-Maximum Suppression)")
149    print("  4. ์ด์ค‘ ์ž„๊ณ„๊ฐ’์œผ๋กœ ์—ฃ์ง€ ๊ฒฐ์ •")
150    print("     - ๊ฐ•ํ•œ ์—ฃ์ง€: > threshold2")
151    print("     - ์•ฝํ•œ ์—ฃ์ง€: threshold1 ~ threshold2")
152    print("     - ๋น„์—ฃ์ง€: < threshold1")
153    print("  5. ํžˆ์Šคํ…Œ๋ฆฌ์‹œ์Šค ์—ฃ์ง€ ์ถ”์ ")
154
155    cv2.imwrite('canny_50_150.jpg', canny_50_150)
156    cv2.imwrite('canny_100_200.jpg', canny_100_200)
157    cv2.imwrite('canny_30_100.jpg', canny_30_100)
158
159
160def canny_with_blur():
161    """๋ธ”๋Ÿฌ์™€ ํ•จ๊ป˜ Canny ์‚ฌ์šฉ"""
162    print("\n" + "=" * 50)
163    print("๋ธ”๋Ÿฌ + Canny")
164    print("=" * 50)
165
166    img = create_test_image()
167
168    # ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€
169    noise = np.random.normal(0, 10, img.shape).astype(np.int16)
170    noisy = np.clip(img.astype(np.int16) + noise, 0, 255).astype(np.uint8)
171
172    # ๋ธ”๋Ÿฌ ์—†์ด
173    canny_no_blur = cv2.Canny(noisy, 50, 150)
174
175    # ๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ ํ›„
176    blurred = cv2.GaussianBlur(noisy, (5, 5), 0)
177    canny_with_blur = cv2.Canny(blurred, 50, 150)
178
179    # Canny ๋‚ด๋ถ€์—์„œ apertureSize ์กฐ์ •
180    canny_aperture3 = cv2.Canny(noisy, 50, 150, apertureSize=3)
181    canny_aperture5 = cv2.Canny(noisy, 50, 150, apertureSize=5)
182
183    print("๋…ธ์ด์ฆˆ ์ œ๊ฑฐ:")
184    print("  - ๋ธ”๋Ÿฌ ์ „์ฒ˜๋ฆฌ ๊ถŒ์žฅ")
185    print("  - apertureSize ์กฐ์ • ๊ฐ€๋Šฅ (3, 5, 7)")
186
187    cv2.imwrite('canny_noisy.jpg', noisy)
188    cv2.imwrite('canny_no_blur.jpg', canny_no_blur)
189    cv2.imwrite('canny_with_blur.jpg', canny_with_blur)
190
191
192def auto_canny_threshold():
193    """์ž๋™ Canny ์ž„๊ณ„๊ฐ’"""
194    print("\n" + "=" * 50)
195    print("์ž๋™ Canny ์ž„๊ณ„๊ฐ’")
196    print("=" * 50)
197
198    img = create_test_image()
199
200    # ์ค‘์•™๊ฐ’ ๊ธฐ๋ฐ˜ ์ž๋™ ์ž„๊ณ„๊ฐ’
201    median = np.median(img)
202    sigma = 0.33
203
204    lower = int(max(0, (1.0 - sigma) * median))
205    upper = int(min(255, (1.0 + sigma) * median))
206
207    auto_canny = cv2.Canny(img, lower, upper)
208
209    print(f"์ด๋ฏธ์ง€ ์ค‘์•™๊ฐ’: {median}")
210    print(f"์ž๋™ ์ž„๊ณ„๊ฐ’: lower={lower}, upper={upper}")
211    print(f"๊ณต์‹: lower = (1-sigma)*median, upper = (1+sigma)*median")
212
213    cv2.imwrite('canny_auto.jpg', auto_canny)
214
215    return lower, upper
216
217
218def log_edge_detection():
219    """LoG (Laplacian of Gaussian) ์—ฃ์ง€ ๊ฒ€์ถœ"""
220    print("\n" + "=" * 50)
221    print("LoG ์—ฃ์ง€ ๊ฒ€์ถœ")
222    print("=" * 50)
223
224    img = create_test_image()
225
226    # LoG = Gaussian ๋ธ”๋Ÿฌ + Laplacian
227    blurred = cv2.GaussianBlur(img, (5, 5), 1.4)
228    log = cv2.Laplacian(blurred, cv2.CV_64F)
229
230    # Zero-crossing ์ฐพ๊ธฐ (๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•)
231    log_abs = cv2.convertScaleAbs(log)
232
233    print("LoG (Laplacian of Gaussian):")
234    print("  - Gaussian์œผ๋กœ ๋…ธ์ด์ฆˆ ์ œ๊ฑฐ")
235    print("  - Laplacian์œผ๋กœ 2์ฐจ ๋ฏธ๋ถ„")
236    print("  - Zero-crossing์ด ์—ฃ์ง€")
237
238    cv2.imwrite('log_edge.jpg', log_abs)
239
240
241def compare_edge_methods():
242    """์—ฃ์ง€ ๊ฒ€์ถœ ๋ฐฉ๋ฒ• ๋น„๊ต"""
243    print("\n" + "=" * 50)
244    print("์—ฃ์ง€ ๊ฒ€์ถœ ๋ฐฉ๋ฒ• ๋น„๊ต")
245    print("=" * 50)
246
247    img = create_test_image()
248
249    # ๊ฐ ๋ฐฉ๋ฒ• ์ ์šฉ
250    sobel_x = cv2.convertScaleAbs(cv2.Sobel(img, cv2.CV_64F, 1, 0))
251    sobel_y = cv2.convertScaleAbs(cv2.Sobel(img, cv2.CV_64F, 0, 1))
252    sobel = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)
253
254    laplacian = cv2.convertScaleAbs(cv2.Laplacian(img, cv2.CV_64F))
255
256    canny = cv2.Canny(img, 50, 150)
257
258    print("""
259    | ๋ฐฉ๋ฒ• | ํŠน์ง• | ์‚ฌ์šฉ ์ƒํ™ฉ |
260    |------|------|----------|
261    | Sobel | 1์ฐจ ๋ฏธ๋ถ„, ๋ฐฉํ–ฅ๋ณ„ | ๊ทธ๋ž˜๋””์–ธํŠธ ๋ฐฉํ–ฅ ํ•„์š”์‹œ |
262    | Scharr | Sobel ๊ฐœ์„  | ๋” ์ •ํ™•ํ•œ ๊ทธ๋ž˜๋””์–ธํŠธ |
263    | Laplacian | 2์ฐจ ๋ฏธ๋ถ„ | ๋ชจ๋“  ๋ฐฉํ–ฅ ํ•œ๋ฒˆ์— |
264    | Canny | ๋‹ค๋‹จ๊ณ„ ์ฒ˜๋ฆฌ | ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ |
265    """)
266
267    # ๋น„๊ต ์ด๋ฏธ์ง€ ์ƒ์„ฑ
268    compare = np.hstack([
269        sobel,
270        laplacian,
271        canny
272    ])
273    cv2.imwrite('edge_compare.jpg', compare)
274
275
276def practical_example():
277    """์‹ค์šฉ ์˜ˆ์ œ: ์œค๊ณฝ์„  ์ถ”์ถœ"""
278    print("\n" + "=" * 50)
279    print("์‹ค์šฉ ์˜ˆ์ œ: ์œค๊ณฝ์„  ์ถ”์ถœ")
280    print("=" * 50)
281
282    # ์ปฌ๋Ÿฌ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
283    img = np.zeros((300, 400, 3), dtype=np.uint8)
284    img[:] = [200, 200, 200]
285
286    cv2.rectangle(img, (50, 50), (150, 150), (0, 0, 200), -1)
287    cv2.circle(img, (300, 150), 60, (200, 0, 0), -1)
288
289    # ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ ๋ณ€ํ™˜
290    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
291
292    # Canny ์—ฃ์ง€
293    edges = cv2.Canny(gray, 50, 150)
294
295    # ์œค๊ณฝ์„ ์„ ์›๋ณธ์— ํ‘œ์‹œ
296    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
297    result = img.copy()
298    cv2.drawContours(result, contours, -1, (0, 255, 0), 2)
299
300    cv2.imwrite('practical_input.jpg', img)
301    cv2.imwrite('practical_edges.jpg', edges)
302    cv2.imwrite('practical_contours.jpg', result)
303    print("์œค๊ณฝ์„  ์ถ”์ถœ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ")
304
305
306def main():
307    """๋ฉ”์ธ ํ•จ์ˆ˜"""
308    # Sobel
309    sobel_demo()
310
311    # Scharr
312    scharr_demo()
313
314    # Laplacian
315    laplacian_demo()
316
317    # Canny
318    canny_demo()
319
320    # ๋ธ”๋Ÿฌ + Canny
321    canny_with_blur()
322
323    # ์ž๋™ ์ž„๊ณ„๊ฐ’
324    auto_canny_threshold()
325
326    # LoG
327    log_edge_detection()
328
329    # ๋ฐฉ๋ฒ• ๋น„๊ต
330    compare_edge_methods()
331
332    # ์‹ค์šฉ ์˜ˆ์ œ
333    practical_example()
334
335    print("\n์—ฃ์ง€ ๊ฒ€์ถœ ๋ฐ๋ชจ ์™„๋ฃŒ!")
336
337
338if __name__ == '__main__':
339    main()