c#基于opencv,開(kāi)發(fā)攝像頭播放程序
前言
Windows下實(shí)現(xiàn)攝像視頻捕捉有多種實(shí)現(xiàn)方式;各種方式的優(yōu)劣,本文不做對(duì)比。但是,opencv是一款老牌開(kāi)發(fā)庫(kù),在圖像處理領(lǐng)域聲名顯赫。采用opencv來(lái)處理攝像視頻,在性能和穩(wěn)定性上,是有保障的。并且,opencv包含很多圖像處理函數(shù),可以更方便的對(duì)視頻處理。
執(zhí)行程序是用wpf開(kāi)發(fā)的,所以先將opencv封裝成c語(yǔ)言接口,以供調(diào)用。opencv也不可能提供現(xiàn)成的控件供wpf使用,兩種不同的開(kāi)發(fā)語(yǔ)言“溝通”起來(lái)有些困難。其實(shí)稍作變通,就可以實(shí)現(xiàn)攝像頭播放功能。
1 對(duì)opencv封裝
opencv的類(lèi)VideoCapture封裝了對(duì)攝像頭的操作,使用起來(lái)也非常簡(jiǎn)單。
bool open(int device); device為攝像頭設(shè)備序號(hào)。
如果有多個(gè)攝像頭,怎么知道哪個(gè)攝像頭的序號(hào)那?可以通過(guò)如下函數(shù),獲取攝像頭列表。攝像頭在list中索引即為設(shè)備序號(hào)。
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打開(kāi)攝像頭非常簡(jiǎn)單。
打開(kāi)之后,就是獲取攝像頭圖像。視頻其實(shí)就是圖像的集合;每秒鐘獲取25幅圖像,將其在控件上顯示,就是視頻。
Mat cameraImg; _pCapture >> cameraImg;
Mat類(lèi)封裝了對(duì)圖像的操作。c#不可能操作Mat,需要將Mat中純圖像部分?jǐn)?shù)據(jù)傳遞出來(lái),圖像才能被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ì)算出來(lái)。c#調(diào)用此函數(shù)后,imgBuffer存放圖像數(shù)據(jù)。對(duì)數(shù)據(jù)imgBuffer處理后,就可以在控件上顯示。
c語(yǔ)言對(duì)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,開(kāi)發(fā)攝像頭播放程序的詳細(xì)內(nèi)容,更多關(guān)于c# opencv攝像頭播放的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- C#調(diào)用usb攝像頭的實(shí)現(xiàn)方法
- C# WPF使用AForge類(lèi)庫(kù)操作USB攝像頭拍照并保存
- C#實(shí)現(xiàn)調(diào)用本機(jī)攝像頭實(shí)例
- C#調(diào)用AForge實(shí)現(xiàn)攝像頭錄像的示例代碼
- C#實(shí)現(xiàn)控制攝像頭的類(lèi)
- C#使用Aforge調(diào)用攝像頭拍照的方法
- C#結(jié)合AForge實(shí)現(xiàn)攝像頭錄像
- C#開(kāi)發(fā)可播放攝像頭及任意格式視頻的播放器
- C# 利用AForge實(shí)現(xiàn)攝像頭信息采集
- C#調(diào)用USB攝像頭的方法
相關(guān)文章
WPF實(shí)現(xiàn)帶篩選功能的DataGrid
在默認(rèn)情況下,WPF提供的DataGrid僅擁有數(shù)據(jù)展示等簡(jiǎn)單功能,如果要實(shí)現(xiàn)像Excel一樣復(fù)雜的篩選過(guò)濾功能,則相對(duì)比較麻煩。本文以一個(gè)簡(jiǎn)單的小例子,簡(jiǎn)述如何通過(guò)WPF實(shí)現(xiàn)DataGrid的篩選功能,僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正2023-03-03
C#將Sql數(shù)據(jù)保存到Excel文件中的方法
這篇文章主要介紹了C#將Sql數(shù)據(jù)保存到Excel文件中的方法,文中的ExportExcel可起到將sql數(shù)據(jù)導(dǎo)出為Excel的作用,需要的朋友可以參考下2014-08-08
c# 如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的json解析器
這篇文章主要介紹了c# 如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的json解析器,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07
C#正則表達(dá)式Regex類(lèi)用法實(shí)例分析
這篇文章主要介紹了C#正則表達(dá)式Regex類(lèi)用法,實(shí)例分析了其中比較常見(jiàn)的幾類(lèi)用法,具有一定的實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10
.NET企業(yè)級(jí)項(xiàng)目中遇到的國(guó)際化問(wèn)題和解決方法
這篇文章主要介紹了.NET企業(yè)級(jí)項(xiàng)目中遇到的國(guó)際化問(wèn)題和解決方法,說(shuō)明了理國(guó)際化問(wèn)題的一些典型例子和經(jīng)驗(yàn)之談,需要的朋友可以參考下2014-07-07
C#使用讀寫(xiě)鎖三行代碼簡(jiǎn)單解決多線程并發(fā)的問(wèn)題
本文主要介紹了C#使用讀寫(xiě)鎖三行代碼簡(jiǎn)單解決多線程并發(fā)寫(xiě)入文件時(shí)提示“文件正在由另一進(jìn)程使用,因此該進(jìn)程無(wú)法訪問(wèn)此文件”的問(wèn)題。需要的朋友可以參考借鑒2016-12-12

