MFC&Halcon之實時視頻監控


上一篇實現了在MFC的窗體內顯示圖片,本篇介紹如何在MFC窗體內實時顯示攝像頭的影像。

要實現的功能是點擊一個“開始”按鈕,可以顯示影像,再點擊“停止”按鈕,可以停止顯示。

因為實時顯示影像需要在一個循環里執行,為了在顯示影像的同時還可以干別的(比如,點擊“停止”按鈕),這里需要用到多線程,即顯示影像的代碼放到子線程中,與主線程並發執行。

重點已經說清楚了,下面是開發步驟:

1、先把Halcon中實時顯示的程序搞定

2、Halcon代碼導出為C++代碼

3、建立MFC工程

4、在MFC中添加Halcon代碼

下面說細節:

1、打開Halcon,點擊助手,選擇打開新的Acquisition

image

從資源選項卡可以看到檢測到的接口為DirectShow,這是微軟開發的視頻設備驅動。

image

從連接選項卡能看到檢測到相機,是筆記本自帶的攝像頭。點擊上方的攝像機圖標,Halcon的圖形窗口就開始實時顯示攝像頭的畫面了,很方便。

image

下面點擊“代碼生成”選項卡,點擊“插入代碼”按鈕,就把實時顯示的代碼插入到代碼窗口中了。

注意這里的采集模式是異步采集,在循環中采集圖像的意思就是實時顯示。

image

生成的Halcon代碼如下:

* Image Acquisition 01: Code generated by Image Acquisition 01
open_framegrabber ('DirectShow', 1, 1, 0, 0, 0, 0, 'default', 8, 'rgb', -1, 'false', 'default', '[0] Integrated Camera', 0, -1, AcqHandle)
grab_image_start (AcqHandle, -1)
while (true)
    grab_image_async (Image, AcqHandle, -1)
    * Image Acquisition 01: Do something
endwhile
close_framegrabber (AcqHandle)
 

2、導出Halcon代碼

imageimage

導出的C++代碼中Action函數如下:

void action()
{
  // Local iconic variables 
  HObject  ho_Image;
  // Local control variables 
  HTuple  hv_AcqHandle;
  //Image Acquisition 01: Code generated by Image Acquisition 01
  OpenFramegrabber("DirectShow", 1, 1, 0, 0, 0, 0, "default", 8, "rgb", -1, "false", 
      "default", "[0] Integrated Camera", 0, -1, &hv_AcqHandle);
  GrabImageStart(hv_AcqHandle, -1);
  while (0 != 1)
  {
    GrabImageAsync(&ho_Image, hv_AcqHandle, -1);
    //Image Acquisition 01: Do something
  }
  CloseFramegrabber(hv_AcqHandle);
}

這就是我們需要添加到MFC的代碼,需要注意到while循環中只是獲取了圖像,並沒有顯示圖像,所以我們還要添加顯示圖像的代碼。

3、建立MFC工程

與上一篇類似,新建基於對話框的MFC項目,添加Picture Control 和兩個按鈕。

image

4、添加C++代碼

首先打開對話框類的頭文件HalconCameraDlg.h,需要做下面四件事:

1、在文件開頭添加Halcon頭文件以及命名空間

#include "halconcpp.h"
using namespace HalconCpp;

2、在類外添加線程函數的聲明

//線程函數的聲明應在類CMultiThread1Dlg的外部
void ThreadFunc(LPVOID lpParam);

3、在類內添加Halcon變量為對話框類的Public成員

HObject  ho_Image;
HTuple  hv_AcqHandle;
HTuple m_HWindowID;
HTuple m_FGHandle,m_ImageWidth,m_ImageHeight;

4、添加線程函數的變量為對話框類的Protected成員

HANDLE hThread;
DWORD ThreadID;

然后在HalconCameraDlg.cpp中添加代碼:

1、首先添加Halcon頭文件和命名空間,並定義全局變量

volatile BOOL m_bRun;

volatile BOOL m_bShowFlag;

Volatile關鍵詞告訴編譯器不對此變量進行優化,使該值可被多個線程修改,對於多線程意義重大。

