2022학년도 졸업작품 최종보고서
분 야	AI엔터테인먼트( ), AI소프트웨어( ○ )
작품명	한글 제목 : 자동 모자이크 APP (영문 제목) : DeepMosaic
팀구성원
구분	성명	전공	학번	연락처(휴대폰, 전자우편주소)
팀장	홍 길 동	AI소프트웨어	9999999	010-xxxx-xxxx xxx@naver.com
팀원	박 길 동	AI소프트웨어	9999990	010-xxxx-xxxx xxx@naver.com
팀원
본인은 위 졸업작품 과제의 팀장으로서 팀원들과 제반 규정을 준수하여 본 졸업작품 과제를 성실히 수행하였으며, 그 결과로 본 졸업작품 최종보고서를 제출합니다. <별첨> 최종보고서 1부 2022년 11월 29 일 졸업작품 팀장 홍 길 동 (사인 또는 날인)
본 졸업작품의 팀은 대학의 졸업작품 관련 제반 규정을 준수하고, 당초 제안한 과제의 내용을 충실히 수행하였음을 확인합니다. 2020년 11월 15일 지도교수 지도교수명 (인) 전공책임교수 박 세 현 (인) (AI소프트웨어) 졸업작품준비위원장 귀하

차 례

1. 개요	2

1.1 개발 동기	2

1.2 개발 목적	2

1.3 개발 요소	2

1.4 최종 개발 목표	2

2. 시스템 구성	3

2.1 시스템 개념	3

2.2 시스템 특징	3

2.3 소프트웨어 구성	4

2.4 동작 또는 촬용 시나리오	5

3. 주요 시스템 구성요소 개발	6

3.1 선택적 모자이크 제외 시스템	6

(1) 기능	6

3.2 모자이크 시스템	7

(1) 기능	7

3.3 사용 절차 및 방법	8

3.4 소프트웨어 동작 로직	8

3.5 버튼 별 기능	9

3.6 실제 프로그램 파일 생성	9

4. 성능 평가	10

4.1 프로그램 실행	10

(1) 초기 실행 화면	10

(2) assign 실행	10

(3) Video Mosaic 실행	12

(4) Image Mosaic 실행	12

4.2 프로그램 한계	13

4.3 문제 개선점	13

5. 개발 일정 및 역할 분담	14

5.1 개발 일정	14

5.2 개발 참여자 및 역할 분담	14

6. 추가 자료	15

6.1 소스코드	15

개요

개발 동기

현대사회에 SNS와 커뮤니티채널들의 사용량이 증가하고 있고 그에 따라 사진과 동영상 업로드횟수가 많아짐으로서 인권침해나 초상권침해가 되는 사례가 많아짐

동영상 편집과정 중 수작업으로 모자이크 처리를 하게 되면 시간이 오래 걸림

시중에 나와있는 모자이크 프로그램들은 직접 얼굴영역을 지정해야하는 번거로움이 있음

모자이크 편집중이던 영상이 오류로 인해 손실 될 경우 처음부터 다시 편집해야하므로 유지보수가 어려움

개발 목적

모자이크 처리가 편해지면서 초상권을 고려하지 않은 영상들의 업로드 될 염려가 적dma

인권침해와 초상권침해를 줄일 수 있음

딥러닝 기술을 이용하여 모자이크 처리를 원하지 않는 얼굴을 자동으로 제외 할 수 있음

빠른 시간내에 편집된 영상을 저장 할 수 있다.

자동으로 얼굴영역을 인식하여 모자이크 처리를 할 수 있음

편집 중이던 영상이 삭제되더라도 다시 바로 제작이 가능하다.

프로그램에서 카메라를 실행시켜 제외할 얼굴을 바로 촬영이 가능하다.

개발 요소

얼굴 모자이크 기능 개발

카메라 실행 기능 개발

컴퓨터 드라이브 연결 기능 개발

선택적 모자이크 제외 기능 개발

jpeg파일과 png파일 둘 다 처리가 가능하도록 개발

최종 개발 목표

딥러닝 기술을 이용하여 자동으로 모자이크 처리가 되도록 구현

모자이크처리를 원하지 않는 얼굴을 제외하는 기능 구현

영상과 사진 둘 다 편집할 수 있도록 프로그램 구현

