본문 바로가기
AI 컴퓨터 비전프로젝트

[DL] 마스크 연산_cv2.copyTo(), 동영상 합성

by 바다의 공간 2024. 10. 1.
6. 마스크 연산 (누끼따기)
- 마스크 연산을 지원하는 픽셀 값 복사 함수
- cv2.copyTo(img, mask)img와 mask를 넣어서 객체를 만들어줍니다.

좌)비행기 중)마스크 우)배경

위 이미지들을 활용하여 배경에 비행기가 copy되는 마스크연산을 해보려고 합니다.

 

mask는 **0인 부분은 "무시"**되고, **0이 아닌 부분은 "복사"**되는 거예요.

 

그림으로 비유:

마스크를 투명 종이라고 생각할 수 있어요. 종이에서 투명한 부분(=마스크가 0인 부분)은 복사되지 않고, 불투명한 부분(=마스크가 0이 아닌 부분)은 복사됩니다.

 

위의 마스크 사진에서는 

  • 검은색 부분0인 부분입니다.
  • 즉, 이 부분은 마스크에서 복사되지 않는 영역을 나타냅니다.
  • 흰색 부분0이 아닌 부분입니다.
  • 마스크에서 복사되는 영역을 나타냅니다.
  • 검은색(배경) 부분: 원본 이미지에서 이 영역은 무시되고, 복사되지 않음.
  • 흰색(비행기 모양) 부분: 이 부분은 원본 이미지에서 복사되어 새로운 이미지에 복사됩니다.

따라서, 이 마스크를 사용하면 비행기 모양의 흰색 영역만 복사되고, 검은색 배경 부분은 복사되지 않게 됩니다.


import cv2


img=cv2.imread('./airplane.bmp')
mask = cv2.imread('./mask_plane.bmp')
dst = cv2.imread('./field.bmp')

temp = cv2.copyTo(img, mask)

# cv2.imshow('img', img)
# cv2.imshow('mask', mask)
cv2.imshow('temp',temp)
cv2.waitKey()

 

 

작업 과정

  1. 마스크 이미지에서 흰색 부분(255)**은 img에서 그 부분을 복사해서 temp에 넣습니다.

 

이렇게 이미지를 딸 수 있습니다.


그리고 field이미지에 비행기까지 같이넣으려면

import cv2


img=cv2.imread('./airplane.bmp')
mask = cv2.imread('./mask_plane.bmp')
dst = cv2.imread('./field.bmp')

temp = cv2.copyTo(img, mask)
cv2.copyTo(img, mask, dst)
# cv2.imshow('img', img)
# cv2.imshow('mask', mask)
cv2.imshow('temp',temp)
cv2.imshow('dst',dst)
cv2.waitKey()

 

cv2.copyTo(img, mask, dst) 로 한 줄 더 추가하고

여기서 dst 즉 3번째 파라미터의 기능이 연산하고 덮는 역할을 합니다.

만약 따로 마지막 연산을 하지않으려면 윗줄처럼 img, mask두개로 쓰고 변수를 하나 만들어주면 됩니다.

 

 

mask를 만들려면 같은 사진으로 ROI를 이용한거 (남이 만든거쓴다던지(?))를 이용할 수 있습니다.


응용 파이널 ... 버전

여기 영상에 뒤에있는 초록색을 따서 픽사베이에서 원하는 영상을 받아서 뒷 배경으로 인서트 하는 작업을

만들어보려고 합니다.

 

 

목표

간단하게 이 이미지를 가져왔고 백그라운드에 copyTo()를 하려고 합니다.

 

 

import cv2

#비디오 파일 열기
cap1 = cv2.VideoCapture('./woman.mp4')
cap2 = cv2.VideoCapture('./background.mp4')

#비디오 너비,높이, fps가져오기
w = round(cap1.get(cv2.CAP_PROP_FRAME_WIDTH))
h = round(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))

frame_cnt1 = round(cap1.get(cv2.CAP_PROP_FRAME_COUNT))
frame_cnt2 = round(cap2.get(cv2.CAP_PROP_FRAME_COUNT))
fps = round(cap1.get(cv2.CAP_PROP_FPS))

print(w) #1280
print(h) #720
print(frame_cnt1) #409
print(frame_cnt2) #906
print(fps) #24

#(반복문) 첫번째 영상에서 frame읽기

while True:
    ret1, frame1 = cap1.read()
    if not ret1:
        break
    ret2, frame2 = cap2.read()
    if not ret2:
        break

    hsv = cv2.cvtColor(frame1, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, (50,150,0), (70,255,255))
    #초록색배경부분을 축구장에서 따서 여성이 있는 부분에 갖다 붙이기
    #여성은 그대로있고 배경만 따져옴
    cv2.copyTo(frame2, mask, frame1)
    cv2.imshow('frame1', frame1)
    key = cv2.waitKey(10)
    if key == ord(' '):
        cv2.waitKey()
    elif key == 27:
        break

cap1.release()
cap2.release()

이렇게 합성이 되어서 깔끔하진 않지만 잘 보여지는걸 확인할 수 있습니다.

 

여기서  공부하고 정리한것.

1. while문이 오랜만에 나와서 개념정리

2. cv2.inRange()에서 여성의 뒷 배경인 초록색을 따려고 하는데 

전 예제에서는 

HSV에서의 녹색계열
#색상
50 <= H <= 80
#채도
150 <= S <= 255
#명도(밝기정보)
0 <= V <= 255
'''

dst = cv2.inRange(hsv,(50, 150, 0), (80, 255,255))

이 녹색이라고 했는데 지금 동영상의 합성한 경우는 

mask = cv2.inRange(hsv, (50,150,0), (70,255,255))

이라서 왜 그런지 궁금했습니다.

 

이유는 아래와 같습니다.

색상 범위를 어떻게 설정할 것인지 결정하게 되는거더라구요.

mask에서 작성된 코드는 hue값이 50에서 70으로 더좁게 설정되어있어서 특정녹색계열에 초점을 맞추는것이였습니다.

 

지금같은경우는 강사님이 다 값을 지정해준거지만

내가 다른 영상을 합성할때에는 HSV값을 내가 알아야할것같습니다.

 

3.release()

영상을 사용하고 꺼주는 역할을 합니다. 물론 위에서 waitKey로 작성했잖아? 라고 

생각할 수 있지만 waitKey는 키 입력할때까지 사용자가 누를때까지 대기하는역할만 한다고 생각하며 되고

release는 '파일'을 닫는 작업을 하는 함수입니다.

 

 

  • **waitKey()**는: "비디오를 재생하는 동안 잠깐 멈추고 키 입력을 기다려라"라는 명령입니다.
  • **release()**는: "비디오 재생이 끝났으니 이 비디오 파일과의 연결을 끊어라"라는 명령입니다.