二、瞭解如何製作簡易繪畫板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 cv2import numpy as npdef 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: breakcv2.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=True sx,sy=x,y
注意,由於回撥函式每次迴圈時都會進行呼叫,若drawing此次為True後下一次不能直接進入繪製,這個時候需要把drawing、sx、sy都設定成全域性變數:
drawing=Falsesx,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 cv2import numpy as npdrawing=Falsesx,sy=0,0def draw(event,x,y,flags,param): global sx,sy,drawing if event==cv2.EVENT_LBUTTONDOWN: drawing=True sx,sy=x,y elif 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==Falseimg=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: breakcv2.destroyAllWindows()
結果如下:
三、總結瞭解了多個滑鼠事件透過事件以及靈活運用繪圖函式製作了一個簡易的繪畫板