OpenCV Python :實作滑鼠選取區域並套用馬賽克效果

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 陣列)
  • cloneimage 的複本,每次拖拉時用來畫出矩形框,不影響原圖
  • start_pointend_point:滑鼠拖拉時的起點與終點座標
  • drawing:布林值,代表滑鼠左鍵是否正被按住,用以判斷是否正在拖拉

2. 套用馬賽克的原理

  • 擷取使用者選取的區域(ROI)
  • 將 ROI 縮小成一個非常小的尺寸(例如 15x15)
  • 再將縮小後的影像放大回原始大小,放大時使用「最近鄰插值(INTER_NEAREST)」保持像素塊狀感
  • 這樣就會造成馬賽克像素化效果
  • 最後將馬賽克區域覆蓋回原影像

3. 滑鼠事件流程

  • 按下左鍵:記錄起點,開始標記區域
  • 拖拉中:動態更新終點,將複本影像拷貝一份,畫出矩形提示框,再顯示給使用者看
  • 放開左鍵:結束拖拉,呼叫馬賽克函式套用,並更新複本影像

4. 主程式迴圈

  • 持續使用 cv2.imshow 顯示影像
  • cv2.waitKey(1) 不斷偵測鍵盤事件
  • 按 ESC (key == 27) 離開迴圈並關閉視窗

五、執行與操作說明

  1. 確認你的環境已安裝 OpenCV:
    pip install opencv-python
  2. 將程式碼存為 mosaic.py,並將影像路徑改成你自己圖片的正確路徑。
  3. 執行:
    python mosaic.py
  4. 影像視窗打開後:
    • 按住滑鼠左鍵並拖拉選擇想馬賽克的區域
    • 放開滑鼠後該區域會馬賽克化
    • 可重複操作多個區域
    • ESC 鍵關閉視窗並結束程式

六、擴充建議

  • 可增加鍵盤快捷鍵,如按 r 重新載入原圖清除馬賽克
  • 支援多區域疊加馬賽克
  • 調整馬賽克大小參數
  • 加入滑鼠右鍵取消選取區域功能

留言

這個網誌中的熱門文章

opencv-畫線條/矩陣/圓/文字

opencv-圖像相素調整(resize)和剪裁(cropping)

原來opencv也能"訓練"人臉辨識