MFC&Halcon之實時視頻監控

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

要實現的功能是點擊一個「開始」按鈕,能夠顯示影像,再點擊「中止」按鈕,能夠中止顯示。多線程

由於實時顯示影像須要在一個循環裏執行,爲了在顯示影像的同時還能夠幹別的(好比,點擊「中止」按鈕),這裏須要用到多線程,即顯示影像的代碼放到子線程中,與主線程併發執行。併發

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

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

二、Halcon代碼導出爲C++代碼函數

三、創建MFC工程優化

四、在MFC中添加Halcon代碼ui

下面說細節:this

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

image

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

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)
 

二、導出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循環中只是獲取了圖像,並無顯示圖像,因此咱們還要添加顯示圖像的代碼。

三、創建MFC工程

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

image

四、添加C++代碼

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

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

#include "halconcpp.h"
using namespace HalconCpp;

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

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

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

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

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

HANDLE hThread;
DWORD ThreadID;

而後在HalconCameraDlg.cpp中添加代碼:

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

volatile BOOL m_bRun;

volatile BOOL m_bShowFlag;

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

二、爲開始按鈕添加單機響應函數

	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,因此下次點擊「開始」按鈕時不會再次開啓子線程,而只是修改線程中的標誌位來啓動實時監控。

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

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時顯示會中止,實現了前述的功能(注意,此時線程並不退出)。

四、中止按鈕的響應函數

只須要一句話就夠了。由於m_bRun被聲明爲volatile變量,在子線程外部能夠更改它,修改成FALSE以後子線程中實時顯示的語句就沒法執行,表現出來就是圖像靜止,再也不更新。

m_bRun=FALSE;

遇到的問題:

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

以前我試過在中止按鈕裏把m_bShowFlag置爲FALSE,即讓線程退出,而後再次點擊開始按鈕時從新啓動線程,可是在關閉窗口時會出現下面的錯誤。

觸發了一個斷點。其緣由多是堆被損壞。緣由也多是用戶在HalconCamera.exe具備焦點時按下了F12。

Image 1

這個錯誤多是退出線程時沒有把空間釋放乾淨所致,在屢次的開啓與關閉子線程(即屢次點擊開始和中止按鈕)後,就會出現問題。

因此只能改成如今的線程不退出方案,讓子線程一直執行,經過修改其中的標誌位來啓動和中止顯示。

相關文章
相關標籤/搜索