原文:如何使用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应用的更多相关文章

  1. 简单的Windows Webcam应用:Barcode Reader

    原文:简单的Windows Webcam应用:Barcode Reader 在Windows上用WinForm创建一个Webcam应用需要用到DirectShow.DirectShow没有提供C#的接 ...

  2. 用C#创建Windows服务(Windows Services)

    用C#创建Windows服务(Windows Services) 学习:  第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(W ...

  3. 玩转Windows服务系列——创建Windows服务

    创建Windows服务的项目 新建项目->C++语言->ATL->ATL项目->服务(EXE) 这样就创建了一个Windows服务项目. 生成的解决方案包含两个项目:Servi ...

  4. .Net创建windows服务入门

    本文主要记录学习.net 如何创建windows服务. 1.创建一个Windows服务程序 2.新建安装程序 3.修改service文件 代码如下 protected override void On ...

  5. C# 创建Windows服务

    创建windows服务项目   2 右键点击Service1.cs,查看代码, 用于编写操作逻辑代码 3 代码中OnStart用于执行服务事件,一般采用线程方式执行方法,便于隔一段事件执行一回 END ...

  6. 使用.net 创建windows service

    最近公司项目需要,写了个windows 服务,windows 服务的内容可以在VS 中新建一个"windows服务项目", (1)服务中的主要代码: public partial ...

  7. 使用Topshelf创建Windows服务

    概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ...

  8. C#创建windows服务列表

    转载自:http://www.cnblogs.com/sorex/archive/2012/05/16/2502001.html Windows Service这一块并不复杂,但是注意事项太多了,网上 ...

  9. [转]C#创建Windows服务与安装

    本文档用于创建windows服务说明,使用vs2010系统平台 创建项目 1 创建windows服务项目 2 右键点击Service1.cs,查看代码, 用于编写操作逻辑代码 3 代码中OnStart ...

随机推荐

  1. 支付宝开发之手机网站支付(H5支付)

    其实官方的文档中:https://docs.open.alipay.com/203 介绍的已经很详细了,我就实地的看文档操作了一遍,具体步骤如下: 一.创建应用 流程如下: 首先要有支付宝开放平台: ...

  2. OSGi开发环境的建立

    1 OSGi开发环境的建立 1.1 Equinox是什么 从代码角度来看,Equinox其实就是OSGi核心标准的完整实现,并且还在这个基础上增加了一些额外的功能(比如为框架增加了命令行和程序执行的入 ...

  3. CSS知识总结之浏览器

    web页面浏览器渲染过程 1.解析html文件,并构建DOM树: 在DOM树中,每一个html标签都有一个对应的节点,并且每一个文本也有一个对应 的节点(js的textNode),DOM树的根节点就是 ...

  4. [UWP]使用Acrylic(亚克力)

    原文:[UWP]使用Acrylic(亚克力) 1. 前言 在 如何使用Fluent Design System 这篇文章里已经简单介绍过Reveal的用法,这篇再详细介绍其它内容. 自Windows ...

  5. python io操作

    一次性读取 # 读取文件 # 默认打开文件的方式是只读 file = None try: file = open("f:/test.sql") print(file.name) # ...

  6. 【非常高%】【codeforces 733A】Grasshopper And the String

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  7. Maven 学习总结

    1. 下载地址       Maven: http://maven.apache.org/download.cgi 2. 为Maven配置本地仓库和远程仓库      修改 Maven 目录中 con ...

  8. Matlab Tricks(三十) —— 任意区间的均匀分布

    matlab 的内置函数 rand返回的是 0-1 区间上的均匀分布,rand的参数多是用于设置返回的矩阵的维度大小. 如果要得到 (a, b) 区间上的均匀分布,只需对其做简单的线性变换即可: a+ ...

  9. Hibernate——(1)Hibernate入门

    一.Hibernate简介 1.Hibernate是一款ORM框架,Object Relation Mapping 对象关系映射. 2.可以将DB映射成Object,这样程序只要对Object对象进行 ...

  10. poj 3071 可能DP

    http://poj.org/problem? id=3071 推方程不难,可是难在怎么算 dp[i][j]表示第i场时第j仅仅队伍存活下来的概率 方程:dp[i][j]=sigma(dp[i-1][ ...