뉴스나 인터넷 방송, 영화촬영에 사용하는 크로마키 배경을 제거하는 방법을 파이썬으로 구현
1. 크로마키란
화면 합성 등의 특수 효과를 이용하기 위해 이용하는 배경. 흔히 초록색과 파란색을 사용하여 그린 스크린, 블루 스크린이라고도 한다. 촬영 과정에서 배우가 단색 배경 앞에서 연기를 하고 후편집 과정에서 같은 색으로 찍힌 부분을 다른 배경으로 바꾸면 바꾼 배경에서 연기한 것과 같은 효과를 낼 수 있다.
원래는 'chroma key'로 두 단어이지만 한국에서는 한 단어인 것처럼 '크로마키'라고 쓴다
[출처] 나무위키
2. 크로마키의 원리
초록색배경을 투명화하는 것이다.
원래 크로마키 기술에서는 어떻게 적용되는지는 모르겠으나 파이썬에서는 초록색이 아닌부분을 추출하고 그 부분을 배경으로원하는 부분위에 올려다 놓는다.
3. 코드
import cv2
import numpy as np
cap = cv2.imread('chim55cap.png')
# 배경사이즈를 타겟이미지와 맞춤
window = cv2.imread('windowbg.jpg')
window = cv2.resize(window, (cap.shape[1],cap.shape[0])) # width, height 고정 크기
# 트랙바 생성
panel = np.zeros([100,400], np.uint8)
cv2.namedWindow('panel')
def nothing(x):
pass
# 트랙바의 범위 설정
cv2.createTrackbar('L-H', 'panel', 0,179, nothing)
cv2.createTrackbar('U-H', 'panel', 179,179, nothing)
cv2.createTrackbar('L-S', 'panel', 0,255, nothing)
cv2.createTrackbar('U-S', 'panel', 255,255, nothing)
cv2.createTrackbar('L-V', 'panel', 0,255, nothing)
cv2.createTrackbar('U-V', 'panel', 255,255, nothing)
# 초록면 없애기 위해 hsv로 변환
hsv = cv2.cvtColor(cap, cv2.COLOR_BGR2HSV)
while True:
# 트랙바의 위치에 따라 변수에 값할당
l_h = cv2.getTrackbarPos('L-H', 'panel')
u_h = cv2.getTrackbarPos('U-H', 'panel')
l_s = cv2.getTrackbarPos('L-S', 'panel')
u_s = cv2.getTrackbarPos('U-S', 'panel')
l_v = cv2.getTrackbarPos('L-V', 'panel')
u_v = cv2.getTrackbarPos('U-V', 'panel')
lower_green = np.array([l_h,l_s,l_v])
upper_green = np.array([u_h,u_s,u_v])
# 범위사이에 있는 놈들을 마스크로 만들어라
mask = cv2.inRange(hsv, lower_green, upper_green)
mask_inv = cv2.bitwise_not(mask) # 마스크를 거꾸로만들어라
bg = cv2.bitwise_and(cap, cap, mask=mask) # lg와 ug 사이 놈들을 마스크 사이놈들만 살린다
# 침착맨의 실루엣을 추출(마스킹)
fg = cv2.bitwise_and(cap, cap, mask=mask_inv) # 위에거의 반대
# 윈도우 배경에서 침착맨의 실루엣을 제거
window_bg = cv2.bitwise_and(window, window, mask=mask)
# 두화면을 더함
result = cv2.addWeighted(src1 = fg, src2=window_bg, alpha=1, beta=1, gamma=0)
# cv2.imshow('bg', bg)
# cv2.imshow('fg', fg)
# cv2.imshow('window', window_bg)
cv2.imshow('result', result)
cv2.imshow('panel', panel)
if cv2.waitKey(1) == ord('q'):
break
cv2.imwrite('result.png', result) # png 형태로 저장
cv2.destroyAllWindows()
실행하면 트랙바가 생기게 되는데
트랙바의 위치 즉 마스킹을 할 범위에 따라서 타겟 이미지가 마스킹 될지 안될지 변한다 트랙바를 적절히 변경을하고 키보드의 q를 누르면 저장이되고 해당 셀이 종료되는 코드이다..
간단하게 원리를 알아보면
이미지의 색을 hsv로 변환시켜서 설정한 hsv값의 범위안에 속하는 녀석들만 남기는 것이다.
배경은 그것의 반대로 응용하고 두개를 합치면된다.
4. 영상에서 응용
cap = cv2.VideoCapture('chim55.mp4')
window = cv2.imread('windowbg.jpg')
# 코덱 정의
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
# 프레임 크기, FPS
width = round(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
# 저장 파일명, 코덱, FPS, 크기 (width, height)
out = cv2.VideoWriter('remove.avi', fourcc, fps, (width, height))
window = cv2.resize(window, (width, height)) # width, height 고정 크기
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_green, upper_green) # 사이에 있는 놈들을 마스크로 만들어라
mask_inv = cv2.bitwise_not(mask) # 마스크를 거꾸로만들어라
bg = cv2.bitwise_and(frame, frame, mask=mask) # lg와 ug 사이 놈들을 마스크 사이놈들만 살린다
fg = cv2.bitwise_and(frame, frame, mask=mask_inv) # 위에거의 반대
window_bg = cv2.bitwise_and(window, window, mask=mask)
result = cv2.addWeighted(src1 = fg, src2=window_bg, alpha=1, beta=1, gamma=0)
if not ret:
break
out.write(result) # 영상 데이터만 저장 (소리 X)
cv2.imshow('video', result)
out.release() # 자원 해제
cap.release()
cv2.destroyAllWindows()
위에서 설정한 범위에 따라서 영상을 저장한다