귀퉁이 서재

OpenCV - 5. 창 관리 및 이벤트 처리 본문

OpenCV

OpenCV - 5. 창 관리 및 이벤트 처리

Baek Kyun Shin 2020. 9. 13. 19:48

이번 포스팅에서는 창을 관리하는 방법과 키보드 및 마우스 이벤트를 처리하는 방법을 알아보겠습니다. 이번 글 역시 파이썬으로 만드는 OpenCV 프로젝트(이세우 저)를 정리한 것입니다.

코드: https://github.com/BaekKyunShin/OpenCV_Project_Python/tree/master/02.interface

창 관리

우선, 창 관리를 하는 5가지 함수에 대해 알아보겠습니다.

cv2.namedWindow(winname, flags) 함수는 winname이라는 이름을 갖는 창을 생성해줍니다. 파라미터는 아래와 같습니다.

winname: 창 구분자로 활용될 창 이름
flags: 창 옵션 (cv2.WINDOW_NORMAL: 사용자가 창 크기를 조정할 수 있음, cv2.WINDOW_AUTOSIZE: 이미지와 동일한 크기로 창 크기를 재조정할 수 없음)

cv2.moveWindow(winname, x, y) 함수를 호출하면 원하는 위치로 창을 옮길 수 있습니다.

winname: 위치를 변경할 창 이름
x, y: 변경할 위치 (x, y 좌표)

cv2.resizeWindow(winname, width, hegith) 함수는 winname 창의 크기를 (width, height) 크기로 변경해줍니다.

cv2.destroyWindow(winname) 함수를 호출하면 winname에 해당하는 창을 닫습니다.

cv2.destroyAllwindows() 함수는 열린 모든 창을 닫습니다.

아래 예시는 위 5개의 함수를 활용하는 코드입니다. 'origin', 'gray'라는 창을 생성하여 위치를 옮기고 크기를 조정하고 창을 닫는 것을 보여줍니다. 주석을 참고해주시기 바랍니다.

# 창 관리 (win.py)

import cv2

file_path = '../img/yeosu.jpg'
img = cv2.imread(file_path)                            # 이미지를 기본 값으로 읽기
img_gray = cv2.imread(file_path, cv2.IMREAD_GRAYSCALE) # 이미지를 그레이 스케일로 읽기

cv2.namedWindow('origin')                               # origin 이름으로 창 생성
cv2.namedWindow('gray', cv2.WINDOW_NORMAL)              # gray 이름으로 창 생성
cv2.imshow('origin', img)                               # origin 창에 이미지 표시
cv2.imshow('gray', img_gray)                            # gray 창에 이미지 표시

cv2.moveWindow('origin', 0, 0)                          # 창 위치 변경
cv2.moveWindow('gray', 100, 100)                        # 창 위치 변경

cv2.waitKey(0)                                          # 아무키나 누르면
cv2.resizeWindow('origin', 200, 200)                    # 창 크기 변경 (변경 안됨)
cv2.resizeWindow('gray', 100, 100)                      # 창 크기 변경 (변경 됨))

cv2.waitKey(0)                                          # 아무키나 누르면
cv2.destroyWindow("gray")                               # gray 창 닫기

cv2.waitKey(0)                                          # 아무키나 누르면
cv2.destroyAllWindows()                                 # 모든 창 닫기

키보드 이벤트 처리

이제 키보드 이벤트를 처리하는 방법에 대해 살펴보겠습니다. 앞서 이미 사용했던 cv2.waitKey(delay) 함수는 delay 밀리초만큼 프로그램을 멈추고 있다가 키보드의 눌린 키에 대응하는 값을 반환합니다. dalay 시간만큼 키보드 입력이 없다면 -1을 반환합니다. delay의 default값은 0인데, 이 경우 키보드 입력이 있을 때까지 영원히 대기합니다. 

아래 코드는 화면에 여수 밤바다 이미지를 나타내고, 키보드의 h, j, k, l 키를 누르면 이미지가 왼쪽, 위쪽, 아래쪽, 오른쪽으로 10픽셀씩 이동합니다. esc나 q를 누르면 창이 종료됩니다.

# 키 이벤트 처리 (event_key.py)

import cv2

img_file = "../img/yeosu.jpg" 
img = cv2.imread(img_file) 
title = 'IMG'                   # 창 이름 
x, y = 100, 100                 # 최초 좌표

while True:
    cv2.imshow(title, img)
    cv2.moveWindow(title, x, y)
    key = cv2.waitKey(0) & 0xFF # 키보드 입력을 무한 대기, 8비트 마스크처리
    print(key, chr(key))        # 키보드 입력 값,  문자 값 출력
    if key == ord('h'):         # 'h' 키 이면 좌로 이동
        x -= 10
    elif key == ord('j'):       # 'j' 키 이면 아래로 이동
        y += 10
    elif key == ord('k'):       # 'k' 키 이면 위로 이동
        y -= 10
    elif key == ord('l'):       # 'l' 키 이면 오른쪽으로 이동
        x += 10
    elif key == ord('q') or key == 27: # 'q' 이거나 'esc' 이면 종료
        break
        cv2.destroyAllWindows()
    cv2.moveWindow(title, x, y )   # 새로운 좌표로 창 이동
        

