如何用MediaCapture解决二维码扫描问题

原文:如何用MediaCapture解决二维码扫描问题(有修改)

二维码扫描的实现,简单的来说可以分三步走:“成像”、“截图”与“识别”。

UWP开发中,最常用的媒体工具非MediaCapture莫属了,下面就来简单介绍一下如何利用MediaCapture来实现扫描和截图并且利用Zxing识别二维码,以及会遇到的问题和需要注意的地方。

1. 初始化与成像

   private async void InitMediaCaptureAsync()
        {   //选择后置摄像头
            var cameraDevice = await FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel.Back);
            if (cameraDevice == null)
            {
                System.Diagnostics.Debug.WriteLine("No camera device found!");
                return;
            }
            var settings = new MediaCaptureInitializationSettings
            {
                StreamingCaptureMode = StreamingCaptureMode.Video,
                //MediaCategory = MediaCategory.Other,
                //AudioProcessing = AudioProcessing.Default,
                PhotoCaptureSource = PhotoCaptureSource.VideoPreview,
                AudioDeviceId = string.Empty,
                VideoDeviceId = cameraDevice.Id
            };
            await _mediaCapture.InitializeAsync(settings);
            //摄像头旋转90度
            //_mediaCapture.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
            var fff = _mediaCapture.MediaCaptureSettings;
            capturePreview.Source = _mediaCapture;
            await _mediaCapture.StartPreviewAsync();

            var focusControl = _mediaCapture.VideoDeviceController.FocusControl;

            if (focusControl.Supported)
            {
                var focusSettings = new FocusSettings()
                {
                    Mode = focusControl.SupportedFocusModes.FirstOrDefault(f => f == FocusMode.Continuous),
                    DisableDriverFallback = true,
                    AutoFocusRange = focusControl.SupportedFocusRanges.FirstOrDefault(f => f == AutoFocusRange.FullRange),
                    Distance = focusControl.SupportedFocusDistances.FirstOrDefault(f => f == ManualFocusDistance.Nearest)
                };

                //设置聚焦,最好使用FocusMode.Continuous,否则影响截图会很模糊,不利于识别
                focusControl.Configure(focusSettings);
            }
            if (focusControl.Supported)
            {
                //开始聚焦
                await focusControl.FocusAsync();
            }
            if (_mediaCapture.VideoDeviceController.FlashControl.Supported)
            {
                //关闭闪光灯
                _mediaCapture.VideoDeviceController.FlashControl.Enabled = false;
            }
        }

 

      private static async Task<DeviceInformation> FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desired)
        {

            var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

            DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desired);

            return desiredDevice ?? allVideoDevices.FirstOrDefault();
        }

 

 

2. 截图与识别

        private void InitTimer()
        {
            _timer = new DispatcherTimer();
            //每50毫秒截一次图
            _timer.Interval = TimeSpan.FromMilliseconds(50);
            _timer.Tick += _timer_Tick;
            _timer.Start();
        }

 

    private async void _timer_Tick(object sender, object e)
        {
            using (var stream = new InMemoryRandomAccessStream())
            {
                var previewProperties = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;
                //将截图写入内存流中
                await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);

                //利用Zxing识别,成功:停止timer;失败:继续
                var reader = new BarcodeReader();
                var bitmapWriteable = new WriteableBitmap((int)previewProperties.Width, (int)previewProperties.Height);
                bitmapWriteable.SetSource(stream.CloneStream()); //bitmapWriteable.SetSource(stream);有问题
                var result = reader.Decode(bitmapWriteable);

                if (!string.IsNullOrEmpty(result.Text))
                {
                    _timer.Stop();
                }
            }
        }

 

这里顺便说一下如何安装Zxing,打开nuget管理器 命令窗口输入 Install-Package ZXing.Net ,回车; 关于Zxing如何使用,到网上搜索一下有很多教程,这里不再赘述

3. 问题与优化

A) 截图有响声

