分為兩步: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到合適的幀。
4.cvGrabFrame
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顯示到控件上 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:后續補充