Skip to main content

High-performance OpenCV + wxWidgets integration for Python

Project description

wxCvModule 使用者指南

PyPI version Python Versions License: MIT

版本:v1.5 最後更新:2026-02-19


目錄

  1. 簡介
  2. 安裝
  3. 各平台注意事項
  4. 快速開始
  5. 核心類別說明
  6. ROI 工具詳解
  7. 疊加層系統(Overlay)
  8. 事件回調
  9. 視窗嵌入與 Resize
  10. API 快速參考
  11. 常見問題

1. 簡介

wxCvModule 是一個高效能的 C++ + Python 混合函式庫,將 OpenCV 影像處理wxWidgets GUI 無縫整合進 Python wxPython 應用程式。

主要特色

特色 說明
高效能渲染 直接 C++ 渲染管線,處理大圖不卡頓
豐富的 ROI 工具 支援矩形、旋轉矩形、圓形、環形、多邊形、點、線段
互動操作 Ctrl+滾輪縮放、滾輪平移、中鍵拖曳、右鍵選單
Python 友好 直接傳遞 NumPy array,零拷貝共享記憶體
事件委派 右鍵點擊、滑鼠移動、雙擊事件可委派給 Python 處理
跨平台 Windows、Linux、macOS 均支援

2. 安裝

2.1 透過 pip 安裝(推薦)

pip install wxcvmodule

安裝必要的 Python 依賴:

pip install wxPython numpy opencv-python

2.2 從原始碼編譯

若要從原始碼編譯,請參閱 CLAUDE.md 中的編譯指令,以及各平台對應的 Build Guide:

  • Windowsdocs/Windows_Local_Build_Guide.md
  • Linuxdocs/Linux_Wheel_Build_Guide.md
  • macOS:CLAUDE.md 的 macOS 編譯章節

編譯完成後,可透過以下指令打包 Wheel:

pip install build scikit-build-core
python -m build --wheel

3. 各平台注意事項

此章節是使用 wxCvModule 前最重要的閱讀內容,特別是 macOS 使用者。

3.1 Windows

