日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于opencv和mfc的摄像头采集代码(GOMFCTemplate2)持续更新

發布時間:2023/12/20 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于opencv和mfc的摄像头采集代码(GOMFCTemplate2)持续更新 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ? 編寫帶界面的圖像處理程序,選擇opencv+mfc是一種很好的選擇;在讀取攝像頭數據方面,網上的方法很多,其中shiqiyu的camerads的方法是較好的。 ? ? ? 基于現有資料,通過在實際項目中的積累,我總結出來一套結合opencv和mfc的攝像頭采集框架。具有以下特點: ? ? ? 1、基于directshow,兼容性好,速度快。到目前為止,無論是工業相機還是普通相機,沒發現不兼容的; ? ? ? 2、攝像頭部分通過線程讀取,保證界面的運行流暢; ? ? ? 3、框架經過多次打磨,已經比較穩定,不會出現異常錯誤;代碼簡潔明了,方便復用。 一、代碼解析 ? ? ? ?框架為對話框模式代碼生成,加入CameraDS類和CvvImage類。 ? ? ?? CameraDS是shiqiyu編寫的,主要完成directshow的引入,提供了以下函數。能夠獲得目前相機總數,讀取相機名稱,打開相機以及獲得當前幀的數據等 //打開攝像頭,nCamID指定打開哪個攝像頭,取值可以為0,1,2,... //bDisplayProperties指示是否自動彈出攝像頭屬性頁 //nWidth和nHeight設置的攝像頭的寬和高,如果攝像頭不支持所設定的寬度和高度,則返回false boolCCameraDS::OpenCamera(int nCamID,bool bDisplayProperties=true,int nWidth=320,int nHeight=240); //關閉攝像頭,析構函數會自動調用這個函數 voidCloseCamera(); //返回攝像頭的數目 //可以不用創建CCameraDS實例,采用int c=CCameraDS::CameraCount();得到結果。 staticintCameraCount(); //根據攝像頭的編號返回攝像頭的名字 //nCamID: 攝像頭編號 //sName: 用于存放攝像頭名字的數組 //nBufferSize: sName的大小 //可以不用創建CCameraDS實例,采用CCameraDS::CameraName();得到結果。 staticintCCameraDS::CameraName(int nCamID,char* sName,int nBufferSize); //返回圖像寬度 intGetWidth(){return m_nWidth;} //返回圖像高度 intGetHeight(){return m_nHeight;} //抓取一幀,返回的IplImage不可手動釋放! //返回圖像數據的為RGB模式的Top-down(第一個字節為左上角像素),即IplImage::origin=0(IPL_ORIGIN_TL) IplImage*QueryFrame(); voidDisplayPinProperties(void);

?

