偵測滑鼠事件
使用 OpenCV 建立視窗後,除了開啟圖片進行預覽,也可透過視窗偵測滑鼠的事件,進一步利用滑鼠和影像互動,這篇教學會介紹如何偵測滑鼠事件,以及取得滑鼠事件後進行的簡單應用 ( 標記、取得顏色...等 )。
快速導覽:
因為程式中的 OpenCV 會需要使用鏡頭或 GPU,所以請使用本機環境 ( 參考:使用 Python 虛擬環境 ) 或使用 Anaconda Jupyter 進行實作 ( 參考:使用 Anaconda ) ,並安裝 OpenCV 函式庫 ( 參考:OpenCV 函式庫 )。
偵測滑鼠事件
使用 cv2.setMouseCallback 方法,可以偵測指定視窗下的滑鼠事件,偵測事件後會透過一個特定的函式處理相關事件參數,每次發生滑鼠事件時會回傳四個參數,第一個是 event,第二個是 x 座標,第三個是 y 座標,第四個是 flag,下方的程式碼執行後,用滑鼠在視窗上滑動以及點擊,後台就會看見印出對應的數值。
import cv2
img = cv2.imread('meme.jpg')
def show_xy(event,x,y,flags,userdata):
print(event,x,y,flags)
# 印出相關參數的數值,userdata 可透過 setMouseCallback 第三個參數垂遞給函式
cv2.imshow('oxxostudio', img)
cv2.setMouseCallback('oxxostudio', show_xy) # 設定偵測事件的函式與視窗
cv2.waitKey(0) # 按下任意鍵停止
cv2.destroyAllWindows()
滑鼠 event 與 flag 列表
當滑鼠在指定視窗中滑動進行某些行為,都會觸發一些事件,相關事件列表如下:
代號 | 事件 | 說明 |
---|---|---|
0 | cv2.EVENT_MOUSEMOVE | 滑動 |
1 | cv2.EVENT_LBUTTONDOWN | 左鍵點擊 |
2 | cv2.EVENT_RBUTTONDOWN | 右鍵點擊 |
3 | cv2.EVENT_MBUTTONDOWN | 中鍵點擊 |
4 | cv2.EVENT_LBUTTONUP | 左鍵放開 |
5 | cv2.EVENT_RBUTTONUP | 右鍵放開 |
6 | cv2.EVENT_MBUTTONUP | 中鍵放開 |
7 | cv2.EVENT_LBUTTONDBLCLK | 左鍵雙擊 |
8 | cv2.EVENT_RBUTTONDBLCLK | 右鍵雙擊 |
9 | cv2.EVENT_MBUTTONDBLCLK | 中鍵雙擊 |
除了事件,滑鼠的行為也會觸發一些 flag,相關 flag 列表如下:
代號 | flag | 說明 |
---|---|---|
1 | cv2.EVENT_FLAG_LBUTTON | 左鍵拖曳 |
2 | cv2.EVENT_FLAG_RBUTTON | 右鍵拖曳 |
4 | cv2.EVENT_FLAG_MBUTTON | 中鍵拖曳 |
8~15 | cv2.EVENT_FLAG_CTRLKEY | 按 Ctrl 不放事件 |
16~31 | cv2.EVENT_FLAG_SHIFTKEY | 按 Shift 不放事件 |
32~39 | cv2.EVENT_FLAG_ALTKEY | 按 Alt 不放事件 |
透過滑鼠點擊,取得像素的顏色
下方的程式碼,會使用一個黑色圓框標記滑鼠的位置,當點擊滑鼠時,會印出該位置像素的顏色。
import cv2
img = cv2.imread('meme.jpg')
def show_xy(event,x,y,flags,param):
if event == 0:
img2 = img.copy() # 當滑鼠移動時,複製原本的圖片
cv2.circle(img2, (x,y), 10, (0,0,0), 1) # 繪製黑色空心圓
cv2.imshow('oxxostudio', img2) # 顯示繪製後的影像
if event == 1:
color = img[y,x] # 當滑鼠點擊時
print(color) # 印出顏色
cv2.imshow('oxxostudio', img)
cv2.setMouseCallback('oxxostudio', show_xy)
cv2.waitKey(0)
cv2.destroyAllWindows()
透過滑鼠點擊,繪製多邊形
下方的程式碼,會在點擊滑鼠時繪製一個實心圓形,並記錄該點擊時的座標,當座標數量大於 1 時,會透過兩個座標繪製直線。
import cv2
img = cv2.imread('meme.jpg')
dots = [] # 記錄座標的空串列
def show_xy(event,x,y,flags,param):
if event == 1:
dots.append([x, y]) # 記錄座標
cv2.circle(img, (x, y), 10, (0,0,255), -1) # 在點擊的位置,繪製圓形
num = len(dots) # 目前有幾個座標
if num > 1: # 如果有兩個點以上
x1 = dots[num-2][0]
y1 = dots[num-2][1]
x2 = dots[num-1][0]
y2 = dots[num-1][1]
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2) # 取得最後的兩個座標,繪製直線
cv2.imshow('oxxostudio', img)
cv2.imshow('oxxostudio', img)
cv2.setMouseCallback('oxxostudio', show_xy)
cv2.waitKey(0)
cv2.destroyAllWindows()
參考資料
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~