Windows 是最簡單的平台,沒有特殊限制。

  • Import 順序:無限制,import wximport wxCvModule 順序不影響功能。
  • 面板座標(x, y):建議使用 -1(讓系統自動決定)。
  • 依賴管理:Wheel 已包含所有 DLL(OpenCV、wxWidgets),安裝後即可使用,不需額外安裝任何套件。
  • 路徑格式LoadImage() 完整支援中文等 Unicode 路徑(內部使用 std::wstring)。
  • GUI 後端:Win32 API(__WXMSW__

典型初始化範例:

import wx
import wxCvModule  # Windows 上 import 順序不影響

handle = container.GetHandle()
cv_panel = wxCvModule.wxCvROIAdvPanel(handle, wx.ID_ANY, -1, -1, width, height)

3.2 Linux

Linux 使用 GTK3 後端,需要系統預先安裝 GTK3 執行環境。

  • Import 順序:無限制。
  • 面板座標(x, y):使用 -1
  • 系統依賴:GTK3 必須存在於系統中。

安裝 GTK3(若尚未安裝):

# Ubuntu / Debian
sudo apt install libgtk-3-0

# Fedora / RHEL
sudo dnf install gtk3

# Arch Linux
sudo pacman -S gtk3
  • 路徑格式LoadImage() 使用 UTF-8 字串處理路徑,支援 Unicode 路徑。
  • Wheel 大小:約 11–12 MB。OpenCV 與 wxWidgets 靜態連結進 .so,GTK3 則使用系統版本。
  • GUI 後端:GTK3 (__WXGTK__)
  • 圖像編解碼:HEIF(.heic)與 JPEG XL(.jxl)需要 libheif / libjxl(Wheel 已包含)。

典型初始化範例:

import wx
import wxCvModule

handle = container.GetHandle()
cv_panel = wxCvModule.wxCvROIAdvPanel(handle, wx.ID_ANY, -1, -1, width, height)

3.3 macOS(重要差異)

macOS 與 Windows/Linux 有根本性的架構差異,使用前務必閱讀以下說明。

⚠️ 關鍵規則:Import 順序

# ✅ 正確:先 import wx,再 import wxCvModule
import wx
import wxCvModule

# ❌ 錯誤:會拋出 RuntimeError
import wxCvModule  # wx 尚未載入,crash!
import wx

原因:macOS 版本的 wxCvModule 使用 -undefined dynamic_lookup 技術,wx 符號在執行時才從 wxPython 的 dylib 解析。若 wxPython 未先載入,C++ 端的 wxAppConsole::GetInstance() 找不到 wxApp,會拋出明確的 RuntimeError

⚠️ 面板座標必須為 (0, 0)

# ✅ macOS 正確:使用 0, 0
cv_panel = wxCvModule.wxCvROIAdvPanel(handle, wx.ID_ANY, 0, 0, width, height)

# ❌ macOS 錯誤:使用 -1, -1 可能導致面板無法正確嵌入
cv_panel = wxCvModule.wxCvROIAdvPanel(handle, wx.ID_ANY, -1, -1, width, height)

⚠️ 關閉視窗時必須手動釋放 C++ panel

def on_close(self, event):
    self.cv_panel = None   # 觸發 C++ 析構 → 避免 wxApp 結束卡住
    self.roi_panel = None
    self.Destroy()

原因:macOS 使用隱藏框架(hidden wxFrame)作為 C++ panel 的臨時父視窗。若不釋放,wxApp 結束時會因 top-level window 仍存在而卡住不退出。

平台比較摘要

項目 Windows Linux macOS
Import 順序限制 必須先 import wx
面板 x, y 參數 -1, -1 -1, -1 0, 0
關閉時需釋放 panel 建議 建議 必須
wxWidgets 連結方式 動態(獨立 DLL) 靜態(內嵌) dynamic_lookup(共用 wxPython)
GUI 後端 Win32 GTK3 Cocoa
路徑 Unicode 支援 std::wstring UTF-8 UTF-8

跨平台最佳寫法

若要讓同一份程式碼在三個平台都能正確執行,建議:

import sys
import os

# 自動搜尋 wxCvModule 位置
_dir = os.path.dirname(os.path.abspath(__file__))
for _p in [_dir, os.path.join(_dir, "..", "build"),
           os.path.join(_dir, "..", "build", "Release")]:
    if os.path.isdir(_p) and _p not in sys.path:
        sys.path.insert(0, os.path.normpath(_p))

# wx 必須在 wxCvModule 之前(macOS 強制要求,其他平台無影響)
import wx
import wxCvModule

# 面板座標:macOS 用 0,0;其他平台用 -1,-1
_X = 0 if sys.platform == "darwin" else -1
_Y = 0 if sys.platform == "darwin" else -1

# 建立面板
cv_panel = wxCvModule.wxCvROIAdvPanel(handle, wx.ID_ANY, _X, _Y, w, h)

4. 快速開始

4.1 基本圖像顯示(wxCvPanel)

import sys
import wx
import numpy as np
import wxCvModule

_X = 0 if sys.platform == "darwin" else -1
_Y = 0 if sys.platform == "darwin" else -1

class BasicViewerFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="wxCvModule Basic Viewer", size=(800, 600))
        self.cv_panel = None

        # 建立容器 Panel
        self.container = wx.Panel(self)
        self.container.SetBackgroundColour(wx.Colour(40, 40, 40))

        # 綁定事件
        self.Bind(wx.EVT_SHOW,  self.on_show)
        self.Bind(wx.EVT_CLOSE, self.on_close)
        self.container.Bind(wx.EVT_SIZE, self.on_resize)
        self.Centre()

    def on_show(self, event):
        if event.IsShown() and self.cv_panel is None:
            wx.CallAfter(self.init_panel)
        event.Skip()

    def on_close(self, event):
        self.cv_panel = None  # macOS 必要
        self.Destroy()

    def init_panel(self):
        handle = self.container.GetHandle()
        size   = self.container.GetSize()
        self.cv_panel = wxCvModule.wxCvPanel(
            handle, wx.ID_ANY, _X, _Y, size.width, size.height
        )
        self.cv_panel.SetCenterImageEnable(True)

        # 建立測試圖像
        img = np.zeros((480, 640, 3), dtype=np.uint8)
        img[:, :, 0] = 100  # B channel
        self.cv_panel.SetMat(img)
        self.cv_panel.SetZoomToFit()

    def on_resize(self, event):
        if self.cv_panel and self.cv_panel.IsOk():
            sz = self.container.GetSize()
            self.cv_panel.SetSize(sz.width, sz.height)
            self.cv_panel.Refresh()
        event.Skip()

if __name__ == "__main__":
    app = wx.App()
    BasicViewerFrame().Show()
    app.MainLoop()

4.2 ROI 編輯(wxCvROIAdvPanel)

class ROIEditorFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="ROI Editor", size=(900, 650))
        self.roi_panel = None

        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)

        self.container = wx.Panel(panel)
        sizer.Add(self.container, 1, wx.EXPAND | wx.ALL, 4)

        # ROI 模式選擇
        mode_sizer = wx.BoxSizer(wx.HORIZONTAL)
        mode_sizer.Add(wx.StaticText(panel, label="ROI Mode:"), 0,
                       wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 6)
        self.mode_choice = wx.Choice(panel, choices=[
            "Nothing", "Point", "Line", "Rectangle",
            "RotatedRect", "Circle", "Annulus", "Polygon"
        ])
        self.mode_choice.SetSelection(0)
        self.mode_choice.Bind(wx.EVT_CHOICE, self.on_mode_change)
        mode_sizer.Add(self.mode_choice)
        sizer.Add(mode_sizer, 0, wx.ALL, 4)

        panel.SetSizer(sizer)

        self.Bind(wx.EVT_SHOW,  self.on_show)
        self.Bind(wx.EVT_CLOSE, self.on_close)
        self.container.Bind(wx.EVT_SIZE, self.on_resize)
        self.Centre()

    def on_show(self, event):
        if event.IsShown() and self.roi_panel is None:
            wx.CallAfter(self.init_panel)
        event.Skip()

    def on_close(self, event):
        self.roi_panel = None  # macOS 必要
        self.Destroy()

    def init_panel(self):
        handle = self.container.GetHandle()
        size   = self.container.GetSize()
        self.roi_panel = wxCvModule.wxCvROIAdvPanel(
            handle, wx.ID_ANY, _X, _Y, size.width, size.height
        )
        # 啟用所有 ROI 工具及右鍵選單
        self.roi_panel.SetFuncEnable(True, True, True)
        self.roi_panel.SetMenuROIEnable(True, True, True, True, True, True, True)
        self.roi_panel.SetCenterImageEnable(True)

        # 設定 Crop 回調:使用者完成 ROI 後觸發
        self.roi_panel.SetOnCropCallback(self.on_crop)

        # 載入圖像
        img = np.zeros((480, 640, 3), dtype=np.uint8)
        self.roi_panel.SetMat(img)
        self.roi_panel.SetZoomToFit()

    def on_mode_change(self, event):
        if self.roi_panel:
            self.roi_panel.SetROIMode(self.mode_choice.GetSelection())

    def on_resize(self, event):
        if self.roi_panel and self.roi_panel.IsOk():
            sz = self.container.GetSize()
            self.roi_panel.SetSize(sz.width, sz.height)
            self.roi_panel.Refresh()
        event.Skip()

    def on_crop(self, rect):
        # rect = (x, y, width, height),原圖座標
        wx.CallAfter(print, f"ROI Crop: {rect}")

