欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-01 08:39:27
前言windows下实现摄像视频捕捉有多种实现方式;各种方式的优劣,本文不做对比。但是,opencv是一款老牌开发库,在图像处理领域声名显赫。采用opencv来处理摄像视频,在性能和稳定性上,是有保障...

前言 

windows下实现摄像视频捕捉有多种实现方式;各种方式的优劣,本文不做对比。但是,opencv是一款老牌开发库,在图像处理领域声名显赫。采用opencv来处理摄像视频,在性能和稳定性上,是有保障的。并且,opencv包含很多图像处理函数,可以更方便的对视频处理。

  执行程序是用wpf开发的,所以先将opencv封装成c语言接口,以供调用。opencv也不可能提供现成的控件供wpf使用,两种不同的开发语言“沟通”起来有些困难。其实稍作变通,就可以实现摄像头播放功能。

1 对opencv封装

opencv的类videocapture封装了对摄像头的操作,使用起来也非常简单。

 bool open(int device); device为摄像头设备序号。

如果有多个摄像头,怎么知道哪个摄像头的序号那?可以通过如下函数,获取摄像头列表。摄像头在list中索引即为设备序号。

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幅图像,将其在控件上显示,就是视频。

mat cameraimg;
_pcapture >> cameraimg;

mat类封装了对图像的操作。c#不可能操作mat,需要将mat中纯图像部分数据传递出来,图像才能被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中存有图像数据,data的大小可以根据图像的高度、每行图像的步幅计算出来。c#调用此函数后,imgbuffer存放图像数据。对数据imgbuffer处理后,就可以在控件上显示。

c语言对opencv封装函数列表如下:

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获取图像,在控件中显示。

 <image x:name="imagevideoplayer" stretch="uniform" ></image>

实现图像显示代码

 bitmapsource bitmapsource = _opencvcamera.getbitmapsource();
      if (bitmapsource == null)
        return false;

 imagevideoplayer.source = bitmapsource;

实现图像显示的关键是构建bitmapsource,暨:如何从opencv中获取图像数据构建bitmapsource。

//获取图像数据
  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摄像头播放的资料请关注其它相关文章!