• Opencv+MFC获取摄像头数据,显示在Picture控件


    分为两步:OpenCV获取摄像头数据+图像在Picture上显示

    第一步:OpenCV获取摄像头数据

    参考:http://www.cnblogs.com/epirus/archive/2012/06/04/2535190.html

    http://blog.sina.com.cn/s/blog_6dbe9bdb0100nii7.html

    http://blog.csdn.net/augusdi/article/details/8762961

    #include "stdafx.h"
    #include <atltime.h>
    #include <highgui.h>
    int main()
    {
        int c;
        CTime time;
        IplImage *img;
        CvCapture* capture = cvCaptureFromCAM(1);
        cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
        cvMoveWindow("mainWin", 50, 50);
        while(1)
        {
            img=cvQueryFrame(capture);
            cvShowImage("mainWin", img );
            c=cvWaitKey(10);
            //按 s 鍵儲存成 jpg 檔
            if(c=='s'){
                time = CTime::GetCurrentTime();
                CStringA filename(time.Format(CString("%Y%m%d%H%M%S"))+".jpg");
                cvSaveImage(filename,img);
            }
            //按 ESC 鍵離開
            if(c == 27)
            break;
        }
        cvReleaseImage(&img);
        cvDestroyWindow("mainWin");
        return 0;
    }

    在这里,要介绍下这几个重要函数:

    1.CvCapture

    视频获取结构   typedef struct CvCapture CvCapture;

    释放这个结构,使用函数cvReleaseCapture

    结构CvCapture 没有公共接口,它只能被用来作为视频获取函数的一个参数。这个是一个很重要的结构   以后无论是读取已有视频还是从摄像头获取都必须用到它。

    2.cvCaptureFromCAM

    CvCapture* cvCaptureFromCAM( int index );

    参数:index     要使用的摄像头索引。如果只有一个摄像头或者用哪个摄像头也无所谓。

      函数给从摄像头的视频流分配和初始化CvCapture结构。目前在Windows下可使用两种接口:Video for Windows(VFW)和Matrox Imaging Library(MIL); Linux下也有两种接口:V4L和FireWire(IEEE1394)。

    读摄像头用:CvCapture* capture=cvCaptureFromCAM(0);//参数也可以是-1,

    读AVI文件演示用: CvCapture* capture=cvCaptureFromFile(“XXX.avi”);

    cvCreateCameraCapture好像还没有什么区别。

    3.cvQueryFrame

    从摄像头或者文件中抓取并返回一帧

    IplImage* cvQueryFrame( CvCapture* capture );
    
    capture 视频获取结构。

    函数cvQueryFrame从摄像头或者文件中抓取一帧,然后解压并返回这一帧。这个函数仅仅是函数cvGrabFrame和函数cvRetrieveFrame在一起调用的组合。返回的图像不可以被用户释放或者修改。抓取后,capture被指向下一帧,可用cvSetCaptureProperty调整capture到合适的帧。

    注意: cvQueryFrame返回的指针总是指向同一块内存。建议cvQueryFrame后拷贝一份。而且返回的帧需要FLIP后才符合OPENCV的坐标系。
    若返回值为NULL,说明到了视频的最后一帧或失败!
    指向同一块内存的证明详解:http://blog.sina.com.cn/s/blog_6d1fb09e0100wcm0.html

    4.cvGrabFrame

    从摄像头或者视频文件中抓取帧
    int cvGrabFrame( CvCapture* capture );
    函数cvGrabFrame从摄像头或者文件中抓取帧。被抓取的帧在内部被存储。这个函数的目的是快速的抓取帧,这一点对同时从几个摄像头读取数据的同步是很重要的。被抓取的帧可能是压缩的格式(由摄像头/驱动定义),所以没有被公开出来。如果要取回获取的帧,请使用cvRetrieveFrame
    cvQueryFrame 是函数 cvGrabFrame 和函数 cvRetrieveFrame 的组合调用,直接返回一幅图像。单独cvGrabFrame不能。
     
    参考:http://blog.csdn.net/autumn20080101/article/details/7515520
    程序示例:
    int main( int argc, char** argv )  
    {  
    // if( argc == 2 && (pImg = cvLoadImage( argv[1], CV_LOAD_IMAGE_UNCHANGED)) != 0 )  
    //    return 0;  
    CvCapture* capture = cvCaptureFromCAM(0); // capture from video device #0  
    //CvCapture* capture = cvCaptureFromAVI("infile.avi");  
    IplImage* img = 0;   
    //CVAPI(int) cvGrabFrame( CvCapture* capture );  
      
    cvNamedWindow("image",CV_WINDOW_AUTOSIZE);  
    char c=cvWaitKey(3);  
    while(c!=27)  
    {  
    if(!cvGrabFrame(capture)){              // capture a frame   
      printf("Could not grab a frame
    7");  
      exit(0);  
    }  
        //CVAPI(IplImage*) cvRetrieveFrame( CvCapture* capture );  
    img=cvRetrieveFrame(capture);           // retrieve the captured frame  
      
    cvShowImage("image",img);  
    c=cvWaitKey(20);  
    }  
    //由视频流捕捉器得到的图像是由捕捉器分配和释放内存的,不需要单独对图像进行释放内存的操作  
    //cvReleaseImage(&img);  
    cvDestroyWindow("image");  
    cvReleaseCapture(&capture);  
     return 0;  
    }  
     第二步:IplImage在Picture控件上显示
    在这里,摄像头视频如果在Picture上显示,并实时更新,实现方法:多线程或定时器,在这里用定时器来实现视频数据的更新。
    参考:http://www.cnblogs.com/leven20061001/archive/2012/10/17/2727865.html ,(定时器实现,较详细)
    http://blog.csdn.net/poem_of_sunshine/article/details/17123577
    程序示例:
    // 将IplImage显示到控件上
    void CPalmVeinRecogDlg::IplDrawToHDC(IplImage* image, UINT ID)// ID 是Picture Control控件的ID号
    {
        CDC* pDC = GetDlgItem(ID)->GetDC();
        HDC pHdc = pDC->GetSafeHdc(); //从MFC的界面上获取Picture控件的绘图句柄HDC, 
        CRect rect;
        GetDlgItem(ID)->GetClientRect(&rect); //rect为控件的大小,获得pictrue控件所在的矩形区域
        //SetStretchBltMode(pHdc, STRETCH_HALFTONE);
        
        CvvImage cimg;  //将IplImage类型的图片转换成MFC能显示的图片格式CvvImage
        cimg.CopyOf(image);
        cimg.DrawToHDC(pHdc, rect);
    
        ReleaseDC(pDC);//一定要记住释放DC,否则会造成内存泄露
    }

    第三步:完整的程序实现

    //打开摄像头事件处理
    void CPalmVeinRecogDlg::OnBnClickedOpencam()
    {
        CString cStr;
        CWnd* pWndOpenCam = GetDlgItem(IDC_OPENCAM);
        //www = GetDlgItem(IDC_ShowImage2);
        pWndOpenCam->GetWindowText(cStr);
    
        if (cStr == "打开摄像头")
        {
            if (!m_capture)
            {
                m_capture = cvCaptureFromCAM(0); 
                if (!m_capture){
                    m_strDebugInfo.SetWindowText(_T("打开摄像头失败!"));
                    return;
                }
                m_isCamOpen = true;
                pWndOpenCam->SetWindowText("关闭摄像头");
                m_strDebugInfo.SetWindowText(_T("打开摄像头成功!"));
    
                //由视频流捕捉器得到的图像是由捕捉器分配和释放内存的,不需要单独对图像进行释放内存的操作
                m_currentFrame = cvQueryFrame(m_capture);
                // 将IplImage显示到控件上
                IplDrawToHDC(m_currentFrame, IDC_ShowImage);
            }
            SetTimer(ID_TIMERCAM, nClockTime, NULL); //定时器ID:1,定时器延时:100,
        }
        else
        {
            cvReleaseCapture(&m_capture);
            KillTimer(ID_TIMERCAM);
            pWndOpenCam->SetWindowText("打开摄像头");
            m_strDebugInfo.SetWindowText(_T("关闭摄像头成功!"));
        }
    }
    
    /********************************************设置定时器*********************************************/
    void CPalmVeinRecogDlg::OnTimer(UINT_PTR nIDEvent)
    {
        // TODO:  在此添加消息处理程序代码和/或调用默认值
        switch (nIDEvent)
        {
            case ID_TIMERCAM: //摄像头显示 定时器
            {
                if (m_isCamOpen){
                    m_currentFrame = cvQueryFrame(m_capture);
                    // 将IplImage显示到控件上
                    IplDrawToHDC(m_currentFrame, IDC_ShowImage);
                }
                break;
            }
        }
        CDialogEx::OnTimer(nIDEvent);
    }

    PS:后续补充

  • 相关阅读:
    函数(五)——装饰器,递归调用,匿名函数
    函数(四)——装饰器
    函数(三)
    函数(二)
    函数(一)
    python基础(九)
    python基础(八)
    python基础(七)
    javaweb开发 idea ssm开发(二)
    PHP计算两个经纬度地点之间的距离
  • 原文地址:https://www.cnblogs.com/zwh0214/p/6049066.html
Copyright © 2020-2023  润新知