OpenCV

현서·2025년 2월 28일

컴퓨터 비전

목록 보기
4/16
post-thumbnail

1. OpenCV (Open Source Computer Vision Library)

  • 실시간 컴퓨터 비전 및 이미지 처리를 위한 오픈소스 라이브러리이다.
  • Python에서 cv2 모듈을 통해 사용할 수 있으며, 이미지 및 영상의 읽기, 변환, 필터링, 객체 검출, 특징 추출 등의 다양한 기능을 제공한다.
  • NumPy와의 호환성이 좋아 배열 연산을 활용한 고속 이미지 처리가 가능하며, 머신러닝 및 딥러닝 모델과도 쉽게 연동할 수 있다.

vscode에서 실행

가상환경 만들기(윈도우)
cmd 창에서 다음을 입력한다.

Python -m venv venv
cd venv/Scripts/
activate

설치
cmd 창에서 다음을 입력한다.

pip install opencv-python

1_cv2.py

import cv2

print('현재 openCV 버전: ', cv2.__version__)

2. 영상 (image or video)

  • 디지털 형태로 표현된 시각적 정보로, 픽셀 단위로 구성된 2차원 또는 3차원 데이터이다.
  • 정지된 이미지는 일반적으로 그레이스케일(흑백) 또는 RGB(컬러) 채널을 가지며, 연속된 이미지 프레임의 집합인 동영상은 시간에 따른 영상 데이터로 볼 수 있다.

2_image.py

import cv2

# 그레이스케일 영상
img1 = cv2.imread('./images/dog.bmp', cv2.IMREAD_GRAYSCALE)
print(img1)

# 트루컬러 영상
# img2 = cv2.imread('./images/dog.bmp')
img2 = cv2.imread('./images/dog.bmp', cv2.IMREAD_COLOR) # cv2.IMREAD_COLOR 생략 가능
# 기본적으로 컬러 이미지로 읽기(B, G, R 순서)
print(img2)

cv2.imshow('img1', img1) # BGR
cv2.imshow('img2', img2)
cv2.waitKey()

waitKey() : 이미지가 떴을 때 키보드의 아무 키나 누르면 이미지가 사라짐.


2-1. 그레이스케일(Grayscale) 영상

  • 흑백 영상, 각 픽셀이 밝기 정보만 포함하는 1채널 영상
  • 일반적으로 0(검은색)~ 255(흰색) 사이의 값으로 표현, 중간값일수록 회색 톤
  • RGB(컬러) 영상에서 색상 정보를 제거하고 밝기 정보만 남기는 방식으로 변환할 수 있다.
  • 엣지 검출, 객체 인식, 얼굴 탐지 등 → 연산량을 줄이고 효율적인 처리를 위해 사용

2-2. 트루컬러(True Color) 영상

  • RGB(Red, Green, Blue) 3채널을 사용하여 색상을 표현하는 컬러 영상
  • 각 픽셀은 세 가지 색상의 조합으로 표현, 일반적으로 각 채널이 0~255 범위의 값을 가진다.
  • 하나의 픽셀은 (R, G, B) 값의 조합으로 이루어져 있어 총 약 1677만(256³) 가지의 색상을 표현할 수 있다.
  • 사진, 영상 스트리밍, AR/VR, 자율주행 등의 다양한 응용 분야에서 사용된다.

3_matplotlib.py

import cv2
import matplotlib.pyplot as plt

# subplot이용하여 left plot에는 그레이스케일 영상, right plot에는 컬러영상을 출력
img_gray = cv2.imread('./images/dog.bmp', cv2.IMREAD_GRAYSCALE)
img_color = cv2.imread('./images/dog.bmp') # RGB 순서 아닌 BGR로 가져옴. 그래서 색이 이상하게 나옴. matplotlib에서는 순서가 RGB여야 한다.
img_color = cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB) # BGR -> RGB 바꿔줌.

plt.subplot(121) # 1행 2열 첫번째
plt.axis('off') # 격자 없애줌.
plt.imshow(img_gray, cmap='gray') 

