Like Share Discussion Bookmark Smile

J.J. Huang   2026-02-24   Python OpenCV 06.視訊與互動篇   瀏覽次數:次   DMCA.com Protection Status

Python | OpenCV 滑鼠與鍵盤事件互動

📚 前言

在前一篇我們學會了 光流分析 (Optical Flow)
這一篇要介紹 滑鼠與鍵盤事件互動,這是 OpenCV 提供的基礎功能之一。
透過事件回呼 (callback) 與按鍵控制,我們可以讓程式更具互動性,例如:

  • 滑鼠點擊選取 ROI 區域
  • 按鍵控制圖片顯示或儲存
  • 結合互動操作進行物件追蹤或圖片編輯

🔎 原理說明

  • 滑鼠事件:透過 cv2.setMouseCallback() 設定事件回呼函式,偵測滑鼠在視窗中的操作。
  • 鍵盤事件:透過 cv2.waitKey() 取得使用者按下的鍵盤按鍵,進行互動控制。

🧠 函式與參數說明

📌 cv2.setMouseCallback()

用途:設定滑鼠事件回呼函式。

1
cv2.setMouseCallback("Window", mouse_event)
  • “Window”:視窗名稱。
  • mouse_event:自訂的事件函式。

📌 滑鼠事件回呼函式

1
2
def mouse_event(event, x, y, flags, param):
...
  • event:事件類型,例如 cv2.EVENT_LBUTTONDOWN (左鍵按下)、cv2.EVENT_RBUTTONDOWN (右鍵按下)、cv2.EVENT_MOUSEMOVE (滑鼠移動)。
  • x, y:滑鼠座標位置。
  • flags:事件狀態,例如是否按下 Ctrl、Shift。
  • param:額外參數,可自訂傳入。

🏷️ 常見滑鼠事件 (event)

  • cv2.EVENT_LBUTTONDOWN:左鍵按下
  • cv2.EVENT_LBUTTONUP:左鍵放開
  • cv2.EVENT_RBUTTONDOWN:右鍵按下
  • cv2.EVENT_RBUTTONUP:右鍵放開
  • cv2.EVENT_MBUTTONDOWN:中鍵按下
  • cv2.EVENT_MOUSEMOVE:滑鼠移動
  • cv2.EVENT_LBUTTONDBLCLK:左鍵雙擊

🏷️ 常見滑鼠旗標 (flags)

  • cv2.EVENT_FLAG_CTRLKEY:Ctrl 鍵按下
  • cv2.EVENT_FLAG_SHIFTKEY:Shift 鍵按下
  • cv2.EVENT_FLAG_ALTKEY:Alt 鍵按下
  • cv2.EVENT_FLAG_LBUTTON:左鍵按住
  • cv2.EVENT_FLAG_RBUTTON:右鍵按住
  • cv2.EVENT_FLAG_MBUTTON:中鍵按住

📌 cv2.waitKey()

用途:等待鍵盤事件。

1
key = cv2.waitKey(0)
  • 0:無限等待。
  • 正數:等待指定毫秒數。
  • 回傳值:按下的鍵盤代碼 (ASCII)。

🏷️ ASCII 簡介

  • ASCII (American Standard Code for Information Interchange):一種字元編碼標準,用數字表示字母、數字與符號。
  • 例如:ord('a') = 97ord('A') = 65
  • 在 OpenCV 中,cv2.waitKey() 會回傳按鍵的 ASCII 值,我們可以用 ord() 來比對。


圖:ASCII 編碼表

來源:ASCII 編碼表

💻 範例程式 — 滑鼠事件互動

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import cv2
import numpy as np

