前言
Windows下实现摄像视频捕捉有多种实现方式;各种方式的优劣,本文不做对比。但是,opencv是一款老牌开发库,在图像处理领域声名显赫。采用opencv来处理摄像视频,在性能和稳定性上,是有保障的。并且,opencv包含很多图像处理函数,可以更方便的对视频处理。
执行程序是用wpf开发的,所以先将opencv封装成c语言接口,以供调用。opencv也不可能提供现成的控件供wpf使用,两种不同的开发语言“沟通”起来有些困难。其实稍作变通,就可以实现摄像头播放功能。
1 对opencv封装
opencv的类VideoCapture封装了对摄像头的操作,使用起来也非常简单。
bool open(int device); device为摄像头设备序号。
如果有多个摄像头,怎么知道哪个摄像头的序号那?可以通过如下函数,获取摄像头列表。摄像头在list中索引即为设备序号。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
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打开摄像头非常简单。
打开之后,就是获取摄像头图像。视频其实就是图像的集合;每秒钟获取25幅图像,将其在控件上显示,就是视频。
1
2
|
Mat cameraImg; _pCapture >> cameraImg; |
Mat类封装了对图像的操作。c#不可能操作Mat,需要将Mat中纯图像部分数据传递出来,图像才能被c#利用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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中存有图像数据,data的大小可以根据图像的高度、每行图像的步幅计算出来。c#调用此函数后,imgBuffer存放图像数据。对数据imgBuffer处理后,就可以在控件上显示。
c语言对opencv封装函数列表如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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-轴翻转, 0: 沿x-轴翻转, <0: x、y轴同时翻转 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实现视频播放
WPF的Image控件实现图像的显示。实现视频播放的逻辑为:设定一个定时器(时间间隔为40毫秒),每隔一段时间从opencv获取图像,在控件中显示。
1
|
<Image x:Name= "imageVideoPlayer" Stretch= "Uniform" ></Image> |
实现图像显示代码
1
2
3
4
5
|
BitmapSource bitmapSource = _openCVCamera.GetBitmapSource(); if (bitmapSource == null ) return false ; imageVideoPlayer.Source = bitmapSource; |
实现图像显示的关键是构建BitmapSource,暨:如何从opencv中获取图像数据构建BitmapSource。
1
2
3
4
5
6
7
8
9
|
//获取图像数据 if (!GetImgData( out byte [] imgData)) return null ; //构建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,开发摄像头播放程序的详细内容,更多关于c# opencv摄像头播放的资料请关注服务器之家其它相关文章!
原文链接:https://www.cnblogs.com/yuanchenhui/p/11332728.html