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()