# 滑鼠事件回呼函式
def mouse_event(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN: # 左鍵按下
print(f"左鍵點擊位置: ({x}, {y})")
cv2.circle(img, (x, y), 5, (0, 0, 255), -1) # 在點擊位置畫紅色圓點
elif event == cv2.EVENT_RBUTTONDOWN: # 右鍵按下
print(f"右鍵點擊位置: ({x}, {y})")
cv2.rectangle(img, (x-10, y-10), (x+10, y+10), (0, 255, 0), 2) # 畫綠色方框
elif event == cv2.EVENT_MOUSEMOVE: # 滑鼠移動
print(f"滑鼠移動位置: ({x}, {y})")

# 建立視窗
cv2.namedWindow("Image")
cv2.setMouseCallback("Image", mouse_event)

# 建立一張白色圖片
img = 255 * np.ones((400, 600, 3), dtype=np.uint8)

while True:
cv2.imshow("Image", img)
if cv2.waitKey(1) & 0xFF == ord('q'): # 按下 q 鍵退出
break

cv2.destroyAllWindows()


圖:滑鼠事件互動,點擊位置會顯示圓點或方框

💻 範例程式 — 滑鼠事件互動 (座標、畫點、連線)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import cv2
import numpy as np

points = [] # 儲存點座標

def mouse_event(event, x, y, flags, param):
global points
if event == cv2.EVENT_LBUTTONDOWN: # 左鍵按下
print(f"左鍵點擊位置: ({x}, {y})")
points.append((x, y))
cv2.circle(img, (x, y), 5, (0, 0, 255), -1) # 畫紅色圓點
if len(points) >= 2:
cv2.line(img, points[-2], points[-1], (255, 0, 0), 2) # 連線

# 建立視窗
cv2.namedWindow("Image")
cv2.setMouseCallback("Image", mouse_event)

# 建立一張白色圖片
img = 255 * np.ones((400, 600, 3), dtype=np.uint8)

while True:
cv2.imshow("Image", img)
if cv2.waitKey(1) & 0xFF == ord('q'): # 按下 q 鍵退出
break

cv2.destroyAllWindows()


圖:滑鼠事件互動,點擊位置會顯示圓點並連線

💻 範例程式 — 滑鼠圈選框框並馬賽克化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import cv2

img = cv2.imread("test.png") # 部落格頭像
backup = img.copy() # 保留原始圖片

# 儲存框選座標
rect_start = None
rect_end = None
drawing = False

def mouse_event(event, x, y, flags, param):
global rect_start, rect_end, drawing, img, backup

if event == cv2.EVENT_LBUTTONDOWN: # 左鍵按下,開始框選
rect_start = (x, y)
drawing = True

elif event == cv2.EVENT_MOUSEMOVE and drawing: # 框選過程
img = backup.copy()
cv2.rectangle(img, rect_start, (x, y), (0, 0, 255), 2)

elif event == cv2.EVENT_LBUTTONUP: # 左鍵放開,完成框選
rect_end = (x, y)
drawing = False

# 取得框選範圍
x1, y1 = rect_start
x2, y2 = rect_end
roi = backup[min(y1,y2):max(y1,y2), min(x1,x2):max(x1,x2)]

# 對 ROI 區域進行馬賽克化
if roi.size > 0:
mosaic = cv2.resize(roi, (20, 20), interpolation=cv2.INTER_LINEAR)
mosaic = cv2.resize(mosaic, (roi.shape[1], roi.shape[0]), interpolation=cv2.INTER_NEAREST)
backup[min(y1,y2):max(y1,y2), min(x1,x2):max(x1,x2)] = mosaic
img = backup.copy()
print(f"框選區域已馬賽克化: ({x1}, {y1}) ~ ({x2}, {y2})")

cv2.namedWindow("Mosaic Demo")
cv2.setMouseCallback("Mosaic Demo", mouse_event)

while True:
cv2.imshow("Mosaic Demo", img)
if cv2.waitKey(1) & 0xFF == ord('q'): # 按下 q 鍵退出
break

cv2.destroyAllWindows()


圖:滑鼠事件互動,圈選框框後該區域會被馬賽克化

💻 範例程式 — 鍵盤事件互動 (調整亮度與對比度)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import cv2
import numpy as np

# 建立一張灰色圖片
img = np.ones((400, 600, 3), dtype=np.uint8) * 127
alpha, beta = 1.0, 0 # 對比度、亮度

while True:
adjusted = cv2.convertScaleAbs(img, alpha=alpha, beta=beta)
cv2.imshow("Keyboard Demo", adjusted)

key = cv2.waitKey(0) & 0xFF

if key == ord('+'): # 增加亮度
beta += 10
print(f"亮度增加: {beta}")
elif key == ord('-'): # 減少亮度
beta -= 10
print(f"亮度減少: {beta}")
elif key == ord(']'): # 增加對比度
alpha += 0.1
print(f"對比度增加: {alpha}")
elif key == ord('['): # 減少對比度
alpha = max(0.1, alpha - 0.1)
print(f"對比度減少: {alpha}")
elif key == ord('r'): # 重置
alpha, beta = 1.0, 0
print("重置亮度與對比度")
elif key == 27 or key == ord('q'): # ESC 或 q 鍵退出
print("程式結束")
break

cv2.destroyAllWindows()


圖:鍵盤事件互動,透過鍵盤調整亮度與對比度

💻 範例程式 — 鍵盤事件互動

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import cv2
import numpy as np

# 建立一張白色圖片
img = 255 * np.ones((400, 600, 3), dtype=np.uint8)
backup = img.copy() # 保留原始圖片

# 滑鼠事件:左鍵畫紅色圓點
def mouse_event(event, x, y, flags, param):
global img
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img, (x, y), 5, (0, 0, 255), -1)
print(f"畫紅點於座標: ({x}, {y})")

