文档章节

如何使用C#创建Windows Webcam应用

yushulx
 yushulx
发布于 2016/09/13 14:42
字数 682
阅读 84
收藏 1

最近想用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

© 著作权归作者所有

yushulx
粉丝 29
博文 107
码字总数 60955
作品 0
杭州
私信 提问
简单的Windows Webcam应用:Barcode Reader

在Windows上用WinForm创建一个Webcam应用需要用到DirectShow。DirectShow没有提供C#的接口。如果要用C#开发,需要创建一个桥接DLL。Touchless SDK是一个免费开源的.NET库,对DirectShow进行了...

yushulx
2016/09/20
92
0
树莓派应用:摄像头条形码扫描

树莓派小而强大,有非常多的应用场景。这里分享下使用树莓派,摄像头,以及C和Python代码来实现一个条形码扫描工具。之前分享过如何把OpenCV Python获取的图像传递到C层处理,会用到里面的代...

yushulx
2016/11/08
923
0
使用DirectShow.NET获取摄像头视频流

开源社区提供了DirectShow的.NET版本,为C#开发者提供了便利。这里分享下如何用DirectShow.NET API来启动摄像头,以及获取视频流数据。 参考原文:Read Barcode from Webcam Viewer with Di...

yushulx
2016/09/29
290
0
轻松使用OpenCV Python控制Webcam,读取Barcode

虽然手机上Barcode应用已经非常流行,但是工作的时候还是用Webcam比较方便。比如需要检测Barcode,我只需要拿Webcam对着电脑屏幕或者纸张扫一下就可以了。今天分享下如何轻松使用OpenCV控制W...

yushulx
2015/08/11
1K
0
linux内核中的webcam模块该如何使用?

我在im.x51硬件平台上想实现USB摄像头功能,网上看到实现uvc协议的usb摄像头,pc机上无需装驱动,我看到内核linux-2.6.35.3中的webcam模块实现了UVC协议,于是就想直接用该模块。但使用过程中...

大葱
2012/12/12
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
今天
5
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
今天
7
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
今天
6
0
【技术分享】TestFlight测试的流程文档

上架基本需求资料 1、苹果开发者账号(如还没账号先申请-苹果开发者账号申请教程) 2、开发好的APP 通过本篇教程,可以学习到ios证书申请和打包ipa上传到appstoreconnect.apple.com进行TestF...

qtb999
今天
10
0
再见 Spring Boot 1.X,Spring Boot 2.X 走向舞台中心

2019年8月6日,Spring 官方在其博客宣布,Spring Boot 1.x 停止维护,Spring Boot 1.x 生命周期正式结束。 其实早在2018年7月30号,Spring 官方就已经在博客进行过预告,Spring Boot 1.X 将维...

Java技术剑
今天
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部