<2-4. Mouse as a Paint-Brush>
OpenCV에서의 마우스 이벤트 다루는 법을 배울 것이다.
- cv2.setMouseCallback() 을 배워 볼 것이다.
Simple Demo
더블 클릭하면 이미지 위에 원이 생기는 간단한 기능을 만들어보자.
먼저, 마우스 이벤트가 발생할 때, 마우스 callback 기능을 만든다. 마우스 이벤트는 좌버튼 아래로, 좌버튼 위로, 좌 버튼 더블 클릭등으로 마우스와 관련된 것이면 된다. 모든 마우스 이벤트에 대해 좌표 (x,y)를 주는 것이다. 이 이벤트와 위치를 가지고, 원하는 모든 것을 할 수 있다. 모든 이벤트를 나열하려면 다음 코드를 실행하면 된다.
import cv2
events = [i for i in dir(cv2) if 'EVENT' in i]
print(events)
위 코드를 실행한 결과는 다음과 같다.
[‘EVENT_FLAG_ALTKEY’, ‘EVENT_FLAG_CTRLKEY’, ‘EVENT_FLAG_LBUTTON’, ‘EVENT_FLAG_MBUTTON’, ‘EVENT_FLAG_RBUTTON’, ‘EVENT_FLAG_SHIFTKEY’, ‘EVENT_LBUTTONDBLCLK’, ‘EVENT_LBUTTONDOWN’, ‘EVENT_LBUTTONUP’, ‘EVENT_MBUTTONDBLCLK’, ‘EVENT_MBUTTONDOWN’, ‘EVENT_MBUTTONUP’, ‘EVENT_MOUSEHWHEEL’, ‘EVENT_MOUSEMOVE’, ‘EVENT_MOUSEWHEEL’, ‘EVENT_RBUTTONDBLCLK’, ‘EVENT_RBUTTONDOWN’, ‘EVENT_RBUTTONUP’]
마우스 callback 기능 생성시 어디에서나 동일한 특정 형식이 있다. 어떤 기능을 하는지만이 차이점이다. 우리의 마우스 callback 기능은 더블 클릭 한 곳에 원을 그리는 그 한가지 일을 한다. 아래 코드를 보자.
# Mouse Callback Function
def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img,(x,y),100,(255,0,0),-1)
# 검정 이미지 생성
img = np.zeros((512,512,3),np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
더블 클릭하면 원이 생기는 것을 볼 수 있다.
More Advanced Demo
더 좋은 기능을 만들어 볼 것이다. 그림 그리는 기능처럼 마우스를 드래그해서 도형을 그려볼 것이다. 그래서 우리의 마우스 callback 기능은 두 가지로, 하나는 직사각형을 그리고, 다른 하나는 원을 그리는 것이다. 이 특정 예제는 트래킹이나 image segmentation과 같은 것을 이해하고 만드는데 큰 도움이 될 것이다.
# True이면 마우스가 눌렸을 때이다.
drawing = False
# True 이면 직사각형을 그린다. 'm'을 누르면 곡선으로 전환된다.
mode = True
ux, iy = -1, -1
# Mouse Callback Function
def draw_circle(event,x,y,flags,param):
global ix, iy, drawing, mode
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
그 다음으로 마우스 callback 기능을 OpenCV 창에 합쳐야한다. 메인 루프는, 키보드 ‘m’에 대한 키보드 바인딩을 설정하여 직사각형과 원을 전환해야 한다.
img = np.zeros((512,512,3),np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == ord('m'):
mode = not mode
elif k == 27:
break
cv2.destroyAllWindows()