2、為開始按鈕添加單機響應函數

	CWnd * pWnd = AfxGetApp()->GetMainWnd();
	if(m_bShowFlag){
		m_bRun=TRUE;
	}else{
		hThread = CreateThread(NULL,
			0,
			(LPTHREAD_START_ROUTINE) ThreadFunc, //
			this, //傳入主窗口指針
			0,
			&ThreadID );
	}
為了能隨時停止和開始實時監控,我設置了m_bShowFlag這個變量,第一次點擊“開始”按鈕時,m_bShowFlag為FALSE,執行CreateThread函數啟動子線程,在子線程中m_bShowFlag被置為TRUE,所以下次點擊“開始”按鈕時不會再次開啟子線程,而只是修改線程中的標志位來啟動實時監控。

3、子線程函數的實現代碼

void ThreadFunc(LPVOID pParam)
{
    CHalconCameraDlg * pMainWindow;
    pMainWindow=(CHalconCameraDlg * ) pParam; //強制轉化為主窗口指針
    HTuple HWindowID;
    CRect Rect;
    CWnd * pWnd = pMainWindow->GetDlgItem( IDC_STATIC);
    HWindowID = (Hlong)pWnd->m_hWnd;
    pWnd->GetWindowRect(&Rect);
    OpenWindow(0,0,Rect.Width(),Rect.Height(),HWindowID,"visible","",&(pMainWindow->m_HWindowID) );
    //顯示相機捕捉的圖像
    OpenFramegrabber("DirectShow", 1, 1, 0, 0, 0, 0, "default", 8, "rgb", -1, "false", 
        "default", "[0] Integrated Camera", 0, -1, &(pMainWindow->hv_AcqHandle) );
    GrabImageStart(pMainWindow->hv_AcqHandle, -1);
    ClearWindow(pMainWindow->m_HWindowID);
    GrabImage(&(pMainWindow->ho_Image), pMainWindow->hv_AcqHandle);
    GetImagePointer1((pMainWindow->ho_Image),NULL,NULL,&(pMainWindow->m_ImageWidth),&(pMainWindow->m_ImageHeight) );
    SetPart(pMainWindow->m_HWindowID,0,0,pMainWindow->m_ImageHeight-1,pMainWindow->m_ImageWidth-1);
    m_bShowFlag=TRUE;//設置運行狀態
    m_bRun=TRUE;
    while (m_bShowFlag){
        if(m_bRun){
            GrabImageAsync(&(pMainWindow->ho_Image), pMainWindow->hv_AcqHandle, -1);
            DispObj(pMainWindow->ho_Image, pMainWindow->m_HWindowID);
            Sleep(50);
        }
    }
    ClearWindow(pMainWindow->m_HWindowID);
    CloseFramegrabber(pMainWindow->hv_AcqHandle);
    CloseWindow(pMainWindow->m_HWindowID);
    ExitThread(0);
}

while循環之前的代碼與上一篇類似,循環中當m_bRun為TRUE時執行獲取與顯示圖像的語句,因此當全局變量m_bRun被置為FALSE時顯示會停止,實現了前述的功能(注意,此時線程並不退出)。

4、停止按鈕的響應函數

只需要一句話就夠了。因為m_bRun被聲明為volatile變量,在子線程外部可以更改它,修改為FALSE之后子線程中實時顯示的語句就無法執行,表現出來就是圖像靜止,不再更新。

m_bRun=FALSE;

遇到的問題:

在這個程序中,子線程一直沒有退出,即m_bShowFlag沒有被置為FLASE。

之前我試過在停止按鈕里把m_bShowFlag置為FALSE,即讓線程退出,然后再次點擊開始按鈕時重新啟動線程,但是在關閉窗口時會出現下面的錯誤。

觸發了一個斷點。其原因可能是堆被損壞。原因也可能是用戶在HalconCamera.exe具有焦點時按下了F12。

Image 1

這個錯誤可能是退出線程時沒有把空間釋放干凈所致,在多次的開啟與關閉子線程(即多次點擊開始和停止按鈕)后,就會出現問題。

所以只能改為現在的線程不退出方案,讓子線程一直執行,通過修改其中的標志位來啟動和停止顯示。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM