前言 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 = ;
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, ); if (hr == S_OK) { //if (!silent)printf("SETUP: Looking For Capture Devices\n");
IMoniker *pMoniker = NULL; while (pEnum->Next(, &pMoniker, NULL) == S_OK) { IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(, , 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, ); if (FAILED(hr))
hr = pPropBag->Read(L"FriendlyName", &varName, ); if (SUCCEEDED(hr)) { hr = pPropBag->Read(L"FriendlyName", &varName, ); int count = ;
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 ;
}
else
{
return ;
}
}

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, , , PixelFormats.Bgr24, null);
img.WritePixels(new Int32Rect(, , _imgWidth, _imgHeight),
imgData, img.BackBufferStride, );
img.Freeze();

至此,就可以显示摄像头图像了。

基于opencv,开发摄像头播放程序的更多相关文章

  1. 用Visual C#开发基于OpenCV的Windows应用程序

    http://blog.163.com/wangxh_jy/blog/static/28233883201001581640283/ 关于详细的配置及程序运行截图,请下载:http://downloa ...

  2. 基于opencv网络摄像头在ubuntu下的视频获取

     基于opencv网络摄像头在ubuntu下的视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译运行步骤 安装编译opencv-2.3  参 ...

  3. 基于opencv在摄像头ubuntu根据视频获取

     基于opencv在摄像头ubuntu根据视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译执行步骤 安装编译opencv-2.3  參考h ...

  4. 基于Dlib、OpenCV开发人脸识别程序的开发建议

    前言 在去年十月的时候参加了一个小比赛,做了一个人脸识别程序并很意外地获得省里面的一等奖,视频演示链接在这里,有同学想要做这方面的毕业设计or课程设计,发一篇博客来分享一下当时的开发过程. 视频演示链 ...

  5. 基于OpenCV读取摄像头进行人脸检测和人脸识别

    前段时间使用OpenCV的库函数实现了人脸检测和人脸识别,笔者的实验环境为VS2010+OpenCV2.4.4,opencv的环境配置网上有很多,不再赘述.检测的代码网上很多,记不清楚从哪儿copy的 ...

  6. 基于opencv的摄像头的标定

    四个坐标系分别为:世界坐标系(Ow),摄像机坐标系(Oc),图像物理坐标系(O1,单位mm),图像像素坐标系(O,位于视野平面的左上角,单位pix). 空间某点P到其像点p的坐标转换过程主要是通过这四 ...

  7. 基于opencv的人脸识别程序

    1. 解析opencv自带人脸识别源码(……/opencv-3.1.0/samples/cpp/facedetect.cpp) @ 操作系统:Ubuntu 15.04 OpenCV版本:3.1.0 # ...

  8. 调试opencv调用摄像头程序时碰到的问题

    昨天晚上想把opencv学习笔记整理一下,当跑opencv调用摄像头的程序的时候老是出现Assertion failed (size.width>0 && size.height ...

  9. 基于VLC库C#开发可播放摄像头及任意格式视频的播放器

    前言 本文主要讲述,在WPF中,借助Vlc.DotNet调用VLC类库,实现视频播功能,下面我们先来做开发前的准备工作. 准备工作 首先,我们创建一个项目WpfVLC,然后,进入Neget搜索Vlc. ...

随机推荐

  1. XTOJ 1267:Highway(树的直径)***

    http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1267 题意:给出一棵树,每条树边有权值,现在要修建n-1条边,边的权值为边 ...

  2. Tensorflow教程(2)Tensorflow的常用函数介绍

    1.tf.constant tf.constant用来定义一个常量,所谓常量,广义上讲就是“不变化的量”.我们先看下官方api是如何对constant函数来定义的: tf.constant( valu ...

  3. Java 垃圾收集总结

    概述 垃圾收集(Garbage Collection,GC),它不是Java语言的伴生产物,它的历史比Java还要久远. 人们主要思考GC需要完成的3件事情: 哪些内存需要回收? 什么时候回收? 如何 ...

  4. 【POJ - 2718】Smallest Difference(搜索 )

    -->Smallest Difference 直接写中文了 Descriptions: 给定若干位十进制数,你可以通过选择一个非空子集并以某种顺序构建一个数.剩余元素可以用相同规则构建第二个数. ...

  5. Java集合类的概述

    前述 复习一下Java中的集合类,是面试笔试中常考察的一个点,特地做的整理. 什么是集合类? 集合类,也叫容器类.Java集合类可以用来存储数量庞大的对象. 我们和数组进行对比: 数组:存储基本数据类 ...

  6. 通讯(tarjan缩点)(20190716NOIP模拟测试4)

    B. 通讯   题目类型:传统 评测方式:文本比较  内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目描述 “这一切都是命运石之门的选择.” 试图研制时间机器的机关SERN截获了 ...

  7. UVA10375 选择与除法 Choose and divide 题解

    题目链接: https://www.luogu.org/problemnew/show/UVA10375 分析: 这道题可以用唯一分解定理来做. 什么是唯一分解定理?百度即可,这里也简介一下. 对于任 ...

  8. 题解 P2949 【[USACO09OPEN]工作调度Work Scheduling】

    P2949 [USACO09OPEN]工作调度Work Scheduling 题目标签是单调队列+dp,萌新太弱不会 明显的一道贪心题,考虑排序先做截止时间早的,但我们发现后面可能会出现价值更高却没有 ...

  9. 在dotnet core实现类似crontab的定时任务

    前段需要在业务中实现某些时间段的简单定时任务,类似crontab的调度,因为业务会放在docker中,所以不想用直接用crontab,在网上搜了一下,发现一个开源的实现 Pomelo.AspNetCo ...

  10. [leetcode] 21. Merge Two Sorted Lists (Easy)

    合并链表 Runtime: 4 ms, faster than 100.00% of C++ online submissions for Merge Two Sorted Lists. class ...