
OpenCV와 NumPy의 자료형을 비교해보면 위의 표와 같다. 단순히 표현 방식만 다를 뿐 같은 의미를 갖는다는 것을 알 수 있다.
import cv2
img1=cv2.imread('cat.bmp',cv2.IMREAD_GRAYSCALE)
img2=cv2.imread('cat.bmp',cv2.IMREAD_COLOR)
print('type(img1):', type(img1)) #type(img1): <class 'numpy.ndarray'>
print('img1.shape:',img1.shape) #img1.shape : (480,640)
print('img2.shape:',img2.shape) #img2.shape : (480,640,3)
print('img2.dtype:',img2.dtype) #img2.dtype: uint8
h,w=img2.shape[:,2] #h:480, w:640 -> 3개의 tuple 중에서 앞의 2개만 가져옴
print('img2 size: {} x {}'.format(w,h))
if len(img1.shape)==2:
print('img1 is a grayscale image')
elif len(img1.shape)==3:
print('img1 is a truecolor image')

위의 코드를 실행하면 다음과 같이 출력된다.
.shape로 출력했을 때 이미지의 크기가 출력되는 것을 알 수 있는데, 이미지가 흑백영상인지 컬러 영상인지에 따라 튜플의 element가 [h,w]인지 [h,w,3]인지가 달라진다. 그 이유는 컬러 영상의 경우 R,G,B 3요소 만으로 전체의 색상을 나타내기 때문이다.
영상 생성, 복사, 부분 영상 추출
지정한 크기로 새 영상 출력
numpy.empty(shape, dtype=float, ...) -> arr
numpy.zeros(shape, drype=float, ...) -> arr
numpy.ones(shape, dtype=None, ...) -> arr
numpy.full(shape, fill_value, dtype=None, ...) -> arr
- shape : 각 차원의 크기 {GrayScale : [h,w]}, {Color : [h,w,3]}
- dtype : 원소의 데이터 타입. 일반적인 영상이면 numpy.uint8
- arr : 생성된 영상
- 참고사항
img1 = np.empty((240, 320), dtype=np.uint8) # grayscale image
img2 = np.zeros((240, 320, 3), dtype=np.uint8) # color image
img3 = np.ones((240, 320), dtype=np.uint8) * 255 # dark gray
img4 = np.full((240, 320, 3), (0, 255, 255), dtype=np.uint8) # yellow

여기서 img4를 보면, shape 말고도 [0,255,255]를 지정해준 것을 확인할 수 있다. 그 이유는 노랑색을 RGB로 표현하면, Red+Green인데 OpenCV의 경우 BGR 순으로 색상을 지정하기 때문에 G와 R에 최댓값 255를 지정하게 되면 노랑색이 화면 사이즈에 맞게 출력되게 된다.

