16_face_detection.py

Download
python 346 lines 10.3 KB
  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()