13_feature_detection.py

Download
python 322 lines 8.8 KB
  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()