一、學習目標
- 了解事件
- 編寫一個簡易繪畫板
二、了解如何制作簡易繪畫板
2.1 了解鼠標多種事件
上一節我們簡單的使用opencv的圖形繪制方法,用鼠標繪制了一些內容。上一節所響應的是簡單的雙擊事件EVENT_LBUTTONDBLCLK,在OpenCV的鼠標事件中還有很多。以下將列舉出來:
- EVENT_MOUSEMOVE:鼠標滑動
- EVENT_LBUTTONDOWN:左鍵單擊
- EVENT_RBUTTONDOWN:右鍵單擊
- EVENT_MBUTTONDOWN:中間單擊
- EVENT_LBUTTONUP:左鍵釋放
- EVENT_RBUTTONUP:右鍵釋放
- EVENT_MBUTTONUP:中鍵釋放
- EVENT_LBUTTONDBLCLK:左鍵雙擊
- EVENT_RBUTTONDBLCLK:右鍵雙擊
- EVENT_MBUTTONDBLCLK:中鍵雙擊
以上事件在setMouseCallback函數回調后將會傳到所執行的函數中,并且以event參數進行對應,取值通過event參數進行取值。
首先我們對一些事件進行監測,先嘗試檢測CV_EVENT_MOUSEMOVE鼠標滑動事件。代碼如下:
import cv2
import numpy as np
def listing(event,x,y,flags,param):if event==cv2.EVENT_MOUSEMOVE:print('EVENT_MOUSEMOVE',' x:',x,' y:',y)
img=np.zeros((600,600,3),np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',listening)
while(1):cv2.imshow('image',img)if cv2.waitKey(20)&0xFF==27:break
cv2.destroyAllWindows()
以上代碼使用listing作為回調后的處理,并且當事件為EVENT_MOUSEMOVE時將會輸出事件名以及當前鼠標所在的x和y坐標的位置。
結果如下:
這時我們可以對所有的事件都進行監聽,這時候修改listen函數就可以了:
def listening(event,x,y,flags,param):if event==cv2.EVENT_MOUSEMOVE:print('EVENT_MOUSEMOVE 鼠標滑動',' x:',x,' y:',y)elif event==cv2.EVENT_LBUTTONDOWN:print('EVENT_LBUTTONDOWN 左鍵單擊',' x:',x,' y:',y)elif event==cv2.EVENT_RBUTTONDOWN:print('EVENT_RBUTTONDOWN 右鍵單擊',' x:',x,' y:',y)elif event==cv2.EVENT_MBUTTONDOWN:print('EVENT_MBUTTONDOWN 中間單擊',' x:',x,' y:',y)elif event==cv2.EVENT_LBUTTONUP:print('EVENT_LBUTTONUP 左鍵釋放',' x:',x,' y:',y)elif event==cv2.EVENT_RBUTTONUP:print('EVENT_RBUTTONUP 右鍵釋放',' x:',x,' y:',y)elif event==cv2.EVENT_MBUTTONUP:print('EVENT_MBUTTONUP 中鍵釋放',' x:',x,' y:',y)elif event==cv2.EVENT_LBUTTONDBLCLK:print('EVENT_LBUTTONDBLCLK 左鍵雙擊',' x:',x,' y:',y)elif event==cv2.EVENT_RBUTTONDBLCLK:print('EVENT_RBUTTONDBLCLK 右鍵雙擊',' x:',x,' y:',y)elif event==cv2.EVENT_MBUTTONDBLCLK:print('EVENT_MBUTTONDBLCLK 中鍵雙擊',' x:',x,' y:',y)
結果如下:
2.2 制作一個簡單的繪畫板
首先我們對繪制一個拖拽繪制板功能做一個行為分析。我們正常進行拖拽畫矩形,一般是按下左鍵,并且不放手,移動鼠標進行矩形的繪制,直到拖拽至我們覺得合適的位置后,我們開始松開鼠標。
在以上的繪制行為中,一共有幾個鼠標事件。有按下鼠標左鍵事件EVENT_LBUTTONDOWN、鼠標移動事件EVENT_MOUSEMOVE、鼠標左鍵釋放事件EVENT_LBUTTONUP。我們在按下鼠標左鍵的時候,從當前鼠標的x與y坐標開始繪制矩形,直到我們松開鼠標后停止繪制。
我們寫一個函數作為回調的處理:
def draw(event,x,y,flags,param):
隨后我們在鼠標按下左鍵的時候需要記住x與y的坐標位置,并且表示開始繪制,需要一個變量表示繪制狀態開啟:
if event==cv2.EVENT_LBUTTONDOWN:drawing=Truesx,sy=x,y
注意,由于回調函數每次循環時都會進行調用,若drawing此次為True后下一次不能直接進入繪制,這個時候需要把drawing、sx、sy都設置成全局變量:
drawing=False
sx,sy=0,0
并且在回調處理的函數中需要加入關鍵字進行聲明是全局變量:
global sx,sy,drawing
接下來我們應該判斷當前是否已經是按下鼠標左鍵并且進行了拖拽移動,這兩個狀態是并列的,所以寫個elif語句進行判斷:
elif event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_FLAG_LBUTTON:
這個時候在該判斷中,使用if語句判斷是否已經按下左鍵后開啟了繪制,防止bug的出現,若已經開啟了繪制則進行繪制矩形:
cv2.rectangle(img,(sx,sy),(x,y),(0,255,0),-1)
如上代碼中為什么起始繪制點是sx與sy呢?那是因為我們按下了鼠標左鍵后的那個點是繪制起始點,從那個點開始繪制矩形到當前鼠標移動到的x和y坐標處,這樣由于每次都覆蓋掉原來的圖像造成一種錯覺,就是在拖拽進行繪制圖像,并且進行填充,顏色為(0,255,0)。由于繪制狀態不能一直開啟,若直接進入了按下左腳與移動時由于保留了上次繪制的繪制開啟,那么會造成初始繪制點的丟失,所以我們還需要判斷當鼠標左鍵釋放彈起后把繪制狀態改為Fasle。代碼如下:
elif event==cv2.EVENT_LBUTTONUP:drawing==False
所有完整的代碼如下:
import cv2
import numpy as npdrawing=False
sx,sy=0,0def draw(event,x,y,flags,param):global sx,sy,drawingif event==cv2.EVENT_LBUTTONDOWN:drawing=Truesx,sy=x,yelif event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_FLAG_LBUTTON:if drawing==True:cv2.rectangle(img,(sx,sy),(x,y),(0,255,0),-1)elif event==cv2.EVENT_LBUTTONUP:drawing==False
img=np.zeros((600,600,3),np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw)
while(1):cv2.imshow('image',img)if cv2.waitKey(20)&0xFF==27:break
cv2.destroyAllWindows()
結果如下:
該系列首發于ebaina
三、總結
- 了解了多個鼠標事件
- 通過事件以及靈活運用繪圖函數制作了一個簡易的繪畫板