plt.subplot(122) # 1행 2열 두번째
plt.axis('off')
plt.imshow(img_color)
plt.show()


4_img_info.py

import cv2
import numpy as np

img_gray = cv2.imread('./images/dog.bmp', cv2.IMREAD_GRAYSCALE)
print('img_gray type: ', type(img_gray))
print('img_gray shape: ', img_gray.shape) # (세로, 가로)
print('img_gray dtype: ', img_gray.dtype)

img_color = cv2.imread('./images/dog.bmp')
print('img_color type: ', type(img_color))
print('img_color shape: ', img_color.shape) # (세로, 가로, 색상)
print('img_color dtype: ', img_color.dtype)

# (364, 548, 3)
h, w = img_color.shape[:2]
print(f'이미지 사이즈: {w} * {h}')

# 그레이스케일 영상인지, 컬러영상인지 구분하기
if len(img_color.shape) == 3:
    print('컬러 영상')
elif len(img_color.shape) == 2:
    print('그레이스케일 영상')

img1 = np.zeros((240, 320, 3), dtype=np.uint8)  # 240x320 크기의 검은색 이미지 생성
img2 = np.empty((240, 320), dtype=np.uint8)  # 240x320 크기의 랜덤한 값의 색상 이미지 생성
img3 = np.ones((240, 320), dtype=np.uint8) * 120  # 120 밝기 정도가 바뀜.
img4 = np.full((240, 320, 3), (255, 102, 255),dtype=np.uint8)

# for x in range(h):
#     for y in range(w):
#         img_color[x, y] = (255, 102, 255)

img1[:, :] = (255, 102, 255) # :는 모든 행, 모든 열을 뜻하므로 → img1[:, :]는 이미지 전체 영역(= 모든 픽셀)을 가리킨다.
            
cv2.imshow('img_color', img_color)
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)
cv2.imshow('img4', img4)

while True:
    keyvalue = cv2.waitKey()
    if keyvalue == ord('i') or keyvalue == ord('I'):
        img_color = ~img_color  # i or I 키 누르면 이미지 반전
        cv2.imshow('img_color', img_color)
    elif keyvalue == 27: # ESC 키를 누르면 종료
        break

cv2.waitKey()
img_gray type:  <class 'numpy.ndarray'>
img_gray shape:  (364, 548)
img_gray dtype:  uint8
img_color type:  <class 'numpy.ndarray'>
img_color shape:  (364, 548, 3)
img_color dtype:  uint8
이미지 사이즈: 548*364
컬러 영상

uint8
u → unsigned (부호 없음: 음수 없음)
int → 정수
8 → 8비트 (1바이트)
즉, 0부터 255 사이의 정수만 저장할 수 있는 자료형


5_mouseevent.py

import cv2
import numpy as np

oldx = oldy = 0
def on_mouse(event, x, y, flags, param):
    global oldx, oldy
    # print(event)
    if event == cv2.EVENT_LBUTTONDOWN:  # 왼쪽 버튼 클릭
        print('왼쪽 버튼이 눌렸어요: %d, %d' % (x, y))
        oldx, oldy = x, y  
    elif event == cv2.EVENT_LBUTTONUP: 
        print('왼쪽 버튼이 떼졌어요: %d, %d' % (x, y))
    elif event == cv2.EVENT_MOUSEMOVE:
        print('마우스가 이동하고 있어요: %d, %d' % (x, y))
        if flags:  # 왼쪽 버튼이 눌린 상태에서 이동
            print('드래그 중이예요')
            cv2.line(img, (oldx, oldy), (x, y), (255, 51, 255), 3) # 선 그리기
            cv2.imshow('img', img)
            oldx, oldy = x, y

img = np.ones((500, 500, 3), dtype=np.uint8) * 255  # 흰색 배경 이미지 생성
cv2.namedWindow('img')

