[opencv-python] 도형 그리기 with 마우스

2019. 7. 2. 00:13Python-이론/python-opencv

이전 글에서 단순히 코드를 사용하여 도형을 그려 보았습니다. 이번에는 마우스 이벤트를 사용하여 도형을 그려보겠습니다. 

 

코드 

import numpy as np
import cv2
from random import shuffle

b = [i for i in range(256)]
g = [i for i in range(256)]
r = [i for i in range(256)]


def onMouse(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDBLCLK:
        shuffle(b), shuffle(g), shuffle(r)
        cv2.circle(param, (x, y), 50, (b[0], g[0], r[0]), -1)


def mouseBrush():
    img = np.zeros((512, 512, 3), np.uint8)
    cv2.namedWindow("making Figure")
    cv2.setMouseCallback("making Figure", onMouse, param=img)

    while True:
        cv2.imshow("making Figure", img)
        k = cv2.waitKey(1) & 0xFF

        if k == 27:
            break

    cv2.destroyAllWindows()


mouseBrush()

코드 설명

onMouse와 라이브러리 사이에 있는 변수

그 사이에 있는 변수들은 전역으로 사용하기 위해서 작성해주었습니다. 

 

mouseBrush 함수 안에서

setMouseCallBack 함수를 제외하고는 나머지 코드들은 이전에 한 코드와 동일하기 때문에 생략하겠습니다. 

 

setMouseCallBack

첫 인자에 윈도우 이름 (무조건 지정한 윈도우 이름과 동일해야한다.) 두번째인자는 함수를 등록해준다. 이 함수에 파라미터는 event, x, y, flags, param으로 해준다. mouse이벤트가 발생하면 자동으로 넘어가지는 것 같다. 

 

onMouse 함수안에서

마우스 이벤트가 발생하면 setMouseCallBack에 의해 자동으로 실행되며 함수 안에서는 shuffle을 통해 random으로 색을 지정하여 원을 그려준다. 

결과

추가로 마우스로 드래그를 통해서 원이랑 직사각형을 그리는 예제를 만들어 보겠습니다. 

 

코드

import numpy as np
import cv2
from random import shuffle
import math

mode, drawing = True, False
ix, iy = -1, -1
B = [i for i in range(256)]
G = [i for i in range(256)]
R = [i for i in range(256)]


def onMouse(event, x, y, flags, param):
    global ix, iy, drawing, mode, B, G, R

    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        ix, iy = x, y
        shuffle(B), shuffle(G), shuffle(R)

    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing:
            if mode:
                cv2.rectangle(param, (ix, iy), (x, y), (B[0], G[0], R[0]), -1)
            else:
                r = (ix - x) ** 2 + (iy - y) ** 2
                r = int(math.sqrt(r))
                cv2.circle(param, (ix, iy), r, (B[0], G[0], R[0]), -1)

    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        if mode:
            cv2.rectangle(param, (ix, iy), (x, y), (B[0], G[0], R[0]), -1)
        else:
            r = (ix - x)**2 + (iy-y)**2
            r = int(math.sqrt(r))
            cv2.circle(param, (ix, iy), r, (B[0], G[0], R[0]), -1)


def mouseBrush():
    global mode

    img = np.zeros((512, 512, 3), np.uint8)
    cv2.namedWindow("figure Test")
    cv2.setMouseCallback("figure Test", onMouse, param=img)

    while True:
        cv2.imshow("figure Test", img)
        k = cv2.waitKey(1) & 0xFF

        if k == 27:
            break
        elif k == ord('m'):
            mode = not mode

    cv2.destroyAllWindows()


mouseBrush()



코드 설명

위의 예제와 같이 mouseBrush는 함수 비슷합니다. 추가적으로 달라진 것은 모드 변경 버튼이 생겼습니다. m키를 통해 원을 그릴 것인지 직사각형을 그릴 것인지 선택할 수 있습니다. global을 통해 함수안에서도 전역변수의 값을 변경시켜 줄 수 있습니다. 

 

onMouse 함수는 완전 변경되었습니다. 

 

이벤트에 따라서 세가지 경우로 나누어 집니다. 

왼쪽 마우스가 클릭 됐을 때 마우스 커서가 움직일 때 마우스 클릭이 떨어질 때 등이 있다. 

 

event == cv2.EVENT_LBUTTONDOWN:

왼쪽이 클릭되었을 때입니다. 첫 클릭할 때 점이랑 색을 shuffle을 통해 랜덤으로 지정되게 해줍니다. 

 

event == cv2.EVENT_MOUSEMOVE:

직사각형 혹은 원을 그려줍니다. 움직일 때 마다 새로운 x, y의 좌표를 가져와서 그려줍니다. m에 따라서 원이냐 직사각형이나 정해집니다. 

 

event == cv2.EVENT_LBUTTONUP:

drawing을 false로 바꾸어 주어서 move를 하며 추가적으로 안그려지게 만들어주고 원과 직사각형을 그려줍니다.

결과