CvvImage類是Opencv自己提供的,這里使用它的主要目的是講mat對象畫到mfc的控件中去 CvvImage cimg; IplImage cpy = dst; cimg.CopyOf(&cpy );// 復制圖片 cimg.DrawToHDC( hDC,&rect );// 將圖片繪制到顯示控件的指定區域內 在GOMfcTemplate2Dlg中是主要代碼,分為以下幾個部分。這塊的東西主要是我自己總結的。 1、攝像頭顯示循環,是單獨的線程 //攝像頭顯示循環 DWORD WINAPI CaptureThread(LPVOID lpParameter) { CGOMfcTemplate2Dlg* pDlg =(CGOMfcTemplate2Dlg*)lpParameter; while(true) { IplImage* queryframe = pDlg->cameraDs.QueryFrame(); Mat matframe(queryframe);//iplimage到Mat轉化 if(pDlg->b_closeCam)//退出循環 break; if(pDlg->b_takeApic ) { pDlg->b_takeApic =false; pDlg->m_mainframe = matframe; Sleep(500); } pDlg->showImage(matframe,IDC_CAM); } return0; } 這個線程函數,在創建的時候讀取主Dlg的指針為參數,這樣能夠進行線程間通信。它主要完成兩項工作,一個是通過camerads的QueryFrame函數讀取當前的圖像并傳遞給主線程;一個是判斷b_closeCam和b_taleApic兩個控制變量是否為true并進行相關操作。 目前的線程間通信采用的變量共享的方式,由于在攝像頭線程中是寫變量,在主線程中是讀變量,一般不會沖突。但是如果攝像頭很多或者實時性非常高,還是應該采用postmessage的方式通信。 2、initdialog中,對界面控件進行初始化 m_nCamCount =CCameraDS::CameraCount();//攝像頭總數 //獲得攝像頭數目 char camera_name[1024]; char istr[25]; for(int i=0; i < m_nCamCount; i++) { int retval =CCameraDS::CameraName(i, camera_name,sizeof(camera_name)); sprintf_s(istr," # %d", i); strcat_s(camera_name,istr ); CString camstr = camera_name; if(retval >0) m_CBNCamList.AddString(camstr); else AfxMessageBox(_T("不能獲取攝像頭的名稱")); } //初始化顯示控件 CRect rect; GetDlgItem(IDC_CAM)->GetClientRect(&rect); m_mainframe =Mat::zeros(rect.Height(),rect.Width(),CV_8UC3); GetDlgItem(IDC_PIC)->GetClientRect(&rect); m_takepic =Mat::zeros(rect.Height(),rect.Width(),CV_8UC3); return TRUE;// 除非將焦點設置到控件,否則返回 TRUE 包括填寫combolist控件,為兩個用于顯示的static控件生成對應大小的mat變量等。 3、打開攝像頭,主要就是根據選擇的攝像頭名稱,創建攝像頭線程 voidCGOMfcTemplate2Dlg::OnBnClickedBtnOpencam() { if(m_nCamCount>=1)//開視頻捕獲線程 { HANDLE hThread = NULL; DWORD dwThreadID =0; OnBnClickedBtnClosecam();//首先關閉現有攝像頭 bool bret = cameraDs.OpenCamera(m_iCamNum,false,640,480);//嘗試打開攝像頭 if(bret) { b_closeCam =false; hThread =CreateThread(NULL,0,CaptureThread,this,0,&dwThreadID); } } else { AfxMessageBox(_T("請確認至少有攝像頭連上了")); } } 稍作修改,可以用于多攝像頭,這個是完全沒有問題并且做過實際項目的。 4、關閉攝像頭 voidCGOMfcTemplate2Dlg::OnBnClickedBtnClosecam() { //嘗試關閉攝像頭 b_closeCam =true; Sleep(100); cameraDs.CloseCamera(); } 傳遞控制變量到攝像頭線程,并且調用camerads的closecamera函數關閉攝像頭; 5、采集圖片 voidCGOMfcTemplate2Dlg::OnBnClickedBtnTakepic() { b_takeApic =true; Sleep(100); if(m_mainframe.rows >0) { showImage(m_mainframe,IDC_PIC); } } 傳遞控制變量到攝像頭線程,并且顯示圖片到控件。 6、顯示圖像函數,為了方便地講mat對象顯示到mfc的控件上,編寫圖像實現函數 voidCGOMfcTemplate2Dlg::showImage(Mat& src, UINT ID) { if(src.empty()) return; CRect rect; Mat dst = src.clone(); GetDlgItem(ID)->GetClientRect(&rect );// 獲取控件尺寸位置 if(dst.channels()==1) cvtColor(dst, dst, CV_GRAY2BGR); CDC* pDC =GetDlgItem( ID )->GetDC(); HDC hDC = pDC ->GetSafeHdc();// 獲取 HDC(設備句柄) 來進行繪圖操作 CvvImage cimg; IplImage cpy = dst; cimg.CopyOf(&cpy );// 復制圖片 cimg.DrawToHDC( hDC,&rect );// 將圖片繪制到顯示控件的指定區域內 ReleaseDC( pDC ); } 主要就是調用cvvimage的drawtohdc函數,并進行相關的錯誤控制。 二、存在問題 ? ? ? 由于directshow本身是com架構,學習曲線陡峭。目前這個框架還存在至少兩個問題: ? ? ? 1、攝像頭熟悉配置問題,以及配置的保持問題。目前框架中的攝像頭配置沒有實現,就是下圖的這種能夠調整攝像頭參數的對話框如何出來。并且上一次的配置數據要能夠保存下來。 ? ? ?? ? ? ? 2、視頻數據采集問題。 ? ? ? 目前我采用的是xvid的攝像頭數據采集方式,能夠解決問題。但是我認為directshow應該本身就能夠才是攝像頭數據,并且保存為.avi。這個方面還需要繼續研究。 ? ? ? 我會在下一步工作中繼續總結這方面資料,同時非常希望能夠得到高人的指點,感謝! 代碼位置 https://github.com/jsxyhelu/GOMfcTemplate2

?[p.s]2016年10月7日 經過對directshow的簡單學習,主要參考了ampcap(vs2012+win7可運行版本 https://git.coding.net/jsxyhelu/AMCa_win7vs2012.git?),解決了攝像頭的屬性操作問題,同時也想辦法解決了分辨率設置問題。在usb攝像頭上和工業攝像頭上測試都沒有問題。

?[p.s]我自己在新裝的機器上測試框架,不會出現需要direct頭文件的情況,但是可能由于操作系統版本不一樣,有一些操作系統還是需要頭文件的。鏈接:https://pan.baidu.com/s/1qXNgzOo?? direct 為完整版本下載,如果連接失敗了請及時聯系我。感謝。

總結

以上是生活随笔為你收集整理的基于opencv和mfc的摄像头采集代码(GOMFCTemplate2)持续更新的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。