1"""
213. ํน์ง์ ๊ฒ์ถ
3- Harris ์ฝ๋ ๊ฒ์ถ
4- FAST ํน์ง์
5- SIFT, ORB
6- ํคํฌ์ธํธ์ ๋์คํฌ๋ฆฝํฐ
7"""
8
9import cv2
10import numpy as np
11
12
13def create_test_image():
14 """์ฝ๋๊ฐ ์๋ ํ
์คํธ ์ด๋ฏธ์ง"""
15 img = np.zeros((400, 500, 3), dtype=np.uint8)
16 img[:] = [200, 200, 200]
17
18 # ์ฌ๊ฐํ (๋ช
ํํ ์ฝ๋)
19 cv2.rectangle(img, (50, 50), (150, 150), (0, 0, 0), 2)
20 cv2.rectangle(img, (50, 50), (150, 150), (100, 100, 100), -1)
21
22 # ๋ค๋ฅธ ์ฌ๊ฐํ
23 cv2.rectangle(img, (200, 80), (350, 180), (50, 50, 50), -1)
24
25 # ์ฒด์ปค๋ณด๋ ํจํด (๋ง์ ์ฝ๋)
26 for i in range(4):
27 for j in range(4):
28 x = 50 + i * 40
29 y = 220 + j * 40
30 if (i + j) % 2 == 0:
31 cv2.rectangle(img, (x, y), (x + 40, y + 40), (0, 0, 0), -1)
32
33 # ์ (์ฝ๋ ์์)
34 cv2.circle(img, (400, 100), 50, (80, 80, 80), -1)
35
36 # ํ
์คํธ
37 cv2.putText(img, 'FEATURES', (280, 300),
38 cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
39
40 return img
41
42
43def harris_corner_demo():
44 """Harris ์ฝ๋ ๊ฒ์ถ ๋ฐ๋ชจ"""
45 print("=" * 50)
46 print("Harris ์ฝ๋ ๊ฒ์ถ")
47 print("=" * 50)
48
49 img = create_test_image()
50 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
51 gray = np.float32(gray)
52
53 # Harris ์ฝ๋ ๊ฒ์ถ
54 # blockSize: ์ฝ๋ ๊ฒ์ถ ์๋์ฐ ํฌ๊ธฐ
55 # ksize: Sobel ์ปค๋ ํฌ๊ธฐ
56 # k: Harris ํ๋ผ๋ฏธํฐ (0.04~0.06)
57 harris = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)
58
59 # ๊ฒฐ๊ณผ ํ์ฅ (์๊ฐํ์ฉ)
60 harris_dilated = cv2.dilate(harris, None)
61
62 # ์๊ณ๊ฐ ์ ์ฉ
63 threshold = 0.01 * harris_dilated.max()
64 result = img.copy()
65 result[harris_dilated > threshold] = [0, 0, 255] # ๋นจ๊ฐ์์ผ๋ก ํ์
66
67 # ์ ๋ฐ ์ฝ๋ ์์น (SubPixel)
68 _, harris_binary = cv2.threshold(harris_dilated, threshold, 255, cv2.THRESH_BINARY)
69 harris_binary = np.uint8(harris_binary)
70
71 # ์ฐ๊ฒฐ๋ ์ปดํฌ๋ํธ๋ก ์ฝ๋ ๊ฐ์ ์ธ๊ธฐ
72 num_corners = cv2.connectedComponents(harris_binary)[0] - 1
73
74 print(f"๊ฒ์ถ๋ ์ฝ๋ ์: {num_corners}")
75 print("\nHarris ์ฝ๋ ํน์ฑ:")
76 print(" - ํ์ ๋ถ๋ณ")
77 print(" - ํฌ๊ธฐ ๋ณํ์๋ ๋ฏผ๊ฐ")
78 print(" - ์ฝ๋ ์๋ต ํจ์ R = det(M) - k*trace(M)^2")
79
80 cv2.imwrite('harris_input.jpg', img)
81 cv2.imwrite('harris_result.jpg', result)
82
83
84def shi_tomasi_demo():
85 """Shi-Tomasi ์ฝ๋ ๊ฒ์ถ ๋ฐ๋ชจ"""
86 print("\n" + "=" * 50)
87 print("Shi-Tomasi ์ฝ๋ ๊ฒ์ถ (goodFeaturesToTrack)")
88 print("=" * 50)
89
90 img = create_test_image()
91 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
92
93 # Shi-Tomasi ์ฝ๋ ๊ฒ์ถ
94 # maxCorners: ์ต๋ ์ฝ๋ ์
95 # qualityLevel: ํ์ง ์์ค (0~1)
96 # minDistance: ์ฝ๋ ๊ฐ ์ต์ ๊ฑฐ๋ฆฌ
97 corners = cv2.goodFeaturesToTrack(
98 gray,
99 maxCorners=100,
100 qualityLevel=0.01,
101 minDistance=10
102 )
103
104 result = img.copy()
105
106 if corners is not None:
107 corners = np.int32(corners)
108 print(f"๊ฒ์ถ๋ ์ฝ๋ ์: {len(corners)}")
109
110 for corner in corners:
111 x, y = corner.ravel()
112 cv2.circle(result, (x, y), 5, (0, 255, 0), -1)
113
114 print("\nShi-Tomasi vs Harris:")
115 print(" - R = min(ฮป1, ฮป2) ์ฌ์ฉ")
116 print(" - Harris๋ณด๋ค ์์ ์ ")
117 print(" - ์ถ์ ์ ์ ํฉํ ์ฝ๋ ์ ํ")
118
119 cv2.imwrite('shi_tomasi_result.jpg', result)
120
121
122def fast_demo():
123 """FAST ํน์ง์ ๊ฒ์ถ ๋ฐ๋ชจ"""
124 print("\n" + "=" * 50)
125 print("FAST ํน์ง์ ๊ฒ์ถ")
126 print("=" * 50)
127
128 img = create_test_image()
129 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
130
131 # FAST ๊ฒ์ถ๊ธฐ ์์ฑ
132 # threshold: ๋ฐ๊ธฐ ์ฐจ์ด ์๊ณ๊ฐ
133 # nonmaxSuppression: ๋น์ต๋ ์ต์
134 fast = cv2.FastFeatureDetector_create(threshold=20, nonmaxSuppression=True)
135
136 # ํคํฌ์ธํธ ๊ฒ์ถ
137 keypoints = fast.detect(gray, None)
138
139 # ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ
140 result = cv2.drawKeypoints(img, keypoints, None, color=(0, 255, 0))
141
142 print(f"๊ฒ์ถ๋ ํคํฌ์ธํธ ์: {len(keypoints)}")
143 print(f"Threshold: {fast.getThreshold()}")
144 print(f"NonMax Suppression: {fast.getNonmaxSuppression()}")
145
146 print("\nFAST ํน์ฑ:")
147 print(" - ๋งค์ฐ ๋น ๋ฅธ ์๋")
148 print(" - ์ํ ํจํด์ผ๋ก ์ฝ๋ ๊ฒ์ถ")
149 print(" - ๋์คํฌ๋ฆฝํฐ ์์ (๊ฒ์ถ๋ง)")
150
151 cv2.imwrite('fast_result.jpg', result)
152
153
154def orb_demo():
155 """ORB ํน์ง์ ๊ฒ์ถ ๋ฐ๋ชจ"""
156 print("\n" + "=" * 50)
157 print("ORB (Oriented FAST and Rotated BRIEF)")
158 print("=" * 50)
159
160 img = create_test_image()
161 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
162
163 # ORB ๊ฒ์ถ๊ธฐ ์์ฑ
164 orb = cv2.ORB_create(nfeatures=500)
165
166 # ํคํฌ์ธํธ์ ๋์คํฌ๋ฆฝํฐ ๊ณ์ฐ
167 keypoints, descriptors = orb.detectAndCompute(gray, None)
168
169 # ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ
170 result = cv2.drawKeypoints(
171 img, keypoints, None,
172 flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
173 )
174
175 print(f"๊ฒ์ถ๋ ํคํฌ์ธํธ ์: {len(keypoints)}")
176 if descriptors is not None:
177 print(f"๋์คํฌ๋ฆฝํฐ shape: {descriptors.shape}")
178 print(f"๋์คํฌ๋ฆฝํฐ ํ์
: {descriptors.dtype}")
179
180 print("\nORB ํน์ฑ:")
181 print(" - FAST ๊ธฐ๋ฐ ํคํฌ์ธํธ ๊ฒ์ถ")
182 print(" - BRIEF ๊ธฐ๋ฐ ๋์คํฌ๋ฆฝํฐ")
183 print(" - ํ์ ๋ถ๋ณ์ฑ ์ถ๊ฐ")
184 print(" - ํนํ ์์, ๋น ๋ฆ")
185
186 cv2.imwrite('orb_result.jpg', result)
187
188 return keypoints, descriptors
189
190
191def sift_demo():
192 """SIFT ํน์ง์ ๊ฒ์ถ ๋ฐ๋ชจ"""
193 print("\n" + "=" * 50)
194 print("SIFT (Scale-Invariant Feature Transform)")
195 print("=" * 50)
196
197 img = create_test_image()
198 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
199
200 try:
201 # SIFT ๊ฒ์ถ๊ธฐ ์์ฑ
202 sift = cv2.SIFT_create()
203
204 # ํคํฌ์ธํธ์ ๋์คํฌ๋ฆฝํฐ ๊ณ์ฐ
205 keypoints, descriptors = sift.detectAndCompute(gray, None)
206
207 # ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ
208 result = cv2.drawKeypoints(
209 img, keypoints, None,
210 flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
211 )
212
213 print(f"๊ฒ์ถ๋ ํคํฌ์ธํธ ์: {len(keypoints)}")
214 if descriptors is not None:
215 print(f"๋์คํฌ๋ฆฝํฐ shape: {descriptors.shape}")
216 print(f"๋์คํฌ๋ฆฝํฐ ํ์
: {descriptors.dtype}")
217
218 print("\nSIFT ํน์ฑ:")
219 print(" - ํฌ๊ธฐ ๋ถ๋ณ (DoG ํผ๋ผ๋ฏธ๋)")
220 print(" - ํ์ ๋ถ๋ณ (๋ฐฉํฅ ํ ๋น)")
221 print(" - 128์ฐจ์ ๋์คํฌ๋ฆฝํฐ")
222 print(" - opencv-contrib-python ํ์")
223
224 cv2.imwrite('sift_result.jpg', result)
225
226 except AttributeError:
227 print("SIFT๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด opencv-contrib-python์ด ํ์ํฉ๋๋ค.")
228 print("pip install opencv-contrib-python")
229
230
231def keypoint_info_demo():
232 """ํคํฌ์ธํธ ์ ๋ณด ๋ฐ๋ชจ"""
233 print("\n" + "=" * 50)
234 print("ํคํฌ์ธํธ ์ ๋ณด")
235 print("=" * 50)
236
237 img = create_test_image()
238 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
239
240 orb = cv2.ORB_create(nfeatures=10)
241 keypoints, _ = orb.detectAndCompute(gray, None)
242
243 print("ํคํฌ์ธํธ ์์ฑ:")
244 for i, kp in enumerate(keypoints[:5]):
245 print(f"\n ํคํฌ์ธํธ {i}:")
246 print(f" ์์น (pt): ({kp.pt[0]:.1f}, {kp.pt[1]:.1f})")
247 print(f" ํฌ๊ธฐ (size): {kp.size:.1f}")
248 print(f" ๊ฐ๋ (angle): {kp.angle:.1f}")
249 print(f" ์๋ต (response): {kp.response:.4f}")
250 print(f" ์ฅํ๋ธ (octave): {kp.octave}")
251
252
253def compare_detectors():
254 """ํน์ง์ ๊ฒ์ถ๊ธฐ ๋น๊ต"""
255 print("\n" + "=" * 50)
256 print("ํน์ง์ ๊ฒ์ถ๊ธฐ ๋น๊ต")
257 print("=" * 50)
258
259 img = create_test_image()
260 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
261
262 detectors = []
263
264 # FAST
265 fast = cv2.FastFeatureDetector_create()
266 kp_fast = fast.detect(gray, None)
267 detectors.append(('FAST', len(kp_fast)))
268
269 # ORB
270 orb = cv2.ORB_create()
271 kp_orb, _ = orb.detectAndCompute(gray, None)
272 detectors.append(('ORB', len(kp_orb)))
273
274 # SIFT (๊ฐ๋ฅํ ๊ฒฝ์ฐ)
275 try:
276 sift = cv2.SIFT_create()
277 kp_sift, _ = sift.detectAndCompute(gray, None)
278 detectors.append(('SIFT', len(kp_sift)))
279 except AttributeError:
280 detectors.append(('SIFT', 'N/A'))
281
282 # Shi-Tomasi
283 corners = cv2.goodFeaturesToTrack(gray, 1000, 0.01, 10)
284 detectors.append(('Shi-Tomasi', len(corners) if corners is not None else 0))
285
286 print("\n| ๊ฒ์ถ๊ธฐ | ํคํฌ์ธํธ ์ | ํน์ง |")
287 print("|--------|-----------|------|")
288 print(f"| FAST | {detectors[0][1]} | ๋น ๋ฆ, ๋์คํฌ๋ฆฝํฐ ์์ |")
289 print(f"| ORB | {detectors[1][1]} | ๋น ๋ฆ, ํนํ ๋ฌด๋ฃ |")
290 print(f"| SIFT | {detectors[2][1]} | ์ ํ, ๋๋ฆผ |")
291 print(f"| Shi-Tomasi | {detectors[3][1]} | ์ถ์ ์ฉ |")
292
293
294def main():
295 """๋ฉ์ธ ํจ์"""
296 # Harris ์ฝ๋
297 harris_corner_demo()
298
299 # Shi-Tomasi
300 shi_tomasi_demo()
301
302 # FAST
303 fast_demo()
304
305 # ORB
306 orb_demo()
307
308 # SIFT
309 sift_demo()
310
311 # ํคํฌ์ธํธ ์ ๋ณด
312 keypoint_info_demo()
313
314 # ๋น๊ต
315 compare_detectors()
316
317 print("\nํน์ง์ ๊ฒ์ถ ๋ฐ๋ชจ ์๋ฃ!")
318
319
320if __name__ == '__main__':
321 main()