OpenCV Python :實作滑鼠選取區域並套用馬賽克效果
OpenCV Python :滑鼠選取區域並套用馬賽克效果
本篇教學會帶你一步步了解一個使用 OpenCV 與 Python 撰寫的程式,如何讓你用滑鼠在影像上拖拉選取區域,並在該選區套用馬賽克(像素化)效果。最後會附上詳細程式碼解說與執行說明。
一、功能概述
- 開啟一張影像並顯示
- 使用者用滑鼠「左鍵拖拉」選取想套用馬賽克的矩形區域
- 放開滑鼠左鍵後,在選取區域套用馬賽克
- 持續可重複選取與套用
- 按 ESC 鍵可離開程式
二、使用到的工具與函式庫
- OpenCV (cv2):影像讀取、顯示、處理與滑鼠事件等
- Python:撰寫邏輯與控制流程
三、程式碼流程說明
import cv2
# 全域變數(方便多函式共用)
image = None # 原始影像
clone = None # 影像複本,用來畫選取框,不破壞原影像
start_point = None # 滑鼠拖拉起點 (x, y)
end_point = None # 滑鼠拖拉終點 (x, y)
drawing = False # 紀錄是否正在拖拉滑鼠
def apply_mosaic(image, start_point, end_point, mosaic_size=15):
"""
在指定區域套用馬賽克效果。
透過縮小再放大區域影像,產生像素化效果。
:param image: 原始影像 (numpy array)
:param start_point: 左上角座標 (x1, y1)
:param end_point: 右下角座標 (x2, y2)
:param mosaic_size: 馬賽克方塊大小(越小馬賽克越粗糙)
:return: 修改後的影像 (同一物件)
"""
x1, y1 = start_point
x2, y2 = end_point
# 確保座標是左上(x1,y1),右下(x2,y2)
x1, x2 = min(x1, x2), max(x1, x2)
y1, y2 = min(y1, y2), max(y1, y2)
# 擷取選取區域(Region of Interest)
roi = image[y1:y2, x1:x2]
# 將選取區縮小到 mosaic_size x mosaic_size
small = cv2.resize(roi, (mosaic_size, mosaic_size), interpolation=cv2.INTER_LINEAR)
# 再放大回原本大小,使用最近鄰差值保持馬賽克效果
mosaic = cv2.resize(small, (x2 - x1, y2 - y1), interpolation=cv2.INTER_NEAREST)
# 覆蓋回原影像
image[y1:y2, x1:x2] = mosaic
return image
def mouse_callback(event, x, y, flags, param):
"""
滑鼠事件回呼函式,監聽滑鼠按下、移動與放開事件,
以便動態繪製選取框及完成馬賽克套用。
:param event: 滑鼠事件類型
:param x: 滑鼠當前 X 座標
:param y: 滑鼠當前 Y 座標
"""
global image, clone, start_point, end_point, drawing
if event == cv2.EVENT_LBUTTONDOWN:
# 使用者按下左鍵,開始拖拉
drawing = True
start_point = (x, y)
end_point = (x, y)
elif event == cv2.EVENT_MOUSEMOVE:
# 拖拉過程中即時更新結束點並畫綠色矩形框提示
if drawing:
end_point = (x, y)
temp_image = clone.copy() # 用複本畫框,避免破壞原圖
cv2.rectangle(temp_image, start_point, end_point, (0, 255, 0), 2)
cv2.imshow("Image", temp_image)
elif event == cv2.EVENT_LBUTTONUP:
# 使用者放開左鍵,結束拖拉並套用馬賽克
drawing = False
end_point = (x, y)
apply_mosaic(image, start_point, end_point)
clone[:] = image.copy() # 更新複本
cv2.imshow("Image", image)
# 載入影像
image = cv2.imread(r'ch02/Happy.jpg') # 請替換為您的圖片路徑
if image is None:
print("無法載入影像,請確認檔案名稱和路徑是否正確。")
else:
clone = image.copy()
cv2.namedWindow("Image")
cv2.setMouseCallback("Image", mouse_callback)
# 主迴圈,不斷顯示影像,直到按下 ESC 鍵離開
while True:
cv2.imshow("Image", image)
key = cv2.waitKey(1) & 0xFF
if key == 27: # ESC key
break
cv2.destroyAllWindows()
四、詳細解說
1. 全域變數說明
image:載入的原始彩色圖片 (numpy 陣列)clone:image的複本,每次拖拉時用來畫出矩形框,不影響原圖start_point、end_point:滑鼠拖拉時的起點與終點座標drawing:布林值,代表滑鼠左鍵是否正被按住,用以判斷是否正在拖拉
2. 套用馬賽克的原理
- 擷取使用者選取的區域(ROI)
- 將 ROI 縮小成一個非常小的尺寸(例如 15x15)
- 再將縮小後的影像放大回原始大小,放大時使用「最近鄰插值(INTER_NEAREST)」保持像素塊狀感
- 這樣就會造成馬賽克像素化效果
- 最後將馬賽克區域覆蓋回原影像
3. 滑鼠事件流程
- 按下左鍵:記錄起點,開始標記區域
- 拖拉中:動態更新終點,將複本影像拷貝一份,畫出矩形提示框,再顯示給使用者看
- 放開左鍵:結束拖拉,呼叫馬賽克函式套用,並更新複本影像
4. 主程式迴圈
- 持續使用
cv2.imshow顯示影像 cv2.waitKey(1)不斷偵測鍵盤事件- 按 ESC (
key == 27) 離開迴圈並關閉視窗
五、執行與操作說明
- 確認你的環境已安裝 OpenCV:
pip install opencv-python - 將程式碼存為
mosaic.py,並將影像路徑改成你自己圖片的正確路徑。 - 執行:
python mosaic.py - 影像視窗打開後:
- 按住滑鼠左鍵並拖拉選擇想馬賽克的區域
- 放開滑鼠後該區域會馬賽克化
- 可重複操作多個區域
- 按
ESC鍵關閉視窗並結束程式
六、擴充建議
- 可增加鍵盤快捷鍵,如按
r重新載入原圖清除馬賽克 - 支援多區域疊加馬賽克
- 調整馬賽克大小參數
- 加入滑鼠右鍵取消選取區域功能
留言
張貼留言