4.3 純邏輯引擎(wxCvEngine,無需 GUI)

wxCvEngine 適合批次影像處理或命令列工具,不需要 wxPython 也不需要顯示視窗

import wxCvModule
import numpy as np

engine = wxCvModule.wxCvEngine()

# 設定圖像
img = np.zeros((480, 640, 3), dtype=np.uint8)
engine.SetMat(img)
print(f"Image size: {engine.GetImageSize()}")  # (width, height)

# 影像處理操作
engine.ConvertToGray()
engine.Resize(320, 240)
engine.GaussianBlur(5, 1.5)
edges = engine.Canny(50, 150)  # 直接回傳結果 numpy array

# 取得處理後的圖像
result = engine.GetMat()  # 回傳 numpy.ndarray

# 從檔案載入 / 儲存(支援 Unicode 路徑)
engine.LoadImage("/path/to/image.png")
engine.SaveImage("/output/result.jpg")
engine.LoadImage("/path/with/unicode/圖片.png", wxCvModule.IMREAD_GRAYSCALE)

5. 核心類別說明

5.1 wxCvEngine — 純邏輯影像引擎

不依賴 GUI,適用於影像前處理、批次轉換等場景。

方法 說明
SetMat(img) 設定圖像(NumPy BGR/BGRA/Gray array)
GetMat() 取得當前圖像(NumPy array)
HasImage() 是否有圖像
GetImageSize() 回傳 (width, height)
LoadImage(path, flag?) 從檔案載入(支援 Unicode 路徑)
SaveImage(path) 儲存到檔案
ConvertToGray() 轉灰階
Resize(w, h) 縮放
GaussianBlur(ksize, sigma) 高斯模糊
Canny(t1, t2) Canny 邊緣偵測,回傳結果圖像
Clear() 清除圖像

imread flag 常數:

wxCvModule.IMREAD_COLOR       # 彩色(預設)
wxCvModule.IMREAD_GRAYSCALE   # 灰階
wxCvModule.IMREAD_UNCHANGED   # 保留 Alpha 通道

5.2 wxCvPanel — 基本圖像顯示面板

繼承 wxScrolledCanvas,提供縮放、平移、置中顯示功能。

方法 說明
SetMat(img) 設定顯示圖像
GetMat() 取得當前圖像
LoadImage(path) 從檔案載入(支援 Unicode 路徑)
SetZoomToFit() 縮放至適合視窗
SetOriginal() 恢復 1:1 原始大小
SetZoomIn() 放大
SetZoomOut() 縮小
SetCenterImageEnable(bool) 啟用圖像置中顯示
SetCanvasBgColor(r, g, b) 設定畫布背景顏色
SetSize(w, h) 調整面板大小
Refresh() 強制重新繪製
IsOk() 面板是否正常初始化
GetHandle() 取得原生視窗 Handle

5.2.1 滑鼠操作快捷鍵

操作 行為
滾輪上 / 下 畫面垂直捲動(圖像放大時生效)
水平傾斜滾輪 畫面水平捲動(支援水平滾輪的滑鼠)
Ctrl + 滾輪上 以滑鼠位置為中心放大圖像
Ctrl + 滾輪下 以滑鼠位置為中心縮小圖像
中鍵按住拖曳 自由平移畫面(圖像放大時生效)
右鍵點擊 開啟 ROI 右鍵選單(或觸發 Python 回調)

此設計符合 CVAT、LabelMe 等主流標注軟體的操作慣例。

5.3 wxCvROIAdvPanel — 進階 ROI 編輯面板

繼承 wxCvPanel,增加完整的 ROI 工具集與事件系統。

除了繼承 wxCvPanel 的所有方法外,還提供:

