쓸데없이 너무 오래 끌었다. 쉬는날이 너무 많았다. 원하는 기능을 다 성공하지 못했다.
웹캠을 통해 이미지 합성하기
옷의 윤곽선 따라 이미지 저장하기
좋지 않은 조명 환경에 의한 실패
조명 환경이 좋지 않아 실시간으로 옷을 파악할 수 없어, 인터넷에서 깔끔한 조명아래의 옷들을 서칭했다. 그 결과 빠른 결과를 얻어낼 수 있었고, 처음 의도했던 "옷을 사기 전, 옷들의 조합이 어울릴까 혹은 나와 어울릴까"를 알아내기 위함에는 변화가 없다고 판단하여 진행하였다.
지금까지 크게 step3 으로 구성하여 해왔던 공부와 코딩들을 바탕으로 하나의 프로그램으로 완성시켜야했다. 사용자를 위한 입력창들을 추가하여 다듬기 시작했다.
크게 4가지로 나눴다.
import cv2 as cv
import numpy as np
from PIL import Image
print("START")
print("옷을 입힐 대상을 불러오세요. ")
print("1. 사진으로 불러오기")
print("2. 카메라를 통해 사진찍기")
print("3. 카메라로 실시간 인식하기")
Input = input()
if Input == "1":
print("파일명을 입력해주세요!")
model_img = input()
i = Image.open(model_img)
X, Y = i.size
print(X,Y)
elif Input == "2":
print("스페이스바를 눌러 캡쳐해주세요!")
cam = cv.VideoCapture(0)
cv.namedWindow("capture")
while True:
ret, frame = cam.read()
cv.imshow("capture", frame)
if not ret:
break
k = cv.waitKey(1)
if k%256 == 27:
print("Closing")
break
elif k%256 == 32:
img_name = "model_cap.png"
cv.imwrite(img_name, frame)
print("{} written!".format(img_name))
cam.release()
cv.destroyAllWindows()
#else:
총세가지 경우로 인물사진을 불러오도록 하였으며, 사진으로 불러오기 / 카메라를 통해 사진찍기/ 카메라로 실시간 인식하기 가 있다.
앞서 이야기 했듯 노트북 웹캠으로는 한계가 있어 첫번째 경우인 사진으로 불러오기 만을 이용하여 진행하였다. 두번째 경우인 카메라를 통해 사진찍기까지 구현하였다.
사진으로 불러오기를 선택하게되면 파일명을 입력하도록 하고, 그 파일의 사이즈를 X,Y로 저장한다.
카메라를 통해 사진찍기 혹은 구현하지 않은 카메라로 실시간 인식하기를 선택하면, cam = cv.VideoCapture(0)
을 통해 웹캠을 불러온다. 그리고 스페이스바를 눌러 화면을 캡쳐하여 저장하도록 한다.
def nothing(x):
pass
print("옷의 이미지를 불러오세요. ")
clothes_img = input()
cv.namedWindow('binary')
cv.createTrackbar('threshold', 'binary', 0, 255, nothing)
cv.setTrackbarPos('threshold', 'binary', 127)
img_color = cv.imread(clothes_img)
img_gray = cv.cvtColor(img_color, cv.COLOR_BGR2GRAY)
while(True):
low = cv.getTrackbarPos('threshold', 'binary')
ret,img_binary = cv.threshold(img_gray, low, 255, cv.THRESH_BINARY_INV)
cv.imshow('binary', img_binary)
kernel = np.ones((1,1), np.uint8)
img_mask = cv.morphologyEx(img_binary, cv.MORPH_OPEN, kernel)
img_mask = cv.morphologyEx(img_binary, cv.MORPH_CLOSE, kernel)
img_result = cv.bitwise_and(img_mask, img_mask, mask = img_mask)
contours, hierarchy = cv.findContours(img_binary, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
cv.drawContours(img_color, contours, 0, (0, 255, 0), 1)
cv.imshow('result', img_result)
cv.imshow("color", img_color)
contours_xy = np.array(contours)
contours_xy.shape
x_min, x_max = 0,0
value = list()
for i in range(len(contours_xy)):
for j in range(len(contours_xy[i])):
value.append(contours_xy[i][j][0][0])
x_min = min(value)
x_max = max(value)
y_min, y_max = 0,0
value = list()
for i in range(len(contours_xy)):
for j in range(len(contours_xy[i])):
value.append(contours_xy[i][j][0][1])
y_min = min(value)
y_max = max(value)
x = x_min
y = y_min
w = x_max-x_min
h = y_max-y_min
#if cv.waitKey(1)%256 == 32:
img_crop = img_color[y:y+h, x:x+w]
img_name = "crop_0.png"
cv.imwrite(img_name, img_crop)
crop_image = cv.imread(img_name)
if cv.waitKey(1)&0xFF == 27: # esc 누르면 닫음
break
cv.imshow('crop result', crop_image)
cv.waitKey(0)
cv.destroyAllWindows()
cv.destroyAllWindows()
cv.waitKey(0)
print("자를 옷이 남았나요? (Y/N)")
crop_input = input()
상의와 하의만을 다루기 때문에 최대 두개의 경우를 생각하였다. 먼저 옷의 이미지 파일을 입력하고 트랙바를 통해 바이너리이미지를 조정하여 contour를 진행한다. 윤곽선이 나타나면 최소 경계상자로 자르게 되고 잘린 이미지를 "crop_{}.png" 의 이름으로 저장한다.
한번의 수행이 끝나면 자를 옷이 남아있는지 물어보고, 있다면 같은 과정을 반복, 아니라면 다음 단계로 넘어가게 된다.
i = Image.open("crop_0.png")
cropX, cropY = i.size
crop = cropY/cropX
i2 = Image.open("crop_1.png")
cropX2, cropY2 = i2.size
crop2 = cropY2/cropX2
font = cv.FONT_HERSHEY_SIMPLEX
def faceDetect():
eye_detect = False
face_cascade = cv.CascadeClassifier('haarcascade_frontface.xml')
eye_cascade = cv.CascadeClassifier('haarcascade_eye.xml')
info = ''
if Input == "1":
try:
model = cv.imread(model_img)
except:
print("Not Found")
return
if Input == "2":
try:
model = cv.imread("model_cap.png")
except:
print("Not Found")
return
print("상의/하의 중 입히고 싶은 옷은 무엇인가요?")
print("1. 상의만")
print("2. 하의만")
print("3. 상 하의 둘다")
plus_input = input()
while True:
if eye_detect:
info = 'Eye Detection On'
else:
info = 'Eye Detection Off'
gray = cv.cvtColor(model, cv.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
cv.putText(model, info, (5, 15), font, 0.5, (255, 0, 255), 1)
for (x, y, w, h) in faces:
cv.rectangle(model, (x, y), (x + w, y + h), (255, 0, 0), 2 )
cv.putText(model, 'Detected Face', (x - 5, y - 5), font, 0.5, (255, 255, 0), 2)
crop_img = cv.imread('crop_0.png')
crop_img1 = cv.imread('crop_1.png')
if plus_input == "1":
resize_img = cv.resize(crop_img, dsize=(int(3 * w), int(crop * 3 * h)), interpolation=cv.INTER_AREA)
model[y+h+(int)(h*0.5):y+h+(int)(h*0.5) + int(crop * 3*h), x - w:x - w + int(3*w)] = resize_img
elif plus_input == "2":
resize_img1 = cv.resize(crop_img1, dsize=(int(2 * w), int(crop2 * 2 * h)), interpolation=cv.INTER_AREA)
model[y+h+(int)(h*0.5) + int(3*h):y+h+(int)(h*0.5) + int(3*h) + int(crop2*2*h), x - int(w*0.5):x - int(w*0.5) + int(2*w)] = resize_img1
elif plus_input == "3":
resize_img = cv.resize(crop_img, dsize=(int(3 * w), int(crop * 3 * h)), interpolation=cv.INTER_AREA)
resize_img1 = cv.resize(crop_img1, dsize=(int(2 * w), int(crop2 * 2 * h)), interpolation=cv.INTER_AREA)
model[y+h+(int)(h*0.5):y+h+(int)(h*0.5) + int(crop *3*h), x - w:x - w + int(3*w)] = resize_img
model[y+h+(int)(h*0.5) + int(3*h):y+h+(int)(h*0.5) + int(3*h) + int(crop2*2*h), x - int(w*0.5):x - int(w*0.5) + int(2*w)] = resize_img1
if eye_detect:
roi_gray = gray[y:y+h, x:x+w]
roi_color = frame[y:y+h, x:x+w]
eyes = eye_cascade.detectMultiScale(roi_gray)
for (ex, ey, ew, eh) in eyes:
cv.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 1)
cv.imshow('result', model)
k = cv.waitKey(30)
if k == ord('i'):
eye_detect = not eye_detect
if k == 27:
break
cv.destroyAllWindows()
faceDetect()
먼저, 잘린 옷들의 가로세로를 cropX, cropY 로 선언하고 상의나 하의의 비율에 따라 인물에 합성되도록 한다. 예를 들어 짧은 치마와 긴 치마가 같은 비율로 리사이징 되면 안되기때문에 원래 옷의 비율로 계산하기 위함이다.
그 계산법은
resize_img = cv.resize(crop_img, dsize=(int(3 * w), int(crop * 3 * h)), interpolation=cv.INTER_AREA)
resize_img1 = cv.resize(crop_img1, dsize=(int(2 * w), int(crop2 * 2 * h)), interpolation=cv.INTER_AREA)
model[y+h+(int)(h*0.5):y+h+(int)(h*0.5) + int(crop *3*h), x - w:x - w + int(3*w)] = resize_img
model[y+h+(int)(h*0.5) + int(3*h):y+h+(int)(h*0.5) + int(3*h) + int(crop2*2*h), x - int(w*0.5):x - int(w*0.5) + int(2*w)] = resize_img1
에 나타난다.
상의 / 하의 / 상의,하의 경우로 나누어 합성을 진행하였다. 모델이미지에서 얼굴을 인식하고, 그 얼굴을 기준으로 상의와 하의가 입혀질 곳을 옷이미지로 바꾸는 방식이다. 웹캠또한 고려하여 만든 코드라 while문을 통해 반복되어 얼굴인식이 여러번 된 경우가 있었다. 그에 따라 옷이미지또한 여러번 겹쳐 합성되었으나, 범위를 많이 벗어나지는 않았다.
이제 상의 하의가 합성된 모델이미지를 저장하는 단계이다.
crop_image를 제대로 저장하지 않았다.
옷의 비율에 맞추어 리사이징 하는 과정에서 왜인지 모르겠지만 문법적으로 오류가 계속 났다. 그래서 cropY/cropX 부분을 따로 저장하여 진행했다.
마지막에 이미지 저장이 안되었다. 얼굴인식을 위한 함수 face detect 안에서 만들어낸 변수 model 을 저장하기 위해 함수내에 그 이미지를 저장하는 기능을 구현하였다.
성공!
실행폴더에 result.png 로 결과이미지가 저장된 것을 확인할 수 있다.