• 网译文章———QR码扫描的Windows Phone ZXlib 7.5


    前言:

    摄像头的访问是芒果7.5的一大新功能。

    通过摄像头的访问出现了一些新的应用,如应用程序QR,条形码扫描,增强摄像头功能和自定义摄像头UI等。

    有很好资源来告诉我们如何使用新的API来访问芒果相机,但是我没有找到任何一个完整的QR码扫描程序,因此我写了这个博客。

     

    正文:                           

    芒果新增了2个新的关于CameraAPI。你可以使用Silverlight 4中引入摄像头的API或者使用芒果提供的新的PhotoCamera类。我不是要覆盖这两个API的所有细节,而我将集中讨论如何实施QR扫描仪解决方案。如果您想了解更多有关Silverlight 4中的API访问摄像机,我推荐你看Rene Schulte’s detailed blog post的博客。关于PhotoCameraAPI信息,我推荐你看(这个MSDN文章展示了如何建立一个为Windows Phone的摄像头应用程序this MSDN article showing how to build a camera application for Windows Phone.

     

    建设QR扫描仪的任务开始时我做的第一件事是研究不同的开源库,做图像识别。幸运的是有很多这样的开源库,但是从谷歌ZXing似乎是最流行的一个。ZXing库有很多个版本,并且支持1D/2D码(QRCode128Code39EAN等等)。其中有一个C#的借口库,被移植到SilverlightWindows Phone 7上了。这样这个QR码扫描程序的任务就是合并ZXing库和芒果的Camera  API了。

     

    扫描器的XAML代码由4个主要部分组成。 一个矩形用来作为显示在取景器的视频流。 相机和矩形的链接方式是通过一个VideoBrush。你可以使用图像资源为VidoBrush设值,在任何的XAML元素上画画。这个转换可以让我们通过videobrush的旋转来协调摄像头的旋转。最好用一个ListBox显示QR码的解码。

     1     <Grid x:Name="LayoutRoot" Background="Transparent">
     2         <Rectangle x:Name="_previewRect" Margin="0" Height="800"Width="600" HorizontalAlignment="Center" VerticalAlignment="Center">
     3             <Rectangle.Fill>
     4                 <VideoBrush x:Name="_previewVideo">
     5                     <VideoBrush.RelativeTransform>
     6                         <CompositeTransform x:Name="_previewTransform" CenterX=".5"CenterY=".5" />
     7                     </VideoBrush.RelativeTransform>
     8                 </VideoBrush>
     9             </Rectangle.Fill>
    10         </Rectangle>
    11         <ListBox Margin="10" x:Name="_matchesList" FontSize="30" FontWeight="ExtraBold" />
    12     </Grid>

    在代码隐藏文件中,我们需要添加一些初始化代码。 在构造函数中,我们实例化一个ObservableCollection它将绑定到ListBox的ItemsSource上.每个成功的QR扫描结果都会加到集合中,然后更新ListBox的items。我们还创建了一个DispatcherTimer每250毫秒执行一次。在每次执行tick时,我们对QR码图像进行解析。在OnNavgiatedTo方法我们实例PhotoCamera类,调用相机初始化事件。在创建XAML是把photocamera设置为videoBruch的source。这样就能把camera看到的景象画到矩形上。然后把ShutterKeyHalfPressed和foucue挂起来.

     1         private readonly DispatcherTimer _timer;
     2         private readonly ObservableCollection<string> _matches;
     3         private PhotoCameraLuminanceSource _luminance;
     4         private QRCodeReader _reader;
     5         private PhotoCamera _photoCamera;
     6         public MainPage()
     7         {
     8             InitializeComponent();
     9             _matches = new ObservableCollection<string>();
    10             _matchesList.ItemsSource = _matches;
    11             _timer = new DispatcherTimer();
    12             _timer.Interval = TimeSpan.FromMilliseconds(250);
    13             _timer.Tick += (o, arg) => ScanPreviewBuffer();
    14         }
    15 
    16         protected override void OnNavigatedTo(NavigationEventArgs e)
    17         {
    18             _photoCamera = new PhotoCamera();
    19             _photoCamera.Initialized += OnPhotoCameraInitialized;
    20             _previewVideo.SetSource(_photoCamera);
    21             CameraButtons.ShutterKeyHalfPressed += (o, arg) => _photoCamera.Focus();
    22             base.OnNavigatedTo(e);
    23         }

    photocamera初始化时,我们运行一些设置代码。这些代码是设置相机预览分辨率的宽和高,因次在相机初始化之前这些代码是不能运行的。下面我们创建一个PhotoCameraLumianceSource的实例。这是一个自定义的类,它扩展了ZXing库。这个类负责从图像中提取亮度信息。ZXing提供了一个基类的扩展,你通过代码得到特定格式的图片信息。接着我们创建一个QRCodeReader的实例。这个类用来解析QR码扫描的图片。ZXing库可以读取很多种码,因此如果你想读取Code128,只需创建一个Code128Reader的实例。最好我们设置预览VideoBrush的旋转并开启时钟。

     1         private void OnPhotoCameraInitialized(object sender, CameraOperationCompletedEventArgs e)
     2         {
     3             int width = Convert.ToInt32(_photoCamera.PreviewResolution.Width);
     4             int height = Convert.ToInt32(_photoCamera.PreviewResolution.Height);
     5             _luminance = new PhotoCameraLuminanceSource(width, height);
     6             _reader = new QRCodeReader();
     7             Dispatcher.BeginInvoke(() =>
     8             {
     9                 _previewTransform.Rotation = _photoCamera.Orientation;
    10                 _timer.Start();
    11             });
    12         }

    每次执行tick事件都会调用ScanPreviewBuffer。这个方法负责获得照相机的图片信息,并对其进行解码。pjotocamera提供了很多方法获取图片。你可以通过捕获全屏的图片得到,也可以通过预览缓存得到。捕捉全分辨率的图像对计算机视觉应用是很慢的,但幸好我们有方法来访问预览缓冲区。你可以得到要么ARGB格式或YCbCr格式的预览缓冲区。相机传感器的内部使用的YCbCr,所以ARGB格式需要转换。如果你只关心亮度(在YCbCr Y)的有一个方便的方法,让你从YCbCr格式中得到Y分量。通过ZXing库实现是很容易的。Rene Schutle有一篇关于Argb vs YCbCr的详细博客

     

    GetPreviewBufferY方法需要一个字节数组作为参数,这个自己数组可以用预览缓冲器的亮度数据来填充。我们可以从亮度源类传递到PerviewBufferY属性中(稍后提到)。 一旦我们捕捉到亮度数据,我们创建了一个HybridBinarizer和BinaryBitmap类。他们是的ZXing库的一部分。 我没有足够的精力与时间完全理解ZXing的架构, 但通过亮度数据的传递,然后传递给的QRCodeReader的解码方法的步骤我们是知道的。 如果解码成功解码的文本将被添加到ObservableCollection,这反过来将更新的ListBox。如果它不能够解码的图像, 解码方法将QRCodeReader抛出一个异常,所以我们需要的代码包装在一个try-catch块。

     1         private void ScanPreviewBuffer()
     2         {
     3             try
     4             {
     5                 _photoCamera.GetPreviewBufferY(_luminance.PreviewBufferY);
     6                 var binarizer = new HybridBinarizer(_luminance);
     7                 var binBitmap = new BinaryBitmap(binarizer);
     8                 var result = _reader.decode(binBitmap);
     9                 Dispatcher.BeginInvoke(() => DisplayResult(result.Text));
    10             }
    11             catch
    12             {
    13 
    14             }
    15         }
    16 
    17         private void DisplayResult(string text)
    18         {
    19             if (!_matches.Contains(text))
    20                 _matches.Add(text);
    21         }

    PhotoCameraLumianceSoure引用了ZXing库里的基类。这个类是负责您正在使用的图像格式的亮度数据方便的PhotoCamera类为我们提供了直接的亮度数据,所以实现类并不需要太多的代码。有一个属性和方法是我们要实现的。Matrix简单的返回一个完整的图片亮度数据。getRow方法返回一个给定的亮度数据。不管属性还是方法,都是每次时钟器调用GetPreviewBufferY方法返回的PreviewBufferY数组。

     1         public class PhotoCameraLuminanceSource : LuminanceSource
     2         {
     3             public byte[] PreviewBufferY { get; private set; }
     4             public PhotoCameraLuminanceSource(int width, int height) : base(width, height)
     5             {
     6                 PreviewBufferY = new byte[width * height];
     7             }
     8 
     9             public override sbyte[] Matrix
    10             {
    11                 get { return (sbyte[])(Array)PreviewBufferY; }
    12             }
    13 
    14             public override sbyte[] getRow(int y, sbyte[] row)
    15             {
    16                 if (row == null || row.Length < Width)
    17                 {
    18                     row = new sbyte[Width];
    19                 }
    20                 for (int i = 0; i < Height; i++)
    21                     row[i] = (sbyte)PreviewBufferY[i * Width + y];
    22                 return row;
    23             }
    24         }

    那么,如何在实际工作?下面是一个YouTube视频,展示了QR扫描仪。正如你可以看到它是相当快速,准确的。我还没有在野外测试,和的ZXing库提供了许多定制扫描器行为的微调,但至少在这个演示如何可以结合ZXing和芒果PhotoCamera API实现在150行代码内扫描QR码。

     

    终于翻译完了,对我这个英语不好的人,还真是不小的挑战。觉得翻译可以的给点掌声。

    转载请注明出处。

     

    原文:http://jonas.follesoe.no/2011/07/22/qr-code-scanning-on-windows-phone-75-using-zxlib/

  • 相关阅读:
    CF85E Guard Towers(二分答案+二分图)
    CF732F Tourist Reform(边双联通)
    CF949C Data Center Maintenance(建图+强联通分量)
    CF402E Strictly Positive Matrix(矩阵,强联通分量)
    CF209C Trails and Glades(欧拉路)
    POJ1201Intervals(差分约束)
    NOIP2016 天天爱跑步(树上差分)
    CF19E Fairy(树上差分)
    NOIP 2017 小凯的疑惑(同余类)
    POJ 3539 Elevator(同余类BFS)
  • 原文地址:https://www.cnblogs.com/qq278360339/p/2579764.html
Copyright © 2020-2023  润新知