CPU를 사용하더라도 빠른시간 내에 편집을 할 수 있도록 구현

프로그램 내에서 카메라를 실행하여 촬영할 수 있도록 구현

사람얼굴이 인식되지 않는 사진이나 영상을 선택 할 경우 얼굴이 인식되지 않는다는 메시지 박스가 뜨도록 구현

시스템 구성

시스템 개념

모자이크 처리를 할 저장된 영상이나 사진 파일을 선택

실행을 시키면 프로그램이 자동으로 얼굴을 인식하여 모자이크 처리

원하지 않는 얼굴 모자이크 제외 가능

자동으로 편집된 파일 ( 사진 or 영상 )이 별도로 저장됨

※ 편의를 위해 바운딩 박스로 표시하였음 ( 실제 프로그램에선 바운딩박스는 나타나지않음 )

시스템 특징

구분	기존 기술	차별화 요소
모자이크 방식	사진이나 영상 속의 인물들을 직접 드래그해서 모자이크를 해야하는 수작업 방식	번거로운 수작업 없이 자동으로 모자이크 처리 가능
유지 보수	원본 파일 삭제 시 새롭게 수작업 모자이크 처리를 해야하므로 유지 보수가 어려움	파일이 삭제되어도 빠른 처리가 가능하므로 유지 보수가 용이
영역 제외	직접 모자이크 처리를 원하지 않는 영역을 제외하고 수작업을 해야하기 때문에 번거로움	원하지 않는 영역을 한 번 지정하면 모든 영상에서 자동으로 그 영역을 제외하고 모자이크 처리 가능

소프트웨어 구성

소스 구성

py파일

mosaic.py : 프로그램을 동작하는 메인 소스코드

폴더

knowns : 제외하고 싶은 얼굴 이미지파일을 저장하는 저장소

result : 프로그램으로 이미지파일을 모자이크 처리하였을 때 편집된 사진을 저장하는 저장소

mosaic : 프로그램을 동작하는데 필요한 폴더와 소스코드가 포함되어있고, 프로그램으로 영상파일을 모자이크 처리하였을 때 편집된 영상을 저장하는 저장소

동작 또는 활용 시나리오

Assign 버튼을 누르면 ‘take picture’, ‘take image file’ 두가지 기능 선택 가능

Take picture 버튼을 누르면 영상이나 사진 편집시 모자이크에서 제외할 얼굴 이미지를 직접 촬영 할 수 있다.

Take image file 버튼을 누르면 영상이나 사진 편집시 모자이크에서 제외할 얼굴 이미지 파일을 선택할 수 있다.

위 버튼 둘 다 지정한 사진은 knowns 폴더에 저장됨

Video Mosaic 버튼을 누르면 원하는 영상을 선택하여 모자이크 처리를 수행 할 수 있음

Image Mosaic 버튼을 누르면 원하는 사진을 선택하여 모자이크 처리를 수행 할 수 있음

파일을 선택하면 프로그램에서 사람 얼굴을 인식함

인식한 얼굴들중 제외한 얼굴이 있으면 그 부분을 제외하고 모자이크 처리를 함

편집된 영상은 별도로 자동 저장됨

영상은 현재디렉토리에 별도로 자동 저장되고 사진은 result 폴더에 별도로 자동 저징됨

주요 시스템 구성요소 개발

선택적 모자이크 제외 시스템

기능

원하는 사람의 얼굴을 제외하고 모자이크처리함

프로그램에서 카메라를 실행시켜 직접 제외할 얼굴이미지 촬영한다.

드라이브에 저장되어있는 사진으로 제외할 얼굴이미지를 선택한다.

얼굴이 인식되지 않는 사진을 선택하거나 촬영할 경우 메시지 박스가 뜨면서 저장되지않는다.

	구성	기능 구현 방향
1	얼굴 제외 기능	‘Knowns’ 폴더를 생성해서 해당 폴더에 얼굴 이미지파일을 넣어두면 이후 프로그램을 실행시킬 때마다 ‘knowns’ 폴더에 있는 얼굴을 제외하고 모자이크 처리하도록 구현
2	카메라 촬영 기능	프로그램에서 ‘assign’버튼을 누르고 ‘take picture’버튼을 누르면 카메라가 실행되도록 구현 카메라로 촬영한 사진은 ‘knowns’ 폴더에 자동 저장됨
3	드라이브에서 사진 선택 기능	프로그램에서 ‘assign’버튼을 누르고 ‘take image file’ 버튼을 누르면 드라이브에서 사진을 선택할 수 있도록 구현 선택한 사진은 ‘knowns’ 폴더에 복사되서 자동 저장됨

