유튜브 "빵형의 개발도상국"을 보면서 공부 및 프로젝트를 진행하였습니다. https://youtu.be/suytB_6aS6M - 해리포터 투명망토 만들기
참고한 깃허브 자료
https://github.com/kairess/invisibility_cloak
출처 : 빵형의 개발도상국 유튜브 [해리포터 투명망토 만들기]
Color Segementation
위의 사진처럼 해당 이미지에서 특정 색을 뽑아낼 것이다! 그 후 특정 색에 해당하는 지점은 흰 색(255)으로 다른 부분은 검은 색(0)인 mask를 만든다.
Mask
그 후 background 이미지를 이용해 masking을 한다. 이 때 background 이미지는 미리 사람이 없는 부분을 찍어둔다! 이 background에 masking을 하면 res1이 나온다.
Result
만들어진 res1과 원본 이미지에서 mask한 부분을 뺀 res2을 합치면 우리가 원하는 결과물이 나온다.
✅ 3. 지금 카메라(또는 비디오)에서 들어온 이미지를 마스크만큼 뺀다 = res2
✅ 4. 두 개를 합친다! result
import cv2
import numpy as np
import time, argparse
parser = argparse.ArgumentParser()
parser.add_argument('--video', help='Input video path')
args = parser.parse_args()
cap = cv2.VideoCapture(args.video if args.video else 0)
# 비디오 파일을 읽는다. 비디오가 없다면 0으로 설정하여 웹캠이 켜진다.
time.sleep(3)
# 3초간 정지 = 카메라를 켜지는데 시간이 걸리기 때문
# Grap background image from first part of the video **비디오 앞 부분에 사람이 나오지 않은 배경이 꼭 필요(중요)**
for i in range(60):
ret, background = cap.read()
# 동영상의 결과값을 기록하기 위한 코드!
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
out = cv2.VideoWriter('videos/output.mp4', fourcc, cap.get(cv2.CAP_PROP_FPS), (background.shape[1], background.shape[0]))
out2 = cv2.VideoWriter('videos/original.mp4', fourcc, cap.get(cv2.CAP_PROP_FPS), (background.shape[1], background.shape[0]))
# fps = cap.get(cv2.CAP_PROP_FPS) 카메라 프레임 수를 가져올 수 있습니다
while(cap.isOpened()):
ret, img = cap.read() # 한 프레임씩 읽어온다! 원본 이미지가 img에 저장됨
if not ret:
break
# Convert the color space from BGR to HSV
# cv2.cvtColor() : 컬러 시스템을 변경한다.
# **원본 이미지를 BGR에서 HSV로 바꾼다.**
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Generate mask to detect red color
# 빨간색의 범위는 0~10 170~180이라 두 개로 나누어 마스크 생성 후 더함!
# 0~10까지 빨간색
lower_red = np.array([0, 120, 70]) # 채도는 120 밝기는 70
upper_red = np.array([10, 255, 255]) # 채도는 255 밝기는 255
mask1 = cv2.inRange(hsv, lower_red, upper_red) # **cv2.inRange() : 범위 안에 해당하는 값들로 마스크를 생성**
# 170~180까지 빨간색
lower_red = np.array([170, 120, 70])
upper_red = np.array([180, 255, 255])
mask2 = cv2.inRange(hsv, lower_red, upper_red)
mask1 = mask1 + mask2 # 빨간색을 다 mask한 마스크가 탄생
# 검정색을 가리고 싶을 떄
# lower_black = np.array([0, 0, 0])
# upper_black = np.array([255, 255, 80])
# mask1 = cv2.inRange(hsv, lower_black, upper_black)
'''
# Refining the mask corresponding to the detected red color
https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html
'''
# Remove noise **마스크를 색만 뽑으면 노이즈가 발생해서 정제해주는 함수임**
mask_cloak = cv2.morphologyEx(mask1, op=cv2.MORPH_OPEN, kernel=np.ones((3, 3), np.uint8), iterations=2) #노이즈 없애고
mask_cloak = cv2.dilate(mask_cloak, kernel=np.ones((3, 3), np.uint8), iterations=1) # 픽셀 크기 늘리기
mask_bg = cv2.bitwise_not(mask_cloak)
cv2.imshow('mask_cloak', mask_cloak)
# Generate the final output
# bitwise_and() : 두개의 행렬이 0이 아닌 것만 통과됨 즉 마스크 영역만 남음(And 연산)
res1 = cv2.bitwise_and(background, background, mask=mask_cloak) # background에서 mask만 남고
res2 = cv2.bitwise_and(img, img, mask=mask_bg) # 캠으로 들어오는 이미지에서 mask가 안 된 부분만 남고
result = cv2.addWeighted(src1=res1, alpha=1, src2=res2, beta=1, gamma=0)
# cv2.addWeighted() 두 개의 이미지를 합친다
cv2.imshow('res1', res1)
# cv2.imshow('ori', img)
cv2.imshow('result', result)
out.write(result)
out2.write(img)
if cv2.waitKey(1) == ord('q'):
break
out.release()
out2.release()
cap.release()
비디오 앞 부분에 사람이 나오지 않은 배경이 꼭 필요(중요)
2초 정도 사람이 없는 배경을 찍어주고 등장하도록 하자! 즉 사람이 없는 60 frame 동안 background에 사람이 없는 이미지를 저장해준다!
원본 이미지를 BGR에서 HSV로 바꾼다.
❓ HSV
Hue 색조 Saturation 채도 Value 명도 를 나타낸다.
openCV의 경우 H는 0~180 S는 0~255 V는 0~255까지의 범위를 갖는다.
BGR보다 HSV가 사람이 인식하는 색깔의 수치와 HSV 컬러시스템이 표현하는 방식이 가장 비슷하다고 한다. 즉 사람이 빨간색으로 인식하는 것을 빨간색으로 잘 표현해줄 수 있다고 한다.
HSV는 각도로 색을 나타낸다 opencv의 경우 위의 사진처럼 해당 각도를 해당 색으로 표현한다.
만약 빨간색으로 얻고 싶으면 다음과 같은 범위(0~10, 170~180)로 잘라주면 된다!
cv2.inRange() : 범위 안에 해당하는 값들로 마스크를 생성
즉 lower_red와 upper_red 사이에 있는 애들은 255로 만들고 나머지는 0으로 만든다.
마스크를 색만 뽑으면 노이즈가 발생해서 정제해주는 함수임
링크를 클릭해보면 dilate함수와 morphologyEx 함수가 존재
dilate는 픽셀을 늘려주는 함수
morphologyEx는 노이즈를 삭제해주는 함수
마침 잠옷이 빨간색이라ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 잘 가려진다