如何使用C#创建Windows Webcam应用
最近想用C#写一个camera的应用。搜索了Google和StackOverflow,发现大部分的sample用了WIA或者DirectShow。WIA和DirectShow都没有直接提供C#接口,所以实现起来也比较复杂。试着运行了几个WIA的工程,在Windows10上还不起作用。发现微软提供了一个MediaCapture类,包含了丰富的C#接口,可用于音频,视频。要用这个类,就需要创建一个UWP工程。这里分享下如何使用MediaCapture的C#接口来获取camera的每一帧数据。
微软示例
微软在GitHub上放了大量的UWP示例,里面包含了各种camera的接口使用方法。
在Android中要获取camera的每一帧数据,可以通过onPreviewCallback的回调函数实现。参考CameraFrames这个示例,也可以实现类似的功能。
如何创建Windows Webcam应用
1. 在package.appxmanifest中获取webcam权限:
2. 创建image element用于绘制webcam的预览界面:
3. 通过Image Element初始化FrameRenderer :
_frameRenderer = new FrameRenderer(PreviewImage);
4. 初始化MediaCapture对象:
// Create a new media capture object.
_mediaCapture = new MediaCapture();
var settings = new MediaCaptureInitializationSettings()
{
// Select the source we will be reading from.
SourceGroup = groupModel.SourceGroup,
// This media capture has exclusive control of the source.
SharingMode = MediaCaptureSharingMode.ExclusiveControl,
// Set to CPU to ensure frames always contain CPU SoftwareBitmap images,
// instead of preferring GPU D3DSurface images.
MemoryPreference = MediaCaptureMemoryPreference.Cpu,
// Capture only video. Audio device will not be initialized.
StreamingCaptureMode = StreamingCaptureMode.Video,
};
try
{
// Initialize MediaCapture with the specified group.
// This can raise an exception if the source no longer exists,
// or if the source could not be initialized.
await _mediaCapture.InitializeAsync(settings);
_logger.Log($"Successfully initialized MediaCapture for {groupModel.DisplayName}");
}
catch (Exception exception)
{
_logger.Log(exception.Message);
DisposeMediaCapture();
}
5. 使用DeviceWatcher 列出所有设备:
var deviceSelector = MediaFrameSourceGroup.GetDeviceSelector();
_watcher = DeviceInformation.CreateWatcher(deviceSelector);
_watcher.Added += Watcher_Added;
_watcher.Removed += Watcher_Removed;
_watcher.Updated += Watcher_Updated;
_watcher.Start();
private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
await AddDeviceAsync(args.Id);
}
private async Task AddDeviceAsync(string id)
{
var group = await MediaFrameSourceGroup.FromIdAsync(id);
if (group != null)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
_sourceCollection.Add(new FrameSourceGroupModel(group));
});
}
}
6. 针对用户的选择更新设备源:
_mediaCapture.FrameSources.TryGetValue(info.SourceInfo.Id, out _source);
7. 通过MediaFrameReader 注册回调函数:
if (_source != null)
{
_reader = await _mediaCapture.CreateFrameReaderAsync(_source);
_reader.FrameArrived += Reader_FrameArrived;
}
8. 启动webcam:
MediaFrameReaderStartStatus result = await _reader.StartAsync();
9. 读取并绘制每一帧数据:
private void Reader_FrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
// TryAcquireLatestFrame will return the latest frame that has not yet been acquired.
// This can return null if there is no such frame, or if the reader is not in the
// "Started" state. The latter can occur if a FrameArrived event was in flight
// when the reader was stopped.
using (var frame = sender.TryAcquireLatestFrame())
{
_frameRenderer.ProcessFrame(frame);
}
}
public void ProcessFrame(MediaFrameReference frame)
{
var softwareBitmap = FrameRenderer.ConvertToDisplayableImage(frame?.VideoMediaFrame);
if (softwareBitmap != null)
{
// Swap the processed frame to _backBuffer and trigger UI thread to render it
softwareBitmap = Interlocked.Exchange(ref _backBuffer, softwareBitmap);
// UI thread always reset _backBuffer before using it. Unused bitmap should be disposed.
softwareBitmap?.Dispose();
// Changes to xaml ImageElement must happen in UI thread through Dispatcher
var task = _imageElement.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
// Don't let two copies of this task run at the same time.
if (_taskRunning)
{
return;
}
_taskRunning = true;
// Keep draining frames from the backbuffer until the backbuffer is empty.
SoftwareBitmap latestBitmap;
while ((latestBitmap = Interlocked.Exchange(ref _backBuffer, null)) != null)
{
var imageSource = (SoftwareBitmapSource)_imageElement.Source;
await imageSource.SetBitmapAsync(latestBitmap);
latestBitmap.Dispose();
}
_taskRunning = false;
});
}
}
参考
Basic photo, video, and audio capture with MediaCapture
源码
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CameraFrames
如何使用C#创建Windows Webcam应用的更多相关文章
- 简单的Windows Webcam应用:Barcode Reader
原文:简单的Windows Webcam应用:Barcode Reader 在Windows上用WinForm创建一个Webcam应用需要用到DirectShow.DirectShow没有提供C#的接 ...
- 用C#创建Windows服务(Windows Services)
用C#创建Windows服务(Windows Services) 学习: 第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(W ...
- 玩转Windows服务系列——创建Windows服务
创建Windows服务的项目 新建项目->C++语言->ATL->ATL项目->服务(EXE) 这样就创建了一个Windows服务项目. 生成的解决方案包含两个项目:Servi ...
- .Net创建windows服务入门
本文主要记录学习.net 如何创建windows服务. 1.创建一个Windows服务程序 2.新建安装程序 3.修改service文件 代码如下 protected override void On ...
- C# 创建Windows服务
创建windows服务项目 2 右键点击Service1.cs,查看代码, 用于编写操作逻辑代码 3 代码中OnStart用于执行服务事件,一般采用线程方式执行方法,便于隔一段事件执行一回 END ...
- 使用.net 创建windows service
最近公司项目需要,写了个windows 服务,windows 服务的内容可以在VS 中新建一个"windows服务项目", (1)服务中的主要代码: public partial ...
- 使用Topshelf创建Windows服务
概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ...
- C#创建windows服务列表
转载自:http://www.cnblogs.com/sorex/archive/2012/05/16/2502001.html Windows Service这一块并不复杂,但是注意事项太多了,网上 ...
- [转]C#创建Windows服务与安装
本文档用于创建windows服务说明,使用vs2010系统平台 创建项目 1 创建windows服务项目 2 右键点击Service1.cs,查看代码, 用于编写操作逻辑代码 3 代码中OnStart ...
随机推荐
- 移动CMPP3.0接口
前段时间准备上线期,同事接了个联调CMPP3.0短信接口的任务,但是一直不成功,抽时间给解决了一下,记录下其中几个要点: 1.短信网关厂家需要提供参数: #网关IP地址 ismgIp=1.1.1.1# ...
- XMPP之ios即时通讯客户端开发-创建工程添加XMPPFramework及其他框架(三)
XMPPFramework GitHub: https://github.com/robbiehanson/XMPPFramework 获取源代码 git clone https://github.c ...
- 【BZOJ 1016】 [JSOI2008]最小生成树计数(matrix-tree定理做法)
[题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1016 [题意] [题解] /* 接上一篇文章; 这里用matrix-tree定理搞最小 ...
- Adaptive partitioning scheduler for multiprocessing system
A symmetric multiprocessing system includes multiple processing units and corresponding instances of ...
- 在深入分析:Fragment与Activity一些互动的方式(一,使用Handler)
在这里,我不再具体介绍了编写更传统的方式,比如静态变量,静态方法.持久性,application全局变量.发送和接收广播等等.. 首先让我们介绍使用Handler实现Fragment与Activity ...
- 读取Jar包外面的配置文件
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/shenxiandashu/article/details/79193705 比较常用的方法是将pro ...
- html head标签的内容跑到body标签中 , 并且body中多了个空格
今天遇到一个奇怪的问题 , 就是在head标签中写的内容跑到body标签中 , 第一种也是经常遇到的情况就是编码 UTF-8 格式带BOM的 , 这种情况是会多一个空格 , 这个基本都知道 , 按ut ...
- vue项目 下载表格 java后台返回的是信息流表格如何下载解决乱码
主要是在请求参数后面加上{responseType: 'blob'}或者arrayBuffer this.$http.get(this.api.export, { params: this.info, ...
- [Example of Sklearn] - Example
reference : http://my.oschina.net/u/175377/blog/84420 目录[-] Scikit Learn: 在python中机器学习 载入示例数据 一个改变数据 ...
- Android中SQLite数据库操作(2)——SQLiteOpenHelper类
如果开发者对SQL语法不熟悉,我要告诉你一个好消息,Android提供了一个SQLiteOpenHelper类. 在实际项目中很少使用SQLiteDatabase的方法(请看:http://blog. ...