적용 기술

위 기능을 구현하는 데에 사용된 기술 을 상세히 기술

학습(훈련 및 검증)이 있으면 데이터셋 설명을 포함해 해당 사항도 추가

모자이크 시스템

(1) 기능

원하는 사진이나 영상을 드라이브에서 선택하면 자동으로 모자이크 처리

편집된 사진이나 영상은 별도로 저장됨

앞서 3.1에서 미리 제외해놓은 얼굴은 제외하고 모자이크 처리

	구성	기능 구현 방향
1	모자이크 처리 기능	드라이브에서 사진이나 영상파일을 선택하면 자동으로 모자이크 처리를 하도록 구현
2	선택적 모자이크 기능	‘knowns’ 폴더에 미리 지정해놓은 얼굴을 제외하고 모자이크처리를 할 수 있도록 구현
3	편집된 파일 저장 기능	사진	편집된 사진은 ‘result’ 폴더에 별도로 저장되도록 구현
		영상	편집된 영상은 현재 디렉토리에 별도로 저장되도록 구현

적용 기술

위 기술을 구현하는데 사용한 기술을 상세히 기술하시오

학습(훈련 및 검증)이 있으면 데이터셋 설명을 포함해 해당 사항도 추가

사용 절차 및 방법

소프트웨어 동작 로직

2.4 동작 또는 활용 시나리오와 동일

하드웨어 부분이 존재하지 않아서 기본 시나리오와 동일하게 진행됨

버튼 별 기능

	구성		기능 구현 방향
1	aasign	Take picture	프로그램에서 카메라를 실행하여 ‘knowns’ 폴더에 저장 할 이미지를 직접 촬영할 수 있음 사람얼굴이 인식되지않는 사진을 찍을 경우 메시지박스가 뜨면서 ‘knowns’폴더에 사진이 저장되지 않음
		Take image file	knowns 폴더에 저장 할 이미지를 드라이브에 저장된 파일들 중에서 선택할 수 있음 사람얼굴이 인식되지않는 사진을 드라이브에서 선택할 경우 메시지박스가 뜨면서 ‘knowns’폴더에 사진이 저장되지 않음
2	Video Mosaic		드라이브에 저장되어있는 영상파일을 가져와서 모자이크 처리 이때 knowns 폴더에 저장되어 있는 얼굴은 제외하고 모자이크 처리
3	Image Mosaic		드라이브에 저장되어있는 이미지파일을 가져와서 모자이크처리 이때 knowns 폴더에 저장되어 있는 얼굴은 제외하고 모자이크 처리

실제 프로그램 파일 생성

프롬프트를 실행하지않고도 바로 실행할 수 있는 exe 파일 생성

성능 평가

프로그램 실행

(1) 초기 실행 화면

Assign : 제외할 얼굴 이미지 선택

Video Mosaic : 영상 모자이크 실행

Image Mosaic : 사진 모자이크 실행

총 세가지 기능 실행 가능

(2) assign 실행

Take picture : 직접 촬영

Take image file : 드라이브에서 사진 선택

Take picture을 누르면 바로 사진이 촬영된다

하단에 save 버튼을 누르면 ‘knowns’폴더에 사진이 저장된다.

아래와 같이 사람 얼굴 이미지가아닌 사진이 촬영 될 경우 메시지 박스가 뜨면서 저장이 되지 않는다.

사람 얼굴이 인식될 경우에만 사진이 저장됨

Take image file 버튼을 눌러 드라이브에서 얼굴 사진을 선택하면 ‘knowns’폴더에 사진이 저장된다.

얼굴이 인식되지 않는 사진을 선택할 경우 메시지 박스가 뜨면서 저장이 되지 않는다.

사람 얼굴이 인식될 경우에만 선택한 사진이 저장됨

(2) Video Mosaic 실행

드라이브에서 사람 얼굴이 인식되는 영상을 선택하면 모자이크 처리를 한 후 별도로 저장된다.