方法 說明
SetFuncEnable(menu, crop, move) 啟用右鍵選單 / Crop 功能 / 移動功能
SetMenuROIEnable(...) 控制右鍵選單中各 ROI 工具的顯示
SetROIMode(mode) 設定當前 ROI 工具(0–7)
GetROIMode() 取得當前 ROI 工具
GetRect() 取得 ROI 邊界框 (x, y, w, h)
GetPolygonPoints() 取得多邊形頂點 [(x,y), ...]
GetRotateAngle() 取得旋轉角度
GetInnerRadius() 取得環形內半徑
GetOuterRadius() 取得環形外半徑
GetStartAngle() 取得環形起始角度
GetEndAngle() 取得環形結束角度
GetLeftMouseDownPoint() 取得拖曳起點(原圖座標)
GetLeftMouseUpPoint() 取得拖曳終點(原圖座標)
SetEditingROI(mode, pts, angle) 以程式設定 ROI
AppendOverlay(mode, pts, color, size, angle?) 新增疊加層
AppendMaskOverlay(mask, color, alpha) 新增遮罩疊加層
ClearOverlay() 清除所有疊加層
SetDisplayOverlay(bool) 顯示 / 隱藏疊加層
UpdateDrawImage(bool) 強制更新渲染(加上 True 重建快取)
ConvertMaskToPolygon(mask) 將二值遮罩轉為多邊形點集

6. ROI 工具詳解

6.1 ROI 模式編號

編號 名稱 說明 互動方式
0 Nothing 無工具(清除 ROI)
1 Point 左鍵點擊
2 Line 線段 左鍵拖曳
3 Rectangle 矩形 左鍵拖曳
4 RotatedRect 旋轉矩形 左鍵拖曳,拖曳邊緣旋轉
5 Circle 圓形 左鍵拖曳
6 Annulus 環形(扇環) 左鍵拖曳
7 Polygon 多邊形 左鍵逐點點擊,雙擊結束(或點擊第一個頂點閉合)
roi_panel.SetROIMode(3)  # 切換到矩形工具

6.2 ROI 參數格式

以下是 SetEditingROIAppendOverlay 使用的點集格式(非常重要,格式不正確會靜默失敗):

模式 SetEditingROI pts 格式 AppendOverlay pts 格式 備註
Point (1) [(x, y)] [(x, y), ...] 多點
Line (2) [(x1, y1), (x2, y2)] 同左
Rectangle (3) [(左上x, 左上y), (寬, 高)] 同左
RotatedRect (4) [(左上x, 左上y), (寬, 高)] + angle 參數 同左 + angle 參數
Circle (5) [(cx, cy), (radius, 0)] 同左 GetRect 回傳的 (x,y) 是圓心
Annulus (6) [(cx, cy), (outer_r, 0), (inner_r, 0), (start, end)] [(cx, cy), (0, 0), (inner_r, outer_r), (start, end)] ⚠️ 兩者格式略有不同
Polygon (7) [(x1, y1), (x2, y2), ..., (xn, yn)] 同左

環形(Annulus)注意SetEditingROIAppendOverlay 的 pts 格式在 pts[1], pts[2] 欄位順序不同,使用前請仔細確認。

6.3 取得 ROI 資料

mode = roi_panel.GetROIMode()
rect = roi_panel.GetRect()  # (x, y, w, h)

if mode == 3:   # Rectangle
    x, y, w, h = rect
    print(f"矩形: ({x}, {y}) 寬={w} 高={h}")

elif mode == 4: # RotatedRect
    x, y, w, h = rect
    angle = roi_panel.GetRotateAngle()
    print(f"旋轉矩形: ({x}, {y}) 寬={w} 高={h} 角度={angle:.1f}°")

elif mode == 5: # Circle
    # 注意:Circle 的 GetRect 回傳 (cx, cy, ?, ?),x,y 是圓心
    cx, cy = rect[0], rect[1]
    radius = roi_panel.GetOuterRadius()
    print(f"圓形: 圓心=({cx}, {cy}) 半徑={radius}")

elif mode == 6: # Annulus
    cx, cy = rect[0], rect[1]
    inner_r = roi_panel.GetInnerRadius()
    outer_r = roi_panel.GetOuterRadius()
    start   = roi_panel.GetStartAngle()
    end     = roi_panel.GetEndAngle()
    print(f"環形: 圓心=({cx}, {cy}) 內徑={inner_r} 外徑={outer_r} "
          f"角度={start:.1f}°~{end:.1f}°")

elif mode == 7: # Polygon
    pts = roi_panel.GetPolygonPoints()
    print(f"多邊形: {len(pts)} 個頂點")
    for i, (x, y) in enumerate(pts):
        print(f"  [{i}] ({x:.1f}, {y:.1f})")

6.4 以程式設定 ROI(SetEditingROI)

# 設定矩形 ROI(左上角 100,80,寬 200,高 150)
roi_panel.SetROIMode(3)
roi_panel.SetEditingROI(3, [(100, 80), (200, 150)], 0.0)

# 設定圓形 ROI(圓心 320,240,半徑 80)
roi_panel.SetROIMode(5)
roi_panel.SetEditingROI(5, [(320, 240), (80, 0.1)], 0.0)
# 注意:第二個點的 y 值用 0.1 而非 0,避免 C++ 有效性檢查拒絕

# 設定多邊形 ROI(五芒星)
import math
pts = []
for j in range(10):
    a = -math.pi/2 + j * math.pi/5
    r = 100 if j % 2 == 0 else 40
    pts.append((320 + r*math.cos(a), 240 + r*math.sin(a)))
roi_panel.SetROIMode(7)
roi_panel.SetEditingROI(7, pts, 0.0)

7. 疊加層系統(Overlay)

Overlay 系統允許在圖像上疊加多個 ROI 形狀,每個可指定不同顏色,用於同時顯示多個標注結果。

7.1 基本使用

# 清除所有既有的 overlay
roi_panel.ClearOverlay()