cv2.rectangle(img, (50, 200, 150, 100), (0, 255, 0), 3)
# 왼쪽 위: (50, 200)
# 오른쪽 아래: (200, 300) → 가로 150, 세로 100
# 초록색 선 ((0, 255, 0)) 굵기 3으로 테두리만 그림
cv2.rectangle(img, (300, 200, 150, 100), (0, 255, 0), -1) # -1 : 색상 채워짐

cv2.circle(img, (150, 400), 50, (255, 0, 0), 3)  # 원 그리기
# 중심 좌표: (150, 400)
# 반지름: 50
# 색상: 파란색 ((255, 0, 0))
# 굵기: 3

cv2.putText(img, 'Hello', (50, 300), cv2.FONT_HERSHEY_DUPLEX, 0.7, (0, 0, 0))
# 'Hello': 출력할 문자열
# (50, 300): 시작 좌표 (왼쪽 아래 기준)
# cv2.FONT_HERSHEY_DUPLEX: 폰트 스타일
# 0.7: 폰트 크기 (scale)
# (0, 0, 0): 글자 색 (검정)

cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)
cv2.waitKey()


6_video_in.py

import cv2
import sys

cap = cv2.VideoCapture('./movies/232538_tiny.mp4')

if not cap.isOpened():
    print('동영상을 불러올 수 없음')
    sys.exit()

print('동영상을 불러올 수 있음')

width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
print(width)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
print(height)

frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)
print(frame_count) # 총 프레임 수

fps = cap.get(cv2.CAP_PROP_FPS)
print(fps) # 초당 프레임 수

while True:
    ret, frame = cap.read()  # 프레임 읽기(ret: 성공 여부, frame: 프레임 이미지)
    if not ret:  # 프레임을 더 이상 읽을 수 없으면 종료
        break
    cv2.imshow('frame', frame)  # 프레임 표시
    if cv2.waitKey(10) == 27:  # 10/1000 초. 0.01초동안 계속 돔. # ESC 키를 누르면 종료
        break

cap.release()  # 비디오 캡처 객체 해제

영상이 출력된다.

픽사베이 사이트에서 영상을 다운 받을 수 있다.


7_camera_in.py

import cv2
import sys

cap = cv2.VideoCapture(0)  # 0은 기본 카메라를 의미
if not cap.isOpened():
    print('카메라를 열 수 없음')
    sys.exit()

print('카메라 연결 성공')

width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
print(width)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
print(height)
fps = cap.get(cv2.CAP_PROP_FPS)
print(fps) # 초당 프레임 수

while True:
    ret, frame = cap.read()  # 프레임 읽기(ret: 성공 여부, frame: 프레임 이미지)
    if not ret:  # 프레임을 더 이상 읽을 수 없으면 종료
        break
    cv2.imshow('frame', frame)  # 프레임 표시
    if cv2.waitKey(10) == 27:  # 10/1000 초. 0.01초동안 계속 돔. # ESC 키를 누르면 종료
        break

cap.release()  # 비디오 캡처 객체 해제

웹캠이 설치되어 있는 컴퓨터라면, 웹캠을 통해 영상이 출력되어 나온다.
웹캠이 설치되어 있지 않다면, 다음과 같이 카메라를 열 수 없다는 메시지가 출력된다.


8_video_out.py

import cv2

cap1 = cv2.VideoCapture('./movies/232538_tiny.mp4')
cap2 = cv2.VideoCapture('./movies/276624_tiny.mp4')

# 두 비디오를 합치려면 두 비디오의 해상도가 같아야 한다.

