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\n\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:后續補充

 


免責聲明!

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



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