1"""
210. ๋ํ ๋ถ์
3- moments (๋ชจ๋ฉํธ)
4- boundingRect, minAreaRect, minEnclosingCircle
5- convexHull (๋ณผ๋ก ๊ป์ง)
6- matchShapes (๋ํ ๋งค์นญ)
7"""
8
9import cv2
10import numpy as np
11
12
13def create_shapes():
14 """๋ค์ํ ๋ํ ์ด๋ฏธ์ง ์์ฑ"""
15 img = np.zeros((400, 500), dtype=np.uint8)
16
17 # ์ง์ฌ๊ฐํ
18 cv2.rectangle(img, (30, 30), (130, 100), 255, -1)
19
20 # ํ์ ๋ ์ฌ๊ฐํ
21 pts = np.array([[200, 30], [280, 60], [250, 140], [170, 110]], np.int32)
22 cv2.fillPoly(img, [pts], 255)
23
24 # ์
25 cv2.circle(img, (400, 80), 50, 255, -1)
26
27 # ๋ถ๊ท์นํ ๋ํ
28 pts2 = np.array([[50, 200], [100, 180], [150, 220], [130, 280],
29 [80, 300], [30, 260]], np.int32)
30 cv2.fillPoly(img, [pts2], 255)
31
32 # L์ ๋ชจ์
33 pts3 = np.array([[200, 180], [280, 180], [280, 220], [240, 220],
34 [240, 320], [200, 320]], np.int32)
35 cv2.fillPoly(img, [pts3], 255)
36
37 # ๋ณ ๋ชจ์
38 pts_star = []
39 for i in range(5):
40 outer = np.radians(i * 72 - 90)
41 inner = np.radians(i * 72 + 36 - 90)
42 pts_star.append([int(400 + 50 * np.cos(outer)), int(250 + 50 * np.sin(outer))])
43 pts_star.append([int(400 + 25 * np.cos(inner)), int(250 + 25 * np.sin(inner))])
44 cv2.fillPoly(img, [np.array(pts_star, np.int32)], 255)
45
46 return img
47
48
49def moments_demo():
50 """๋ชจ๋ฉํธ ๋ฐ๋ชจ"""
51 print("=" * 50)
52 print("๋ชจ๋ฉํธ (moments)")
53 print("=" * 50)
54
55 img = create_shapes()
56 contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
57
58 color_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
59
60 for i, cnt in enumerate(contours):
61 # ๋ชจ๋ฉํธ ๊ณ์ฐ
62 M = cv2.moments(cnt)
63
64 # ๋ฌด๊ฒ์ค์ฌ (centroid)
65 if M['m00'] != 0:
66 cx = int(M['m10'] / M['m00'])
67 cy = int(M['m01'] / M['m00'])
68
69 # ์ค์ฌ์ ํ์
70 cv2.circle(color_img, (cx, cy), 5, (0, 0, 255), -1)
71 cv2.putText(color_img, f'{i}', (cx+10, cy),
72 cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
73
74 print(f"\n๋ํ {i}:")
75 print(f" ๋ฉด์ (m00): {M['m00']:.1f}")
76 print(f" ๋ฌด๊ฒ์ค์ฌ: ({cx}, {cy})")
77
78 # Hu ๋ชจ๋ฉํธ (๋ถ๋ณ ๋ชจ๋ฉํธ)
79 hu = cv2.HuMoments(M)
80 print(f" Hu[0]: {hu[0][0]:.6f}")
81
82 print("\n๋ชจ๋ฉํธ ์ข
๋ฅ:")
83 print(" m00: ๋ฉด์ (0์ฐจ ๋ชจ๋ฉํธ)")
84 print(" m10, m01: 1์ฐจ ๋ชจ๋ฉํธ (๋ฌด๊ฒ์ค์ฌ ๊ณ์ฐ)")
85 print(" m20, m02, m11: 2์ฐจ ๋ชจ๋ฉํธ")
86 print(" Hu ๋ชจ๋ฉํธ: ํ์ , ํฌ๊ธฐ ๋ถ๋ณ")
87
88 cv2.imwrite('moments_centroids.jpg', color_img)
89
90
91def bounding_shapes_demo():
92 """๊ฒฝ๊ณ ๋ํ ๋ฐ๋ชจ"""
93 print("\n" + "=" * 50)
94 print("๊ฒฝ๊ณ ๋ํ")
95 print("=" * 50)
96
97 img = create_shapes()
98 contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
99
100 # ๊ฐ ๊ฒฝ๊ณ ๋ํ ์ข
๋ฅ๋ณ ์ด๋ฏธ์ง
101 bound_rect = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
102 min_rect = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
103 min_circle = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
104 fit_ellipse = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
105
106 for cnt in contours:
107 # 1. ๋ฐ์ด๋ฉ ์ฌ๊ฐํ (์ถ ์ ๋ ฌ)
108 x, y, w, h = cv2.boundingRect(cnt)
109 cv2.rectangle(bound_rect, (x, y), (x+w, y+h), (0, 255, 0), 2)
110
111 # 2. ์ต์ ๋ฉด์ ํ์ ์ฌ๊ฐํ
112 rect = cv2.minAreaRect(cnt)
113 box = cv2.boxPoints(rect)
114 box = np.int32(box)
115 cv2.drawContours(min_rect, [box], 0, (0, 255, 0), 2)
116
117 # 3. ์ต์ ์ธ์ ์
118 (x_c, y_c), radius = cv2.minEnclosingCircle(cnt)
119 cv2.circle(min_circle, (int(x_c), int(y_c)), int(radius), (0, 255, 0), 2)
120
121 # 4. ํ์ ํผํ
(์ ์ด 5๊ฐ ์ด์ ํ์)
122 if len(cnt) >= 5:
123 ellipse = cv2.fitEllipse(cnt)
124 cv2.ellipse(fit_ellipse, ellipse, (0, 255, 0), 2)
125
126 print("๊ฒฝ๊ณ ๋ํ ์ข
๋ฅ:")
127 print(" boundingRect: ์ถ ์ ๋ ฌ ์ฌ๊ฐํ")
128 print(" minAreaRect: ์ต์ ๋ฉด์ ํ์ ์ฌ๊ฐํ")
129 print(" minEnclosingCircle: ์ต์ ์ธ์ ์")
130 print(" fitEllipse: ํ์ ํผํ
")
131
132 cv2.imwrite('bound_rect.jpg', bound_rect)
133 cv2.imwrite('min_rect.jpg', min_rect)
134 cv2.imwrite('min_circle.jpg', min_circle)
135 cv2.imwrite('fit_ellipse.jpg', fit_ellipse)
136
137
138def convex_hull_demo():
139 """๋ณผ๋ก ๊ป์ง ๋ฐ๋ชจ"""
140 print("\n" + "=" * 50)
141 print("๋ณผ๋ก ๊ป์ง (Convex Hull)")
142 print("=" * 50)
143
144 img = create_shapes()
145 contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
146
147 hull_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
148 defects_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
149
150 for cnt in contours:
151 # ๋ณผ๋ก ๊ป์ง
152 hull = cv2.convexHull(cnt)
153 cv2.drawContours(hull_img, [hull], 0, (0, 255, 0), 2)
154
155 # ๋ณผ๋ก์ฑ ๊ฒ์ฌ
156 is_convex = cv2.isContourConvex(cnt)
157
158 # ๋ณผ๋ก ๊ฒฐํจ (Convexity Defects)
159 hull_indices = cv2.convexHull(cnt, returnPoints=False)
160 if len(hull_indices) > 3:
161 defects = cv2.convexityDefects(cnt, hull_indices)
162 if defects is not None:
163 for i in range(defects.shape[0]):
164 s, e, f, d = defects[i, 0]
165 far = tuple(cnt[f][0])
166 # ๊น์ด๊ฐ ์ถฉ๋ถํ ํฐ ๊ฒฐํจ๋ง ํ์
167 if d > 1000:
168 cv2.circle(defects_img, far, 5, (0, 0, 255), -1)
169
170 # ๋ฉด์ ๋น๊ต
171 contour_area = cv2.contourArea(cnt)
172 hull_area = cv2.contourArea(hull)
173 solidity = contour_area / hull_area if hull_area > 0 else 0
174
175 M = cv2.moments(cnt)
176 if M['m00'] != 0:
177 cx = int(M['m10'] / M['m00'])
178 cy = int(M['m01'] / M['m00'])
179 print(f"๋ํ at ({cx}, {cy}): ๋ณผ๋ก={is_convex}, Solidity={solidity:.2f}")
180
181 print("\n๋ณผ๋ก ๊ป์ง ์ฉ๋:")
182 print(" - ๋ํ ๋จ์ํ")
183 print(" - Solidity = ๋ฉด์ /๋ณผ๋ก๊ป์ง๋ฉด์ (์ฑ์ ์ ๋)")
184 print(" - ์ ์ ์ค์ฒ ์ธ์ (๊ฒฐํจ์ ์ด ์๊ฐ๋ฝ ์ฌ์ด)")
185
186 cv2.imwrite('convex_hull.jpg', hull_img)
187 cv2.imwrite('convex_defects.jpg', defects_img)
188
189
190def match_shapes_demo():
191 """๋ํ ๋งค์นญ ๋ฐ๋ชจ"""
192 print("\n" + "=" * 50)
193 print("๋ํ ๋งค์นญ (matchShapes)")
194 print("=" * 50)
195
196 # ๊ธฐ์ค ๋ํ
197 template = np.zeros((200, 200), dtype=np.uint8)
198 cv2.circle(template, (100, 100), 50, 255, -1)
199
200 # ๋น๊ต ๋ํ๋ค
201 shapes = []
202
203 # ์ (๋น์ทํจ)
204 shape1 = np.zeros((200, 200), dtype=np.uint8)
205 cv2.circle(shape1, (100, 100), 60, 255, -1)
206 shapes.append(('Circle (larger)', shape1))
207
208 # ํ์ (๋ค๋ฆ)
209 shape2 = np.zeros((200, 200), dtype=np.uint8)
210 cv2.ellipse(shape2, (100, 100), (60, 40), 0, 0, 360, 255, -1)
211 shapes.append(('Ellipse', shape2))
212
213 # ์ฌ๊ฐํ (๋ง์ด ๋ค๋ฆ)
214 shape3 = np.zeros((200, 200), dtype=np.uint8)
215 cv2.rectangle(shape3, (40, 40), (160, 160), 255, -1)
216 shapes.append(('Square', shape3))
217
218 # ์ผ๊ฐํ (๋ง์ด ๋ค๋ฆ)
219 shape4 = np.zeros((200, 200), dtype=np.uint8)
220 pts = np.array([[100, 30], [30, 170], [170, 170]], np.int32)
221 cv2.fillPoly(shape4, [pts], 255)
222 shapes.append(('Triangle', shape4))
223
224 # ํ
ํ๋ฆฟ ์ค๊ณฝ์
225 cnt_template, _ = cv2.findContours(template, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
226
227 print("ํ
ํ๋ฆฟ: ์")
228 print("๋งค์นญ ๊ฒฐ๊ณผ (๋ฎ์์๋ก ์ ์ฌ):\n")
229
230 for name, shape in shapes:
231 cnt_shape, _ = cv2.findContours(shape, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
232
233 # Hu ๋ชจ๋ฉํธ ๊ธฐ๋ฐ ๋งค์นญ
234 match1 = cv2.matchShapes(cnt_template[0], cnt_shape[0], cv2.CONTOURS_MATCH_I1, 0)
235 match2 = cv2.matchShapes(cnt_template[0], cnt_shape[0], cv2.CONTOURS_MATCH_I2, 0)
236 match3 = cv2.matchShapes(cnt_template[0], cnt_shape[0], cv2.CONTOURS_MATCH_I3, 0)
237
238 print(f" {name:15}: I1={match1:.4f}, I2={match2:.4f}, I3={match3:.4f}")
239
240 print("\n๋งค์นญ ๋ฐฉ๋ฒ:")
241 print(" CONTOURS_MATCH_I1: โ|1/huA - 1/huB|")
242 print(" CONTOURS_MATCH_I2: โ|huA - huB|")
243 print(" CONTOURS_MATCH_I3: max(|huA - huB|/|huA|)")
244
245 cv2.imwrite('match_template.jpg', template)
246
247
248def extreme_points_demo():
249 """๊ทน๋จ์ ๋ฐ๋ชจ"""
250 print("\n" + "=" * 50)
251 print("๊ทน๋จ์ (Extreme Points)")
252 print("=" * 50)
253
254 img = create_shapes()
255 contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
256
257 color_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
258
259 for cnt in contours:
260 # ๊ทน๋จ์ ์ฐพ๊ธฐ
261 leftmost = tuple(cnt[cnt[:, :, 0].argmin()][0])
262 rightmost = tuple(cnt[cnt[:, :, 0].argmax()][0])
263 topmost = tuple(cnt[cnt[:, :, 1].argmin()][0])
264 bottommost = tuple(cnt[cnt[:, :, 1].argmax()][0])
265
266 # ํ์
267 cv2.circle(color_img, leftmost, 5, (255, 0, 0), -1) # ํ๋: ์ผ์ชฝ
268 cv2.circle(color_img, rightmost, 5, (0, 255, 0), -1) # ์ด๋ก: ์ค๋ฅธ์ชฝ
269 cv2.circle(color_img, topmost, 5, (0, 0, 255), -1) # ๋นจ๊ฐ: ์
270 cv2.circle(color_img, bottommost, 5, (255, 255, 0), -1) # ์ฒญ๋ก: ์๋
271
272 print("๊ทน๋จ์ :")
273 print(" - ๊ฐ์ฅ ์ผ์ชฝ, ์ค๋ฅธ์ชฝ, ์, ์๋ ์ ")
274 print(" - ์ ๊ฒ์ถ์์ ์๊ฐ๋ฝ ๋ ์ฐพ๊ธฐ์ ํ์ฉ")
275
276 cv2.imwrite('extreme_points.jpg', color_img)
277
278
279def shape_descriptors_demo():
280 """๋ํ ๊ธฐ์ ์ ๋ฐ๋ชจ"""
281 print("\n" + "=" * 50)
282 print("๋ํ ๊ธฐ์ ์ (Shape Descriptors)")
283 print("=" * 50)
284
285 img = create_shapes()
286 contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
287
288 for i, cnt in enumerate(contours):
289 area = cv2.contourArea(cnt)
290 perimeter = cv2.arcLength(cnt, True)
291 x, y, w, h = cv2.boundingRect(cnt)
292 hull = cv2.convexHull(cnt)
293 hull_area = cv2.contourArea(hull)
294
295 # ๊ธฐ์ ์ ๊ณ์ฐ
296 aspect_ratio = float(w) / h
297 extent = area / (w * h) # ๊ฒฝ๊ณ ์ฌ๊ฐํ ๋๋น ๋ฉด์
298 solidity = area / hull_area if hull_area > 0 else 0 # ๋ณผ๋ก ๊ป์ง ๋๋น ๋ฉด์
299 equiv_diameter = np.sqrt(4 * area / np.pi) # ๋ฑ๊ฐ ์ง๊ฒฝ
300 circularity = 4 * np.pi * area / (perimeter ** 2) if perimeter > 0 else 0
301
302 print(f"\n๋ํ {i}:")
303 print(f" Aspect Ratio (๊ฐ๋ก/์ธ๋ก): {aspect_ratio:.2f}")
304 print(f" Extent (๋ฉด์ /๊ฒฝ๊ณ๋ฉด์ ): {extent:.2f}")
305 print(f" Solidity (๋ฉด์ /๋ณผ๋ก๋ฉด์ ): {solidity:.2f}")
306 print(f" Equivalent Diameter: {equiv_diameter:.1f}")
307 print(f" Circularity (์ํ๋): {circularity:.2f}")
308
309
310def main():
311 """๋ฉ์ธ ํจ์"""
312 # ๋ชจ๋ฉํธ
313 moments_demo()
314
315 # ๊ฒฝ๊ณ ๋ํ
316 bounding_shapes_demo()
317
318 # ๋ณผ๋ก ๊ป์ง
319 convex_hull_demo()
320
321 # ๋ํ ๋งค์นญ
322 match_shapes_demo()
323
324 # ๊ทน๋จ์
325 extreme_points_demo()
326
327 # ๋ํ ๊ธฐ์ ์
328 shape_descriptors_demo()
329
330 print("\n๋ํ ๋ถ์ ๋ฐ๋ชจ ์๋ฃ!")
331
332
333if __name__ == '__main__':
334 main()