w = int(cap1.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_count1 = int(cap1.get(cv2.CAP_PROP_FRAME_COUNT))
frame_count2 = int(cap2.get(cv2.CAP_PROP_FRAME_COUNT))
fps1 = cap1.get(cv2.CAP_PROP_FPS)
fps2 = cap2.get(cv2.CAP_PROP_FPS)

print(w, h)
print(frame_count1, frame_count2)
print(fps1, fps2)

fourcc = cv2.VideoWriter.fourcc(*'DIVX')
out = cv2.VideoWriter('mix.avi', fourcc, fps1, (w, h))

for i in range(frame_count1):
    ret, frame = cap1.read()
    cv2.imshow('output', frame)
    out.write(frame)
    if cv2.waitKey(10) == 27:  # ESC 키를 누르면 종료
        break

for i in range(frame_count2):
    ret, frame = cap2.read()
    cv2.imshow('output', frame)
    out.write(frame)
    if cv2.waitKey(10) == 27:  # ESC 키를 누르면 종료
        break

cap1.release()
cap2.release() 
out.release()

두 개의 영상이 연이어 나온다.

이후 mix.avi 라는 파일이 생성되어, 두 개의 영상이 합쳐진 결과물이 하나의 파일로 생성된다.


FourCC (Four Character Code)

  • 비디오 파일에서 압축 형식을 나타내는 4글자의 코드
    예: 'DIVX', 'XVID', 'MJPG', 'MP4V', 'X264' 등

비디오를 저장할 때 어떤 압축 방식(코덱)으로 저장할지 지정해줘야 하는데,
그것을 이 fourcc를 통해 설정한다.

자주 쓰는 FourCC 코드

코드설명파일 확장자
'DIVX'DivX MPEG-4.avi
'XVID'XviD MPEG-4.avi
'MJPG'Motion JPEG.avi
'MP4V'MPEG-4 Video.mp4
'X264'H.264 (설치 필요).mp4

코드설명
cap.release()비디오 입력 (예: 카메라, 파일) 닫기
out.release()비디오 출력 (파일 저장 객체) 닫기

안 해주면 웹캠이 다른 앱에서 안 열리거나, 시스템 리소스를 계속 차지할 수 있고,
저장 중인 영상 파일이 깨지거나, 재생이 안 될 수도 있다.


9_camera_out.py

import cv2

cap = cv2.VideoCapture(0)  # 0은 기본 카메라를 의미
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)

fourcc = cv2.VideoWriter.fourcc(*'DIVX')
out = cv2.VideoWriter('camera.avi', fourcc, fps, (w, h))

while True:
    ret, frame = cap.read()  # 프레임 읽기(ret: 성공 여부, frame: 프레임 이미지)
    if not ret:  # 프레임을 더 이상 읽을 수 없으면 종료
        break
    cv2.imshow('frame', frame)  # 프레임 표시
    out.write(frame)  # 프레임을 비디오 파일에 저장
    if cv2.waitKey(10) == 27:  # 10/1000 초. ESC 키를 누르면 종료
        break

cap.release()
out.release()

웹캠을 통해 영상을 찍을 수 있다.
이후 camera.avi 라는 파일이 생성되어 웹캠으로 찍은 영상이 저장된다.


10_add.py

import cv2

