Study
드라마 《스타트업》 속 AI는 왜 사람을 변기로 인식했을까?
Python과 OpenCV로 알아보는 이미지 인식과 얼굴 인식의 원리

요즘 tvN 드라마 《스타트업》을 재미있게 보고 있다.

개발자가 주인공으로 등장하는 드라마라 그런지 자연스럽게 관심이 갔는데 특히 극 중 남도산이 개발하는 인공지능 기술이 꽤 흥미로웠다. 보통 드라마에서 개발자라고 하면 검은 화면에 알 수 없는 코드를 빠르게 입력하는 모습이 전부였는데 이번에는 실제 개발 환경과 기술적인 개념까지 제법 구체적으로 등장한다.
그중 가장 기억에 남았던 장면이 하나 있다.
2화에서 남도산은 아버지에게 자신이 개발한 이미지 인식 프로그램을 보여준다. 카메라를 통해 사물을 인식하는 프로그램인데, 정작 아버지를 비추자 화면에는 엉뚱한 결과가 나타난다.

Toilet.
사람을 변기로 인식한 것이다. ㅋㅋㅋㅋㅋㅋㅋㅋㅋ
웃긴 장면이긴 한데 개발 관점에서 보면 꽤 흥미로운 부분인 것 같다. 사람과 변기는 전혀 다르게 생겼는데 컴퓨터는 왜 이런 실수를 했을까? 그리고 컴퓨터가 사람의 얼굴을 정확하게 인식하려면 어떤 기술이 필요할까? 이번에는 이 장면을 시작으로 이미지 인식과 얼굴 인식의 원리를 살펴보고 Python을 이용해 간단한 얼굴 인식 프로그램까지 만들어보려고 한다.
1. 컴퓨터는 이미지를 어떻게 바라볼까?
우리는 사진을 보면 그 안에 무엇이 있는지 쉽게 알아차린다. 사람의 얼굴인지, 강아지인지, 자동차인지 구분하는 데 특별한 노력이 필요하지 않다. 그런데 컴퓨터는 조금 다르다. 컴퓨터에게 사진은 사람이나 사물의 모습이 아니라 숫자로 이루어진 데이터다. 이미지를 구성하는 각각의 픽셀(Pixel)에 색상 정보가 들어 있고 컴퓨터는 이 숫자들을 계산하여 이미지를 처리한다.
예를 들어 컬러 이미지는 일반적으로 다음과 같은 형태로 표현할 수 있다.
import numpy as np
image = np.array([
[[255, 0, 0], [0, 255, 0]],
[[0, 0, 255], [255, 255, 255]]
])
print(image.shape)
# (2, 2, 3)여기서 (2, 2, 3)은 가로와 세로가 각각 2픽셀이고 픽셀마다 3개의 색상 채널이 존재한다는 뜻이다. 위 배열은 RGB 순서이며 OpenCV에서는 일반적으로 BGR 순서를 사용한다. 사람 눈에는 하나의 이미지로 보이지만 컴퓨터에게는 결국 숫자가 모여 있는 다차원 배열인 셈이다.
그렇다면 이 숫자만 가지고 어떻게 사람의 얼굴을 구분할 수 있을까?
2. CNN, 이미지의 특징을 학습하는 신경망
이미지 인식에 많이 활용되는 기술 중 하나가 CNN(Convolutional Neural Network), 즉 합성곱 신경망이다.
CNN은 이미지의 공간적인 특징을 추출하는 데 적합한 신경망 구조로, 이미지 전체를 단순히 하나의 긴 숫자 배열로 처리하는 대신 작은 영역을 살펴보면서 특징을 찾아낸다.

