📒 작품 소개 ☆
이번 프로젝트는 YOLO 모델뿐만 아니라 FaceNet이라는 모델을 적용해 보았다.
1인 크리에이터와 SNS 인플루언서 분들이 공개적으로 사진 또는 영상을 게시하는 일들이 많아졌다.
하지만, 인파가 많은 곳에서 사진이나 영상을 찍을 경우 일반 사람들이 함께 촬영되어 초상권을 보호받지 못할 수 있는 경우가 생길 수 있다.
이로 인해, 보행자는 원치 않게 노출이 발생할 수 있고,
크리에이터 입장에서는 초상권 보호를 위한 영상 삭제 요청 시 금전적인 피해를 볼 수 있거나 사람의 얼굴을 직접 모자이크 해야 하는 불편함을 겪을 수 있을 것이라고 생각했다.
그래서 특정 인물을 제외하고 원하지 않는 사람들은 자동으로 모자이크 처리를 할 수 있는 모델을 만들어 보고자 하였다.
https://drive.google.com/drive/folders/10BtvndKGUIEfBFq66WxDkwASNDcVvRGN?usp=share_link
Portrait-Protection-Mosaic-Processing-System - Google Drive
이 폴더에 파일이 없습니다.이 폴더에 파일을 추가하려면 로그인하세요.
drive.google.com
목차
1. 개발 환경
2. 목표
3. 나의 역할
4. 활동 내용
5. 활동 결과
6. 마무리
#3 YOLO와 FaceNet 모델을 이용한 초상권 보호 모자이크 처리 모델 생성하기
작품기간 : 2022.09.23 ~ 2022.10.14 (약 3주)
1. 개발 환경
- 활용한 모델 : YOLOv5s, YOLOv5m, YOLO7, FaceNet
- 개발 언어 : Python
- 개발 도구 : google colab, jupyter notebook, labelImg
2. 목표
- 원하는 얼굴 이미지를 학습하고 학습한 얼굴과 다른 얼굴은 자동으로 모자이크 처리해 주는 모델을 만들어본다.
3. 나의 역할
- 특정 인물 이미지 데이터 수집 및 라벨링 작업 수행 (YOLO, FaceNet)
- OpenCV를 활용한 모자이크 처리 코드 작성
- FaceNet 모델의 구조 이해
- YOLOv5s 모델과 YOLOv7 모델 생성 및 학습
- FaceNet 모델 생성 및 학습
- 각 모델에 모자이크 처리 코드와 탐지하는 코드 결합
4. 활동 내용
>> 특정 인물 이미지 데이터 수집 및 라벨링 작업 수행
- 데이터를 수집하기 위해 연예인 아이유와 김용명을 특정 인물로 정하여, 데이터를 수집하였다.
- 데이터를 수집하고 라벨링하는 작업의 경우 이전 글에서 수행한 방식과 같아서 자세한 설명은 아래 링크를 참고하면 좋을 것 같다.
- YOLO 모델을 활용하여 야생 동물 LoadKill 방지 모델 생성하기
YOLO 모델을 활용하여 야생 동물 LoadKill 방지 모델 생성하기
작품 소개 ☆ YOLOv5 모델을 활용하여 처음 만들어보는 인공지능 프로젝트 최근 야생 동물이 고속도로에 뛰어들어 차량과 사고가 발생하는 것을 한문철 블랙박스 사고 영상에서 본 적 있다. 사고
my-portfolio-log.tistory.com
- YOLO 모델과 다르게 FaceNet에서 활용하기 위한 데이터는 다소 간단하게 수집하였는데, FaceNet을 위한 데이터 수집은 아래 'FaceNet 모델의 구조 이해' 부분에서 설명하도록 하겠다.
>> OpenCV를 활용한 모자이크 처리 코드 작성
- OpenCV 라이브러리를 활용하여 모자이크 처리해주는 코드를 작성해보았다.
- 모자이크의 경우, 이미지 안에서 원하는 범위를 추출해서 추출한 부분을 일부러 깨지게 하는 방식으로 만들어 볼 수 있다.
import cv2
def blur_fun(frame, x, y, w, h) :
try :
face_img = frame[y:y+h, x:x+w] # 탐지된 얼굴 이미지 crop
face_img = cv2.resize(face_img, dsize=(0, 0), fx=0.04, fy=0.04) # 축소
face_img = cv2.resize(face_img, (w, h), interpolation=cv2.INTER_AREA) # 확대
frame[y:y+h, x:x+w] = face_img # 탐지된 얼굴 영역 모자이크 처리
return frame
except :
return frame
- 이 함수를 이후에 모델 detect하는 코드와 결합시킬 것이다.
>> FaceNet 모델의 구조 이해
- 간단하게 설명을 해보자면, 인물 이미지의 구체적인 특징을 찾아내주고, 이 특징을 바탕으로 새로운 이미지가 입력으로 들어왔을 때 다른 사람의 이미지와 인물의 이미지와의 거리를 비교해서 더 가까운 이미지로 식별해 낼 수 있는 모델이다.
- 약간 k-최근접 이웃 머신러닝 모델과 비슷한 느낌이었다.
- 이 모델 학습 구조를 이해하기 위해서 Triplet Loss를 먼저 이해하는 것이 중요하다.
- Triplet Loss를 예를 들어 설명하면, 한 방에서 특정 인물(A)과 다른 인물(B) 사이에서 어떤 사람(C)이 들어왔는데, C가 A와 B 중 더 닮은 사람에게 가까이 서 있다고 생각할 수 있다. 그리고 가까운 사람의 거리와 먼 사람의 거리를 계산해서 서로 얼마나 차이가 나는지 Loss 함수를 만들어 계산해주는 개념이다.
- FaceNet 모델의 자세한 설명은 아래 링크에서 확인해 볼 수 있다.(영어를 잘 못한다면, 번역기 필수,,,ㅎㅎ)
- https://arxiv.org/abs/1503.03832
FaceNet: A Unified Embedding for Face Recognition and Clustering
Despite significant recent advances in the field of face recognition, implementing face verification and recognition efficiently at scale presents serious challenges to current approaches. In this paper we present a system, called FaceNet, that directly le
arxiv.org
- 일단 모델을 공부하고 난 후, 특정 인물의 데이터와 그렇지 않은 인물 데이터를 수집하는 것이 필요해 보였다.
- 그리고 FaceNet 모델의 경우, 적은 이미지 개수로도 이미지의 특징값을 구해주기 때문에 같은 인물의 데이터와 그렇지 않은 인물 데이터를 각각 30장 이내로 수집해보았다.
>> YOLOv5s 모델과 YOLOv7 모델 생성 및 학습
- YOLOv5 모델은 아래 링크에서 받아볼 수 있을 것이다.
- https://github.com/ultralytics/
Ultralytics
Simpler. Smarter. Further. Ultralytics has 35 repositories available. Follow their code on GitHub.
github.com
- 마찬가지로 YOLOv7 또한 아래 링크를 통해 받을 수 있다.
- https://github.com/WongKinYiu/yolov7
GitHub - WongKinYiu/yolov7: Implementation of paper - YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time
Implementation of paper - YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors - GitHub - WongKinYiu/yolov7: Implementation of paper - YOLOv7: Trainable bag-of...
github.com
- YOLOv5s와 YOLOv5m 모델의 .yaml 파일 수정과 학습시키는 과정은 이전 글에서 확인해볼 수 있다.
- YOLOv7의 경우도 YOLOv5와 비슷하다.
- 먼저, 구글 드라이브 마운트해주고 깃에서 yolo 7을 다운받아준다.
# 구글 드라이브 연결
from google.colab import drive
drive.mount('/content/drive')
# /content 경로 이동
%cd /content/프로젝트 경로
# 깃에서 욜로 7 가져오기
!git clone https://github.com/WongKinYiu/yolov7.git
- 그리고 YOLOv5와 마찬가지로 data.yaml 파일과 yolo7.yaml 를 같은 방식으로 수정해준 후, 학습시켜 준다.
- 한계점 : 여기서 여러 모델을 사용한 이유는 최대한 다양한 모델을 적용해보고 더 성능이 좋은 모델을 선정하는 방식으로 하려했지만, 구글 코랩에서 제공하는 GPU 할당을 유료 결제를 통해 학습을 돌려봐도 턱없이 부족하였다. 특히 모델이 더 무거운 모델의 경우는 GPU 자원을 상당히 많이 먹어서 동일한 학습 조건을 만들지 못하였다.
>> FaceNet 모델 생성 및 학습
- FaceNet 모델은 아래 링크를 통해 다운받을 수 있다.
- https://github.com/AISangam/Facenet-Real-time-face-recognition-using-deep-learning-Tensorflow/blob/master/classifier.py
GitHub - AISangam/Facenet-Real-time-face-recognition-using-deep-learning-Tensorflow: Facenet-Real-time-face-recognition-using-de
Facenet-Real-time-face-recognition-using-deep-learning-Tensorflow - GitHub - AISangam/Facenet-Real-time-face-recognition-using-deep-learning-Tensorflow: Facenet-Real-time-face-recognition-using-dee...
github.com
- 여기서도 깃으로 링크를 통해 설치할 수 있다.
!git clone https://github.com/AISangam/Facenet-Real-time-face-recognition-using-deep-learning-Tensorflow
- 데이터 수집에서 특정 인물과 그렇지 않은 인물에 대한 데이터를 새로운 폴더를 하나 생성하여 넣어준다.
- 그리고 data_preprocess.py 파일을 실행하여 이미지의 특징을 찾아줄 수 있도록 하였다.
- data_preprocess.py 에서 새로 만든 폴더명이 train_img가 아니라면 새롭게 만든 폴더명 이름으로 변경해준다. (웬만하면, 영어이름으로 폴더를 만들어 줍시다~!!)
!python '절대 경로 지정'/data_preprocess.py
- 이 특징값을 가지고, train_main.py를 실행시켜 각각의 이미지를 학습시켜준다.
!python '절대 경로 지정'/train_main.py
- 여기까지 학습된 FaceNet 모델로 face_recognition.py 파일을 실행시켜주면 얼굴을 찾아내는 것을 확인해볼 수 있다.
!python '절대 경로 지정'/face_recognition.py
- 전체적으로 FaceNet 모델을 사용하기 위한 순서를 간단하게 정리해보면,
- 두 명 이상의 인물 이미지 데이터를 수집한다.
- FaceNet 모델을 생성한다.
- 수집한 이미지를 새로운 폴더를 만들어서 넣어준다.
- data_preprocess.py를 실행하여 이미지 특징 찾기 해준다.
- 다음으로 train_main.py로 학습을 진행한다.
- 학습이 끝났다면, face_recognition.py 파일로 detecting 해볼 수 있다.
>> 각 모델에 모자이크 처리 코드와 detect 코드 결합
- 위에서 만들었던 모자이크 처리 코드를 각 모델의 탐지하는 코드와 결합시킨다.
- 먼저 yolo 모델이다. yolo 모델의 경우 detect.py 라는 코드를 실행하면 detecting 할 수 있다.
- detect.py를 수정하여 모자이크 처리를 할 수 있도록 수정해준다.
<생략>
from utils.torch_utils import select_device, smart_inference_mode
#####################################추가된 코드#####################################
def blur_fun(frame, x, y, w, h) :
try :
face_img = frame[y:y+h, x:x+w] # 탐지된 얼굴 이미지 crop
face_img = cv2.resize(face_img, dsize=(0, 0), fx=0.04, fy=0.04) # 축소
face_img = cv2.resize(face_img, (w, h), interpolation=cv2.INTER_AREA) # 확대
frame[y:y+h, x:x+w] = face_img # 탐지된 얼굴 영역 모자이크 처리
return frame
except :
return frame
###################################################################################
@smart_inference_mode()
def run(
weights=ROOT / 'yolov5s.pt', # model.pt path(s)
<생략>
):
<생략>
if len(det):
# Rescale boxes from img_size to im0 size
det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round()
##############################특정 인물 제외한 얼굴 모자이크##################################
tmp_list = det[:, :4].cpu().numpy()
tmp_list = tmp_list.astype(np.int64)
x1, y1, x2, y2, w, h = 0, 0, 0, 0, 0, 0
class_num = det[:, 5].cpu().numpy()
idx = 0
for num in class_num :
if num == 0 :
x1, y1, x2, y2 = tmp_list[idx][0], tmp_list[idx][1], tmp_list[idx][2], tmp_list[idx][3]
##
if idx < len(tmp_list)-1 :
x1_cmp, y1_cmp, x2_cmp, y2_cmp = tmp_list[idx+1][0], tmp_list[idx+1][1], tmp_list[idx+1][2], tmp_list[idx+1][3]
# if x
w = x2 - x1
h = y2 - y1
im0 = blur_fun(im0, x1, y1, w, h)
idx += 1
###############################################################################################
<생략>
- yolo의 경우 바운딩 박스의 좌표를 tensor 자료형으로 반환해주는데, 여기서는 numpy 자료형으로 변경해서 좌표값을 바꿔주었다.
- 또한, FaceNet 모델의 경우 face_recognition.py 파일로 detecting을 진행할 수 있다.
- face_recognition.py 파일도 모자이크 처리를 할 수 있도록 수정한다.
(생략)
########################################################################
# 영상 프레임 너비
width = video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)
# 영상 프레임 높이
height = video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
# 초당 영상 프레임
fps = video_capture.get(cv2.CAP_PROP_FPS)
# 저장 동영상 코덱 정의
fourcc = cv2.VideoWriter_fourcc(*'XVID')
# 저장 영상 파일명 정의
##########################
from pytz import timezone
from datetime import datetime
today = datetime.now(timezone('Asia/Seoul'))
dt_string = today.strftime('%m/%d/%H:%M.avi')
filename = 'yong18_90.avi'
#filename1 = dt_string
#out = cv2.VideoWriter(filename1, fourcc, fps, (int(width), int(height)))
out = cv2.VideoWriter(filename, fourcc, fps, (int(width), int(height)))
########################################################################
print('Start Recognition')
while True:
(생략)
try:
# inner exception
if xmin <= 0 or ymin <= 0 or xmax >= len(frame[0]) or ymax >= len(frame):
print('Face is very close!')
continue
cropped.append(frame[ymin:ymax, xmin:xmax,:])
cropped[i] = facenet.flip(cropped[i], False)
scaled.append(np.array(Image.fromarray(cropped[i]).resize((image_size, image_size))))
scaled[i] = cv2.resize(scaled[i], (input_image_size,input_image_size),
interpolation=cv2.INTER_CUBIC)
scaled[i] = facenet.prewhiten(scaled[i])
scaled_reshape.append(scaled[i].reshape(-1,input_image_size,input_image_size,3))
feed_dict = {images_placeholder: scaled_reshape[i], phase_train_placeholder: False}
emb_array[0, :] = sess.run(embeddings, feed_dict=feed_dict)
predictions = model.predict_proba(emb_array)
best_class_indices = np.argmax(predictions, axis=1)
best_class_probabilities = predictions[np.arange(len(best_class_indices)), best_class_indices]
###################쓰레시홀드 수정######################
if best_class_probabilities>0.90:
###################쓰레시홀드 수정######################
#cv2.rectangle(frame, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2) #boxing face
for H_i in HumanNames:
if HumanNames[best_class_indices[0]] == H_i:
result_names = HumanNames[best_class_indices[0]]
print("Predictions : [ name: {} , accuracy: {:.3f} ]".format(HumanNames[best_class_indices[0]],best_class_probabilities[0]))
#cv2.rectangle(frame, (xmin, ymin-20), (xmax, ymin-2), (0, 255,255), -1)
# cv2.putText(frame, result_names, (xmin,ymin-5), cv2.FONT_HERSHEY_COMPLEX_SMALL,
# 1, (0, 0, 0), thickness=1, lineType=1)
############################################
if result_names != 'yong' :
face_img = frame[ymin:ymin+(ymax-ymin), xmin:xmin+(xmax-xmin)] # 탐지된 얼굴 이미지 crop
face_img = cv2.resize(face_img, dsize=(0, 0), fx=0.04, fy=0.04) # 축소
face_img = cv2.resize(face_img, ((xmax-xmin), (ymax-ymin)), interpolation=cv2.INTER_AREA) # 확대
frame[ymin:ymin+(ymax-ymin), xmin:xmin+(xmax-xmin)] = face_img # 탐지된 얼굴 영역 모자이크 처리
####################
########################
else : # 모르는 사람 인식 했을때
#cv2.rectangle(frame, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2)
#cv2.rectangle(frame, (xmin, ymin-20), (xmax, ymin-2), (0, 255,255), -1)
# cv2.putText(frame, "?", (xmin,ymin-5), cv2.FONT_HERSHEY_COMPLEX_SMALL,
# 1, (0, 0, 0), thickness=1, lineType=1)
##########################모자이크 코드 삽입##########################
face_img = frame[ymin:ymin+(ymax-ymin), xmin:xmin+(xmax-xmin)] # 탐지된 얼굴 이미지 crop
face_img = cv2.resize(face_img, dsize=(0, 0), fx=0.04, fy=0.04) # 축소
face_img = cv2.resize(face_img, ((xmax-xmin), (ymax-ymin)), interpolation=cv2.INTER_AREA) # 확대
frame[ymin:ymin+(ymax-ymin), xmin:xmin+(xmax-xmin)] = face_img # 탐지된 얼굴 영역 모자이크 처리
######################################################################
except:
print("error")
(생략)
####################################################################
#out.write(frame)
out.write(frame)
####################################################################
(생략)
- yolo 모델의 경우에는 detect를 한 후 영상을 저장하는 코드가 기본적으로 포함되어 있지만, FaceNet은 그렇지 않다. 그래서 OpenCV를 활용해서 영상을 저장할 수 있는 코드를 작성해주었다.
- 그리고, FaceNet은 특정 인물의 이름과 다르다면, 모두 모자이크를 처리해주도록 코드를 작성하였다.
5. 활동 결과
- 아쉬웠던 점 : 모든 모델을 동일한 에포크 횟수로 진행하지 못해서 모든 에포크에서 학습을 가장 완벽히 수행한 yolov5s 모델이 가장 성능이 좋게 나왔다. 동일하지 못한 조건으로 인해 좋은 성능을 가진 모델을 비교해보고 선정해보는 것을 하지 못해 아쉬움으로 남게 되었던 것 같다.
- 평가 1 : 각 모델에 있어 모자이크 처리 코드를 포함한 detect 파일들을 실행하여 정확히 동작하는지 확인해보았다.
- 이 프로젝트에서 실시간으로 적용하지 않고 영상으로 테스트해보았다.
- YOLOv5s 결과
- YOLOv5m 결과
- YOLOv7 결과
- FaceNet 결과
6. 마무리
저번 야생 동물 글에서는 데이터의 수집과 분석 및 라벨링에 대해서 중점적으로 프로젝트를 진행하였다면,
이번 프로젝트에서는 다양한 모델을 살펴보고 활용해볼 수 있는 프로젝트였다.
만들어진 인공지능 모델을 활용하여 객체를 탐지하도록 짜여진 코드를 직접 분석해보고, 프로젝트 목적에 맞게 코드를 수정 해보면서 YOLO와 FaceNet 인공지능 모델 구조를 깊이 있게 공부할 수 있었다.
나중에 조금 더 좋은 성능을 가진 하드웨어 자원이 생기면,
그때 다시 적용해서 프로젝트 결과물을 실시간으로 동작시켜 볼 것이다. ✔✔