마우스 이벤트 처리

마우스 이벤트는 cv2.setMouseCallback(windowName, onMouse, param=None) 함수로 처리할 수 있습니다. 파라미터는 다음과 같습니다.

windowName: 이벤트를 등록할 윈도우 이름
onMouse: 이벤트 처리를 위해 미리 선언해 놓은 마우스 콜백 함수

콜백 함수인 onMouse(evnet, x, y, flags, param) 함수는 마우스의 이벤트와 마우스 좌표를 처리합니다. 여기서 event에는 마우스의 움직임, 왼쪽 버튼 누름, 왼쪽 버튼 뗌, 오른쪽 버튼 누름, 오른쪽 버튼 뗌, 왼쪽 버튼 더블 클릭, 휠 스크롤 등이 있습니다. cv2.EVENT_로 시작하는 12가지 이벤트가 있습니다. (ex. cv2.EVENT_MOSEMOVE: 마우스 움직임, cv2.EVENT_LBUTTONDOWN: 왼쪽 버튼 누름) flags는 컨트롤, 쉬프트, 알트와 같은 키를 함께 누른 상태처럼 이벤트를 처리하게 합니다. flags와 param을 사용하지 않는다 하더라도 콜백 함수 선언부에 flags와 param을 기재해야 합니다. 그렇지 않으면 오류가 발생합니다. 

아래 코드를 실행한 뒤 마우스 클릭을 하면 화면에 까만 원을 그릴 수 있습니다.

# 마우스 이벤트로 원 그리기 (event_mouse_circle.py)

import cv2

title = 'mouse event'                   # 창 제목
img = cv2.imread('../img/blank_500.jpg') # 백색 이미지 읽기
cv2.imshow(title, img)                  # 백색 이미지 표시

def onMouse(event, x, y, flags, param): # 아무스 콜백 함수 구현 ---①
    print(event, x, y, )                # 파라미터 출력
    if event == cv2.EVENT_LBUTTONDOWN:  # 왼쪽 버튼 누름인 경우 ---②
        cv2.circle(img, (x,y), 30, (0,0,0), -1) # 지름 30 크기의 검은색 원을 해당 좌표에 그림
        cv2.imshow(title, img)          # 그려진 이미지를 다시 표시 ---③

cv2.setMouseCallback(title, onMouse)    # 마우스 콜백 함수를 GUI 윈도우에 등록 ---④

while True:
    if cv2.waitKey(0) & 0xFF == 27:     # esc로 종료
        break
cv2.destroyAllWindows()

 

 

 

아래 코드를 통해 flags를 활용해보겠습니다. flag에 전달되는 인자는 다음과 같습니다.

cv2.EVENT_FLAG_CTRLKEY(8): Ctrl 키를 누름
cv2.EVENT_FLAG_SHIFTKEY(16): Shift 키를 누름
cv2.EVENT_FLAG_ALTKEY(32): Alt 키를 누름

마우스 클릭만 했을 때는 위 코드처럼 검정 원이 그려집니다. 컨트롤과 쉬프트 키를 동시에 누르고 마우스 클릭을 하면 초록색 원이, 컨트롤 키만 누르고 마우스 클릭을 하면 빨간색 원이, 쉬프트 키만 누르고 마우스 클릭을 하면 파란색 원이 그려집니다.

# flags를 활용하여 원 그리기 (event_mouse_circle_flag.py)

import cv2

title = 'mouse event'                   # 창 제목
img = cv2.imread('../img/blank_500.jpg') # 백색 이미지 읽기
cv2.imshow(title, img)                  # 백색 이미지 표시

colors = {'black':(0,0,0),
         'red' : (0,0,255),
         'blue':(255,0,0),
         'green': (0,255,0) } # 색상 미리 정의

def onMouse(event, x, y, flags, param): # 아무스 콜백 함수 구현 ---①
    print(event, x, y, flags)                # 파라미터 출력
    color = colors['black']
    if event == cv2.EVENT_LBUTTONDOWN:  # 왼쪽 버튼 누름인 경우 ---②
        # 컨트롤키와 쉬프트 키를 모두 누른 경우
        if flags & cv2.EVENT_FLAG_CTRLKEY and flags & cv2.EVENT_FLAG_SHIFTKEY : 
            color = colors['green']
        elif flags & cv2.EVENT_FLAG_SHIFTKEY : # 쉬프트 키를 누른 경우
            color = colors['blue']
        elif flags & cv2.EVENT_FLAG_CTRLKEY : # 컨트롤 키를 누른 경우
            color = colors['red']
        # 지름 30 크기의 검은색 원을 해당 좌표에 그림
        cv2.circle(img, (x,y), 30, color, -1) 
        cv2.imshow(title, img)          # 그려진 이미지를 다시 표시 ---③

cv2.setMouseCallback(title, onMouse)    # 마우스 콜백 함수를 GUI 윈도우에 등록 ---④

while True:
    if cv2.waitKey(0) & 0xFF == 27:     # esc로 종료
        break
cv2.destroyAllWindows()

참고로, 컨트롤을 누르면 flags & cv2.EVENT_FLAG_CTRLKEY가 True를 반환합니다.

이상으로 창관리 및 마우스, 키보드 이벤트 처리 방법에 대해 알아봤습니다.

Comments