cv2.namedWindow("Demo")
cv2.setMouseCallback("Demo", mouse_event)

while True:
cv2.imshow("Demo", img)
key = cv2.waitKey(1) & 0xFF

if key == ord('s'): # 按下 s 鍵儲存圖片
cv2.imwrite("output.png", img)
print("圖片已儲存為 output.png")
elif key == ord('c'): # 按下 c 鍵清除圖片 (回到原始白色)
img = backup.copy()
print("圖片已清除")
elif key == ord('q'): # 按下 q 鍵退出
print("程式結束")
break

cv2.destroyAllWindows()


圖:鍵盤事件互動,支援滑鼠畫點,並可透過 s 鍵儲存圖片、c 鍵清除畫面、q 鍵退出

⚠️ 注意事項

  • 滑鼠事件必須搭配 cv2.namedWindow()cv2.setMouseCallback() 使用。
  • cv2.waitKey() 的回傳值需搭配 ord() 判斷字元。
  • 不同作業系統的鍵盤代碼可能略有差異。
  • 建議在迴圈中使用 cv2.waitKey(1),避免程式卡住
  • 滑鼠事件與鍵盤事件可以結合,例如:滑鼠框選 ROI,再用鍵盤確認或儲存。

📊 應用場景

  • ROI 選取:透過滑鼠框選物件區域。
  • 互動式標註:人工標記圖片中的特徵點。
  • 遊戲互動:結合鍵盤控制與圖片顯示。
  • 圖片編輯:透過滑鼠與鍵盤操作進行裁切、儲存。

🎯 結語

本篇我們學會了如何使用 OpenCV 滑鼠與鍵盤事件互動,透過事件回呼與按鍵控制,讓程式更具互動性。
這些技術在 ROI 選取、圖片標註、互動式應用中非常常見,後續可以結合物件追蹤或光流分析,打造更完整的互動系統。

📖 如在學習過程中遇到疑問,或是想了解更多相關主題,建議回顧一下 Python | OpenCV 系列導讀,掌握完整的章節目錄,方便快速找到你需要的內容。

註:以上參考了
OpenCV Tutorials
OpenCV-Python Tutorials
Pexels — 免費影片素材