부분 영상 추출
`# 부분 영상 추출
img1 = cv2.imread('HappyFish.jpg')
img2 = img1[40:120, 30:150] # numpy.ndarray의 슬라이싱
img3 = img1[40:120, 30:150].copy()
cv2.circle(img2,(50,50),20,(0,0,255),2)
#(50,50)을 중심으로 하고 반지름이 20이면서 두께가 2인 원
img2.fill(0) # img2에 적용했는데 img1에도 적용됨 (img1을 슬라이싱 해왔기 때문)
코드를 해석해보면, img1은 이미지를 불러오고 img2는 높이가 40~120 너비가 30~150인 사각형 모양을 추출해서 img3에 복사를 하는데, img2.fill[0]으로 인해 img2는 검정 화면이 출력되게 되고, img3는 그대로 출력이 되게 된다.

마스크 연산과 ROI
- ROI : Region of Interest = 영상에서 특정 연산을 수행하고자 하는 임의의 부분 영역
- 마스크 연산
- OpenCV는 일부 함수에 대해 ROI 연산을 지원하며, 이 때 마스크 영상을 인자로 함께 전달해야한다
e.g.) cv2.copyTo, ccv2.calcHist, cv.bitwise_or, cv2.matchTemplate, etc.- 마스크 영상은 cv2.CV_8UC1 타입 [그레이스케일 영상]
- 마스크 영상의 픽셀 값이 0이 아닌 위치에서만 연산이 수행된다
마스크 연산을 지원하는 픽셀 값 복사 함수
cv2.copyTo(src, mask, dst=None) -> dst
- src : 입력 영상
- mask : 마스크 영상 ... 0이 아닌 픽셀에 대해서만 복사 연산을 수행
- dst : 출력 영상. 만약 src와 크기 및 타입이 같은 dst를 입력으로 지정하면 dst를 새로 생성하지 않고 연산을 수행하는데, 그렇지 않다면 dst를 새로 생성하여 연산을 수행한 후 반환한다.
# 마스크 영상을 이용한 영상 합성
src = cv2.imread('airplane.bmp', cv2.IMREAD_COLOR)
mask = cv2.imread('mask_plane.bmp', cv2.IMREAD_GRAYSCALE)
dst = cv2.imread('field.bmp', cv2.IMREAD_COLOR)
cv2.copyTo(src,mask,dst) # dst가 없으면 검정 배경에 비행기만 보임
위의 코드는 비행기 사진을 풀과 맑은 하늘이 있는 배경에 집어 넣으려는 code이다. 결과물을 보면 알겠지만, 결국 이미지 합성에 대한 code이다.

또한 이런식으로도 할 수 있다.

OpenCV 그리기 함수
주의 사항
- 그리기 알고리즘을 이용하여 영상의 픽셀 값 자체를 변경
→ 원본 영상이 필요하면 복사본을 만들어서 그리기 & 출력 - 그레이스케일 영상에는 컬러로 그릴 수 없다.
→ cv2.cvtColor로 BGR 컬러영상으로 변환한 뒤 그리기 함수를 호출해야 한다.
따라서, 복사본을 만들어서 작업을 하거나 원본 데이터를 백업해 놓는 것이 보다 안전하다.
도형
직선 그리기
cv2.line(img, pt1, pt2, color, thickness=None, lineType=None, shift=None) -> img
- img : 그림을 그릴 영상
- pt1, pt2 : 직선의 시작점과 끝점. [x,y] 튜플
- color : 선 색상 또는 밝기. [B,G,R] 튜플 또는 정수값
- thickness : 선 두께. 기본 값은 1
- lineType : 선 타입. cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA 중 선택, 기본 값은 cv2.LINE_8
- shift : 그리기 좌표 값의 축소 비율. 기본 값은 0
사각형 그리기
cv2.rectangle(img, pt1, pt2, color, thickness=None, lineType=None, shift=None) -> img
cv2.rectangle(img, rec, color, thickness=None, lineType=None, shift=None) -> img
cv2.rectangle(img, (50, 200, 150, 100), (0, 255, 0), 2)
# 50,200 좌표에서 (0,255,0) [녹색] 으로 두께가 2인 사각형을 그림
cv2.rectangle(img, (70, 220), (180, 280), (0, 128, 0), -1)
# 70,220 좌표에서 180,280 까지 (0,128,0) [연두] 으로 두께가 -1인 사각형을 그리는데 내부를 채움
- img : 그림을 그릴 영상
- pt1, pt2 : 사각형의 두 꼭짓점 좌표 [x,y] 튜플
- rec : 사각형 위치 정보 [x,y,w,h] 튜플
- color : 선 색상 또는 밝기. [B,G,R] 튜플 또는 정수값
- thickness : 선 두께. 기본 값은 1, 음수 [-1]를 지정하면 내부를 채움
- lineType : 선 타입. cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA 중 선택, 기본 값은 cv2.LINE_8
- shift : 그리기 좌표 값의 축소 비율. 기본 값은 0
원 그리기
cv2.circle(img, center, raduis, color, thickness=None, lineType=None, shift=None) ->img
cv2.circle(img, (300, 100), 30, (255, 255, 0), -1, cv2.LINE_AA)
# (300,100)에서 반지름이 30인 원을 하늘색으로 내부를 채워서 LINE_AA로 그림
# LINE_AA : Anti-Aliasing -> 거친 테두리가 부드러워짐
cv2.circle(img, (300, 100), 60, (255, 0, 0), 3, cv2.LINE_AA)
- img : 그림을 그릴 영상
- center : 원의 중심 좌표 [x,y] 튜플
- radius : 원의 반지름
- color : 선 색상 또는 밝기. [B,G,R] 튜플 또는 정수값
- thickness : 선 두께. 기본 값은 1, 음수 [-1]를 지정하면 내부를 채움
- lineType : 선 타입. cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA 중 선택, 기본 값은 cv2.LINE_8
- shift : 그리기 좌표 값의 축소 비율. 기본 값은 0
다각형 그리기
cv2.polylines(img, pts, isClosed, color, thickness=None, lineType=None, shift=None)->img
pts = np.array([[250, 200], [300, 200], [350, 300], [250, 300]])
cv2.polylines(img, [pts], True, (255, 0, 255), 2)
# pts 좌표에 보라색으로 두께가 2인 폐곡선을 그림 => pts를 보면 사다리꼴임을 알 수 있다.
- img : 그림을 그릴 영상
- pts : 다각형 외곽 점들의 좌표 배열. numpy.ndarrray의 리스트
e.g) [np.array[10,10],[50,50],[10,50]],dtype=np.int32] - isClosed : 폐곡선 여부. True or False 지정
- color : 선 색상 또는 밝기. [B,G,R] 튜플 또는 정수값
- thickness : 선 두께. 기본 값은 1,선 타입. cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA 중 선택, 기본 값은 cv2.LINE_8
- 음수 [-1]를 지정하면 내부를 채움
- lineType : 선 타입. cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA 중 선택, 기본 값은 cv2.LINE_8
- shift : 그리기 좌표 값의 축소 비율. 기본 값은 0
예시 코드
위의 예시 코드들을 합치면 아래와 같은 코드가 된다.
import numpy as np
import cv2
img = np.full((400, 400, 3), 255, np.uint8)
cv2.line(img, (50, 50), (200, 50), (0, 0, 255), 5)
cv2.line(img, (50, 60), (150, 160), (0, 0, 128))
cv2.rectangle(img, (50, 200, 150, 100), (0, 255, 0), 2)
cv2.rectangle(img, (70, 220), (180, 280), (0, 128, 0), -1)
cv2.circle(img, (300, 100), 30, (255, 255, 0), -1, cv2.LINE_AA)
cv2.circle(img, (300, 100), 60, (255, 0, 0), 3, cv2.LINE_AA)
pts = np.array([[250, 200], [300, 200], [350, 300], [250, 300]])
cv2.polylines(img, [pts], True, (255, 0, 255), 2)
text = 'Hello? OpenCV ' + cv2.__version__
cv2.putText(img, text, (50, 350), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 1, cv2.LINE_AA)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

문자열
문자열 출력
cv2.putText(img, text, org, fontFace, fontScale, color, thickness=None,
lineType=None, bottomLeftOrigin=None) -> img
text = 'Hello? OpenCV ' + cv2.__version__
cv2.putText(img, text, (50, 350), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 1, cv2.LINE_AA)
# 50,350 위치에 SIMPLEX 글꼴, 0.8 크기, 두께가 1, 색상은 빨간색인 text를 적음
- img : 그림을 그릴 영상
- test : 출력할 문자열
- org : 영상에서 문자열을 출력할 위치의 좌측 하단 좌표 [x,y] 튜플
- fontface : 폰트 종류. cv2.FONTHERSHEY로 시작하는 상수 중 선택
- fontscale : 폰트 크기 확대/축소 비율
- color : 선 색상 또는 밝기. [B,G,R] 튜플 또는 정수값
- thickness : 선 두꼐. 기본 값은 1, 음수 [-1]를 지정하면 내부를 채움
- lineType : 선 타입. cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA 중 선택, 기본 값은 cv2.LINE_8
- bottomLeftOrigin : True이면 영상의 좌측 하단을 원점으로 간주. 기본값은 False


카메라와 동영상 처리하기
컴퓨터비전은 말 그래도 컴퓨터에게 인간의 눈을 달아준다는 의미이기 때문에 카메라를 다루는 것을 빼놓을 수 없다. OpenCV에서는 카메라와 동영상으로부터 frame을 받아오는 작업을 VideoCapture 클래스 하나로 처리한다.

카메라 열기
cv2.VideoCapture(index, apiPreference=None) -> retval
- index : camera_id + domain_offset_id == 시스템 기본카메라를 기본 방법으로열려면 index에 0을 전달
- apiPreference : 선호하는 카메라 처리 방법을 지정
- retval : cv2.VideoCapture객체
cv2.VideoCapture.open(index, apiPreference=None) -> retval
- retval : 성공하면 True, 실패하면 False
동영상, 정지 영상 시퀀스, 비디오 스트림 열기
cv2.VideoCapture(filename, apiPreference=None) -> retval
- filename : 비디오 파일 이름, 정지 영상 시퀀스, 비디오 스트림 URL 등
- apiPreference : 선호하는 동영상 처리 방법을 지정
- retval : cv2.VideoCapture 객체
cv2.VideoCapture.open(filename, apiPreference=None) -> retval
- retval : 성공하면 True, 실패하면 False
비디오 캡쳐가 준비 되었는지 확인
cv2.VideoCapture.isOpened() -> retval
- retval : 성공하면 True, 실패하면 False
프레임 받아오기
cv2.VideoCapture.read(image=None) -> retval, image
- retval : 성공하면 True, 실패하면 False
- image : 현재 프레임
카메라, 비디오 장치 속성 값 참조
cv2.VideoCapture.get(propId) -> retval

cv2.VideoCapture.set(propId, value) -> retval
- propId : 속성 상수
- value : 속성 값
- retval : 성공하면 True, 실패하면 False
예시 코드
import sys
import cv2
# 카메라 열기
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Camera open failed!")
sys.exit()
# 카메라 프레임 크기 출력
print('Frame width:', int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)))
print('Frame height:', int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
# 카메라 프레임 처리
while True:
ret, frame = cap.read()
if not ret:
break
inversed = ~frame # 반전
cv2.imshow('frame', frame)
cv2.imshow('inversed', inversed)
if cv2.waitKey(10) == 27:
break
cap.release()
cv2.destroyAllWindows()
위의 코드를 실행시키면, 현재 이 코드가 실행되는 디바이스에 내장되어 있는 카메라가 켜지면서 실제 화면과 frame이 반전된 화면이 동시에 출력된다. 그리고 waitkey[10]==27의 의미는 이전 게시물에서 언급했지만 ESC를 누르면 카메라가 종료된다는 의미이다.

동영상 저장하기
OpenCV에서는 cv2.VideoWriter 클래스를 이용하여 일련의 프레임을 동영상 파일로 저장할 수 있다. 단, 일련의 프레임은 모두 크기와 데이터 타입이 같아야 한다.
- Fourcc [4-문자 코드]
: 동영상 파일의 코덱, 압축 방식, 색상, 픽셀 포맷 등을 정의하는 정수 값

저장을 위한 동영상 파일 열기
cv2.VideoWriter(filename, fourcc, fps, framesize, isColor=None) -> retval
- filename : 비디오 파일 이름 e.g., 'video.mp4'
- fps : 초당 프레임 수 [frame per second]
- frameSize : 프레임 크기 [width, height] 튜플
- isColor : 컬러 영상이면 True, 그렇지 않으면 False
- retval : cv2.VideoWriter 객체
cv2.VideoWriter.open(filename, fourcc, fps, frameSize, isColor=None) -> retval
비디오 파일이 준비되었는지 확인
cv2.VideoWriter.isOpened() -> retval
예시 코드
import sys
import cv2
# 비디오 파일 열기
cap = cv2.VideoCapture('video1.mp4')
if not cap.isOpened():
print("Video open failed!")
sys.exit()
# 비디오 프레임 크기, 전체 프레임수, FPS 등 출력
print('Frame width:', int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)))
print('Frame height:', int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
print('Frame count:', int(cap.get(cv2.CAP_PROP_FRAME_COUNT)))
fps = cap.get(cv2.CAP_PROP_FPS)
print('FPS:', fps)
delay = round(1000 / fps)
# 비디오 매 프레임 처리
while True:
ret, frame = cap.read()
if not ret:
break
inversed = ~frame # 반전
cv2.imshow('frame', frame)
cv2.imshow('inversed', inversed)
if cv2.waitKey(delay) == 27:
break
cap.release()
cv2.destroyAllWindows()
위의 코드를 실행시키면 원숭이가 바나나먹는 영상이 화면에 띄워지는데, 동시에 terminal에 frame에 대한 정보가 출력된다.

키보드 이벤트 처리하기
키보드 입력 대기 함수
cv2.waitKey(delay=None) ->retval
- delay : 밀리초 단위 대기 시간. delay<=0이면 무한히 기다린다. 기본값=0
- retval : 눌린 키 값 [ASCII code]. 키가 눌리지 않으면 -1
- 참고사항
- cv2.waitKey() 함수는 OpenCV 창이 하나라도 있을 때 동작한다.
- 특정 키의 입력을 확인하여면 ord() 함수를 이용하면 된다.
```python
while True:
if cv2.waitKey()==ord('q'):
break
```

예시 코드
import sys
import numpy as np
import cv2
img = cv2.imread('cat.bmp', cv2.IMREAD_GRAYSCALE)
if img is None:
print('Image load failed!')
sys.exit()
cv2.namedWindow('image')
cv2.imshow('image', img)
while True:
keycode = cv2.waitKey()
if keycode == ord('i') or keycode == ord('I'): # i를 누르면 영상 반전
img = ~img
cv2.imshow('image', img)
elif keycode == 27: # ESC 누르면 화면 닫기
break
cv2.destroyAllWindows()
마우스 이벤트 처리하기
마우스 이벤트 콜백함수 등록 함수
cv2.setMouseCallback(windowName, onMouse, param=None) -> None
- windowName : 마우스 이벤트 처리를 수행할 창 이름
- onMouse : 마우스 이벤트 처리를 위한 콜백 함수 이름
- param : 콜백 함수에 전달할 데이터
마우스 이벤트 처리 함수 [콜백 함수] 형식
onMouse(event,x,y,flags,param) -> None
- event : 마우스 이벤트 종류. cv2.EVENT로 시작하는 상수

- x : 마우스 이벤트가 발생한 x좌표
- y : 마우스 이벤트가 발생한 y좌표
- flags : 마우스 이벤트 발생 시 상태. cv2.EVENT_FLAG로 시작하는 상수

- param : cv2.setMouseCallbask 함수에서 설정한 데이터
예시 코드
import sys
import numpy as np
import cv2
oldx = oldy = -1
def on_mouse(event, x, y, flags, param):
global oldx, oldy
if event == cv2.EVENT_LBUTTONDOWN:
oldx, oldy = x, y
print('EVENT_LBUTTONDOWN: %d, %d' % (x, y))
elif event == cv2.EVENT_LBUTTONUP:
print('EVENT_LBUTTONUP: %d, %d' % (x, y))
elif event == cv2.EVENT_MOUSEMOVE:
if flags & cv2.EVENT_FLAG_LBUTTON:
cv2.line(img, (oldx, oldy), (x, y), (0, 0, 255), 4, cv2.LINE_AA)
cv2.imshow('image', img)
oldx, oldy = x, y
img = np.ones((480, 640, 3), dtype=np.uint8) * 255
cv2.namedWindow('image')
cv2.setMouseCallback('image', on_mouse, img)
cv2.imshow('image', img)
cv2.waitKey()
cv2.destroyAllWindows()
위의 코드를 실행시키면, 마우스 좌클릭을 할 때마다 좌표를 찍는데, line함수로 두께가 4인 빨간색 선을 그으면서 시작점과 끝지점의 x,y 좌표를 return한다.


첫 번째부터 두 번째 줄이 하트 모양, 세 번째부터 네 번째 줄이 별, 나머지 줄이 막 그린 모양의 시작점과 끝점의 x,y좌표 튜플이다.
트랙바 사용하기
Trackbar
: 프로그램 동작 중 사용자가 지정한 범위 안의 값을 선택할 수 있는 컨트롤로 OpenCV에서 제공하는 그래픽 사용자 인터페이스이다.

트랙바 생성 함수
cv2.createTrackbar(trackbarName, windowName, value, count, onChange) -> None
- trackbarName : 트랙바 이름
- windowName : 트랙바를 생성할 창 이름
- value : 트랙바 위치 초기값
- count : 트랙바 최댓값. 최솟값은 항상 0
- onChange : 트랙바 위치가 변경될 때마다 호출할 콜백 함수 이름
예시 코드
import numpy as np
import cv2
def on_level_change(pos):
value = pos * 16
if value >= 255:
value = 255
# value=np.clip(value, 0, 255)
img[:] = value
cv2.imshow('image', img)
img = np.zeros((480, 640), np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('level', 'image', 0, 16, on_level_change)
cv2.imshow('image', img)
cv2.waitKey()
cv2.destroyAllWindows()
위의 코드를 실행시키면 0~16단계로 나뉘어져 있는데, level이 낮을 수록 어두워지고, level이 높아질 수록 흰색에 가까워진다.


연산 시간 측정 방법
: 컴퓨터 비전은 대용량 데이터를 다루고, 일련의 과정을 통해 최종 결과를 얻으므로 매 단계에서 연산 시간을 측정하여 관리할 필요가 있다.

예시 코드
import sys
import time
import numpy as np
import cv2
img = cv2.imread('hongkong.jpg')
tm = cv2.TickMeter() # tm 객체 생성
tm.reset()
tm.start()
t1 = time.time()
edge = cv2.Canny(img, 50, 150)
tm.stop()
print('time:', (time.time() - t1) * 1000)
print('Elapsed time: {}ms.'.format(tm.getTimeMilli()))
# start부터 stop까지 경과된 시간 출력
---------------------------------------------------------------------------------
time: 169.4018840789795
Elapsed time: 169.0095ms.
실습
위의 코드들로 할 수 있는게 동영상 합성이있다. ppt나 영상에서 볼 수 있는 fade-in/out, dissolve등의 기능을 코드로 구현할 수 있다.
먼저, 두 동영상을 동시에 열어서 첫 번째 동영상의 마지막 N개의 프레임과 두 번째 동영상의 처음 N개의 프레임을 합성한 뒤, 저장하면 합성된 영상이 저장되게 된다. 이 과정을 그림과 코드로 나타내면 다음과 같다.

import sys
import numpy as np
import cv2
# 두 개의 동영상을 열어서 cap1, cap2로 지정
cap1 = cv2.VideoCapture('video1.mp4')
cap2 = cv2.VideoCapture('video2.mp4')
if not cap1.isOpened() or not cap2.isOpened():
print('video open failed!')
sys.exit()
# 두 동영상의 크기, FPS는 같다고 가정함
frame_cnt1 = round(cap1.get(cv2.CAP_PROP_FRAME_COUNT))
frame_cnt2 = round(cap2.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap1.get(cv2.CAP_PROP_FPS)
effect_frames = int(fps * 2)
print('frame_cnt1:', frame_cnt1)
print('frame_cnt2:', frame_cnt2)
print('FPS:', fps)
delay = int(1000 / fps)
w = round(cap1.get(cv2.CAP_PROP_FRAME_WIDTH))
h = round(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
# 출력 동영상 객체 생성
out = cv2.VideoWriter('output.avi', fourcc, fps, (w, h))
# 1번 동영상 복사
for i in range(frame_cnt1 - effect_frames):
ret1, frame1 = cap1.read()
if not ret1:
print('frame read error!')
sys.exit()
out.write(frame1)
print('.', end='')
cv2.imshow('output', frame1)
cv2.waitKey(delay)
# 1번 동영상 뒷부분과 2번 동영상 앞부분을 합성
for i in range(effect_frames):
ret1, frame1 = cap1.read()
ret2, frame2 = cap2.read()
if not ret1 or not ret2:
print('frame read error!')
sys.exit()
dx = int(w / effect_frames) * i
# frame = np.zeros((h, w, 3), dtype=np.uint8)
# frame[:, 0:dx, :] = frame2[:, 0:dx, :]
# frame[:, dx:w, :] = frame1[:, dx:w, :]
alpha = i / effect_frames
frame = cv2.addWeighted(frame1, 1 - alpha, frame2, alpha, 0) # dissolve
out.write(frame)
print('.', end='')
cv2.imshow('output', frame)
cv2.waitKey(delay)
# 2번 동영상을 복사
for i in range(effect_frames, frame_cnt2):
ret2, frame2 = cap2.read()
if not ret2:
print('frame read error!')
sys.exit()
out.write(frame2)
print('.', end='')
cv2.imshow('output', frame2)
cv2.waitKey(delay)
print('\noutput.avi file is successfully generated!')
cap1.release()
cap2.release()
out.release()
cv2.destroyAllWindows()
여기까지가 두 번째 posting이다. 쫌 길었지만, 이미지와 영상 편집을 하는데 꽤나 유용하게 쓸 수 있는 코드들이 있기 때문에 도움이 많이 될 것이다.
- Chapter2 끝! -

'OpenCV' 카테고리의 다른 글
[OpenCV] 영상의 특징 추출 0 | 2025.04.04 |
---|---|
[OpenCV] 기하학적 변환 0 | 2025.04.04 |
[OpenCV] 필터링 1 | 2025.04.04 |
[OpenCV] 기본 영상 처리 0 | 2025.04.04 |
[OpenCV] 컴퓨터비전의 시작 2 | 2025.04.04 |