처음에는 선이나 모서리처럼 단순한 특징을 추출하지만 여러 층을 거치면서 점차 복잡한 형태를 학습할 수 있다. 얼굴을 예로 들면 눈, 코, 입과 관련된 특징뿐 아니라 이들이 배치된 구조까지 학습하는 것이다. 물론 각 층이 반드시 특정 신체 부위 하나만을 담당하는 것은 아니지만 학습을 거듭하며 분류에 필요한 특징을 추출한다는 것이 핵심이다.
이렇게 추출한 특징을 바탕으로 모델은 입력 이미지가 어떤 종류에 속할 가능성이 높은지 계산한다.
가령 모델이 다음과 같은 예측값을 출력했다고 가정해보자.
이 결과라면 모델은 Person을 최종 결과로 선택할 가능성이 높다. 그런데 학습이 충분하지 않거나 특정 이미지에서 특징을 제대로 추출하지 못하면 다른 분류의 점수가 더 높게 나올 수도 있다. 남도산의 프로그램에서도 비슷한 문제가 발생했다고 생각해볼 수 있다. 다만 드라마에 등장한 모델의 실제 구조나 학습 데이터가 공개된 것은 아니기 때문에 CNN이 원인이었다고 단정할 수는 없다.
3. 이미지 인식과 얼굴 인식은 같은 기술일까?
여기서 한 가지 구분해야 할 개념이 있다. 이미지에서 사람을 발견하는 것과 그 사람이 누구인지 알아내는 것은 서로 다른 문제라는 것이다. 흔히 이미지 인식, 얼굴 탐지, 얼굴 인식을 비슷한 의미로 사용하지만 실제로는 구분된다.
Face Detection은 얼굴이 어디 있는지 찾는 기술이고, Face Recognition은 그 얼굴이 누구의 얼굴인지 비교하는 기술이다. 예를 들어 사진에 사람이 세 명 있다면 얼굴 탐지 모델은 세 얼굴의 위치를 찾아낸다. 하지만 그 세 명이 누구인지 알려면 별도의 얼굴 특징 추출과 비교 과정이 필요하다. 남도산의 장면은 얼굴의 신원을 식별하는 Face Recognition보다는 이미지 분류에서 발생한 오류에 가깝다. 그렇다면 얼굴 인식은 실제로 어떤 과정을 거칠까?
4. 얼굴 인식의 핵심, 특징 벡터
사람은 친구의 얼굴을 기억할 때 픽셀 하나하나를 외우지 않는다. 눈과 코의 형태, 얼굴 윤곽처럼 여러 특징을 종합해서 기억하고, 다시 만났을 때 기억 속 얼굴과 비교한다. 얼굴 인식 모델도 이와 비슷한 접근을 사용한다.