‘knowns’폴더에 지정한 얼굴은 제외하고 모자이크 처리를 한다.

현재 디렉토리에 별도로 영상이 저장된다.

* 앞서‘knowns’폴더에 넣어두었던 얼굴 이미지를 제외하고 영상을 모자이크 처리함

(3) Image Mosaic 실행

드라이브에서 사람 얼굴이 인식되는 사진을 선택하면 모자이크 처리를 한 후 별도로 저장된다.

‘knowns’폴더에 지정한 얼굴은 제외하고 모자이크 처리를 한다.

‘result’폴더에 사진이 별도로 저장된다.

현재 프로그램의 한계

얼굴을 인식하는 부분에서 정확도가 떨어짐

마스크를 끼고있으면 사람얼굴로 인식하지 못함

편집된 영상이 저장되는 경로 지정 하지 않음

비율이 맞지 않는 영상을 넣을 시 화면이 회전되어 얼굴인식이 제대로 이루어지지 않음

향후 과제

지속적이고 오랜 학습을 통한 얼굴 인식 정확도 개선 필요

모자이크 처리 후 화질 감소되는 부분 개선 필요

<아래 다른 과제 의 향후 과제 내용임 참조해서 좀더 구체적으로 작성>

웹 서버를 구축한 PC 환경을 통해서만 웹에 접속할 수 있는 단점을 포트 포워딩을 통해 보완

이로 인해, 외부 WI-FI 와 데이터(LTE, 5G)를 사용하여 웹 서버(Beauty_Sniper)에 접근 가능

포트 포워딩 - 컴퓨터에서 특정 통신 포트를 개방하여 통신이 되도록 하는 것

추후, 사용한 화장품의 색상이나 형태를 보고 image-classification을 진행해 화장품 정보를 제공한다면 더 좋은 서비스가 될 것으로 판단

개발 참여자 및 역할

성명	역할
정영광	결과보고서 작성 중간보고서 작성 Mosaic S/W 메인 제작
김승현	중간보고서 작성 결과보고서 작성 최종발표영상 제작 Mosaic S/W 보조 제작
박권도	중간보고서 작성 Mosaic S/W 보조 제작

추가 자료

소스코드

import sys
from os import path
import os
import threading
import cv2
import numpy as np
import face_recognition
import dlib
import time
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPixmap
import datetime
from time import sleep

#출력 높이 넓이 설정과 모자이크 비율 설정
OUTPUT_SIZE_WIDTH = 775
OUTPUT_SIZE_HEIGHT = 600
MOSAIC_RATE = 15
BASE_SIZE_WIDTH = 320
BASE_SIZE_HEIGHT = 240

known_face_encodings = []
known_face_names = []
faces_locations = []
face_encodings = []
face_names = {}
startevent = False
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
out = cv2.VideoWriter('output.mp4', fourcc, 25.0, (OUTPUT_SIZE_WIDTH,OUTPUT_SIZE_HEIGHT))
# 디렉토리 생성
def createDirectory(directory):
try:
if not os.path.exists(directory):
os.makedirs(directory)
except OSError:
print("Error: Failed to create the directory.")
dirname = 'knowns'
resultdir = 'result'
createDirectory(dirname)
createDirectory(resultdir)
files = os.listdir(dirname)
# knows디렉토리에 있는 얼굴데이터 인코딩
for filename in files:
name, ext = os.path.splitext(filename)
if ext == '.jpg' or ext == '.png':
known_face_names.append(name)
pathname = os.path.join(dirname, filename)
img = face_recognition.load_image_file(pathname)
face_encoding = face_recognition.face_encodings(img)[0]
known_face_encodings.append(face_encoding)
rectangleColor = (0,165,255)

frameCounter = 0
currentFaceID = 0

faceTrackers = {}
faceNames = {}

# 얼굴 등록 gui구현
class Assign(QDialog):
def __init__(self):
super().__init__()
self.initUI()

def initUI(self):
layout = QtWidgets.QVBoxLayout()
self.take_picture = QtWidgets.QPushButton("take picture")
layout.addWidget(self.take_picture)
self.take_picture.clicked.connect(self.btn1)
self.take_file = QtWidgets.QPushButton("take image file")
layout.addWidget(self.take_file)
self.take_file.clicked.connect(self.btn2)