# 顏色格式為 OpenCV BGR:(Blue, Green, Red)
red    = (0, 0, 255)
green  = (0, 255, 0)
blue   = (255, 0, 0)
yellow = (0, 255, 255)

# AppendOverlay(mode, points, color, line_width, angle=0.0)

# 矩形:[(左上x, 左上y), (寬, 高)]
roi_panel.AppendOverlay(3, [(50, 50), (200, 100)], red, 2)

# 圓形:[(圓心x, 圓心y), (半徑, 0)]
roi_panel.AppendOverlay(5, [(320, 240), (80, 0)], green, 2)

# 旋轉矩形:帶 angle 參數
roi_panel.AppendOverlay(4, [(150, 150), (180, 90)], blue, 2, 30.0)

# 環形:[(圓心), (0, 0), (inner_r, outer_r), (start_angle, end_angle)]
roi_panel.AppendOverlay(6, [(400, 300), (0, 0), (40, 80), (30, 210)], yellow, 2)

# 顯示 overlay
roi_panel.SetDisplayOverlay(True)

# 更新畫面(True = 重建快取)
roi_panel.UpdateDrawImage(True)

7.2 遮罩疊加(Mask Overlay)

適合顯示語義分割模型的輸出結果(如 SAM 分割遮罩):

import numpy as np
import cv2

# 建立二值遮罩(0 = 背景,255 = 前景)
mask = np.zeros((480, 640), dtype=np.uint8)
cv2.fillPoly(mask, [np.array([(100,100),(300,100),(300,300),(100,300)])], 255)

# AppendMaskOverlay(mask, color_bgr, alpha)
# alpha: 0.0 = 完全透明,1.0 = 完全不透明
roi_panel.AppendMaskOverlay(mask, (0, 0, 255), 0.5)  # 半透明紅色

roi_panel.SetDisplayOverlay(True)
roi_panel.UpdateDrawImage(True)

7.3 遮罩轉多邊形

# 將 AI 模型輸出的 pixel mask 轉換為可編輯的多邊形
polygon_pts = roi_panel.ConvertMaskToPolygon(mask)

# 設定為可編輯的 ROI
roi_panel.SetEditingROI(7, polygon_pts, 0.0)
roi_panel.SetROIMode(7)

8. 事件回調

8.1 Crop 事件(使用者完成 ROI)

使用者拖曳完成 ROI 後觸發:

def on_crop(rect):
    # rect = (x, y, w, h),原圖座標
    x, y, w, h = rect
    print(f"ROI 完成: x={x:.0f} y={y:.0f} w={w:.0f} h={h:.0f}")

roi_panel.SetOnCropCallback(on_crop)

注意:回調在 C++ 執行緒觸發,若要更新 GUI(如 wx.TextCtrl),必須使用 wx.CallAfter

def on_crop(rect):
    wx.CallAfter(self.info_label.SetLabel, f"Rect: {rect}")

8.2 右鍵點擊委派(REQ-006)

攔截右鍵點擊,由 Python 自定義行為:

def on_right_click(pt, hit_index):
    """
    pt         : (x, y) 原圖座標(浮點數)
    hit_index  : 點擊到的 overlay 索引;-1 表示沒有點到任何 ROI
    return True  → 攔截(隱藏 C++ 原生右鍵選單)
    return False → 不攔截(顯示 C++ 原生右鍵選單)
    """
    x, y = pt
    if hit_index >= 0:
        print(f"點擊到第 {hit_index} 個 ROI,座標: ({x:.1f}, {y:.1f})")
        # 在此實作自定義選單
        return True   # 攔截原生選單
    return False      # 未點到 ROI,顯示原生選單

roi_panel.SetOnRightClickCallback(on_right_click)

# 恢復 C++ 原生選單
roi_panel.SetOnRightClickCallback(None)

8.3 滑鼠移動與雙擊(REQ-010)

即時追蹤滑鼠在圖像上的座標,以及雙擊事件(適合 SAM 互動標注、快速刪除等):

def on_mouse_move(pt):
    """pt = (x, y) 原圖座標,高頻觸發"""
    # 使用 CallAfter 更新 GUI,避免跨執行緒問題
    wx.CallAfter(status_bar.SetStatusText, f"座標: ({pt[0]:.1f}, {pt[1]:.1f})")

def on_left_dclick(pt):
    """左鍵雙擊,適合快速選取 / SAM 前景點"""
    wx.CallAfter(print, f"左鍵雙擊: ({pt[0]:.1f}, {pt[1]:.1f})")

def on_right_dclick(pt):
    """右鍵雙擊,適合快速刪除 / SAM 背景點"""
    wx.CallAfter(print, f"右鍵雙擊: ({pt[0]:.1f}, {pt[1]:.1f})")

roi_panel.SetOnMouseMoveCallback(on_mouse_move)
roi_panel.SetOnLeftDClickCallback(on_left_dclick)
roi_panel.SetOnRightDClickCallback(on_right_dclick)

# 取消回調
roi_panel.SetOnMouseMoveCallback(None)

效能說明on_mouse_move 為高頻回調,只在有註冊回調時才有 Python GIL 開銷。未註冊時完全無效能影響。


9. 視窗嵌入與 Resize

9.1 Resize 手動同步

由於 C++ panel 使用原生 API 嵌入(非 wxSizer 管理),不會自動跟隨父容器縮放,需手動同步:

