본문 바로가기

머신러닝,딥러닝/opencv

opencv 입문하기 4편 키보드, 마우스 이벤트(1)

이번 시간에는 opencv 에서의 키보드,마우스 이벤트에 다뤄 보겠습니다. 

 

1. 키보드 이벤트

 

● 키보드 입력 대기 

cv2.waitKey(delay=None) -> retval 

 

delau 매개변수에서 ms(밀리세컨즈) 단위 시간은 (1초=1000)입니다. 

delay <= 0 이면 무한대기인데요.

별도의 값을 입력하지 않으면 default 인 None으로 입력이 되는데 이는 무한대기를 의미합니다. 

 

특정키 입력은 ord() 함수를 활용합니다. 

'q' 를 누르면 영상의 밝기가 반전되도록 해보는 예제를 진행해보겠습니다.

 

 

 

 

 

 

위의 원본 이미지를 grayscale 한 다음에 반전을 시켜보겠습니다. 

grayscale 이미지의 ~ 표시를 붙여주면 반전이 됩니다. 

이를 활용한 위의 결과를 보여주는 코드는 아래와 같습니다. 

 

 

 

import os

import cv2

path = os.path.join('my_images', '고양이.jpg')
img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)

cv2.namedWindow('image1', cv2.WINDOW_NORMAL)
cv2.imshow('image1', img)
cv2.moveWindow('image1', 200, 200)
cv2.resizeWindow('iamge1', 700, 900)

while True:
    key = cv2.waitKey()

    if key == ord('q'):
        img = ~img
        cv2.imshow('image1', img)
    elif key == 27:
        break

cv2.destroyAllWindows()

 

 

 

두 번째 예제는 컬러 영상을 입력 받고 이를 w 버튼을 눌러서 BRG 영상을 RGB 로 바꾸고, 다시 w 를 누르면 RGB 를  BRG 으로 바꾸는 예제를 작성해보겠습니다. 

 

 

 

 

BRG 영상
RGB 영상 

코드는 아래와 같습니다. 

 

 

import os

import cv2

path = os.path.join('my_images', '고양이.jpg')
img = cv2.imread(path)

cv2.imshow('image1', img)

while True:
    key = cv2.waitKey()

    if key == ord('w'):
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        cv2.imshow('image1', img)
    elif key == 27:
        break

cv2.destroyAllWindows()

 

2. 마우스 이벤트

마우스 이벤트는 키보드 이벤트보다는 조금(?) 복잡합니다.

setMouseCallback 함수를 사용하여 특정 윈도우를 위한 콜백함수를 지정해주면 마우스 이벤트가 발생할 때마다 콜백함수가 호출됩니다. 이 말이 조금 어렵게 느껴지시는 분들이 있을까 비유를 하자면, 보통 저희가 파이썬으로 어떤 문제를 해결하려는 기능이 들어간 함수를  def main(*kwargs)처럼 만든 다음 마지막에

 

f __name__=="__main"__

    def main(*kwargs)

 

으로 불러서 사용하는거와 같은 느낌으로 이해하시면 됩니다. (느낌만을 얘기한건데, 음 저 비유 자체를 이해하는 사람이라면 콜백함수 호출해서 사용한다는 말 자체도 이해를 당연히 하겠네요...;;;)

 

● 마우스 콜백함수 등록 함수

cv2.setMouseCallback(windowName, mouse_fn, param=None)

 

windowName : 마우스 이벤트를 실행할 윈도우 이름 

onMouse 

- 마우스 이벤트 처리를 위한 콜백 함수 

마우스 이벤트 콜백함수는 아래 형식을 따릅니다.

mouse(event, x, y , flags, param)

- param: 콜백 함수에 전달할 데이터 

 

● 마우스 콜백함수 

mouse(event, x, y, flags, param)

event: 마우스 이벤트 type

x, y : 마우스 이벤트가 발생한 x, y 좌표

flag: 마우스 이벤트 발생시 상태

param: 콜백 함수에 전달할 데이터 

 

 

※ 이벤트 타입 리스트

MouseEventTypes value  설명
cv2.EVENT_MOUSEMOVE 0 마우스가 창 위에서 움직이는 경우
cv2.EVENT_LBUTTONDOWN 1 마우스 왼쪽 버튼이 눌려지는 경우
cv2.EVENT_RBUTTONDOWN 2 마우스 오른쪽 버튼이 눌려지는 경우
cv2.EVENT_MBUTTONDOWN 3 마우스 가운데 버튼이 눌려지는 경우
cv2.EVENT_LBUTTONUP 4 마우스 왼쪽 버튼이 떼어지는 경우
cv2.EVENT_RBUTTONUP 5 마우스 오른쪽 버튼이 떼어지는 경우
cv2.EVENT_MBUTTONUP 6 마우스 가운데 버튼이 떼어지는 경우
cv2.EVENT_LBUTTONDBLCLK 7 마우스 왼쪽 버튼을 더블클릭하는 경우
cv2.EVENT_RBUTTONDBLCLK 8 마우스 오른쪽 버튼을 더블클릭하는 경우
cv2.EVENT_MBUTTONDBLCLK 9 마우스 가운데 버튼을 더블클릭 하는 경우
cv2.EVENT_MOUSEWHEEL 10 마우스 휠을 앞뒤로 돌리는 경우 

 