self.setLayout(layout)

#사진 찍는 버튼
def btn1(self):
dlg = Take_pic()
dlg.exec_()

#다른 경로에서 사진 불러오는 버튼
def btn2(self):
filename = QFileDialog.getOpenFileName()
fname, ext = os.path.splitext(filename[0])
if ext == '.jpg' or ext == '.png':
image = cv2.imread(filename[0])
baseImage = cv2.resize(image, (BASE_SIZE_WIDTH, BASE_SIZE_HEIGHT))
faces = face_recognition.face_locations(baseImage)
if faces:
if filename[0]:
QMessageBox.about(self, "message", "saved")
suffix = datetime.datetime.now().strftime("%y%m%d_%H%M%S")
cv2.imwrite('Knowns/data' + suffix + '.jpg', image)
known_face_names = []
known_face_encodings = []
dirname = 'knowns'
files = os.listdir(dirname)
for filename in files:
name, ext = os.path.splitext(filename)
if ext == '.jpg':
known_face_names.append(name)
pathname = os.path.join(dirname, filename)
img = face_recognition.load_image_file(pathname)
face_encoding = face_recognition.face_encodings(img)[0]
known_face_encodings.append(face_encoding)
else:
QMessageBox.about(self, "message", "unsuitable image, please take frontal face")
else:
QMessageBox.about(self, "message", "not a image file")

class Take_pic(QDialog):
def __init__(self):
super().__init__()
self.title = 'PyQt5 Video'
self.left = 100
self.top = 100
self.width = 640
self.height = 480
self.initUI()
self.image
#사진을 찍고 얼굴인식이 되었으면 저장하는 함수
def save_clicked(self):
QMessageBox.about(self, "message", "saved")
suffix = datetime.datetime.now().strftime("%y%m%d_%H%M%S")
faces= face_recognition.face_locations(self.image)
if faces:
cv2.imwrite('Knowns/data'+suffix+'.jpg' ,self.image)
QMessageBox.about(self, "message", "saved")
known_face_names =[]
known_face_encodings =[]
dirname = 'knowns'
files = os.listdir(dirname)
for filename in files:
name, ext = os.path.splitext(filename)
if ext == '.jpg':
known_face_names.append(name)
pathname = os.path.join(dirname, filename)
img = face_recognition.load_image_file(pathname)
face_encoding = face_recognition.face_encodings(img)[0]
known_face_encodings.append(face_encoding)

#얼굴인식을 못했을 경우 에러 메세지 출력
else :
QMessageBox.about(self, "message", "unsuitable image, please take frontal face")

# 캠을 켜서 사진을 캡쳐
def initUI(self):

self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.resize(640, 500)

layout=QGridLayout()

#create a label
label = QLabel(self)
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
convertToQtFormat = QtGui.QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0],
QtGui.QImage.Format_RGB888)
convertToQtFormat = QtGui.QPixmap.fromImage(convertToQtFormat)
pixmap = QPixmap(convertToQtFormat)
rgbImage=cv2.cvtColor(rgbImage, cv2.COLOR_RGB2BGR)
cv2.resize(rgbImage, dsize =(640, 480))
resizeImage = pixmap.scaled(640, 480, QtCore.Qt.KeepAspectRatio)
QApplication.processEvents()
label.setPixmap(resizeImage)
self.image=rgbImage
#사진 저장하는 함수 호출하여 버튼과 연결
self.save_button = QPushButton("save")
self.save_button.clicked.connect(self.save_clicked)
layout.addWidget(label)
layout.addWidget(self.save_button)
self.setLayout(layout)

#얼굴의 대한 정보 저장하는 함수
def doRecognizePerson(faceNames, fid):
time.sleep(2)
faceNames[ fid ] = "Person " + str(fid)

#동영상을 불러와서 데이터를 읽어오는 클래스
class RecordVideo(QtCore.QObject):
image_data = QtCore.pyqtSignal(np.ndarray)

def __init__(self, camera_port=0, parent=None):
super().__init__(parent)

def start_recording(self):
self.filename = QFileDialog.getOpenFileName()
self.camera = cv2.VideoCapture(self.filename[0])
self.timer = QtCore.QBasicTimer()
self.timer.start(0, self)

