服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - c#基于opencv,开发摄像头播放程序

c#基于opencv,开发摄像头播放程序

2022-11-04 12:11源之缘 C#

这篇文章主要介绍了c#基于opencv,开发摄像头播放程序的示例,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下

前言 

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,开发摄像头播放程序的详细内容,更多关于c# opencv摄像头播放的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/yuanchenhui/p/11332728.html

延伸 · 阅读

精彩推荐
  • C#C# WPF上位机实现和下位机TCP通讯的方法

    C# WPF上位机实现和下位机TCP通讯的方法

    这篇文章主要介绍了C# WPF上位机实现和下位机TCP通讯的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    Samberger9532022-07-13
  • C#C#中系统时间和UNIX时间戳互相转换

    C#中系统时间和UNIX时间戳互相转换

    本文主要介绍C#中系统时间和UNIX时间戳相互转换的方法,大家可以直接拿去用,希望有用。...

    yourber7762021-11-22
  • C#C#利用反射技术实现去掉按钮选中时的边框效果

    C#利用反射技术实现去掉按钮选中时的边框效果

    这篇文章主要介绍了C#利用反射技术实现去掉按钮选中时的边框效果,涉及C#针对窗口的参数设置技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    我心依旧3652021-10-25
  • C#WinForm中BackgroundWorker控件用法简单实例

    WinForm中BackgroundWorker控件用法简单实例

    这篇文章主要介绍了WinForm中BackgroundWorker控件用法,以一个简单实例形式分析了BackgroundWorker控件的定义、设置及使用技巧,具有一定参考借鉴价值,需要的朋友...

    我心依旧7382021-10-20
  • C#C#图书管理系统 附源码下载

    C#图书管理系统 附源码下载

    这篇文章主要为大家详细介绍了C#图书管理系统,文章中附源码下载,示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    11362021-12-06
  • C#WPF/Silverlight实现图片局部放大的方法分析

    WPF/Silverlight实现图片局部放大的方法分析

    这篇文章主要介绍了WPF/Silverlight实现图片局部放大的方法,结合实例形式分析了WPF/Silverlight针对图片属性操作相关实现技巧,需要的朋友可以参考下...

    Rising_Sun6552021-12-29
  • C#C#网页跳转方法总结

    C#网页跳转方法总结

    这篇文章主要介绍了C#网页跳转方法总结的相关资料,需要的朋友可以参考下...

    jerrylsxu6242021-11-08
  • C#C#内插字符串的简单使用

    C#内插字符串的简单使用

    这篇文章主要为大家详细介绍了C#内插字符串的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    在代码的世界里游走9142022-03-05