※ 이벤트 Flag 타입 리스트

MouseEventFlags value 설명
cv2.EVENT_FLAG_LBUTTON 1 마우스 왼쪽 버튼이 눌려져 있음
cv2.EVENT_FLAG_RBUTTON 2 마우스 오른쪽 버튼이 눌려져 있음
cv2.EVENT_FLAG_MBUTTON 2 마우스 가운데 버튼이 눌려져 있음
cv2.EVENT_FLAG_CTRLKEY 8 CTRL 키가 눌려져 있음
cv2.EVENT_FLAG_SHIFTKEY 16 SHIFT 키가 눌려져 있음
cv2.EVENT_FLAG_ALTKEY 32 ALT 키가 눌려져 있음

 

 

 

자, 이제 이를 활용하여 영상을 마우스로 드레그한 영역을 grayscale 로 변환해주는 새로운 윈도우에 띄우는 프로그램을 만들어보겠습니다. 우선, 결과를 먼저 보겠습니다. 

 

좌측의 원본 이미지에서 마우스로 드래그하면 우측에 새로운 윈도우 창이 나오면서 해당 부분만 grayscale 로 바꿔주는 걸 확인할 수 있습니다. 

 

 

 

 

'''영상을 마우스로 드레그한 영역을 grayscale 로 변환하여 새로운 윈도우에 띄우는 프로그램 개발'''

import os

import cv2


# 마우스 왼쪽 버튼 상태 체크를 위한 변수
mouse_is_pressing = False
# 최초로 마우스 왼쪽 버튼 누른 위치를 저장하기 위해 사용
start_x, start_y = -1, -1


def mouse_callback(event, x, y, flags, param):
    global mouse_is_pressing, start_x, start_y

    img_result = img_color.copy()

    # 마우스 왼쪽 버튼 누를 시 발생 이벤트
    if event == cv2.EVENT_LBUTTONDOWN:

        mouse_is_pressing = True
        start_x, start_y = x, y
        cv2.circle(img_result, (x, y), 10, (0, 0, 255), -1)
        cv2.imshow('img_color', img_result)

    # 마우스 이동시 발생하는 이벤트
    elif event == cv2.EVENT_MOUSEMOVE:
        if mouse_is_pressing:
            # 마우스 이동하는 조건인 true 동안 rectangle 그리기
            cv2.rectangle(img_result, (start_x, start_y),
                          (x, y), (0, 0, 255), -1)
            cv2.imshow('img_color', img_result)

    # 마우스 왼쪽 버튼에서 손을 떼면 발생하는 이벤트
    elif event == cv2.EVENT_LBUTTONUP:
        mouse_is_pressing = False

        # min, max가 들어가는 이유는 클릭을 한 뒤에 마우스의 이동방향이 상하좌우 아무 방향으로든 향할 수 있다. 이 때, grayscale 이 적용되는 일부 픽셀을 선택하고 추출해서 변수화.
        img_cat = img_color[min(start_y, y):max(start_y, y), min(start_x, x): max(start_x, x)]
        img_cat = cv2.cvtColor(img_cat, cv2.COLOR_BGR2GRAY)
        img_cat = cv2.cvtColor(img_cat, cv2.COLOR_GRAY2BGR)

        img_result[min(start_y, y):max(start_y, y), min(start_x, x): max(start_x, x)] = img_cat

        # 그림에 대한 세가지 객체가 존재합니다. img_color(원본), img_result(원본에서 일부 픽셀에 grayscale 적용되어 변한 사본), img_cat (gray scale 적용된 일부 픽셀)
        cv2.imshow('img_result', img_result)
        cv2.imshow('img_cat', img_cat)


path = os.path.join('my_images', '고양이.jpg')
img_color = cv2.imread(path)

# 최초의 영상
cv2.imshow('img_color', img_color)

cv2.setMouseCallback('img_color', mouse_callback)

cv2.waitKey()
cv2.destroyAllWindows()

 

 

 

위 코드를 실행하면 앞에 나온 보여준 이미지 2개만 나오지 않고, 3개가 나오는데 이는 공부하시는 분의 이해를 돕고자 그렇게 바꿨습니다. 잠시 위 코드 실행 결과를 보여주면, 

 

마우스 클릭과 드래그 할때는 좌측의 원본 'img_color' 이미지에 원과 직사각형이 그려지고 마우스 왼쪽 버튼에서 손을 떼면 가운데 이미지와 오른쪽 이미지가 생성됩니다. 

img_color 가 윈도우에서 바로 변하게 하려면 왼쪽버튼에서 손을 떼는 조건문이 있는 부분에서 imshow 부분을 바꿔주면 됩니다.