def timerEvent(self, event):
if (event.timerId() != self.timer.timerId()):
return

read, data = self.camera.read()
if read:
self.image_data.emit(data)

#얼굴 인식하는 클래스
class FaceDetectionWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.image = QtGui.QImage()

def detect_faces(self, image: np.ndarray):
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray_image = cv2.equalizeHist(gray_image)

faces = self.classifier.detectMultiScale(gray_image,
scaleFactor=1.3,
minNeighbors=4,
flags=cv2.CASCADE_SCALE_IMAGE,
minSize=self._min_size)

return faces
#동영상 모자이크 진행하는 함수
def image_data_slot(self, image_data):
#프레임을 받아와서 resize진행 후 복사
baseImage = cv2.resize( image_data, (BASE_SIZE_WIDTH, BASE_SIZE_HEIGHT))
mosaicImage = baseImage.copy()
global frameCounter
frameCounter += 1

fidsToDelete = []
#얼굴을 찾아 트랙킹진행
for fid in faceTrackers.keys():
trackingQuality = faceTrackers[fid].update(baseImage)

if trackingQuality < 5:
fidsToDelete.append( fid )
for fid in fidsToDelete:
print("Removing fid " + str(fid) + " from list of trackers")
faceTrackers.pop( fid , None)
face_names.pop(fid, None)

if (frameCounter % 5) == 0:
#얼굴의 위치 정보를 읽음
faces = face_recognition.face_locations(baseImage)

for (top, right, bottom, left) in faces:
x = int(left)
y = int(top)
w = int(right - left)
h = int(bottom - top)
#센터 포인트 계산
x_bar = x + 0.5 * w
y_bar = y + 0.5 * h

matchedFid = None

for fid in faceTrackers.keys():
tracked_position =  faceTrackers[fid].get_position()

t_x = int(tracked_position.left())
t_y = int(tracked_position.top())
t_w = int(tracked_position.width())
t_h = int(tracked_position.height())

t_x_bar = t_x + 0.5 * t_w
t_y_bar = t_y + 0.5 * t_h

if ( ( t_x <= x_bar   <= (t_x + t_w)) and
( t_y <= y_bar   <= (t_y + t_h)) and
( x   <= t_x_bar <= (x   + w  )) and
( y   <= t_y_bar <= (y   + h  ))):
matchedFid = fid

global currentFaceID
if matchedFid is None:

print("Creating new tracker " + str(currentFaceID))

tracker = dlib.correlation_tracker()
tracker.start_track(baseImage,
dlib.rectangle( x-10,
y-20,
x+w+10,
y+h+20))

faceTrackers[ currentFaceID ] = tracker
# 페이스 인코딩
face_encodings = face_recognition.face_encodings(baseImage, [(top, right, bottom, left)])
distances = face_recognition.face_distance(known_face_encodings, face_encodings[0])
min_value = min(distances)

name = "Unknown"
#knows에 있는 사람과 얼굴 랜드마크 값을 비교
if min_value < 0.4:
index = np.argmin(distances)
name = known_face_names[index]

face_names[ currentFaceID ] = name

print(face_names)

t = threading.Thread( target = doRecognizePerson ,
args=(faceNames, currentFaceID))
t.start()

# Increase the currentFaceID counter
currentFaceID += 1

for fid in faceTrackers.keys():
tracked_position =  faceTrackers[fid].get_position()

t_x = int(tracked_position.left())
t_y = int(tracked_position.top())
t_w = int(tracked_position.width())
t_h = int(tracked_position.height())

