首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

MFC + OpenCV 多執行緒讀取多攝像頭並顯示至 Picture Control 實作架構

     編輯:程式設計綜合問答

需求

主對話框同時啟動多個攝像頭,每個攝像頭專屬執行緒抓取影像並即時顯示於對應的 Picture Control。

核心架構

  1. 參數封裝結構體:傳遞攝像頭索引/RTSP URL、目標 Picture Control ID、主視窗 `HWND`、停止旗標。
  2. 工作執行緒函數:`UINT __cdecl CameraThread(LPVOID pParam)`,內部建立 `cv::VideoCapture`、迴圈 `cap >> frame`、轉格式、送 UI 執行緒顯示。
  3. 跨執行緒 UI 更新:使用 `PostMessage` / `SendMessage` 將 `HBITMAP` 或 `cv::Mat` 指標傳給主視窗,主視窗 `OnCameraFrame` 處理 `SetBitmap`/`StretchBlt`。
  4. 資源管理:執行緒結束時釋放 `VideoCapture`、關閉事件、刪除結構體記憶體。

關鍵代碼骨架

// 參數結構
struct CameraParam {
    int camIndex;           // 或 CString rtspUrl
    UINT picCtrlId;         // 目標 Picture Control ID
    HWND hMainWnd;          // 主視窗接收訊息
    volatile bool* pStop;   // 停止旗標指標
    HANDLE hEventStop;      // 事件同步
};

// 執行緒函數
UINT __cdecl CameraThread(LPVOID pParam) {
    CameraParam* p = (CameraParam*)pParam;
    cv::VideoCapture cap(p->camIndex);
    if (!cap.isOpened()) { PostMessage(p->hMainWnd, WM_CAM_ERROR, p->picCtrlId, 0); return 1; }

    cv::Mat frame, bgr;
    while (!(*p->pStop)) {
        if (!cap.read(frame)) break;
        cv::cvtColor(frame, bgr, cv::COLOR_BGR2RGB); // Picture Control 需 RGB
        // 建立 HBITMAP (需深拷貝,因 frame 會被覆寫)
        HBITMAP hBmp = CreateBitmap(bgr.cols, bgr.rows, 1, 24, bgr.data);
        // 發送至主視窗,WPARAM=picCtrlId, LPARAM=hBmp
        PostMessage(p->hMainWnd, WM_CAM_FRAME, p->picCtrlId, (LPARAM)hBmp);
        Sleep(30); // 控制幀率 ~30fps
    }
    cap.release();
    SetEvent(p->hEventStop);
    return 0;
}

// 主視窗訊息處理
LRESULT CMainDlg::OnCamFrame(WPARAM wParam, LPARAM lParam) {
    UINT ctrlId = (UINT)wParam;
    HBITMAP hBmp = (HBITMAP)lParam;
    CStatic* pPic = (CStatic*)GetDlgItem(ctrlId);
    if (pPic) {
        HBITMAP hOld = pPic->SetBitmap(hBmp);
        if (hOld) DeleteObject(hOld); // 刪除舊位圖
    }
    return 0;
}

// 啟動多攝像頭
void CMainDlg::StartCameras() {
    for (int i = 0; i < CAM_COUNT; ++i) {
        CameraParam* p = new CameraParam{i, IDC_PIC_CAM1 + i, m_hWnd, &m_bStop[i], CreateEvent(NULL, TRUE, FALSE, NULL)};
        m_threads[i] = AfxBeginThread(CameraThread, p, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
        m_threads[i]->m_bAutoDelete = FALSE;
        m_threads[i]->ResumeThread();
    }
}

關鍵細節

  • HBITMAP 所有權轉移:`PostMessage` 後由主視窗負責 `DeleteObject`,避免 GDI 洩漏。
  • 影像格式:OpenCV 預設 BGR,Windows Bitmap 需 RGB/BGRA,務必 `cvtColor`。
  • 解析度適配:Picture Control 固定尺寸時,建議在主視窗 `StretchBlt` 或 `SetStretchBltMode(HALFTONE)` 縮放,而非傳輸前縮放 (減少執行緒負載)。
  • 優雅停止:關閉對話框時設 `m_bStop[i]=true`,`WaitForSingleObject(hEventStop, 5000)` 確認執行緒結束再 `DeleteObject` 事件與刪除參數結構體。

進階優化

  • 雙緩衝/三緩衝隊列 (`std::queue` + `std::mutex` + `std::condition_variable`) 解耦擷取與顯示。
  • 使用 Intel Media SDK / NVIDIA NVDEC 硬體解碼 RTSP 流。
  • 改用 `CImage` / `ATL::CBitmap` 簡化 GDI 操作。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved