layout: single
๋ชฉํ
์ค๋น๋ฌผ
์ค๋น ์ธ๋ถ
ํ์ผ ๋๋ ํ ๋ฆฌ ์์ฑ
$ mkdir -p ~/aiffel/camera_sticker/models$
$ mkdir -p ~/aiffel/camera_sticker/images ln -s ~/data/* ~/aiffel/camera_sticker/images$
pip install opencv-python
โ opencv-python : OpenCV ๋ฉ์ธ ๋ชจ๋
pip install opencv-contrib-python
โ opencv-contrib-python contrib ๋ชจ๋(๋ํฐ ํจํค์ง)
cf.
pip install numpy
โ numpy : ๋ฐ์ดํฐ ๋ถ์ ํ๊ฒฝ์์ ๋ง์ด ์ฌ์ฉ๋๋ ํ๋ ฌ ์ฐ์ฐ์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
pip install matplotlib
โ matplotlib : ๋ํ, ์ฐจํธ, ๊ทธ๋ํ ๋ฑ์ ๊ตฌํํ ์ ์๊ฒ ๋ง๋ ๊ทธ๋ํฝ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์ผ๋จ ๋ชจ๋์ ๋ถ๋ฌ์์ผ ์๋ฌ๊ฐ ์๋๋๊น ใ
import os
import cv2
import matplotlib.pyplot as plt
import numpy as np
import dlib
my_image_path = './camera_sticker/images/image.png'
img_bgr = cv2.imread(my_image_path) # OpenCV๋ก ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ต๋๋ค
img_show = img_bgr.copy() # ์ถ๋ ฅ์ฉ ์ด๋ฏธ์ง๋ฅผ ๋ฐ๋ก ๋ณด๊ดํฉ๋๋ค
plt.imshow(img_bgr) # ์ด๋ฏธ์ง ์ถ๋ ฅํ๊ธฐ
plt.show() # ์ด๊ฑด ์ ์จ์ผํ ๊น์???
ํธ๋ฅธ์๊ฐ์ด ๋๋ ๊ฒ์ opencv์ ํน์ง
matplotlib, dlib ๋ฑ์ RGB์์ผ๋ก ์ฌ์ฉํ๋
opencv๋ ์์ธ์ ์ผ๋ก BGR๋ก ๋ฐ๊พธ์ด ์ฌ์ฉํ์ฌ
๋ถ์์ โ ํธ๋ฅธ์, ํธ๋ฅธ์ โ ๋ถ์์์ผ๋ก ๋ฐ๋์ด ์ถ๋ ฅ
๋ณด์ ์ด ํ์
์ฐธ๊ณ : OpenCV : ์ด๋ฏธ์ง ๋ค๋ฃจ๊ธฐ
# plt.imshow ์ด์ ์ RGB ์ด๋ฏธ์ง๋ก ๋ฐ๊พธ๋ ๊ฒ์ ์์ง๋ง์ธ์.
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.show()
์ฐธ๊ณ .
cv2.imread('img.png', 0) ์์ 0 ์ ์๋ฏธ
๋ฌธ์์ ๋ฐ๋ฅด๋ฉด ์ด๋ฏธ์ง ์ฝ๊ธฐ์ flag๋ ๋ค์ 3๊ฐ์ง๊ฐ ์์ต๋๋ค. ์์๋๋ก 1, 0, -1์ ๊ฐ์ ๊ฐ์ต๋๋ค.
cv2.IMREAD_COLOR : ์ด๋ฏธ์ง ํ์ผ์ Color๋ก ์ฝ์ด๋ค์ ๋๋ค. ํฌ๋ช ํ ๋ถ๋ถ์ ๋ฌด์๋๋ฉฐ, Default๊ฐ์ ๋๋ค.
cv2.IMREAD_GRAYSCALE : ์ด๋ฏธ์ง๋ฅผ Grayscale๋ก ์ฝ์ด ๋ค์ ๋๋ค. ์ค์ ์ด๋ฏธ์ง ์ฒ๋ฆฌ์ ์ค๊ฐ๋จ๊ณ๋ก ๋ง์ด ์ฌ์ฉํฉ๋๋ค.
cv2.IMREAD_UNCHANGED : ์ด๋ฏธ์งํ์ผ์ alpha channel๊น์ง ํฌํจํ์ฌ ์ฝ์ด ๋ค์ ๋๋ค.
cv2.imread('img.png', 0)์ด๋ผ๊ณ ํธ์ถํ๋ค๋ฉด ์ด๋ฏธ์ง๋ฅผ Grayscale๋ก ์ฝ์ด ๋ค์ด๊ฒ ๋ค๋ ๋ป
dlib์ face detector๋ HOG(Histogram of Oriented Gradients)์ SVM(Support Vector Machine)์ ์ฌ์ฉ
HOG๋ ์ด๋ฏธ์ง์์ ์์์ ๋ณํ๋
โ ์ด๋ฏธ์ง๋ก๋ถํฐ ๋ฌผ์ฒด์ ํน์ง์ ์ ์ก์๋ธ๋ค.
2000๋ ๋ ์ด๋ฐ ๋ง์ด ์ฌ์ฉ(์ผ๊ตด ์ด์ ์ก๋ ์ฉ๋)
โ HOG๋ฅผ ์๊ฐํํ ์ด๋ฏธ์ง
SVM ์ ํ ๋ถ๋ฅ๊ธฐ
์ผ๊ตด์ ์์น๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ
# detector๋ฅผ ์ ์ธํฉ๋๋ค
import dlib
detector_hog = dlib.get_frontal_face_detector()
print("๐ซ๐ธ")
๐ซ๐ธ
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
dlib_rects = detector_hog(img_rgb, 1) # (image, num of image pyramid)
print("๐ซ๐ธ")
๐ซ๐ธ
dlib์ rgb ์ด๋ฏธ์ง๋ฅผ ์ ๋ ฅ์ผ๋ก ๋ฐ๊ธฐ ๋๋ฌธ์
cvtColor() ๋ฅผ ์ด์ฉํด์
opencv ์ bgr ์ด๋ฏธ์ง๋ฅผ rgb๋ก ๋ณํ
<# ์ฐพ๋ ์ผ๊ตด์ ํ๋ฉด์ ์ถ๋ ฅ
# ์ฐพ์ ์ผ๊ตด ์์ญ ๋ฐ์ค ๋ฆฌ์คํธ
# ์ฌ๋ฌ ์ผ๊ตด์ด ์์ ์ ์์ต๋๋ค
print(dlib_rects)
for dlib_rect in dlib_rects:
l = dlib_rect.left()
t = dlib_rect.top()
r = dlib_rect.right()
b = dlib_rect.bottom()
cv2.rectangle(img_show, (l,t), (r,b), (0,255,0), 2, lineType=cv2.LINE_AA)
img_show_rgb = cv2.cvtColor(img_show, cv2.COLOR_BGR2RGB)
plt.imshow(img_show_rgb)
plt.show()
rectangles[[(485, 1252) (1635, 2403)]]
dlib detector ๋
dlib.rectangles ๋
dlib.rectangle๊ฐ์ฒด๋
์ฐธ๊ณ : dlib.rectangles
- ์ด๋ชฉ๊ตฌ๋น์ ์์น๋ฅผ ์๋ ๊ฒ์ด ์ค์
- ์ด๋ชฉ๊ตฌ๋น์ ์์น๋ฅผ ์ถ๋ก ํ๋ ๊ฒ์ face landmark localization ๊ธฐ์
- face landmark
- detection ์ ๊ฒฐ๊ณผ๋ฌผ์ธ bounding box ๋ก ์๋ผ๋ธ(crop) ์ผ๊ตด ์ด๋ฏธ์ง๋ฅผ ์ด์ฉ
์ด ์ ์ ๊ฐ์๋ ๋ฐ์ดํฐ์ ๊ณผ ๋ ผ๋ฌธ๋ง๋ค ๋ค๋ฆ
์ฐธ๊ณ : AFLW dataset
wget http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
mv shape_predictor_68_face_landmarks.dat.bz2 ~/aiffel/camera_sticker/models
cd ~/aiffel/camera_sticker && bzip2 -d ./models/shape_predictor_68_face_landmarks.dat.bz2
์ ์ฅํ landmark ๋ชจ๋ธ์ ๋ถ๋ฌ์ค๊ธฐ.
import os, dlib
model_path = os.getenv('HOME')+'/aiffel/camera_sticker/models/shape_predictor_68_face_landmarks.dat'
landmark_predictor = dlib.shape_predictor(model_path)
print("๋ถ๋ฌ์ค๊ธฐ ์๋ฃ")
๋ถ๋ฌ์ค๊ธฐ ์๋ฃ
landmark_predictor ๋ RGB ์ด๋ฏธ์ง์ dlib.rectangle์ ์ ๋ ฅ ๋ฐ์ dlib.full_object_detection ๋ฅผ ๋ฐํ
list_landmarks = []
# ์ผ๊ตด ์์ญ ๋ฐ์ค ๋ง๋ค face landmark๋ฅผ ์ฐพ์๋
๋๋ค
for dlib_rect in dlib_rects:
points = landmark_predictor(img_rgb, dlib_rect)
# face landmark ์ขํ๋ฅผ ์ ์ฅํด๋ก๋๋ค
list_points = list(map(lambda p: (p.x, p.y), points.parts()))
list_landmarks.append(list_points)
print(len(list_landmarks[0]))
68
points ๋ dlib.full_object_detection ์ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ parts() ํจ์๋ก ๊ฐ๋ณ ์์น์ ์ ๊ทผํ ์ ์์ต๋๋ค. ์กฐ๊ธ ๋ ์ง๊ด์ ์ธ (x, y) ํํ๋ก ์ ๊ทผํ ์ ์๋๋ก ๋ณํํด ์ฃผ์์ต๋๋ค. ๋ฐ๋ผ์ list_points ๋ tuple (x, y) 68๊ฐ๋ก ์ด๋ฃจ์ด์ง ๋ฆฌ์คํธ๊ฐ ๋ฉ๋๋ค. ์ด๋ฏธ์ง์์ ์ฐพ์์ง ์ผ๊ตด ๊ฐ์๋ง๋ค ๋ฐ๋ณตํ๋ฉด list_landmark์ 68๊ฐ์ ๋๋๋งํฌ๊ฐ ์ผ๊ตด ๊ฐ์๋งํผ ์ ์ฅ
for landmark in list_landmarks:
for point in landmark:
cv2.circle(img_show, point, 10, (0, 255, 255), -1)
img_show_rgb = cv2.cvtColor(img_show, cv2.COLOR_BGR2RGB)
plt.imshow(img_show_rgb)
plt.show()
๋๋๋งํฌ๋ฅผ ๊ธฐ์ค์ผ๋ก '๋์น ์ ์ผ๊ตด ์ค์' ์ ์คํฐ์ปค๋ฅผ ์์ฐ๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๊ตฌํ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ต๋๋ค. ์ ๊ทธ๋ฆผ์ฒ๋ผ ์ฝ ์ค์ฌ์ ๊ธฐ์ค์ผ๋ก ๋์ด x ์ด์์ ๊ทธ๋ ค๋ ๋๊ณ ๋์น ์ n ํฝ์ ์์ ์คํฐ์ปค๋ฅผ ๊ตฌํ
์ค์ํ ๊ฒ์ ์ผ๊ตด ์์น, ์นด๋ฉ๋ผ์ ๊ฑฐ๋ฆฌ์ ๋ฐ๋ผ ํฝ์ x ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋น์จ๋ก ๊ณ์ฐ์ ํด์ค์ผ ํฉ๋๋ค. ๊ณ์ฐํ ์์น๋ ๋ ๊ฐ์ง
for dlib_rect, landmark in zip(dlib_rects, list_landmarks):
print (landmark[30]) # ์ฝ์ index๋ 30 ์
๋๋ค
x = landmark[30][0]
y = landmark[30][1] - dlib_rect.height()//2
w = h = dlib_rect.width()
print ('(x,y) : (%d,%d)'%(x,y))
print ('(w,h) : (%d,%d)'%(w,h))
(984, 1899)
(x,y) : (984,1323)
(w,h) : (1151,1151)
์ค๋นํด๋ ์คํฐ์ปค ์ด๋ฏธ์ง๋ฅผ ์ฝ์ด์ ์ ์ฉ.
sticker_path = './camera_sticker/images/king.png'
img_sticker = cv2.imread(sticker_path) # ์คํฐ์ปค ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ต๋๋ค
img_sticker = cv2.resize(img_sticker, (w,h))
print (img_sticker.shape)
(1151, 1151, 3)
์๊ด ์ด๋ฏธ์ง๋ฅผ ์ฝ๊ณ ์๋จ๊ณ์์ ๊ณ์ฐํ ํฌ๊ธฐ๋ก resize
์๋ณธ ์ด๋ฏธ์ง์ ์คํฐ์ปค ์ด๋ฏธ์ง๋ฅผ ์ถ๊ฐํ์ ์ํด์ x,y์ขํ ์กฐ์
์ด๋ฏธ์ง ์์์ ์ top-left ์ขํ
refined_x = x - w // 2
refined_y = y - h
print ('(x,y) : (%d,%d)'%(refined_x, refined_y))
(x,y) : (409,172)
# ๊ฒฐ๊ณผ๊ฐ์ด ์์๊ฐ ๊ณ์ฐ
# ์คํฐ์ปค์ ์์์ ์ด ์ผ๊ตด ์ฌ์ง์ ์์ญ์ ๋ฒ์ด๋๋ฉด ์์๋ก ํํ
# opencv ๋ฐ์ดํฐ๋ numpy ndarray ํํ์ ๋ฐ์ดํฐ ์ฌ์ฉ
# ndarray๋ ์์ ์ธ๋ฑ์ค ์ ๊ทผ ๋ถ๊ฐ
# ์๋ณธ ์ด๋ฏธ์ง์ ๋ฒ์๋ฅผ ๋ฒ์ด๋ ์คํฐ์ปค ๋ถ๋ถ์ ์ ๊ฑฐ ํ์
์คํฐ์ปค์ ์์์ + ์คํฐ์ปค ์ฌ์ง์ ํฌ๊ธฐ๊ฐ ์๋ณธ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ณด๋ค ํฐ ๊ฒฝ์ฐ์ ๋๋ค. ์คํฐ์ปค ์ฌ์ง์ ์ค๋ฅธ์ชฝ์ด๋ ์๋์ชฝ์ผ๋ก ๋์ด๊ฐ๋ ๊ฒฝ์ฐ์ฃ . ์ด ๊ฒฝ์ฐ๋ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊น.
if refined_x < 0:
img_sticker = img_sticker[:, -refined_x:]
refined_x = 0
if refined_y < 0:
img_sticker = img_sticker[-refined_y:, :]
refined_y = 0
print ('(x,y) : (%d,%d)'%(refined_x, refined_y))
(x,y) : (409,172)
-y ํฌ๊ธฐ๋งํผ ์คํฐ์ปค๋ฅผ cropํ๊ณ top์ x,y ์ขํ๋ฅผ ๊ฐ๊ฐ์ ๊ฒฝ์ฐ์ ๋ง์ถฐ ์๋ณธ ์ด๋ฏธ์ง์ ๊ฒฝ๊ณ๊ฐ์ผ๋ก ์์
# ์๋ณธ ์ด๋ฏธ์ง์ ์คํฐ์ปค ์ ์ฉ
# ๊ธธ์ด์ ๋ณต์กํด ๋ณด์ด์ง๋ง img_show[from:to] ํ์์
๋๋ค
sticker_area = img_show[refined_y:refined_y+img_sticker.shape[0], refined_x:refined_x+img_sticker.shape[1]]
img_show[refined_y:refined_y+img_sticker.shape[0], refined_x:refined_x+img_sticker.shape[1]] = \
np.where(img_sticker==0,sticker_area,img_sticker).astype(np.uint8)
print("์~")
์~
sticker_area๋ ์๋ณธ์ด๋ฏธ์ง์์ ์คํฐ์ปค๋ฅผ ์ ์ฉํ ์์น๋ฅผ cropํ ์ด๋ฏธ์ง ์ ๋๋ค. ์์ ์์๋ (344,0) ๋ถํฐ (344+187, 0+89) ๋ฒ์์ ์ด๋ฏธ์ง๋ฅผ ์๋ฏธํฉ๋๋ค.
์คํฐ์ปค ์ด๋ฏธ์ง์์ ์ฌ์ฉํ ๋ถ๋ถ์ 0 ์ด ์๋ ์์ด ์๋ ๋ถ๋ถ์ ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ผ์ np.where๋ฅผ ํตํด img_sticker ๊ฐ 0 ์ธ ๋ถ๋ถ์ sticker_area๋ฅผ ์ฌ์ฉํ๊ณ 0์ด ์๋ ๋ถ๋ถ์ img_sticker๋ฅผ ์ฌ์ฉํ์๋ฉด ๋ฉ๋๋ค. img_show ์ ๋ค์ ์ ์ฉ
# ๊ฒฐ๊ณผ ์ด๋ฏธ์ง๋ฅผ ์ถ๋ ฅํ๋ฉด
plt.imshow(cv2.cvtColor(img_show, cv2.COLOR_BGR2RGB))
plt.show()
bounding box์ landmark๋ฅผ ์ ๊ฑฐํ๊ณ ์ต์ข ๊ฒฐ๊ณผ๋ง ์ถ๋ ฅํด ๋ด ์๋ค. img_show ๋์ , ์ง๊ธ๊น์ง ์๊ปด ๋์๋ img_rgb๋ฅผ ํ์ฉ
sticker_area = img_bgr[refined_y:refined_y +img_sticker.shape[0], refined_x:refined_x+img_sticker.shape[1]]
img_bgr[refined_y:refined_y +img_sticker.shape[0], refined_x:refined_x+img_sticker.shape[1]] = \
np.where(img_sticker==0,sticker_area,img_sticker).astype(np.uint8)
plt.imshow(cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB))
plt.show()