# 1) 필요한 모듈 임포트
import cv2 as cv
import numpy as np
# 5) 원본 영상 마우스 클릭시 (x, y) 좌표와 rgb, hsv 값 반환하고 사각형 오리는 작업
def mouse_callback(event, x, y, flags, param):
global s_x, s_y, e_x, e_y, mouse_pressed, drawing_needed, print_xy
if event == cv.EVENT_LBUTTONDOWN:
mouse_pressed = True
print_xy = False
s_x, s_y = x, y # 선택 시작 좌표 기록
elif event == cv.EVENT_MOUSEMOVE: # 마우스 이동 중
if mouse_pressed: # 누른 상태에서
image_to_show = np.copy(ch_key_black)
cv.rectangle(image_to_show, (s_x, s_y), (x, y), (255, 0, 0), 1) # 선택 영역 파란색으로 보이기
cv.imshow('A',image_to_show)
elif event == cv.EVENT_LBUTTONUP:
mouse_pressed = False
e_x, e_y = x, y # 선택 종료 좌표 기록
drawing_needed = True
print('(x,y) =', (s_x, s_y)) # 클릭한 좌표 출력
print('r,g,b =', ch_key[s_x][s_y][..., ::-1]) # 좌표의 r,g,b값 출력
print('h,s,v =', ch_key_hsv[s_x][s_y]) # 좌표의 h,s,v값 출력
# 6) 트랙바로 HSV margin 조절
# 6-2) 트랙바로 H,S,V 마진 값 변경 시 호출되는 함수
def Adjust_HSV(value):
margin_h = cv.getTrackbarPos('H','A') # 트랙바로 입력받은 H의 마진
margin_s = cv.getTrackbarPos('S','A') # 트랙바로 입력받은 S의 마진
margin_v = cv.getTrackbarPos('V','A') # 트랙바로 입력받은 V의 마진
h = ch_key_hsv[s_x][s_y][0] # 클릭한 좌표의 H값
s = ch_key_hsv[s_x][s_y][1] # 클릭한 좌표의 S값
v = ch_key_hsv[s_x][s_y][2] # 클릭한 좌표의 V값
# 배경은 0으로 객체는 255로 만드는 mask
mask = cv.inRange(ch_key_hsv, np.array([h-margin_h, s-margin_s, v-margin_v]), np.array([h+margin_h, s+margin_s, v+margin_v]))
mask = 255 - mask
# 배경을 검은색으로 만든 영상
global ch_key_black
ch_key_black = cv.bitwise_and(ch_key, ch_key, mask=mask)
# 9) 크로마키 객체(crop.jpg)를 삽입할 위치의 사각형을 선택하는 작업
def mouse_callback2(event, x, y, flags, param):
global s_x2, s_y2, e_x2, e_y2, mouse_pressed2, drawing_needed2
if event == cv.EVENT_LBUTTONDOWN:
mouse_pressed2 = True
s_x2, s_y2 = x, y # 선택 시작 좌표 기록
elif event == cv.EVENT_MOUSEMOVE: # 마우스 이동 중
if mouse_pressed2: # 누른 상태에서
image_to_show = np.copy(back_gr)
cv.rectangle(image_to_show, (s_x2, s_y2), (x, y), (255, 0, 0), 1) # 선택 영역 파란색으로 보이기
cv.imshow('B', image_to_show)
elif event == cv.EVENT_LBUTTONUP:
mouse_pressed2 = False
e_x2, e_y2 = x, y # 선택 종료 좌표 기록
drawing_needed2 = True
# 2) 크로마키 영상에서 객체만 오려낼 창 염
cv.namedWindow('A')
cv.setMouseCallback('A', mouse_callback)
# 3) 크로마키 영상 입력받음
ch_key = 'data/chro1.jpg'
ch_key = cv.imread(ch_key) # 원본 영상 입력받음
#ch_key = cv.resize(ch_key, (512, 512)) # 크기 조절
cv.imshow('A',ch_key) # 화면에 원본 영상 출력
# 4) 영상을 bgr에서 hsv로 변환
ch_key_hsv = cv.cvtColor(ch_key,cv.COLOR_BGR2HSV)
# 6-1) H,S,V 마진값 조절하는 트랙바 생성
cv.createTrackbar('H', 'A', 0, 100, Adjust_HSV) # H 마진 조절 트랙바 생성
cv.createTrackbar('S', 'A', 0, 100, Adjust_HSV) # S 마진 조절 트랙바 생성
cv.createTrackbar('V', 'A', 0, 100, Adjust_HSV) # V 마진 조절 트랙바 생성
# 8) 배경 영상 입력 받음
back_gr = 'data/back.jpg'
back_gr = cv.imread(back_gr)
back_gr = cv.resize(back_gr, (512, 512)) # 크기 조절
# 변수들 초기화
s_x = s_y = e_x = e_y = -1
mouse_pressed = False
drawing_needed = False
ch_key_black = ch_key.copy()
s_x2 = s_y2 = e_x2 = e_y2 = -1
mouse_pressed2 = False
drawing_needed2 = False
# main 부분
while(True):
k = cv.waitKey(100)
cv.imshow('A', ch_key_black)
# 14) ‘esc’ 누르면 모든 창 닫힘
if k == 27:
break
# 7) 마우스 드래그로 원하는 부분 오려내어 저장 (객체 추출)
if drawing_needed == True:
if s_y > e_y: # y축 상의 시작점과 끝점이 바뀌었으면 두 좌표를 바꿈
s_y, e_y = e_y, s_y
if s_x > e_x: # x축 상의 시작점과 끝점이 바뀌었으면 두 좌표를 바꿈
s_x, e_x = e_x, s_x
if e_y - s_y > 1 and e_x - s_x > 0:
img_crop = ch_key_black[s_y:e_y, s_x:e_x]
crop = cv.resize(img_crop, (img_crop.shape[1] * 2, img_crop.shape[0] * 2))
crop_img = np.copy(crop)
cv.imwrite('data/crop.jpg', img_crop)
cv.imshow('crop', crop)
drawing_needed = False
# 9) 'b' 입력하면 새로운 창 B 열어 배경영상 출력
if k == ord('b'):
cv.destroyWindow('crop')
cv.namedWindow('B') # 새로운 창 생성
cv.setMouseCallback('B', mouse_callback2)
cv.imshow('B', back_gr)
# 11) 선택한 위치에 crop영상 삽입함
if drawing_needed2 == True: # crop 영상 놓을 사각형 선택하였으면
result_img = np.copy(back_gr)
# 선택한 사각형의 크기에 맞추어 crop 영상을 크기 조절함
crop = cv.resize(crop_img, (e_x2 - s_x2, e_y2 - s_y2))
# 선택한 위치에 crop 영상의 객체만 삽입
result_img[s_y2:e_y2, s_x2:e_x2] = crop
result_img = np.where(result_img == 0, back_gr, result_img)
cv.imshow('B', result_img)
# 12) ‘c’ 입력하면 11)의 동작을 취소하여 다른 위치의 다른 크기로 다시 시도 가능
if k == ord('c'):
result_img = np.copy(back_gr)
drawing_needed2 = False
drawing_needed = False
cv.destroyWindow('B')
# 13) 's' 입력하면 최종 결과를 저장
if k == ord('s'):
cv.imwrite('data/image.jpg', result_img)
cv.destroyAllWindows()
# 크로마키 영상('doll.jpg')
- 이 영상은 단색 배경에 다른 유색 객체가 있는 영상
- 적당한 크기로 조절함
# 마우스 왼쪽 버튼 클릭하여 얻은 배경 화소 샘플 xy 좌표, rgb값, hsv값 출력
- 마우스 왼쪽 버튼을 클릭하여 배경 화소 샘플 채취함
- 클릭하면 좌표와 좌표의 r,g,b값과 h,s,v값 출력함
- 이 작업은 반복 수행 가능
# 트랙 바로 HSV 마진 값 조절
- H,S,V의 마진 값을 트랙 바로 입력받아 해당 범위에 속하는 부분(배경 부분)을 0으로,
- 이외에 부분(객체 부분)을 255로 만드는 mask 생성
- cv.inRange() 함수를 이용하여 배경 부분을 255, 객체 부분을 0 으로 만든 후 반전시킴
- mask을 원본 영상과 cv.bitwise_and() 함수를 이용하여 배경 부분만 0으로 되어 객체만 남아있음
- 마진 값을 각각 15, 83, 74로 정하였음
# 마우스 드래그로 원하는 부분 오려내어 저장 (객체 추출)
- 5)의 mouse_callback 함수에서 cv.rectangle() 함수로 마우스 드래그 한 부분을 파란색 사각형으로 화면에 표시함
- 오려낸 영상(img_crop)을 ‘crop’창에 출력하고 ‘crop.jpg’로 저장(main 부분에서 수행함)
# 배경 영상('back.jpg')
- ‘crop’ 창 닫고 ‘B’창 염
# 크로마키 객체(crop.jpg)를 삽입할 위치의 사각형을 선택
- 마우스를 클릭하여 선택 시작 좌표와 선택 종료 좌표를 얻어 삽입할 위치의 사각형 좌표 얻음
- 선택 영역은 파란색으로 표시함
- 삽입 원하는 위치 사각형으로 선택
# 선택한 위치에 crop영상 삽입 (결과 영상 'image.jpg')
- 선택한 사각형의 크기에 맞추어 crop 영상을 크기 조절하여 객체만 덮음
- 검정색인 부분은 배경 영상으로 덮음
- np.where() 함수를 이용하여 0인 부분은 배경 영상, 이외의 부분은 객체 영상 덮음
- 배경 영상과 객체 영상 합성한 결과 영상 출력함
# ‘c’ 입력하면 11)의 동작을 취소하여 다른 위치의 다른 크기로 다시 시도 가능
- result_img(배경 영상에 객체 삽입한 영상)를 다시 배경 영상으로 복사하여 삽입 취소함
- drawing_needed2와 drawing_need를 False 바꾸어 다시 다른 위치의 다른 크기로 시도 가능하게 함
- ‘B’ 창을 종료하고 다시 ‘A’ 창으로 가서 크로마키 객체를 오려내는 작업 수행하고 ‘B’ 창으로 와서 배경 영상에 삽입함
# 느낀 점
크로마키 영상을 얼굴로 하려고 단색 배경을 찾아서 사진을 찍는 걸 시도해보고 작업해보았지만 완벽한 단색 배경이 아니어서 작은 단색 배경을 찾아 인형으로 대체함. 이 크로마키 사진을 찍는 데에 시간을 많이 투자하고 어려웠음. 배경을 검은 색으로 만드는 작업에서 그림자 부분은 잘 안 지워졌음. 이번 과제 중 가장 시간이 오래 걸렸던 작업임. 평소 신기해하던 크로마키 작업을 직접 작성하면서 어려웠지만 과정을 알게 되어 좋았음.
'전공 공부 > 영상처리' 카테고리의 다른 글
푸리에 변환 기반의 잡음 제거 (0) | 2020.12.29 |
---|---|
푸리에 변환 기반의 블러링 검출 (1) | 2020.12.29 |
UnsharpMasking 커널 기반 처리(나만의 생각..) (0) | 2020.12.29 |
UnsharpMasking 트랙 바로 시그마, 스케일 조정 (0) | 2020.12.29 |
히스토그램 명세화 작업 후 r,g,b 채널별 히스토그램 출력 (0) | 2020.12.29 |