使用CapturePhotoToStreamAsync来截取图片有的时候会有“咔擦咔擦”声,很影响用户体验,最理想的做法是找到一种能从视频流中直接截取图片的方法,在这里不得不说一句MediaCapture真的真的很强大,MediaCapture给我们提供了直接从视频流中取出其中一帧的方法GetPreviewFrameAsync,于是我把代码进行了如下修改,即流畅又没有烦人的“咔擦咔擦”声

  async void _timer_Tick(object sender, object e)
   {
       var previewProperties = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;

       using (var videoFrame = new VideoFrame(BitmapPixelFormat.Rgba8, (int) previewProperties.Width, (int) previewProperties.Height))
       {
           using (var currentFrame = await _mediaCapture.GetPreviewFrameAsync(videoFrame))
           {
               using (var previewFrame = currentFrame.SoftwareBitmap)
                {

                    WriteableBitmap bitmap = new WriteableBitmap(previewFrame.PixelWidth, previewFrame.PixelHeight);
                    previewFrame.CopyToBuffer(bitmap.PixelBuffer);

                    var buffer = new Windows.Storage.Streams.Buffer((uint)(4 * previewFrame.PixelWidth * previewFrame.PixelHeight));
                    previewFrame.CopyToBuffer(buffer);
                    //利用Zxing识别,成功:停止timer;失败:继续
                    var reader = new BarcodeReader();
                    var result = reader.Decode(bitmap.PixelBuffer.ToArray(), bitmap.PixelWidth, bitmap.PixelHeight, RGBLuminanceSource.BitmapFormat.Unknown);
                    //var result = reader.Decode(bitmapWriteable);

                        if (!string.IsNullOrEmpty(result.Text))
                        {
                            _timer.Stop();
                        }

                }
            }
        }
    }
 

 

顺便提一下记得要使用如下两个命名空间

using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;

否则无法实现buffer.AsStream().AsRandomAccessStream()

B) 连续聚焦

并不是所有机型都支持连续聚焦的(FocusMode.Continuous),这个时候只能自己实现间断性持续聚焦了

C) 截图之后图片处理

有的时候为了实现一些功能(比如说扫描框)或者提高识别率,我们需要对截取出来的图片进行一些二次处理,或剪裁或缩放或旋转,我们可以使用BitmapDecoder和BitmapEncoder来实现



  var previewProperties = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;

            using (var videoFrame = new VideoFrame(BitmapPixelFormat.Rgba8, (int)previewProperties.Width, (int)previewProperties.Height))
            {
                using (var currentFrame = await _mediaCapture.GetPreviewFrameAsync(videoFrame))
                {
                    using (var previewFrame = currentFrame.SoftwareBitmap)
                    {

                        WriteableBitmap bitmap = new WriteableBitmap(previewFrame.PixelWidth, previewFrame.PixelHeight);
                        previewFrame.CopyToBuffer(bitmap.PixelBuffer);

                        var buffer = new Windows.Storage.Streams.Buffer((uint)(4 * previewFrame.PixelWidth * previewFrame.PixelHeight));
                        previewFrame.CopyToBuffer(buffer);
                        imageShowPicture.Source = bitmap;//show the picture 

                        //利用Zxing识别,成功:停止timer;失败:继续
                        var reader = new BarcodeReader();
                        var result = reader.Decode(bitmap.PixelBuffer.ToArray(), bitmap.PixelWidth, bitmap.PixelHeight, RGBLuminanceSource.BitmapFormat.Unknown);

                        using (var stream = buffer.AsStream() .AsRandomAccessStream())
                        {
                            //var decoder = await BitmapDecoder.CreateAsync(stream);

                            var destStream = new InMemoryRandomAccessStream();
                            BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, destStream);
                            //var encoder = await BitmapEncoder.CreateForTranscodingAsync(destStream, decoder);

                            encoder.SetSoftwareBitmap(previewFrame);

                            //剪裁
                            encoder.BitmapTransform.Bounds = new BitmapBounds() { X = 0, Y = 0, Width = 100, Height = 100 };
                            //缩放
                            encoder.BitmapTransform.ScaledWidth = 100;
                            encoder.BitmapTransform.ScaledHeight = 100;
                            //旋转
                            encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise90Degrees;

                            await encoder.FlushAsync();
                            await destStream.FlushAsync();

                            var bitmapImage = new BitmapImage();
                            bitmapImage.SetSource(destStream);
                            imageShowPicture.Source = bitmapImage;//show the picture 

                        }
                    }
                }
            }

            if (!string.IsNullOrEmpty(result.Text))
            {
                _timer.Stop();
            }

 


D) 挂起和唤醒

另外值得注意的是,程序在Suspending和Resuming还有Activated时出现的一系列状态转换,这时候很容易引起bug,需要处理好避免crash。

4. 最后

识别出来的字符串处理一般也就超链接和普通文本两种,当然也可以增加条码扫描功能,识别出的是编码,不管怎样,大家可以根据项目具体需求做相应的处理。

时间: 2024-08-26 23:31:36

如何用MediaCapture解决二维码扫描问题的相关文章

Android开发框架之自定义ZXing二维码扫描界面并解决取景框拉伸问题_Android