m_x = int(t_x > 0 and t_x or 0)
m_y = int(t_y > 0 and t_y or 0)
m_w = int(t_x + t_w < BASE_SIZE_WIDTH and t_w or BASE_SIZE_WIDTH - t_x)
m_h = int(t_y + t_h < BASE_SIZE_HEIGHT and t_h or BASE_SIZE_HEIGHT - t_y)
#knows파일에 없는 사람일 경우 모자이크 진행
if(face_names[fid] == 'Unknown'):
face_img = mosaicImage[m_y:m_y + m_h, m_x:m_x + m_w]
face_img = cv2.resize(face_img, (m_w //MOSAIC_RATE, m_h//MOSAIC_RATE))
face_img = cv2.resize(face_img, (m_w, m_h), interpolation=cv2.INTER_AREA)
mosaicImage[m_y:m_y + m_h, m_x:m_x + m_w] = face_img

mosaicResult = cv2.resize(mosaicImage,
(OUTPUT_SIZE_WIDTH,OUTPUT_SIZE_HEIGHT))

self.image = self.get_qimage(mosaicResult)
if self.image.size() != self.size():
self.setFixedSize(self.image.size())
#모자이크된 프레임을 영상으로 저장
out.write(mosaicResult)
self.update()
#이미지 색변환하는 함수
def get_qimage(self, image: np.ndarray):
height, width, colors = image.shape
bytesPerLine = 3 * width
QImage = QtGui.QImage

image = QImage(image.data,
width,
height,
bytesPerLine,
QImage.Format_RGB888)

image = image.rgbSwapped()
return image

def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.drawImage(0, 0, self.image)
self.image = QtGui.QImage()

#메인 위젯
class MainWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.face_detection_widget = FaceDetectionWidget()

# TODO: set video port
self.record_video = RecordVideo()

image_data_slot = self.face_detection_widget.image_data_slot
self.record_video.image_data.connect(image_data_slot)
#assign 버튼 위젯 생성
layout = QtWidgets.QVBoxLayout()
self.assign_button = QtWidgets.QPushButton("assign")
layout.addWidget(self.assign_button)
self.assign_button.clicked.connect(self.btn1_clicked)
#Video Mosaic 버튼 위젯 생성
layout.addWidget(self.face_detection_widget)
self.run_button = QtWidgets.QPushButton('Video Mosaic')
layout.addWidget(self.run_button)
#Image Mosaic 버튼 위젯 생성
self.btn = QPushButton("Image Mosaic")
layout.addWidget(self.btn)

self.le = QLabel("")

layout.addWidget(self.le)
self.btn.clicked.connect(self.imgput)

self.run_button.clicked.connect(self.record_video.start_recording)
self.setLayout(layout)

def btn1_clicked(self):
dlg = Assign()
dlg.exec_()
#이미지를 넣었을 때 모자이크하는 함수
def imgput(self):
fname = QFileDialog.getOpenFileName(self, 'Open file',
'.',"Image files (*.jpg *.gif *.png)")
baseImage = face_recognition.load_image_file(fname[0])
path = fname[0].split("/")
print(path[-1])
faces = face_recognition.face_locations(baseImage)
mosaicImage = baseImage.copy()
for (top, right, bottom, left) in faces:
x = int(left)
y = int(top)
w = int(right-left)
h = int(bottom - top)
face_encodings = face_recognition.face_encodings(baseImage, [(top, right, bottom, left)])
distances = face_recognition.face_distance(known_face_encodings, face_encodings[0])
min_value = min(distances)
m_x = int(x > 0 and x or 0)
m_y = int(y > 0 and y or 0)
m_w = int(x + w < BASE_SIZE_WIDTH and w or BASE_SIZE_WIDTH - x)
m_h = int(y + h < BASE_SIZE_HEIGHT and h or BASE_SIZE_HEIGHT - y)
#knows디렉토리에 있는 얼굴의 랜드마크와 비교 후 모자이크 진행
if min_value > 0.4 :
face_img = mosaicImage[y :y+h, x:x+w]
face_img = cv2.resize(face_img, (w//MOSAIC_RATE, h//MOSAIC_RATE))
face_img = cv2.resize(face_img, (w,h), interpolation = cv2.INTER_AREA)
mosaicImage[y:y + h, x:x + w] = face_img
mosaicResult = cv2.resize(mosaicImage,
(OUTPUT_SIZE_WIDTH,OUTPUT_SIZE_HEIGHT))
RGBResult=cv2.cvtColor(mosaicResult, cv2.COLOR_RGB2BGR)
#result파일에 모자이크 된 사진 저장
cv2.imwrite("result/"+path[-1],RGBResult)
QMessageBox.about(self, "message", "Success!")

#메인 위젯 실행
def main():
app = QtWidgets.QApplication(sys.argv)

main_window = QtWidgets.QMainWindow()
main_widget = MainWidget()
main_window.setCentralWidget(main_widget)
main_window.show()
sys.exit(app.exec_())

if __name__ == '__main__':

script_dir = path.dirname(path.realpath(__file__))

main()