class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, size=(800, 600))
        self.container = wx.Panel(self)
        self.cv_panel  = None

        # 綁定容器的 resize 事件(注意是 container,不是 frame)
        self.container.Bind(wx.EVT_SIZE, self.on_container_resize)

    def on_container_resize(self, event):
        if self.cv_panel and self.cv_panel.IsOk():
            sz = self.container.GetSize()
            self.cv_panel.SetSize(sz.width, sz.height)
            self.cv_panel.Refresh()
        event.Skip()  # 必須呼叫,讓 sizer 繼續處理

9.2 延遲初始化(必須在視窗顯示後)

C++ panel 需要有效的原生 Handle 才能初始化。Handle 在視窗顯示後才穩定可用,因此推薦使用 EVT_SHOW + wx.CallAfter

def on_show(self, event):
    if event.IsShown() and self.cv_panel is None:
        wx.CallAfter(self.init_panel)  # 延遲一個事件循環,確保 Handle 有效
    event.Skip()

10. API 快速參考

顯示控制

方法 說明
SetMat(img) 設定 NumPy array 圖像(BGR/BGRA/Gray)
GetMat() 取得圖像
LoadImage(path) 從檔案載入(支援 Unicode 路徑)
SetZoomToFit() 縮放至適合
SetOriginal() 1:1 原始大小
SetZoomIn() 放大
SetZoomOut() 縮小
SetCenterImageEnable(bool) 啟用圖像置中
SetCanvasBgColor(r, g, b) 設定背景顏色

ROI 控制

方法 說明
SetROIMode(mode) 設定工具(0–7)
GetROIMode() 取得當前工具
SetFuncEnable(m, c, mv) 啟用選單 / Crop / 移動
SetMenuROIEnable(...) 控制選單中各工具可見性(7個 bool)
SetEditingROI(mode, pts, angle) 以程式設定 ROI
GetRect() 取得邊界框 (x, y, w, h)
GetPolygonPoints() 取得多邊形頂點
GetRotateAngle() 取得旋轉角度
GetInnerRadius() 取得環形內半徑
GetOuterRadius() 取得環形外半徑
GetStartAngle() 取得環形起始角度
GetEndAngle() 取得環形結束角度

Overlay 控制

方法 說明
AppendOverlay(mode, pts, color, size, angle?) 新增疊加形狀
AppendMaskOverlay(mask, color, alpha) 新增遮罩疊加
ClearOverlay() 清除所有疊加
SetDisplayOverlay(bool) 顯示 / 隱藏疊加
UpdateDrawImage(True) 強制更新渲染
ConvertMaskToPolygon(mask) 遮罩轉多邊形

回調設定

方法 說明
SetOnCropCallback(fn) ROI 完成回調 fn(rect)
SetOnRightClickCallback(fn) 右鍵回調 fn(pt, hit_index) → bool
SetOnMouseMoveCallback(fn) 滑鼠移動回調 fn(pt)
SetOnLeftDClickCallback(fn) 左鍵雙擊回調 fn(pt)
SetOnRightDClickCallback(fn) 右鍵雙擊回調 fn(pt)

11. 常見問題

Q1:macOS 出現 RuntimeError: wxCvModule on macOS requires 'import wx' before 'import wxCvModule'

原因:macOS 版本的 wxCvModule 使用 dynamic_lookup 在執行時從 wxPython 解析 wx 符號。若 wxPython 未先載入,C++ 找不到 wxApp 實例。

解決:確保程式碼中 import wximport wxCvModule 之前執行,包含所有間接匯入路徑。


Q2:面板建立後空白(白色或黑色畫面)

常見原因與解決方式:

症狀 可能原因 解決方式
白色畫面(macOS) 未使用 Reparent,直接 NSView 嵌入 使用 wxCvModule 提供的 API,不要自行做 Cocoa 嵌入
黑色畫面(macOS) setWantsLayer:YES 衝突 不要對容器 NSView 手動設定 layer
空白(所有平台) init_panel 在視窗顯示前執行 使用 EVT_SHOW + wx.CallAfter 延遲初始化
空白(所有平台) Handle 取得時機過早 確保 GetHandle()Show() 之後才呼叫

Q3:視窗關閉後 Python 程式不退出(macOS)

原因:C++ 隱藏框架(hidden wxFrame)是 top-level window,會阻止 wxApp 結束。

解決:在 EVT_CLOSE 中手動釋放 panel:

def on_close(self, event):
    self.cv_panel  = None  # 觸發 C++ 析構 → 銷毀隱藏框架
    self.roi_panel = None
    self.Destroy()

Q4:Resize 後圖像沒有跟著縮放

C++ panel 不使用 wxSizer 管理,必須手動同步:

def on_resize(self, event):
    if self.cv_panel and self.cv_panel.IsOk():
        sz = self.container.GetSize()
        self.cv_panel.SetSize(sz.width, sz.height)
        self.cv_panel.Refresh()
    event.Skip()

Q5:Linux 上出現 libgtk-3.so: cannot open shared object file

安裝 GTK3 執行時函式庫:

sudo apt install libgtk-3-0          # Ubuntu/Debian
sudo dnf install gtk3                 # Fedora/RHEL
sudo pacman -S gtk3                   # Arch Linux

Q6:回調函數更新 GUI 時出現 Assertion 或崩潰