先给大家展示下效果图: 扫描内容是下面这张,二维码是用zxing库生成的 由于改了好几个类,还是去年的事都忘得差不多了,所以只能上这个类的代码了,主要就是改了这个CaptureActivity.java package com.zxing.activity; import java.io.IOException; import java.util.Vector; import android.app.Activity; import android.content.Intent; import

Android Zxing二维码扫描图片拉伸的解决方法

二维码扫描,Android Zxing图片拉伸解决. Zxing是google提供的二维码扫描工程 默认是横屏的  转换成竖屏后图片出现拉伸 这里提供解决办法: Zxing 修改 CameraConfigurationManager.Java文件的void initFromCameraParameters(Camera camera)方法 在Log.d(TAG, "Screen resolution: " + screenResolution);这句之后增加 Point screenR

Android Zxing二维码扫描图片拉伸问题的解决方法

还是这个接手项目,二维码扫描集成的是zxing,扫描界面的图像有明显的拉伸变形. 这种问题,根据以往的经验,一般是x,y轴错位引起的,处理好x,y轴的问题,一般可以解决问题. 由于这个问题,之前有很多人遇到,并分享在网上了,所以,我这里也就不需要重复造轮子了. 这里看了一篇博客:Android Zxing二维码扫描图片拉伸,用了上面的办法, 成功的解决图片拉伸问题. 解决方法如下: 修改CameraConfigurationManager.Java里面的initFromCameraParamet

Android实现二维码扫描并登陆网页_Android

之前写过一个二维码扫描demo,用的Zxing的框架,点击下载,后续扫描二维码中出现一些问题,比如解决压缩图片,调整扫描窗口大小等等.后续单位要求做扫描登录实现,发现难点就是怎么知道你扫描的是这台电脑,后台必须获取到(后台技术的问题)然后把这个参数给我,再传递到后台,后台判断登录即可.这样自己扫描后直接传递个参数就可以实现登录了. 效果如下: 大概代码实现:扫描跳转: //扫描登录a case R.id.tv_more_qr: if (PventQuickClick.isFastDoubleCl

ios ZBar 二维码扫描。。。。

问题描述 ios ZBar 二维码扫描.... ld: warning: directory not found for option '-LZBarSDK' ld: '/Users/**/Documents/**/**/ios7 Scan QRCode/ZBarSDK-for-iOS-master/libzbar.a(ZBarReaderController.o)' does not contain bitcode. You must rebuild it with bitcode enabl

微信公众平台 二维码扫描关注并跳转到url

问题描述 微信公众平台 二维码扫描关注并跳转到url 微信中扫描二维码,可以实现扫描后需要先 关注该公众账号,关注后后自动跳转到指定url(在微信浏览器中打开的.) 请问这种业务如何实现的? 微信官方api提供可以生成带场景值的二维码,扫描后先关注,关注成功微信服务器是向开发者服务器发送场景值:我的需要是关注成功后微信服务器给用户返回指定url~ 我发现很多人提出相同问题,却没找到相关资料~求大神帮忙! 解决方案 我们这本地的一个平台已经实现了,扫一个商家的二维码,能自动关注平台,关注以后,自动

自动-微信二维码扫描关注并跳转页面

问题描述 微信二维码扫描关注并跳转页面 微信中扫描二维码,可以实现扫描后需要先 关注该公众账号,关注后后自动跳转到指定url(在微信浏览器中打开的.)请问这种业务如何实现的?微信官方api提供可以生成带场景值的二维码,扫描后先关注,关注成功微信服务器是向开发者服务器发送场景值:我的需要是关注成功后微信服务器给用户返回指定url~我发现很多人提出相同问题,却没找到相关资料~求大神帮忙! 解决方案 同问!!!!!!!!!!!!!!!!!!!! 解决方案二: 对啊,好多这样的需求却没有一个给出解决这样

编码-ios7自带的二维码扫描出现中文乱码

问题描述 ios7自带的二维码扫描出现中文乱码 扫描utf8格式的二维码的时候是没有问题的,今天客户拿了他们那边的二维码过来,结果就乱码了,应该是编码的问题,请大神们帮忙看下,附上一张图 急啊 求解决 乱码为:lzurl://??á?éê?? 正确的是:lzurl://车辆申请 解决方案 ios7以上的二维码扫描IOS7 二维码扫描iOS自带扫描 和 生成二维码

摄像头-ZBar二维码扫描,无法连续点击扫描

问题描述 ZBar二维码扫描,无法连续点击扫描 大概第三次的时候,进入摄像头的速度特别的慢..如何解决? 附上代码: CameraViewController *camera=[CameraViewController new] ; [self presentViewController:camera animated:YES completion:nil]; [camera release]; camera 这部分是用ZBarReaderView自定义的界面... 解决方案 ZBar 二维码扫