앞 장에서 face_recognition의 dlib 의존과 유지보수 정체를 짚었습니다. 그 대안으로 가장 부담이 적은 선택지가 OpenCV에 내장된 SFace입니다. 추가 설치가 전혀 없고(이미 깔린 OpenCV만으로 동작), PART 02에서 쓴 YuNet과 자연스럽게 이어집니다. 이 장에서는 SFace로 얼굴을 인식해 봅니다.
SFace란 — 설치 0의 매력
SFace는 OpenCV에 FaceRecognizerSF라는 클래스로 들어 있는 얼굴 인식기입니다. 가장 큰 장점은 이름 그대로 "설치 0"입니다. PART 02에서 YuNet을 쓰려고 이미 OpenCV를 깔아 두었으니, 별도 라이브러리 없이 모델 파일 하나만 내려받으면 바로 인식이 됩니다. dlib에도, 무거운 딥러닝 프레임워크에도 기대지 않습니다.
흐름은 PART 02~04에서 배운 그대로입니다. YuNet으로 검출·정렬하고, SFace로 임베딩(특징)을 뽑아 비교합니다.
정렬] C --> D[SFace feature
특징 추출] D --> E[match
코사인 유사도 비교]
필요한 모델은 두 개입니다. 검출·정렬용 face_detection_yunet_2023mar.onnx(PART 02에서 이미 사용)와 인식용 face_recognition_sface_2021dec.onnx로, 둘 다 OpenCV Zoo에서 받습니다.
SFace 인식 코드
# 파일: sface_compare.py"""OpenCV SFace로 두 얼굴이 같은 사람인지 비교한다(추가 설치 없음)."""import cv2# 검출·정렬용 YuNet, 인식용 SFacedetector = cv2.FaceDetectorYN.create( "face_detection_yunet_2023mar.onnx", "", (320, 320), 0.9, 0.3, 5000)recognizer = cv2.FaceRecognizerSF.create( "face_recognition_sface_2021dec.onnx", "")def get_feature(path): img = cv2.imread(path) h, w = img.shape[:2] detector.setInputSize((w, h)) _, faces = detector.detect(img) if faces is None: return None aligned = recognizer.alignCrop(img, faces[0]) # YuNet 결과로 정렬 return recognizer.feature(aligned) # 특징(임베딩) 추출f1 = get_feature("a.jpg")f2 = get_feature("b.jpg")# 코사인 유사도: 클수록 닮음 (권장 임계값 약 0.363)score = recognizer.match(f1, f2, cv2.FaceRecognizerSF_FR_COSINE)print(f"코사인 유사도: {score:.3f} →", "같은 사람" if score > 0.363 else "다른 사람")
코드의 핵심은 alignCrop입니다. YuNet이 찾아 준 얼굴 정보(faces[0])에는 박스뿐 아니라 5점 랜드마크가 들어 있어, SFace가 그것으로 얼굴을 정렬해 줍니다. PART 03의 정렬이 여기서 자동으로 일어나는 것입니다. 그다음 feature로 특징을 뽑고 match로 비교합니다.
코사인과 L2, 두 가지 비교 기준
match의 마지막 인자로 비교 방식을 고릅니다. PART 04에서 배운 두 척도가 그대로 옵션으로 제공됩니다.
| 상수 | 척도 | 닮을수록 | 권장 임계값 |
|---|---|---|---|
cv2.FaceRecognizerSF_FR_COSINE |
코사인 유사도 | 커짐 | 약 0.363 |
cv2.FaceRecognizerSF_FR_NORM_L2 |
L2(유클리드) 거리 | 작아짐 | 약 1.128 |
코사인을 쓰면 점수가 0.363보다 크면 같은 사람, L2를 쓰면 거리가 1.128보다 작으면 같은 사람으로 봅니다. 이 권장 임계값들은 SFace 모델에 맞춰진 출발점이며, 늘 그렇듯 내 데이터로 조정합니다.
face_recognition과 비교하면
| 항목 | face_recognition | OpenCV SFace |
|---|---|---|
| 설치 | dlib 필요(conda로 해결) | 0 (OpenCV 내장) |
| 정렬 | 자동(내부) | YuNet alignCrop |
| 임베딩 | 128차원 | 128차원 |
| 유지보수 | 정체 | OpenCV와 함께 유지 |
| API 친절함 | 매우 쉬움(한 줄) | 단계가 조금 더 보임 |
SFace는 코드가 face_recognition보다 한두 줄 더 길지만, "OpenCV만 있으면 된다"는 점과 OpenCV 본체와 함께 꾸준히 유지된다는 점이 강점입니다. 설치 부담을 줄이고 싶거나 dlib 의존을 피하고 싶을 때 좋은 균형점입니다.
실무 팁. 여러 명을 등록하는 DB도 SFace로 똑같이 만들 수 있습니다. 앞 장의 DB 구축에서
face_encodings대신 위get_feature를 쓰고, 비교는recognizer.match로 바꾸면 됩니다. 인식 부분만 갈아 끼우는 구조(4장 실무 팁)를 따랐다면, 이 교체는 함수 하나를 바꾸는 일로 끝납니다.
이 장에서 기억할 것
OpenCV SFace(FaceRecognizerSF)는 추가 설치 없이 OpenCV만으로 쓰는 인식기로, YuNet 검출·정렬(alignCrop)과 이어 feature로 특징을 뽑고 match로 비교합니다. 코사인(클수록 닮음)과 L2(작을수록 닮음) 두 기준을 고를 수 있고 각자 권장 임계값이 있습니다. dlib 의존과 유지보수 부담을 피하려는 경우의 좋은 대안입니다. 다음 장에서는 지금까지 배운 것을 모아 출석 체크 프로토타입을 만듭니다.