여기서 가장 중요한 개념은 Embedding(임베딩) 이다.
임베딩은 이미지에서 추출한 특징을 숫자 벡터로 표현한 것이다. 예를 들어 face_recognition 라이브러리에서는 얼굴을 128차원의 특징 벡터로 표현하는 방식을 사용한다.
face_encoding = [
-0.12, 0.08, 0.04, -0.15,
# ... 총 128개 값
]이 숫자 하나하나가 눈의 크기나 코의 길이를 직접 의미하는 것은 아니다. 신경망이 얼굴을 구분하는 데 유용하다고 학습한 특징을 수치화한 결과다. 같은 사람의 얼굴이라면 촬영 환경이 조금 달라도 특징 벡터 사이의 거리가 상대적으로 가까워지도록 학습하고 다른 사람의 얼굴이라면 상대적으로 멀어지도록 학습한다.
두 얼굴 벡터의 거리를 구하는 대표적인 방법으로는 유클리드 거리(Euclidean Distance)가 있다.
[
d(A,B)=\sqrt{\sum_{i=1}^{n}(A_i-B_i)^2}
]
여기서 A와 B는 각각 얼굴의 특징 벡터다. 거리가 작을수록 두 얼굴이 비슷하다는 의미이며 일정한 임계값을 기준으로 동일 인물인지 판단할 수 있다. 물론 거리가 작다고 해서 반드시 같은 사람이라는 뜻은 아니다. 모델의 정확도와 촬영 조건, 비교 기준에 따라 오인식이 발생할 수 있기 때문이다.
5. Python으로 얼굴 인식 프로그램 만들어보기
원리를 살펴봤으니 간단한 프로그램을 만들어보자. 사용할 라이브러리는 OpenCV와 face_recognition이다. OpenCV는 이미지와 영상을 처리하기 위한 라이브러리이고, face_recognition은 dlib 기반의 얼굴 탐지 및 특징 비교 기능을 제공한다.
개발 환경
먼저 필요한 라이브러리를 설치한다.
python -m venv venv
# macOS / Linux
source venv/bin/activate
# Windows
# venv\Scripts\activate
pip install numpy==1.19.4
pip install opencv-python==4.4.0.46
pip install face_recognition==1.3.0face_recognition은 내부적으로 dlib을 사용하기 때문에 운영체제에 따라 CMake나 C++ 빌드 도구가 추가로 필요할 수 있다.
5-1. 얼굴 등록하기
우선 비교 기준으로 사용할 얼굴 사진 한 장을 준비한다. 프로젝트 구조는 다음과 같이 구성한다.
face-recognition/
├── known.jpg
├── main.py
└── venv/known.jpg에는 등록할 사람의 얼굴이 선명하게 나온 사진을 넣는다. 실습에서는 본인이 촬영한 사진을 사용하는 편이 좋다.
import face_recognition
known_image = face_recognition.load_image_file(
"known.jpg"
)
face_encodings = face_recognition.face_encodings(
known_image
)
if not face_encodings:
raise ValueError("얼굴을 찾을 수 없습니다.")
known_encoding = face_encodings[0]
print(len(known_encoding))
# 128face_encodings() 함수는 이미지 속 얼굴을 찾아 각각의 특징 벡터를 반환한다. 사진에 얼굴이 하나 있다고 가정했으므로 첫 번째 벡터를 사용했다. 만약 여러 사람의 얼굴이 있다면 각각의 벡터가 반환될 수 있기 때문에 별도의 선택 과정이 필요하다.
5-2. 웹캠에서 얼굴 찾기
이번에는 OpenCV로 웹캠을 실행하고 실시간으로 들어오는 영상에서 얼굴을 탐지해보자.
import cv2
import face_recognition
video_capture = cv2.VideoCapture(0)
if not video_capture.isOpened():
raise RuntimeError("카메라를 열 수 없습니다.")
while True:
ret, frame = video_capture.read()
if not ret:
break
rgb_frame = cv2.cvtColor(
frame,
cv2.COLOR_BGR2RGB
)
face_locations = face_recognition.face_locations(
rgb_frame,
model="hog"
)
for top, right, bottom, left in face_locations:
cv2.rectangle(
frame,
(left, top),
(right, bottom),
(0, 255, 0),
2
)
cv2.imshow("Face Detection", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
video_capture.release()
cv2.destroyAllWindows()실행하면 웹캠 화면이 나타나고 얼굴이 발견되는 영역에 초록색 사각형이 표시되도록 작성한 코드다.
여기서는 얼굴 탐지에 HOG(Histogram of Oriented Gradients) 기반 방식을 사용했다. HOG는 이미지의 밝기 변화 방향과 형태적 특징을 활용하는 방법으로, 비교적 가볍게 얼굴을 탐지할 수 있다. 또한 OpenCV는 이미지를 기본적으로 BGR 순서로 읽기 때문에 cv2.cvtColor()를 이용해 RGB로 변환해주었다.
5-3. 등록된 얼굴과 비교하기
이제 단순히 얼굴을 찾는 것에서 한 단계 더 나아가, 앞서 등록한 사람과 동일 인물인지 비교해보자.
import cv2
import face_recognition
# 등록할 얼굴 이미지 로드
known_image = face_recognition.load_image_file(
"known.jpg"
)
known_encodings = face_recognition.face_encodings(
known_image
)
if not known_encodings:
raise ValueError("등록할 얼굴을 찾지 못했습니다.")
known_encoding = known_encodings[0]
# 웹캠 실행
video_capture = cv2.VideoCapture(0)
if not video_capture.isOpened():
raise RuntimeError("카메라를 열 수 없습니다.")
while True:
ret, frame = video_capture.read()
if not ret:
break
rgb_frame = cv2.cvtColor(
frame,
cv2.COLOR_BGR2RGB
)
# 얼굴 위치 탐지
face_locations = face_recognition.face_locations(
rgb_frame,
model="hog"
)
# 탐지한 얼굴들의 특징 벡터 추출
face_encodings = face_recognition.face_encodings(
rgb_frame,
face_locations
)
for (top, right, bottom, left), face_encoding in zip(
face_locations,
face_encodings
):
# 등록된 얼굴과 거리 계산
distance = face_recognition.face_distance(
[known_encoding],
face_encoding
)[0]
# 임계값을 이용한 비교
if distance < 0.6:
name = "Known"
else:
name = "Unknown"
# 얼굴 영역 표시
cv2.rectangle(
frame,
(left, top),
(right, bottom),
(0, 255, 0),
2
)
cv2.putText(
frame,
name,
(left, top - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.8,
(0, 255, 0),
2
)
cv2.imshow("Face Recognition", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
video_capture.release()
cv2.destroyAllWindows()이 코드는 웹캠에서 얼굴을 탐지한 다음, 각 얼굴의 특징 벡터를 생성하고 등록된 사진과의 거리를 계산한다. 그 거리가 0.6보다 작으면 Known, 그렇지 않으면 Unknown으로 표시한다.
여기서 0.6은 절대적인 정답이 아니라 비교 기준으로 사용하는 임계값이다. 값을 낮추면 더 엄격하게 비교하고, 높이면 더 많은 얼굴을 같은 인물로 판단할 수 있다.
6. 얼굴 인식의 정확도를 높이려면?
코드를 보면 생각보다 간단하게 얼굴 인식 기능을 구현할 수 있다는 것을 알 수 있다. 하지만 실제 서비스에서 높은 정확도를 확보하는 문제는 별개다.
예를 들어 같은 사람이라도 다음과 같은 상황에서는 인식 결과가 달라질 수 있다.
- 정면이 아닌 측면에서 촬영한 경우
- 조명이 어둡거나 얼굴에 그림자가 생긴 경우
- 마스크나 안경 등으로 얼굴 일부가 가려진 경우
- 카메라 화질이 낮아 얼굴의 특징이 손실된 경우
- 학습 데이터가 특정 환경이나 인구 집단에 편중된 경우

[기사 내용 일부 발췌]
실험에서 백인 남성들의 얼굴 오인식률은 1%에 그쳤고, 백인 여성에 대한 오인식률이 7%로 다소 높아졌다. 흑인 남성은 최대 12%까지 오인식률이 올라갔고, 흑인 여성은 최대 35%까지 오인식률이 발생했다. 업체별로는 마이크로소프트가 21%, IBM과 메그비는 35%였다.
전문가들은 AI를 구성하는 알고리즘이 매우 다양하고 이를 설계하는 사람의 기준에 따라 쓰임새나 구현 방식이 달라질 수 있는 것처럼, AI를 학습시키는 데이터에 따라 결과도 크게 달라질 수 있다고 지적한다.
이를 개선하려면 우선 다양한 환경에서 촬영한 데이터를 확보할 필요가 있다. 밝기나 회전 등을 조정하는 데이터 증강(Data Augmentation)도 하나의 방법이다.
모델 구조 역시 중요하다. 2015년에 발표된 FaceNet은 얼굴 이미지를 임베딩 공간으로 변환해 같은 사람의 얼굴은 가깝게 배치하고 다른 사람의 얼굴은 멀어지도록 학습하는 방법을 제안했다. 이처럼 특징 벡터 간 거리를 학습하는 방식은 얼굴 인식 기술의 중요한 접근법 중 하나다. 그러나 좋은 모델을 사용한다고 해서 모든 문제가 해결되는 것은 아니다.
실제로는 어떤 환경에서 사용되는지에 따라 적절한 임계값을 설정하고, 서로 다른 사람을 동일 인물로 잘못 판단하는 비율(False Acceptance Rate)과 같은 사람을 다른 인물로 판단하는 비율(False Rejection Rate)을 함께 검토해야 한다.

얼굴 정보를 저장하는 경우에는 개인정보 보호도 중요하다. 특징 벡터 역시 개인을 식별하는 데 활용될 수 있으므로 동의와 보관 정책, 접근 통제 등이 필요하다.
7. 다시 드라마 《스타트업》으로 돌아가서
남도산이 개발한 인공지능이 아버지를 변기로 인식하는 장면은 단순히 웃기기 위해 넣은 장면처럼 보이지만 한편으로는 머신러닝의 특성을 잘 보여준다. 컴퓨터는 사람처럼 사물을 이해하는 것이 아니라, 학습한 데이터에서 발견한 패턴을 이용해 결과를 예측한다.
우리가 아무리 명확하다고 생각하는 대상도 모델에게는 어렵게 느껴질 수 있고 충분한 학습을 거쳤더라도 처음 마주하는 환경에서는 예상하지 못한 결과가 나올 수 있다. 삼산텍이 이미지 인식 기술을 개발하고 이를 기반으로 새로운 서비스를 구상하는 과정도 이런 관점에서 보면 흥미롭다.

특히 시각장애인을 위한 서비스인 '눈길'처럼 실제 사용자의 생활과 연결되는 기능에서는 단순한 이미지 분류 정확도뿐 아니라 잘못된 안내가 사용자에게 어떤 영향을 줄 수 있는지도 고민해야 한다.
이미지를 정확하게 인식하는 것과 그 기술을 믿고 사용할 수 있는 서비스를 만드는 것은 다른 문제이기 때문이다.
마치며
처음에는 드라마 속 짧은 장면 하나가 궁금해서 이미지 인식 기술을 찾아봤는데, 공부하다 보니 얼굴 탐지부터 특징 벡터, 딥러닝 모델의 학습 방식까지 자연스럽게 연결되었다. 이번에 살펴본 얼굴 인식 프로그램은 이미 학습된 모델을 활용한 간단한 예제지만 내부적으로 어떤 과정을 거쳐 결과를 내놓는지 이해하니 코드도 조금 다르게 보인다. 얼굴에 사각형을 그리는 것은 어렵지 않다. 그 사각형 안의 얼굴이 누구인지 신뢰할 수 있게 판단하는 것이 훨씬 어려운 문제다.
그리고 어쩌면 그게 남도산의 인공지능이 아버지를 변기로 인식했던 이유를 이해하는 첫걸음일지도 모르겠다.
참고 자료
- 인프런, 드라마 속 개발 이모저모, 2020.11.17
- OpenCV, 공식 문서
- Adam Geitgey, face_recognition GitHub
- Schroff et al., FaceNet: A Unified Embedding for Face Recognition and Clustering, CVPR 2015
- tvN, 《스타트업》, 2020
댓글
익명 캐릭터로 가볍게 이야기를 남겨 주세요.