img1 = cv2.imread('./images/dog.bmp', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('./images/dog.bmp')  # 기본적으로 컬러 이미지로 읽기(B, G, R 순서)

dst1 = cv2.add(img1, 100)  # 그레이스케일 이미지에 100 더하기
dst2 = cv2.add(img2, (100, 100, 100))  # 컬러 이미지에 (100, 100, 100) 더하기
dst3 = cv2.subtract(img1, 100)  # 그레이스케일 이미지에서 100 빼기
dst4 = cv2.multiply(img1, 10)
dst5 = cv2.divide(img1, 10)  # 그레이스케일 이미지에서 10으로 나누기

cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.imshow('dst3', dst3)
cv2.imshow('dst4', dst4)
cv2.imshow('dst5', dst5)
cv2.waitKey()


11_blending.py

import cv2
import matplotlib.pyplot as plt

img1 = cv2.imread('./images/man.jpg')
img2 = cv2.imread('./images/turkey.jpg')

# 0~255 값을 벗어나면 256으로 나눈 나머지가 됨
dst1 = img1 + img2

# 0~255 값을 벗어나도 0 또는 255 값으로 보정
dst2 = cv2.add(img1, img2)

# cv2.imshow('dst1', dst1)
# cv2.imshow('dst2', dst2)
# cv2.waitKey()

img = {'img1': img1, 'img2': img2, 'dst1': dst1, 'dst2': dst2}
for i, (k, v) in enumerate(img.items()):
    plt.subplot(2, 2, i + 1)
    plt.imshow(v[:, :, ::-1])
    plt.title(k)
plt.show()

v[:, :, ::-1]
v는 3차원 이미지 배열 (Height x Width x Channels)
v[:, :, ::-1]는 채널 축(axis=2)을 역순으로 뒤집는 표현이다.
::는 슬라이싱, ::-1은 거꾸로 뒤집기
BGR → RGB로 바뀐다.


12_arithmetic.py

import cv2
import matplotlib.pyplot as plt

img1 = cv2.imread('./images/dog.jpg')
img2 = cv2.imread('./images/square.bmp')

dst1 = cv2.add(img1, img2)
# 가중치 합성
# 두 이미지를 비율로 섞음
dst2 = cv2.addWeighted(img1, 0.5, img2, 0.5, 0) # 0.5, 0.5 비율로 더하고, 추가 더할 값은 0
dst3 = cv2.subtract(img1, img2)
# 절대 차이
# 두 이미지 간의 절대 차이값: abs(img1(x, y) - img2(x, y))
# 예) img1 = 80, img2 = 100 = abs(-20) = 20
dst4 = cv2.absdiff(img1, img2)

img = {'dst1': dst1, 'dst2': dst2, 'dst3': dst3, 'dst4': dst4}
for i, (k, v) in enumerate(img.items()):
    plt.subplot(2, 2, i + 1)
    plt.imshow(v[:, :, ::-1])
    plt.title(k)
plt.show()


13_hist.py

import cv2
import matplotlib.pyplot as plt

img1 = cv2.imread('./images/candies.png', cv2.IMREAD_GRAYSCALE)

# 히스토그램
# 이미지 히스토그램: 밝기(또는 색상) 값의 분포를 그래프로 표현
# 어떤 픽셀이 밝기 0(검정)인지 255(흰색)인지, 각 값이 몇 개나 있는지를 확인
# images : 대상 이미지 리스트
# channel : 분석할 채널 번호(B:0, G:1, R:2)
# mask : 분석할 영역 마스크(None: 전체)
# histSize : 히스토그램의 빈 개수
# ranges : 값의 범위(0~255)
hist1 = cv2.calcHist([img1], [0], None, [256], [0, 255])

plt.figure(figsize = (10, 4))
plt.subplot(1, 2, 1)
plt.plot(hist1, color='gray')

img2 = cv2.imread('./images/candies.png')
print('shape: ', img2.shape)
print('dtype: ', img2.dtype)

'''
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
'''
colors = ['b', 'g', 'r']
channels = cv2.split(img2)
plt.subplot(1, 2, 2)
for ch, color in zip(channels, colors):
    hist = cv2.calcHist([ch], [0], None, [256], [0, 255])
    plt.plot(hist, color=color, label=color.upper())

b, g, r = cv2.split(img2)

cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('b', b)
cv2.imshow('g', g)
cv2.imshow('r', r)
plt.plot(hist1)
plt.show()

cv2.waitKey()

이미지들을 보면,
b 이미지 : 파란색 계열이 밝게 나타난 것을 확인할 수 있고,
g 이미지 : 노랑~초록색 계열이 밝게 나타난 것을 확인할 수 있다.
r 이미지 : 빨간색 계열이 밝게 나타난 것을 확인할 수 있다.


14_equalize.py

import cv2
import matplotlib.pyplot as plt

img1 = cv2.imread('./images/Hawkes.jpg', cv2.IMREAD_GRAYSCALE)
# 히스토그램 평활화
# 이미지의 전체 밝기 분포를 고르게 퍼뜨려 명암 대비를 향상시키는 기법
dst1 = cv2.equalizeHist(img1)

img2 = cv2.imread('./images/field.bmp')
# YCrCb 색 공간
# Y : 밝기(명도), Cr : 빨강 계열 색상 정보, Cb : 파랑 계열 색상 정보
dst2 = cv2.cvtColor(img2, cv2.COLOR_BGR2YCrCb)
'''
ycrcb = cv2.split(dst2)
ycrcb = list(ycrcb)
# print(ycrcb)
ycrcb[0] = cv2.equalizeHist(ycrcb[0])  # Y 채널에 대해서만 히스토그램 평활화
dst2 = cv2.merge(ycrcb)
dst2 = cv2.cvtColor(dst2, cv2.COLOR_YCrCb2BGR)
'''
dst2[:, :, 0] = cv2.equalizeHist(dst2[:, :, 0])
dst2 = cv2.cvtColor(dst2, cv2.COLOR_YCrCb2BGR) 

# img1: 원본 이미지 또는 배열
# None: 출력 배열(None이면 새로 생성)
# 0: 정규화 후 최소값
# 255: 정규화 후 최대값
# cv2.NORM_MINMAX: 정규화 방식
dst3 = cv2.normalize(img1, None, 0, 255, cv2.NORM_MINMAX)

hist1 = cv2.calcHist([img1], [0], None, [256], [0, 255])
hist2 = cv2.calcHist([dst1], [0], None, [256], [0, 255])
hist3 = cv2.calcHist([dst3], [0], None, [256], [0, 255])

hists = {'hist1': hist1, 'hist2': hist2, 'hist3': hist3}

cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.imshow('dst3', dst3)

plt.figure(figsize=(12, 8))
for i, (k, v) in enumerate(hists.items()):
    plt.subplot(1, 3, i + 1)
    plt.title(k)
    plt.plot(v)
plt.show()

cv2.waitKey()


15_hsv.py

import cv2

# HSV
# 색을 표현하는 한 방식으로 이미지 처리와 색상 추출에서 매우 자주 사용되는 장점을 갖음
# H: 색상 (빨강, 초록, 파랑 등, 0~179), S: 채도(색의 선명함, 0~255), V: 명도(밝기, 0~255)

img = cv2.imread('./images/candies.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

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

'''
색상 H 값 (OpenCV 기준)     
빨강 (Red) 0 또는 179   
주황 (Orange) 10~20   
노랑 (Yellow) 20~30   
초록 (Green) 40~85   
파랑 (Blue) 90~130   
> 보라 (Violet) 130~160

채도: 150 ~ 255
명도: 0 ~ 255
'''

dst = cv2.inRange(hsv, (90, 150, 0), (130, 255, 255))

# copyTo
# 마스크를 이용한 선택적 복사
temp = cv2.copyTo(airplane, mask)
cv2.copyTo(airplane, mask, field) # 마스크를 이용하여 field에 airplane을 복사

cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.imshow('temp', temp)
cv2.imshow('field', field)
cv2.waitKey()

cv2.copyTo(src, mask, dst)

매개변수설명
src복사할 원본 이미지 (source)
mask복사할 위치를 지정하는 마스크 (0 또는 255로 구성된 단일 채널 이미지)
dst복사 대상 이미지 (destination) — 이곳에 src의 픽셀이 복사됨

16_chromakey.py

import cv2

cap1 = cv2.VideoCapture('./movies/woman.mp4')
cap2 = cv2.VideoCapture('./movies/sea.mp4')

w = int(cap1.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))

frame_count1 = int(cap1.get(cv2.CAP_PROP_FRAME_COUNT))
frame_count2 = int(cap2.get(cv2.CAP_PROP_FRAME_COUNT))

fps = int(cap1.get(cv2.CAP_PROP_FPS))

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)
    if cv2.waitKey(10) == ord(' '):
        cv2.waitKey()
    elif cv2.waitKey(10) == 27:  # ESC 키를 누르면 종료
        break

cap1.release()
cap2.release()

첫 번째 cv2.waitKey(10) → 스페이스바인지 확인 → 영상 멈춤
두 번째 cv2.waitKey(10) → ESC 키인지 확인 → 영상 종료

profile
The light shines in the darkness.

0개의 댓글