zoukankan      html  css  js  c++  java
  • 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

    这个错误可能是退出线程时没有把空间释放干净所致,在多次的开启与关闭子线程(即多次点击开始和停止按钮)后,就会出现问题。

    所以只能改为现在的线程不退出方案,让子线程一直执行,通过修改其中的标志位来启动和停止显示。

  • 相关阅读:
    HDU
    HDU
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/oucsheep/p/5911852.html
Copyright © 2011-2022 走看看