C++ 回調可能在非 GUI 執行緒觸發。使用 wx.CallAfter 確保 GUI 更新在主執行緒執行:

def on_mouse_move(pt):
    # ❌ 直接更新可能崩潰
    # self.label.SetLabel(f"{pt}")

    # ✅ 透過 CallAfter 安全更新
    wx.CallAfter(self.label.SetLabel, f"({pt[0]:.0f}, {pt[1]:.0f})")

Q7:AppendOverlay 沒有效果

常見原因:

  1. 忘記呼叫 SetDisplayOverlay(True) 開啟 overlay 顯示。
  2. 忘記呼叫 UpdateDrawImage(True) 觸發重繪。
  3. 點集格式不正確(請對照第 6.2 節的格式表)。
roi_panel.ClearOverlay()
roi_panel.AppendOverlay(3, [(100, 100), (200, 150)], (0, 0, 255), 2)
roi_panel.SetDisplayOverlay(True)   # 必須!
roi_panel.UpdateDrawImage(True)     # 必須!

本指南對應 wxCvModule v1.5 及以上版本。 完整範例程式請參閱 examples/python_demo.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

wxcvmodule-0.1.0-cp314-cp314-win_amd64.whl (36.4 MB view details)

Uploaded CPython 3.14Windows x86-64

wxcvmodule-0.1.0-cp313-cp313-win_amd64.whl (36.4 MB view details)

Uploaded CPython 3.13Windows x86-64

wxcvmodule-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.2 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

wxcvmodule-0.1.0-cp313-cp313-macosx_26_0_arm64.whl (32.8 MB view details)

Uploaded CPython 3.13macOS 26.0+ ARM64

wxcvmodule-0.1.0-cp312-cp312-win_amd64.whl (36.4 MB view details)

Uploaded CPython 3.12Windows x86-64

wxcvmodule-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.2 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

wxcvmodule-0.1.0-cp312-cp312-macosx_26_0_arm64.whl (32.8 MB view details)

Uploaded CPython 3.12macOS 26.0+ ARM64

wxcvmodule-0.1.0-cp311-cp311-win_amd64.whl (36.4 MB view details)

Uploaded CPython 3.11Windows x86-64

wxcvmodule-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.2 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

wxcvmodule-0.1.0-cp311-cp311-macosx_26_0_arm64.whl (32.8 MB view details)

Uploaded CPython 3.11macOS 26.0+ ARM64

wxcvmodule-0.1.0-cp310-cp310-win_amd64.whl (36.4 MB view details)

Uploaded CPython 3.10Windows x86-64

wxcvmodule-0.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.2 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

wxcvmodule-0.1.0-cp310-cp310-macosx_26_0_arm64.whl (32.7 MB view details)

Uploaded CPython 3.10macOS 26.0+ ARM64

wxcvmodule-0.1.0-cp39-cp39-win_amd64.whl (36.4 MB view details)

Uploaded CPython 3.9Windows x86-64

wxcvmodule-0.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.2 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

wxcvmodule-0.1.0-cp39-cp39-macosx_26_0_arm64.whl (32.8 MB view details)

Uploaded CPython 3.9macOS 26.0+ ARM64

wxcvmodule-0.1.0-cp38-cp38-win_amd64.whl (36.4 MB view details)

Uploaded CPython 3.8Windows x86-64

wxcvmodule-0.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.2 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

