728x90
# 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_needed2drawing_needFalse 바꾸어 다시 다른 위치의 다른 크기로 시도 가능하게 함

- ‘B’ 창을 종료하고 다시 ‘A’ 창으로 가서 크로마키 객체를 오려내는 작업 수행하고 ‘B’ 창으로 와서 배경 영상에 삽입함

 

# 느낀 점

크로마키 영상을 얼굴로 하려고 단색 배경을 찾아서 사진을 찍는 걸 시도해보고 작업해보았지만 완벽한 단색 배경이 아니어서 작은 단색 배경을 찾아 인형으로 대체함. 이 크로마키 사진을 찍는 데에 시간을 많이 투자하고 어려웠음. 배경을 검은 색으로 만드는 작업에서 그림자 부분은 잘 안 지워졌음. 이번 과제 중 가장 시간이 오래 걸렸던 작업임. 평소 신기해하던 크로마키 작업을 직접 작성하면서 어려웠지만 과정을 알게 되어 좋았음.

 

 

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기