"얼굴추적"의 두 판 사이의 차이
둘러보기로 가기
검색하러 가기
(→준비) |
|||
4번째 줄: | 4번째 줄: | ||
단순히 찾는 것 뿐이라면 cv2만으로도 가능하지만, 매끄럽게 처리하려면 dlib이 있어야 좋다. | 단순히 찾는 것 뿐이라면 cv2만으로도 가능하지만, 매끄럽게 처리하려면 dlib이 있어야 좋다. | ||
− | + | = 방법 = | |
− | === | + | == 준비 == |
+ | |||
+ | === 공통과정 === | ||
+ | 아래에 이어질 모든 과정 이전에 사용될 준비과정을 여기에 담는다. | ||
{| class="wikitable" | {| class="wikitable" | ||
!과정 | !과정 | ||
15번째 줄: | 18번째 줄: | ||
|- | |- | ||
|사용할 모듈 설치 및 불러오기 | |사용할 모듈 설치 및 불러오기 | ||
− | |pip install | + | |pip install cmake dlib opencv-python numpy |
* 윈도우에선 visual studio 설치가 선행되어야 한다.(설치 옵션에서 C++ 모듈을 포함하게 하면 관련 컴파일러 등이 함께 설치된다.) | * 윈도우에선 visual studio 설치가 선행되어야 한다.(설치 옵션에서 C++ 모듈을 포함하게 하면 관련 컴파일러 등이 함께 설치된다.) | ||
− | + | * cmake는 dlib를 설치하기 위해 필요하다. | |
− | cmake는 dlib를 설치하기 위해 필요하다.<syntaxhighlight lang="python"> | + | <syntaxhighlight lang="python"> |
import dlib # 얼굴인식 | import dlib # 얼굴인식 | ||
import cv2 # 이미지처리 | import cv2 # 이미지처리 | ||
30번째 줄: | 33번째 줄: | ||
|- | |- | ||
|모델객체 생성 | |모델객체 생성 | ||
− | |<syntaxhighlight lang="python"> | + | |이미 학습된 bat파일을 불러오는데, 이는 [https://github.com/davisking/dlib-models/blob/master/shape_predictor_68_face_landmarks.dat.bz2 링크]에서 다운받을 수 있다.<syntaxhighlight lang="python"> |
detector = dlib.get_frontal_face_detector() # 얼굴탐지모델 | detector = dlib.get_frontal_face_detector() # 얼굴탐지모델 | ||
− | predictor = dlib.shape_predictor(' | + | predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') # 얼굴 랜드마크 탐지 모델. 학습된 모델을 가져온다. |
− | + | cap = cv2.VideoCapture(0) # 영상 캡쳐. 경로 대신 0을 넣으면 웹캠이 켜진다. | |
</syntaxhighlight> | </syntaxhighlight> | ||
|} | |} | ||
− | + | == 얼굴 찾기 == | |
− | <syntaxhighlight lang="python"> | + | 얼굴을 찾아 네모칸으로 표시한다.(필요에 따라 변형하여 사용하면 될듯.) |
− | + | {| class="wikitable" | |
− | + | !과정 | |
− | + | !코드 및 설명 | |
− | def find_face( | + | |- |
− | + | |함수 정의 | |
− | + | |코드를 파편화 하기 위해 함수를 정의하여 사용한다.<syntaxhighlight lang="python"> | |
− | + | def find_face(img): | |
+ | '''이미지를 받아 해당 얼굴을 찾는다.''' | ||
faces = detector(img) # 디텍터에 이미지를 넣어주어 얼굴을 찾는다. | faces = detector(img) # 디텍터에 이미지를 넣어주어 얼굴을 찾는다. | ||
− | face = faces[0] # 인식된 얼굴 중 첫번째. | + | try: |
− | + | face = faces[0] # 인식된 얼굴 중 첫번째. | |
− | + | # 인식이 잘 되었는지 확인. 네모 그리기. 기존 이미지에 덧씌워 보여준다. | |
− | + | img = cv2.rectangle(img, pt1=(face.left(), face.top()), pt2=(face.right(), face.bottom()), | |
− | + | color=(255, 255, 255), # 색 지정이 가능하다. | |
− | + | thickness=2, # 두께지정 | |
− | + | lineType=cv2.LINE_AA # 선의 타입 지정 | |
− | + | ) | |
− | + | except: # 얼굴이 없으면 faces[0]에서 인덱스 에러가 뜬다. 그럴 땐 그냥 패스! | |
− | + | pass | |
− | + | cv2.imshow('window', img) # 창에 해당하는 이미지를 띄운다. | |
− | |||
− | |||
− | cv2.imshow(' | ||
cv2.waitKey(1) # 1ms만큼 대기 해야 창이 제대로 열린다. | cv2.waitKey(1) # 1ms만큼 대기 해야 창이 제대로 열린다. | ||
− | + | </syntaxhighlight> | |
− | + | |- | |
− | + | |실행 | |
− | + | |다음과 같이 실행한다.<syntaxhighlight lang="python"> | |
while True: # 기본적으로 계속 진행 | while True: # 기본적으로 계속 진행 | ||
− | find_face( | + | ret, img = cap.read() # 캡처한 영상을 프레임 단위로 읽는다. |
+ | if not ret: # 잘 찍히면 ret은 True를 반환한다. | ||
+ | break # 프레임이 없다면 종료. | ||
+ | find_face(img) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |} | ||
− | + | == 얼굴 특징점 찾기 == | |
− | + | 위에서 함수만 바꾸어주면 얼굴의 특징점을 찾아준다.<syntaxhighlight lang="python"> | |
− | def find_shape(img | + | def find_shape(img): |
− | dlib_shape = predictor(img, face) # 특징점을 리턴받는다. | + | '''이미지를 받아 얼굴의 특징점을 찾는다.''' |
− | + | faces = detector(img) # 디텍터에 이미지를 넣어주어 얼굴을 찾는다. | |
− | + | try: | |
− | + | face = faces[0] # 인식된 얼굴 중 첫번째. | |
− | + | dlib_shape = predictor(img, face) # 특징점을 리턴받는다. | |
+ | shape_2d = np.array([[p.x, p.y] for p in dlib_shape.parts()]) # 연산을 위해 배열로 저장. | ||
+ | for s in shape_2d: # 해당 좌표에 원 그리기. 68개의 특징점을 찾는다. | ||
+ | cv2.circle(img, center=tuple(s), radius=1, color=(255, 255, 255), thickness=2, lineType=cv2.LINE_AA) | ||
+ | except: | ||
+ | pass | ||
+ | cv2.imshow('window', img) # 창에 해당하는 이미지를 띄운다. | ||
+ | cv2.waitKey(1) # 1ms만큼 대기 해야 창이 제대로 열린다. | ||
+ | </syntaxhighlight>앞으로의 목표는 많은 얼굴에 대해서도 찾는 것... | ||
+ | |||
+ | == 얼굴을 특정 이미지로 가리기 == | ||
+ | {| class="wikitable" | ||
+ | !과정 | ||
+ | !코드 및 설명 | ||
+ | |- | ||
+ | |함수 정의 | ||
+ | |코드를 파편화 하기 위해 함수를 정의하여 사용한다.<syntaxhighlight lang="python"> | ||
+ | def blind_face(img, address='test_image.png'): | ||
+ | '''1. 이미지를 받아 얼굴의 중심점을 찾는다. 2. 그 지점에 이미지를 불러온다.''' | ||
+ | faces = detector(img) # 디텍터에 이미지를 넣어주어 얼굴을 찾는다. | ||
+ | try: | ||
+ | face = faces[0] # 인식된 얼굴 중 첫번째. | ||
+ | dlib_shape = predictor(img, face) # 특징점을 리턴받는다. | ||
+ | shape_2d = np.array([[p.x, p.y] for p in dlib_shape.parts()]) # 연산을 위해 배열로 저장. | ||
+ | center_x, center_y = np.mean(shape_2d, axis=0).astype(np.int) # 중심점을 찾는다. | ||
+ | overlay = cv2.imread(address, cv2.IMREAD_UNCHANGED) # 이미지를 불러온다. 알파채널까지 읽기 위한 옵션. | ||
+ | # 얼굴 경계 찾기. | ||
+ | min_coords = np.min(shape_2d, axis=0) # 각 열에 대해 가장 작은 값들. | ||
+ | max_coords = np.max(shape_2d, axis=0) | ||
+ | face_size = max(max_coords - min_coords) | ||
+ | # 덮을 이미지가 얼굴 인식에 따라 급격하게 변하기 때문에, 이를 중화하기 위한 코드. | ||
+ | face_sizes.append(face_size) | ||
+ | if len(face_sizes) > 10: | ||
+ | del face_sizes[0] | ||
+ | mean_face_size = int(np.mean(face_sizes) * 2.0) # 얼굴을 적절히 덮기 위한 숫자보정. | ||
+ | origin_image = img.copy() | ||
+ | # 다음 사용하는 함수는 아랫쪽에 정의되어 있다. | ||
+ | result = overlay_transparent(x=center_x, y=center_y - 25, # 얼굴의 중심을 찾고 숫자로 보정해준다. | ||
+ | background_img=origin_image, # 기존 이미지. | ||
+ | img_to_overlay_t=overlay, # 덮을 이미지. | ||
+ | overlay_size=(mean_face_size, mean_face_size)) | ||
+ | cv2.imshow('window', result) # 창에 해당하는 이미지를 띄운다. | ||
+ | except: | ||
+ | cv2.imshow('window', img) # 얼굴 인식이 안되면 이미지를 그냥 띄우기 | ||
+ | pass | ||
+ | cv2.waitKey(1) # 1ms만큼 대기 해야 창이 제대로 열린다. | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | |- | |
− | + | |이미지로 덮기 | |
− | <syntaxhighlight lang="python"> | + | |위에서 사용하는, 이미지로 덮는 함수는 다음과 같다.<syntaxhighlight lang="python"> |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
def overlay_transparent(background_img, img_to_overlay_t, x, y, overlay_size=None): | def overlay_transparent(background_img, img_to_overlay_t, x, y, overlay_size=None): | ||
bg_img = background_img.copy() | bg_img = background_img.copy() | ||
129번째 줄: | 158번째 줄: | ||
return bg_img | return bg_img | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |- | ||
+ | |실행 | ||
+ | |맨 위의 과정에서 face_size들을 담는 리스트가 추가된다.<syntaxhighlight lang="python"> | ||
+ | while True: # 기본적으로 계속 진행 | ||
+ | ret, img = cap.read() # 캡처한 영상을 프레임 단위로 읽는다. | ||
+ | if not ret: # 잘 찍히면 ret은 True를 반환한다. | ||
+ | break # 프레임이 없다면 종료. | ||
+ | face_sizes = [] # 얼굴 크기를 자연스럽게 변형하기 위한 리스트. | ||
+ | blind_face(img) | ||
+ | </syntaxhighlight> | ||
+ | |} | ||
[[분류:딥러닝 트래킹]] | [[분류:딥러닝 트래킹]] |
2021년 9월 25일 (토) 23:09 판
1 개요
주 방법은 링크, 링크(얼굴인식 스노우 카메라 따라만들기)를 참고하였습니다.
단순히 찾는 것 뿐이라면 cv2만으로도 가능하지만, 매끄럽게 처리하려면 dlib이 있어야 좋다.
2 방법
2.1 준비
2.1.1 공통과정
아래에 이어질 모든 과정 이전에 사용될 준비과정을 여기에 담는다.
과정 | 코드 및 설명 |
---|---|
model 디렉터리에 모델 준비하기 | 이후 이 디렉터리 안의 모델을 사용한다. |
사용할 모듈 설치 및 불러오기 | pip install cmake dlib opencv-python numpy
import dlib # 얼굴인식
import cv2 # 이미지처리
import numpy as np # 연산
|
과정 | 코드 및 설명 |
---|---|
모델객체 생성 | 이미 학습된 bat파일을 불러오는데, 이는 링크에서 다운받을 수 있다.detector = dlib.get_frontal_face_detector() # 얼굴탐지모델
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') # 얼굴 랜드마크 탐지 모델. 학습된 모델을 가져온다.
cap = cv2.VideoCapture(0) # 영상 캡쳐. 경로 대신 0을 넣으면 웹캠이 켜진다.
|
2.2 얼굴 찾기
얼굴을 찾아 네모칸으로 표시한다.(필요에 따라 변형하여 사용하면 될듯.)
과정 | 코드 및 설명 |
---|---|
함수 정의 | 코드를 파편화 하기 위해 함수를 정의하여 사용한다.def find_face(img):
'''이미지를 받아 해당 얼굴을 찾는다.'''
faces = detector(img) # 디텍터에 이미지를 넣어주어 얼굴을 찾는다.
try:
face = faces[0] # 인식된 얼굴 중 첫번째.
# 인식이 잘 되었는지 확인. 네모 그리기. 기존 이미지에 덧씌워 보여준다.
img = cv2.rectangle(img, pt1=(face.left(), face.top()), pt2=(face.right(), face.bottom()),
color=(255, 255, 255), # 색 지정이 가능하다.
thickness=2, # 두께지정
lineType=cv2.LINE_AA # 선의 타입 지정
)
except: # 얼굴이 없으면 faces[0]에서 인덱스 에러가 뜬다. 그럴 땐 그냥 패스!
pass
cv2.imshow('window', img) # 창에 해당하는 이미지를 띄운다.
cv2.waitKey(1) # 1ms만큼 대기 해야 창이 제대로 열린다.
|
실행 | 다음과 같이 실행한다.while True: # 기본적으로 계속 진행
ret, img = cap.read() # 캡처한 영상을 프레임 단위로 읽는다.
if not ret: # 잘 찍히면 ret은 True를 반환한다.
break # 프레임이 없다면 종료.
find_face(img)
|
2.3 얼굴 특징점 찾기
위에서 함수만 바꾸어주면 얼굴의 특징점을 찾아준다.
def find_shape(img):
'''이미지를 받아 얼굴의 특징점을 찾는다.'''
faces = detector(img) # 디텍터에 이미지를 넣어주어 얼굴을 찾는다.
try:
face = faces[0] # 인식된 얼굴 중 첫번째.
dlib_shape = predictor(img, face) # 특징점을 리턴받는다.
shape_2d = np.array([[p.x, p.y] for p in dlib_shape.parts()]) # 연산을 위해 배열로 저장.
for s in shape_2d: # 해당 좌표에 원 그리기. 68개의 특징점을 찾는다.
cv2.circle(img, center=tuple(s), radius=1, color=(255, 255, 255), thickness=2, lineType=cv2.LINE_AA)
except:
pass
cv2.imshow('window', img) # 창에 해당하는 이미지를 띄운다.
cv2.waitKey(1) # 1ms만큼 대기 해야 창이 제대로 열린다.
앞으로의 목표는 많은 얼굴에 대해서도 찾는 것...
2.4 얼굴을 특정 이미지로 가리기
과정 | 코드 및 설명 |
---|---|
함수 정의 | 코드를 파편화 하기 위해 함수를 정의하여 사용한다.def blind_face(img, address='test_image.png'):
'''1. 이미지를 받아 얼굴의 중심점을 찾는다. 2. 그 지점에 이미지를 불러온다.'''
faces = detector(img) # 디텍터에 이미지를 넣어주어 얼굴을 찾는다.
try:
face = faces[0] # 인식된 얼굴 중 첫번째.
dlib_shape = predictor(img, face) # 특징점을 리턴받는다.
shape_2d = np.array([[p.x, p.y] for p in dlib_shape.parts()]) # 연산을 위해 배열로 저장.
center_x, center_y = np.mean(shape_2d, axis=0).astype(np.int) # 중심점을 찾는다.
overlay = cv2.imread(address, cv2.IMREAD_UNCHANGED) # 이미지를 불러온다. 알파채널까지 읽기 위한 옵션.
# 얼굴 경계 찾기.
min_coords = np.min(shape_2d, axis=0) # 각 열에 대해 가장 작은 값들.
max_coords = np.max(shape_2d, axis=0)
face_size = max(max_coords - min_coords)
# 덮을 이미지가 얼굴 인식에 따라 급격하게 변하기 때문에, 이를 중화하기 위한 코드.
face_sizes.append(face_size)
if len(face_sizes) > 10:
del face_sizes[0]
mean_face_size = int(np.mean(face_sizes) * 2.0) # 얼굴을 적절히 덮기 위한 숫자보정.
origin_image = img.copy()
# 다음 사용하는 함수는 아랫쪽에 정의되어 있다.
result = overlay_transparent(x=center_x, y=center_y - 25, # 얼굴의 중심을 찾고 숫자로 보정해준다.
background_img=origin_image, # 기존 이미지.
img_to_overlay_t=overlay, # 덮을 이미지.
overlay_size=(mean_face_size, mean_face_size))
cv2.imshow('window', result) # 창에 해당하는 이미지를 띄운다.
except:
cv2.imshow('window', img) # 얼굴 인식이 안되면 이미지를 그냥 띄우기
pass
cv2.waitKey(1) # 1ms만큼 대기 해야 창이 제대로 열린다.
|
이미지로 덮기 | 위에서 사용하는, 이미지로 덮는 함수는 다음과 같다.def overlay_transparent(background_img, img_to_overlay_t, x, y, overlay_size=None):
bg_img = background_img.copy()
# convert 3 channels to 4 channels
if bg_img.shape[2] == 3:
bg_img = cv2.cvtColor(bg_img, cv2.COLOR_BGR2BGRA)
if overlay_size is not None:
img_to_overlay_t = cv2.resize(img_to_overlay_t.copy(), overlay_size)
b, g, r, a = cv2.split(img_to_overlay_t)
mask = cv2.medianBlur(a, 5)
h, w, _ = img_to_overlay_t.shape
roi = bg_img[int(y-h/2):int(y+h/2), int(x-w/2):int(x+w/2)]
img1_bg = cv2.bitwise_and(roi.copy(), roi.copy(), mask=cv2.bitwise_not(mask))
img2_fg = cv2.bitwise_and(img_to_overlay_t, img_to_overlay_t, mask=mask)
bg_img[int(y-h/2):int(y+h/2), int(x-w/2):int(x+w/2)] = cv2.add(img1_bg, img2_fg)
# convert 4 channels to 4 channels
bg_img = cv2.cvtColor(bg_img, cv2.COLOR_BGRA2BGR)
return bg_img
|
실행 | 맨 위의 과정에서 face_size들을 담는 리스트가 추가된다.while True: # 기본적으로 계속 진행
ret, img = cap.read() # 캡처한 영상을 프레임 단위로 읽는다.
if not ret: # 잘 찍히면 ret은 True를 반환한다.
break # 프레임이 없다면 종료.
face_sizes = [] # 얼굴 크기를 자연스럽게 변형하기 위한 리스트.
blind_face(img)
|