c#基于opencv,開發(fā)攝像頭播放程序
前言
Windows下實(shí)現(xiàn)攝像視頻捕捉有多種實(shí)現(xiàn)方式;各種方式的優(yōu)劣,本文不做對比。但是,opencv是一款老牌開發(fā)庫,在圖像處理領(lǐng)域聲名顯赫。采用opencv來處理攝像視頻,在性能和穩(wěn)定性上,是有保障的。并且,opencv包含很多圖像處理函數(shù),可以更方便的對視頻處理。
執(zhí)行程序是用wpf開發(fā)的,所以先將opencv封裝成c語言接口,以供調(diào)用。opencv也不可能提供現(xiàn)成的控件供wpf使用,兩種不同的開發(fā)語言“溝通”起來有些困難。其實(shí)稍作變通,就可以實(shí)現(xiàn)攝像頭播放功能。
1 對opencv封裝
opencv的類VideoCapture封裝了對攝像頭的操作,使用起來也非常簡單。
bool open(int device); device為攝像頭設(shè)備序號。
如果有多個(gè)攝像頭,怎么知道哪個(gè)攝像頭的序號那?可以通過如下函數(shù),獲取攝像頭列表。攝像頭在list中索引即為設(shè)備序號。
int GetCameraDevices(vector<wstring>& list) { ICreateDevEnum *pDevEnum = NULL; IEnumMoniker *pEnum = NULL; int deviceCounter = 0; CoInitialize(NULL); HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pDevEnum)); if (SUCCEEDED(hr)) { // Create an enumerator for the video capture category. hr = pDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &pEnum, 0); if (hr == S_OK) { //if (!silent)printf("SETUP: Looking For Capture Devices\n"); IMoniker *pMoniker = NULL; while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { IPropertyBag *pPropBag; hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag)); if (FAILED(hr)) { pMoniker->Release(); continue; // Skip this one, maybe the next one will work. } // Find the description or friendly name. VARIANT varName; VariantInit(&varName); hr = pPropBag->Read(L"Description", &varName, 0); if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0); if (SUCCEEDED(hr)) { hr = pPropBag->Read(L"FriendlyName", &varName, 0); int count = 0; wstring str2 = varName.bstrVal; list.push_back(str2); } pPropBag->Release(); pPropBag = NULL; pMoniker->Release(); pMoniker = NULL; deviceCounter++; } pDevEnum->Release(); pDevEnum = NULL; pEnum->Release(); pEnum = NULL; } } return deviceCounter; }
總之,使用opencv打開攝像頭非常簡單。
打開之后,就是獲取攝像頭圖像。視頻其實(shí)就是圖像的集合;每秒鐘獲取25幅圖像,將其在控件上顯示,就是視頻。
Mat cameraImg; _pCapture >> cameraImg;
Mat類封裝了對圖像的操作。c#不可能操作Mat,需要將Mat中純圖像部分?jǐn)?shù)據(jù)傳遞出來,圖像才能被c#利用。
int Camera_GetImgData(INT64 handle, char* imgBuffer) { CameraInfo *pCameraInfo = (CameraInfo*)handle; Mat cameraImg; *(pCameraInfo->_pCapture) >> cameraImg; if (!cameraImg.empty()) { int height = cameraImg.rows;int dataLen = height * cameraImg.step; memcpy(imgBuffer, cameraImg.data, dataLen); return 0; } else { return 1; } }
cameraImg.data中存有圖像數(shù)據(jù),data的大小可以根據(jù)圖像的高度、每行圖像的步幅計(jì)算出來。c#調(diào)用此函數(shù)后,imgBuffer存放圖像數(shù)據(jù)。對數(shù)據(jù)imgBuffer處理后,就可以在控件上顯示。
c語言對opencv封裝函數(shù)列表如下:
extern "C" { OpenCVCamera_API int Camera_GetCameraName(char* listName); OpenCVCamera_API INT64 Camera_CreateHandle(); OpenCVCamera_API void Camera_CloseHandle(INT64 handle); OpenCVCamera_API BOOL Camera_IsOpen(INT64 handle); OpenCVCamera_API int Camera_Open(INT64 handle, int index); OpenCVCamera_API int Camera_Close(INT64 handle); OpenCVCamera_API int Camera_GetImgInfo(INT64 handle,int& width,int& height,int& channel, int& step, int& depth); OpenCVCamera_API int Camera_GetImgData(INT64 handle, char* imgBuffer); //flipCode >0: 沿y-軸翻轉(zhuǎn), 0: 沿x-軸翻轉(zhuǎn), <0: x、y軸同時(shí)翻轉(zhuǎn) OpenCVCamera_API int Camera_GetImgData_Flip(INT64 handle, char* imgBuffer, int flipCode); OpenCVCamera_API int Camera_ImgData_Compress(int rows, int cols, int type, void* imgBuffer, int param,void* destBuffer,int* destLen); }
2 WPF實(shí)現(xiàn)視頻播放
WPF的Image控件實(shí)現(xiàn)圖像的顯示。實(shí)現(xiàn)視頻播放的邏輯為:設(shè)定一個(gè)定時(shí)器(時(shí)間間隔為40毫秒),每隔一段時(shí)間從opencv獲取圖像,在控件中顯示。
<Image x:Name="imageVideoPlayer" Stretch="Uniform" ></Image>
實(shí)現(xiàn)圖像顯示代碼
BitmapSource bitmapSource = _openCVCamera.GetBitmapSource(); if (bitmapSource == null) return false; imageVideoPlayer.Source = bitmapSource;
實(shí)現(xiàn)圖像顯示的關(guān)鍵是構(gòu)建BitmapSource,暨:如何從opencv中獲取圖像數(shù)據(jù)構(gòu)建BitmapSource。
//獲取圖像數(shù)據(jù) if (!GetImgData(out byte[] imgData)) return null; //構(gòu)建WriteableBitmap WriteableBitmap img = new WriteableBitmap(_imgWidth, _imgHeight, 96, 96, PixelFormats.Bgr24, null); img.WritePixels(new Int32Rect(0, 0, _imgWidth, _imgHeight), imgData, img.BackBufferStride, 0); img.Freeze();
至此,就可以顯示攝像頭圖像了。
以上就是c#基于opencv,開發(fā)攝像頭播放程序的詳細(xì)內(nèi)容,更多關(guān)于c# opencv攝像頭播放的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
WPF實(shí)現(xiàn)帶篩選功能的DataGrid
在默認(rèn)情況下,WPF提供的DataGrid僅擁有數(shù)據(jù)展示等簡單功能,如果要實(shí)現(xiàn)像Excel一樣復(fù)雜的篩選過濾功能,則相對比較麻煩。本文以一個(gè)簡單的小例子,簡述如何通過WPF實(shí)現(xiàn)DataGrid的篩選功能,僅供學(xué)習(xí)分享使用,如有不足之處,還請指正2023-03-03C#將Sql數(shù)據(jù)保存到Excel文件中的方法
這篇文章主要介紹了C#將Sql數(shù)據(jù)保存到Excel文件中的方法,文中的ExportExcel可起到將sql數(shù)據(jù)導(dǎo)出為Excel的作用,需要的朋友可以參考下2014-08-08c# 如何實(shí)現(xiàn)一個(gè)簡單的json解析器
這篇文章主要介紹了c# 如何實(shí)現(xiàn)一個(gè)簡單的json解析器,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07.NET企業(yè)級項(xiàng)目中遇到的國際化問題和解決方法
這篇文章主要介紹了.NET企業(yè)級項(xiàng)目中遇到的國際化問題和解決方法,說明了理國際化問題的一些典型例子和經(jīng)驗(yàn)之談,需要的朋友可以參考下2014-07-07