Details for the file wxcvmodule-0.1.0-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: wxcvmodule-0.1.0-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 36.4 MB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for wxcvmodule-0.1.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 86be909708298cdba06a6c00ab152bdcff7bd18ebdefc448c8861e319dc44a61
MD5 9023b510948ab050ed962af4ac724aa5
BLAKE2b-256 7e2e5d5c116fec293e0bcad3c676dc11a09748f5772ac4aadc7d85bbb7a85351

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: wxcvmodule-0.1.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 36.4 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for wxcvmodule-0.1.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 c5d088b140e33caf778c6e7a1cf2d82cccdc48ace304a0c361838dc4d2c1558c
MD5 2cced0c014aa92735ef3c1191c5844a2
BLAKE2b-256 c2d01d0534bee3d72fee41c91c7b50825d0b7ba97865c0460c8cffb6d49e2ab4

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1b77c05e74977986b67d9512dc94c4591cbcbdf679541e9bb365eaeb7fe8f094
MD5 97817510088002a0e4834c5278fcceca
BLAKE2b-256 533cfe3a3cc5e10f58cce81816aabb210f7d3b15feb881e30c42e58c14cb12ab

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp313-cp313-macosx_26_0_arm64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp313-cp313-macosx_26_0_arm64.whl
Algorithm Hash digest
SHA256 94bc72c5ecb099cd465dffa8542a006eb3fafe5df77fc44d8502daa653ceb244
MD5 b5bf10273b34e7e43f72aa884b13c554
BLAKE2b-256 b9fa2962e78751c6ccf756bc33968a16c4c8a9137d050999738470a2897f33bb

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: wxcvmodule-0.1.0-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 36.4 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for wxcvmodule-0.1.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 b4f3206ea3770058d7d5f0e83cf5d4aa52ec8e0b559d653c25a37d2d91b424a4
MD5 5243f7e066cad66222139c4cde10cedf
BLAKE2b-256 7f647b0a4576d64d939c8156914d04c5eaef116399763601ca1ae0f070d22614

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 325e7834eb51310ffa2ed39ecd2d3cc46a730648adcbaebf82c031b7d1d5be48
MD5 c69246d5159946a38c14b2511d76de33
BLAKE2b-256 2a2bb1a640b0de9bd0983cdd0b68cace3078d4816e4d39ffa3d3755792f12a9f

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp312-cp312-macosx_26_0_arm64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp312-cp312-macosx_26_0_arm64.whl
Algorithm Hash digest
SHA256 db077c7b2a44f81928c990fada5d40125fc86235ce7e28c85a3a57cf28ce081b
MD5 6ed32e92edfb0209a63ac6e86f7bd0a5
BLAKE2b-256 07b7a9f3320a4b228474fbd7780680b8c40e11b8f86e931ec6cdd589dc7b00d2

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: wxcvmodule-0.1.0-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 36.4 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for wxcvmodule-0.1.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 97670892fbf4f231b8cf58e05d5f7e28ed775456807965c88d73e7991ea946a9
MD5 defb38bc98eb99b855537f42724f358f
BLAKE2b-256 8e90629a70fcc765d6b93af2b2a5247d049be5dbe1a93f07a10060a70045c05c

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ca558f45a480c2d9885db17b640b884e4200fbb307c4b7607f7e9f444ab3268b
MD5 c17bfb925d880ec0c3c7c5436a9a5900
BLAKE2b-256 d93cd107c3378e4d60288fe7bc6e4913630cfd002029b79f345361f19e16c0bb

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp311-cp311-macosx_26_0_arm64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp311-cp311-macosx_26_0_arm64.whl
Algorithm Hash digest
SHA256 bfacb8b048674819e3f71b3724c5fd2b805a8a13cebf06fe76c2a4e1569e42c1
MD5 f47cee029ed903c2008569eed5eabad2
BLAKE2b-256 ab845c5172e739da0c0d11287e9b631733f923bcc8bf35e9c3a8b3f795230e8a

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: wxcvmodule-0.1.0-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 36.4 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for wxcvmodule-0.1.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 126074a687881df337f9758062523e4e2e5d761db5217869edc513524d81a6d0
MD5 0857b66e4395411ef794dc2df1d66ebc
BLAKE2b-256 7d44c14094327b7b950b0e79694e3ce92eec33524a95c3894389bd829222001d

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e50f282d6165900d0752840616a71fda26d713e273ded881c19dc58d3ca0d325
MD5 9eed279ebabd597a05bf4f6461bdba1f
BLAKE2b-256 e796fe46d4977b6830f7db287dcc0bd847468d388e1ef57480733c94a84a31d4

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp310-cp310-macosx_26_0_arm64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp310-cp310-macosx_26_0_arm64.whl
Algorithm Hash digest
SHA256 4c907f6969229f17e8a2d8347ba060ab19d610da75f2a94bc6a70f12539f3ec1
MD5 3b2f4e066f5e2c680291b0718fddf507
BLAKE2b-256 ad9f779a4c71b0d44e5c6ff072b738e49b65b44d11f35c301a56e429cec5d455

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: wxcvmodule-0.1.0-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 36.4 MB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for wxcvmodule-0.1.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 adffc8ba100f64e99ac2acc1d0f9a9e7cb52f548f6af8856d287d488f44d5572
MD5 ee91da3b6244887b50cc101a99cbcb1f
BLAKE2b-256 9e28e954d6cc8813433248671ef294b0fde636d05b733474d2d692f34b7bfdc9

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 43af7e7fc9aea0ebd1c6f0c66ddc4bf232c158fdadaea1482bfb59cf22a4b875
MD5 785c2dc2438f759874d425df0054a70c
BLAKE2b-256 5092cd35795676890e2d9a5caca8d74081da891eb3cf76b9a6055de00f2a3e07

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp39-cp39-macosx_26_0_arm64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp39-cp39-macosx_26_0_arm64.whl
Algorithm Hash digest
SHA256 e0c6b0d34eb6f02c720ebfbf97ec74121d9e6eee4560473b4bbef40a0c38c5b0
MD5 accf6b43dbe0c3a177c373264ee1383c
BLAKE2b-256 c9e0614b549b763b850d4780869b358e0c6d4700cacce06d6fbb00434b45e89f

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp38-cp38-win_amd64.whl.

File metadata

  • Download URL: wxcvmodule-0.1.0-cp38-cp38-win_amd64.whl
  • Upload date:
  • Size: 36.4 MB
  • Tags: CPython 3.8, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for wxcvmodule-0.1.0-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 a1cf2a5d23ecfa8a9eb62e77118e3bf074b1d6b86ef8d19ec232261eb8b85536
MD5 bdd79bc9cd91b50824b571953048ed5e
BLAKE2b-256 30ba011aba2a3212f5fe5833210e8eb68eb633949994e9d22e7002c56e517a90

See more details on using hashes here.

File details

Details for the file wxcvmodule-0.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for wxcvmodule-0.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 8e8e4e093c8c0b00abc9b10c16b655af2d522a95349b2d54fc7963ac410223a5
MD5 5d743b029a2db8f7ab9ba744e07e7457
BLAKE2b-256 53855203f2154e6aebf6cb65c70d11ce4f59362cbb87093f9f7b3a7d321f93f6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page