Language - Python(Opencv)

Python Opencv - #8, 키보드 & 마우스 이벤트 처리

KimTory 2021. 11. 22. 17:45

▶ 키보드 이벤트 처리하기

 이번 포스팅에서는 키보드 이벤트 처리하기를 알아보고 응용으로 'I' 키를 누르면 영상이 반전되는 것을 해보겠습니다.

 

→ 키보드 입력 대기 함수

 cv2.waitkey 함수로 키보드 이벤트를 처리할 수 있습니다.

 

[명령어 설명]

cv2.waitKey(delay=None) -> retval

 

• delay: 밀리초 단위 대기 시간. delay  0 이면 무한히 기다림. 기본값은 0

• retval: 눌린 키 값(ASCII code). 키가 눌리지 않으면 -1.

 

[참고 사항]

▪ cv2.waitKey() 함수는 OpenCV 창이 하나라도 있을 때 동작합니다.

▪ 특정 키 입력을 확인하려면 ord() 함수를 이용합니다.

▪ 주요 특수키 코드: 27(ESC), 13(ENTER), 9(TAB)

 

[예시 코드]

while True: # 무한 루프
    if cv2.waitKey() == ord('q'): # q를 누르면 종료
        break

 

 영상이 출력되면 q를 눌렀을 때 종료하는 코드입니다.

 

▶ 특수키 입력 처리하는 방법

 cv2.waitKey()는 일반적인 키보드를 처리할 수 있지만 특수 키를 처리하지 못합니다.

 cv2.waitKeyEX() 함수를 이용하면 방향키, 함수키와 같은 특수 키를 처리할 수 있습니다.

 

 

▶ 키보드에서 'i' 또는 'I' 키를 누르면 영상을 반전시키기

 cv2.waitKey 함수를 이용해서 'i', 'I' 키를 누르면 영상을 반전시키도록 해보겠습니다.

 

[코드]

# 영상을 흑백 영상으로 불러옵니다.
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 또는 I 누르면 영상 반전
        img = ~img               # 영상 반전, 그레이스케일 영상에만 가능
        cv2.imshow('image', img) # 반전된 영상 출력
    elif keycode == 27:          # ESC 누를 시 종료
        break

# 모든 창 닫기
cv2.destroyAllWindows()

 

 

 출력된 영상에서 i 를 누르면 반전된 영상이 출력됩니다.

 다시 i를 누르면 반전이 되어 기본 영상으로 되돌아갑니다.

 


마우스 이벤트 처리하기

 마우스 이벤트 처리하는 방법을 알아보고 마우스를 이용해 그림을 그려보도록 하겠습니다.

 

→ 마우스 이벤트 콜백함수 등록 함수 - cv2.setMouseCallback

 마우스 이벤트가 입력되면 사전에 작성한 함수를 불러와서 작동시킵니다.

 

[함수 설명]

cv2.setMouseCallback(windowName, onMouse, param=None) -> None

 

• windowName: 마우스 이벤트 처리를 수행할 창 이름

• onMouse: 마우스 이벤트 처리를 위한 콜백 함수 이름. 

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

 

[예시 코드]

# 윈도우 창
cv2.namedWindow('image')

# 마우스 입력, namedWIndow or imshow가 실행되어 창이 떠있는 상태에서만 사용가능
# 마우스 이벤트가 발생하면 on_mouse 함수 실행
cv2.setMouseCallback('image', on_mouse, img)

 

→ 마우스 이벤트 콜백함수 - onMouse

 마우스 입력 값에 따라 어떤 동작을 실행할 것인지 지정하는 함수입니다.

 지정해둔 함수를 cv2.setMouseCallback함수로 등록해서 사용할 수 있습니다.

 

[함수 설명]

onMouse(event, x, y, flags, param) -> None

 

• event: 마우스 이벤트 종류. cv2.EVENT_로 시작하는 상수.

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

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

• flags: 마우스 이벤트 발생 시 상태. cv2.EVENT_FLAG_로 시작하는 상수

• param: cv2.setMouseCallback() 함수에서 설정한 데이터

 

[예시 코드]

def on_mouse(event, x, y, flags, param):
    # event는 마우스 동작 상수값, 클릭, 이동 등등
    # x, y는 내가 띄운 창을 기준으로 좌측 상단점이 0,0이 됌
    # flags는 마우스 이벤트가 발생할 때 키보드 또는 마우스 상태를 의미, Shif+마우스 등 설정가능
    # param은 영상이룻도 있도 전달하고 싶은 데이타, 안쓰더라도 넣어줘야함

    global oldx, oldy 함수 밖에 있는 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: # ==를 쓰면 다른 키도 입력되었을 때 작동안하므로 &(and) 사용
            # cv2.circle(img, (x, y), 5, (0, 255, 0), -1) # 단점이 빠르게 움직이면 끊김

            # circle은 끊기므로 line 이용
            # 마우스 클릭한 좌표에서 시작해서 마우스 좌표까지 그림
            cv2.line(img, (oldx, oldy), (x, y), (0, 0, 255), 4, cv2.LINE_AA)
            cv2.imshow('image', img)
            oldx, oldy = x, y # 그림을 그리고 또 좌표 저장

 

 이처럼 마우스를 이용해 그림을 그릴 수 있는 함수를 만들었습니다.

 함수 이름은 onMouse가 아니어도 됩니다.

 

▶ 마우스 이벤트 처리 함수의 event, flags 인자

 onMouse에 입력값은 event, flags 인자에 대해 알아보겠습니다.

 

 

 

4. 마우스를 이용해 그리기

 앞에서 열거한 코드들을 조합하여 마우스를 이용해 그림을 그려보겠습니다.

 

[코드]

import sys
import numpy as np
import cv2


oldx = oldy = -1 # 좌표 기본값 설정

# 내가 만든 마우스 함수를 실행시켜줘


def on_mouse(event, x, y, flags, param):
    # event는 마우스 동작 상수값, 클릭, 이동 등등
    # x, y는 내가 띄운 창을 기준으로 좌측 상단점이 0,0이 됌
    # flags는 마우스 이벤트가 발생할 때 키보드 또는 마우스 상태를 의미, Shif+마우스 등 설정가능
    # param은 영상이룻도 있도 전달하고 싶은 데이타, 안쓰더라도 넣어줘야함

    global oldx, oldy # 밖에 있는 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: # ==를 쓰면 다른 키도 입력되었을 때 작동안하므로 &(and) 사용
            # cv2.circle(img, (x, y), 5, (0, 255, 0), -1) # 단점이 빠르게 움직이면 끊김

            # circle은 끊기므로 line 이용
            # 마우스 클릭한 좌표에서 시작해서 마우스 좌표까지 그림
            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')

# 마우스 입력, namedWIndow or imshow가 실행되어 창이 떠있는 상태에서만 사용가능
# 마우스 이벤트가 발생하면 on_mouse 함수 실행
cv2.setMouseCallback('image', on_mouse, img)


# 영상 출력
cv2.imshow('image', img)
cv2.waitKey()

cv2.destroyAllWindows()

 

[결과]

출력된 좌표값