1"""
216. ์ผ๊ตด ๊ฒ์ถ ๋ฐ ์ธ์
3- Haar Cascade ์ผ๊ตด ๊ฒ์ถ
4- ๋, ๋ฏธ์ ๊ฒ์ถ
5- LBP (Local Binary Patterns)
6- ์ผ๊ตด ์ธ์ ๊ธฐ์ด
7"""
8
9import cv2
10import numpy as np
11
12
13def create_face_image():
14 """์ผ๊ตด ํํ ์๋ฎฌ๋ ์ด์
์ด๋ฏธ์ง"""
15 img = np.zeros((400, 500, 3), dtype=np.uint8)
16 img[:] = [220, 220, 220]
17
18 # ์ผ๊ตด 1 (์ผ์ชฝ)
19 cv2.ellipse(img, (150, 180), (60, 75), 0, 0, 360, (180, 160, 140), -1)
20 cv2.circle(img, (130, 160), 10, (50, 50, 50), -1) # ์ผ์ชฝ ๋
21 cv2.circle(img, (170, 160), 10, (50, 50, 50), -1) # ์ค๋ฅธ์ชฝ ๋
22 cv2.ellipse(img, (150, 210), (20, 10), 0, 0, 180, (100, 80, 80), 2) # ์
23
24 # ์ผ๊ตด 2 (์ค๋ฅธ์ชฝ)
25 cv2.ellipse(img, (350, 200), (55, 70), 0, 0, 360, (175, 155, 135), -1)
26 cv2.circle(img, (332, 180), 9, (45, 45, 45), -1) # ์ผ์ชฝ ๋
27 cv2.circle(img, (368, 180), 9, (45, 45, 45), -1) # ์ค๋ฅธ์ชฝ ๋
28 cv2.ellipse(img, (350, 225), (18, 8), 0, 0, 180, (90, 70, 70), 2) # ์
29
30 return img
31
32
33def haar_cascade_face_detection():
34 """Haar Cascade ์ผ๊ตด ๊ฒ์ถ ๋ฐ๋ชจ"""
35 print("=" * 50)
36 print("Haar Cascade ์ผ๊ตด ๊ฒ์ถ")
37 print("=" * 50)
38
39 img = create_face_image()
40 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
41
42 # Haar Cascade ๋ถ๋ฅ๊ธฐ ๋ก๋
43 face_cascade_path = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
44 face_cascade = cv2.CascadeClassifier(face_cascade_path)
45
46 if face_cascade.empty():
47 print("์ผ๊ตด ๊ฒ์ถ๊ธฐ๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค.")
48 return
49
50 # ์ผ๊ตด ๊ฒ์ถ
51 # scaleFactor: ๊ฐ ์ด๋ฏธ์ง ์ค์ผ์ผ์์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ค์ด๋ ๋น์จ
52 # minNeighbors: ๊ฐ ํ๋ณด ์ฌ๊ฐํ์ด ์ ์ง๋๊ธฐ ์ํด ํ์ํ ์ด์ ์
53 # minSize: ์ต์ ๊ฐ์ฒด ํฌ๊ธฐ
54 faces = face_cascade.detectMultiScale(
55 gray,
56 scaleFactor=1.1,
57 minNeighbors=5,
58 minSize=(30, 30),
59 flags=cv2.CASCADE_SCALE_IMAGE
60 )
61
62 result = img.copy()
63 print(f"๊ฒ์ถ๋ ์ผ๊ตด ์: {len(faces)}")
64
65 for i, (x, y, w, h) in enumerate(faces):
66 # ์ผ๊ตด ์์ญ ํ์
67 cv2.rectangle(result, (x, y), (x+w, y+h), (0, 255, 0), 2)
68 cv2.putText(result, f'Face {i+1}', (x, y-10),
69 cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
70 print(f" Face {i+1}: x={x}, y={y}, w={w}, h={h}")
71
72 print("\nHaar Cascade ํ๋ผ๋ฏธํฐ:")
73 print(" scaleFactor: 1.1~1.3 (์์์๋ก ์ ๋ฐ, ๋๋ฆผ)")
74 print(" minNeighbors: 3~6 (ํด์๋ก ์๊ฒฉ)")
75 print(" minSize: ์ต์ ๊ฒ์ถ ํฌ๊ธฐ")
76
77 cv2.imwrite('face_haar_input.jpg', img)
78 cv2.imwrite('face_haar_result.jpg', result)
79
80
81def cascade_eye_detection():
82 """๋ ๊ฒ์ถ ๋ฐ๋ชจ"""
83 print("\n" + "=" * 50)
84 print("๋ ๊ฒ์ถ (Haar Cascade)")
85 print("=" * 50)
86
87 img = create_face_image()
88 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
89
90 # ๋ถ๋ฅ๊ธฐ ๋ก๋
91 face_cascade = cv2.CascadeClassifier(
92 cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
93 )
94 eye_cascade = cv2.CascadeClassifier(
95 cv2.data.haarcascades + 'haarcascade_eye.xml'
96 )
97
98 if face_cascade.empty() or eye_cascade.empty():
99 print("๋ถ๋ฅ๊ธฐ๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค.")
100 return
101
102 # ์ผ๊ตด ๊ฒ์ถ
103 faces = face_cascade.detectMultiScale(gray, 1.1, 5)
104
105 result = img.copy()
106
107 for (x, y, w, h) in faces:
108 cv2.rectangle(result, (x, y), (x+w, y+h), (0, 255, 0), 2)
109
110 # ์ผ๊ตด ์์ญ ๋ด์์ ๋ ๊ฒ์ถ
111 roi_gray = gray[y:y+h, x:x+w]
112 roi_color = result[y:y+h, x:x+w]
113
114 eyes = eye_cascade.detectMultiScale(
115 roi_gray,
116 scaleFactor=1.1,
117 minNeighbors=10,
118 minSize=(15, 15)
119 )
120
121 for (ex, ey, ew, eh) in eyes:
122 cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (255, 0, 0), 2)
123
124 print(f"์ผ๊ตด ({x}, {y})์์ ๊ฒ์ถ๋ ๋: {len(eyes)}")
125
126 print("\n๋ ๊ฒ์ถ ํ:")
127 print(" - ์ผ๊ตด ์์ญ ๋ด์์๋ง ๊ฒ์ถ (ROI)")
128 print(" - minNeighbors๋ฅผ ๋๊ฒ ์ค์ ")
129 print(" - ์๋ฐ๋ถ์์๋ง ๊ฒ์ถํ๋ฉด ์ ํ๋ ํฅ์")
130
131 cv2.imwrite('face_eye_result.jpg', result)
132
133
134def available_cascades():
135 """์ฌ์ฉ ๊ฐ๋ฅํ Haar Cascade ๋ชฉ๋ก"""
136 print("\n" + "=" * 50)
137 print("์ฌ์ฉ ๊ฐ๋ฅํ Haar Cascade ๋ถ๋ฅ๊ธฐ")
138 print("=" * 50)
139
140 cascades = [
141 ('haarcascade_frontalface_default.xml', '์ ๋ฉด ์ผ๊ตด'),
142 ('haarcascade_frontalface_alt.xml', '์ ๋ฉด ์ผ๊ตด (๋์ฒด)'),
143 ('haarcascade_frontalface_alt2.xml', '์ ๋ฉด ์ผ๊ตด (๋์ฒด 2)'),
144 ('haarcascade_profileface.xml', '์ธก๋ฉด ์ผ๊ตด'),
145 ('haarcascade_eye.xml', '๋'),
146 ('haarcascade_eye_tree_eyeglasses.xml', '๋ (์๊ฒฝ ํฌํจ)'),
147 ('haarcascade_smile.xml', '๋ฏธ์'),
148 ('haarcascade_upperbody.xml', '์์ฒด'),
149 ('haarcascade_lowerbody.xml', 'ํ์ฒด'),
150 ('haarcascade_fullbody.xml', '์ ์ '),
151 ]
152
153 print(f"\n๊ฒฝ๋ก: {cv2.data.haarcascades}\n")
154
155 for filename, description in cascades:
156 cascade = cv2.CascadeClassifier(cv2.data.haarcascades + filename)
157 status = "OK" if not cascade.empty() else "N/A"
158 print(f" [{status}] {filename}")
159 print(f" - {description}")
160
161
162def lbp_face_detection():
163 """LBP ๊ธฐ๋ฐ ์ผ๊ตด ๊ฒ์ถ ๋ฐ๋ชจ"""
164 print("\n" + "=" * 50)
165 print("LBP ์ผ๊ตด ๊ฒ์ถ")
166 print("=" * 50)
167
168 img = create_face_image()
169 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
170
171 # LBP Cascade ๋ก๋ (์๋ ๊ฒฝ์ฐ)
172 lbp_cascade_path = cv2.data.haarcascades + '../lbpcascades/lbpcascade_frontalface_improved.xml'
173
174 try:
175 lbp_cascade = cv2.CascadeClassifier(lbp_cascade_path)
176
177 if lbp_cascade.empty():
178 raise FileNotFoundError
179
180 faces = lbp_cascade.detectMultiScale(gray, 1.1, 5)
181
182 result = img.copy()
183 for (x, y, w, h) in faces:
184 cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2)
185
186 print(f"LBP๋ก ๊ฒ์ถ๋ ์ผ๊ตด: {len(faces)}")
187 cv2.imwrite('face_lbp_result.jpg', result)
188
189 except (FileNotFoundError, cv2.error):
190 print("LBP Cascade๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.")
191 print("๋๋ถ๋ถ์ ๊ฒฝ์ฐ Haar Cascade ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค.")
192
193 print("\nHaar vs LBP ๋น๊ต:")
194 print(" Haar: ๋ ์ ํ, ๋๋ฆผ, ์กฐ๋ช
๋ณํ์ ๋ฏผ๊ฐ")
195 print(" LBP: ๋ ๋น ๋ฆ, ์กฐ๋ช
๋ณํ์ ๊ฐ๊ฑด, ์ ํ๋ ๋ฎ์")
196
197
198def face_recognition_concept():
199 """์ผ๊ตด ์ธ์ ๊ฐ๋
์ค๋ช
"""
200 print("\n" + "=" * 50)
201 print("์ผ๊ตด ์ธ์ ๊ฐ๋
")
202 print("=" * 50)
203
204 # ํ
์คํธ ์ด๋ฏธ์ง ์์ฑ
205 img1 = np.zeros((100, 100), dtype=np.uint8)
206 cv2.ellipse(img1, (50, 50), (30, 40), 0, 0, 360, 150, -1)
207 cv2.circle(img1, (40, 45), 5, 50, -1)
208 cv2.circle(img1, (60, 45), 5, 50, -1)
209
210 img2 = img1.copy() # ๋์ผ์ธ
211 img3 = np.zeros((100, 100), dtype=np.uint8) # ๋ค๋ฅธ ์ฌ๋
212 cv2.ellipse(img3, (50, 50), (35, 35), 0, 0, 360, 160, -1)
213 cv2.circle(img3, (35, 45), 6, 60, -1)
214 cv2.circle(img3, (65, 45), 6, 60, -1)
215
216 print("์ผ๊ตด ์ธ์ ํ์ดํ๋ผ์ธ:")
217 print(" 1. ์ผ๊ตด ๊ฒ์ถ (Detection)")
218 print(" 2. ์ผ๊ตด ์ ๋ ฌ (Alignment)")
219 print(" 3. ํน์ง ์ถ์ถ (Feature Extraction)")
220 print(" 4. ํน์ง ๋น๊ต (Matching)")
221
222 print("\nOpenCV ์ผ๊ตด ์ธ์๊ธฐ (opencv-contrib ํ์):")
223 print(" - EigenFaces: PCA ๊ธฐ๋ฐ")
224 print(" - FisherFaces: LDA ๊ธฐ๋ฐ")
225 print(" - LBPH: Local Binary Pattern Histogram")
226
227 # LBPH ์ผ๊ตด ์ธ์๊ธฐ ์์ (opencv-contrib ํ์)
228 try:
229 recognizer = cv2.face.LBPHFaceRecognizer_create()
230
231 # ํ์ต ๋ฐ์ดํฐ
232 faces = [img1, img2, img3]
233 labels = np.array([0, 0, 1]) # 0: ์ฒซ ๋ฒ์งธ ์ฌ๋, 1: ๋ ๋ฒ์งธ ์ฌ๋
234
235 recognizer.train(faces, labels)
236
237 # ์์ธก
238 label, confidence = recognizer.predict(img1)
239 print(f"\nํ
์คํธ: label={label}, confidence={confidence:.2f}")
240 print(" confidence๊ฐ ๋ฎ์์๋ก ์ ์ฌ")
241
242 except AttributeError:
243 print("\n์ฐธ๊ณ : LBPH ์ธ์๊ธฐ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด")
244 print(" pip install opencv-contrib-python")
245
246 cv2.imwrite('face_sample1.jpg', img1)
247 cv2.imwrite('face_sample2.jpg', img3)
248
249
250def face_detection_comparison():
251 """์ผ๊ตด ๊ฒ์ถ ๋ฐฉ๋ฒ ๋น๊ต"""
252 print("\n" + "=" * 50)
253 print("์ผ๊ตด ๊ฒ์ถ/์ธ์ ๋ฐฉ๋ฒ ๋น๊ต")
254 print("=" * 50)
255
256 print("""
257 | ๋ฐฉ๋ฒ | ์ฅ์ | ๋จ์ | ์ฉ๋ |
258 |------|------|------|------|
259 | Haar Cascade | ๋น ๋ฆ, ๊ฐ๋จ | ์ธก๋ฉด/๊ธฐ์ธ๊ธฐ ์ฝํจ | ์ค์๊ฐ ๊ฒ์ถ |
260 | LBP | ๋งค์ฐ ๋น ๋ฆ | ์ ํ๋ ๋ฎ์ | ์๋ฒ ๋๋ |
261 | HOG + SVM | ์ ํ | ๋๋ฆผ | ๊ฒ์ถ |
262 | DNN (SSD) | ๋งค์ฐ ์ ํ | GPU ๊ถ์ฅ | ๊ณ ์ ๋ฐ ๊ฒ์ถ |
263 | DNN (Face) | ํน์ง ์ถ์ถ | ๋ชจ๋ธ ํ์ | ์ธ์ |
264 """)
265
266 print("์ต์ ํธ๋ ๋:")
267 print(" - MTCNN: ๋ค๋จ๊ณ CNN (๊ฒ์ถ+์ ๋ ฌ)")
268 print(" - RetinaFace: ๊ณ ์ ๋ฐ ๊ฒ์ถ")
269 print(" - ArcFace, FaceNet: ์๋ฒ ๋ฉ ๊ธฐ๋ฐ ์ธ์")
270 print(" - InsightFace: ์ข
ํฉ ํ๋ ์์ํฌ")
271
272
273def real_time_detection_template():
274 """์ค์๊ฐ ๊ฒ์ถ ํ
ํ๋ฆฟ"""
275 print("\n" + "=" * 50)
276 print("์ค์๊ฐ ์ผ๊ตด ๊ฒ์ถ ํ
ํ๋ฆฟ")
277 print("=" * 50)
278
279 code = '''
280# ์ค์๊ฐ ์ผ๊ตด ๊ฒ์ถ ์ฝ๋
281import cv2
282
283face_cascade = cv2.CascadeClassifier(
284 cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
285)
286
287cap = cv2.VideoCapture(0)
288
289while True:
290 ret, frame = cap.read()
291 if not ret:
292 break
293
294 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
295 faces = face_cascade.detectMultiScale(gray, 1.1, 5, minSize=(50, 50))
296
297 for (x, y, w, h) in faces:
298 cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
299
300 cv2.imshow('Face Detection', frame)
301
302 if cv2.waitKey(1) & 0xFF == ord('q'):
303 break
304
305cap.release()
306cv2.destroyAllWindows()
307'''
308
309 print(code)
310
311 print("์ฑ๋ฅ ์ต์ ํ ํ:")
312 print(" 1. ํ๋ ์ ์คํต (๋งค ํ๋ ์ ๊ฒ์ถ ๋ถํ์)")
313 print(" 2. ์ด๋ฏธ์ง ์ถ์ ํ ๊ฒ์ถ")
314 print(" 3. ์ด์ ๊ฒ์ถ ์์ญ ์ฃผ๋ณ๋ง ํ์")
315 print(" 4. ๋ฉํฐ์ค๋ ๋ฉ ํ์ฉ")
316
317
318def main():
319 """๋ฉ์ธ ํจ์"""
320 # Haar Cascade ์ผ๊ตด ๊ฒ์ถ
321 haar_cascade_face_detection()
322
323 # ๋ ๊ฒ์ถ
324 cascade_eye_detection()
325
326 # ์ฌ์ฉ ๊ฐ๋ฅํ Cascade ๋ชฉ๋ก
327 available_cascades()
328
329 # LBP ๊ฒ์ถ
330 lbp_face_detection()
331
332 # ์ผ๊ตด ์ธ์ ๊ฐ๋
333 face_recognition_concept()
334
335 # ๋ฐฉ๋ฒ ๋น๊ต
336 face_detection_comparison()
337
338 # ์ค์๊ฐ ํ
ํ๋ฆฟ
339 real_time_detection_template()
340
341 print("\n์ผ๊ตด ๊ฒ์ถ ๋ฐ ์ธ์ ๋ฐ๋ชจ ์๋ฃ!")
342
343
344if __name__ == '__main__':
345 main()