Zxing获得图像流

本文关键字:图像 Zxing | 更新日期: 2023-09-27 18:06:30

我想从QR库zxing获得UWP的视频流。

我打算将流复制成两个输出。因此,底层流可以通过Gaussian Blur Filter,而顶部的流将在屏幕中心清晰地显示为二次几何(没有失真,就像"剪出窗口"一样)。这就产生了一种效果,用户正在扫描并聚焦于未模糊的区域(在屏幕中间),而周围是模糊的。

我打算用Lumia SDK或新的Composition API做模糊,这两个都应该是非常快的视频处理。

我怎样才能做到这一点?对于QR扫描仪来说,这绝对是一个漂亮的糖果,同时不会对CPU/GPU造成太大的负担。

Zxing获得图像流

我想从QR库zxing获得UWP的视频流

基于ZXing.Mobile的源代码,目前还没有从ZXing获取视频流的API,但我们可以自己实现。

让我们看看Zxing。Mobile:

  1. MobileBarcodeScanner.Scan方法中,它实际上导航到ScanPage视图

    rootFrame.Navigate(typeof(ScanPage), new ScanPageNavigationParameters 
    {//......
    }
    
  2. ScanPage视图,ZXingScannerControl控件将用于承担主要任务:

    <zxing:ZXingScannerControl x:Name="scannerControl">
    </zxing:ZXingScannerControl>
    
  3. StartScanningAsync方法中,原理是使用MediaCapture API启动相机预览,并调用GetPreviewFrameAsync方法在定时器中获得预览帧,该帧可以转换为LuminanceSource,通过BarcodeReader.Decode方法解码该图像中的条形码。

    // Set the capture element's source to show it in the UI
        captureElement.Source = mediaCapture;
        // Start the preview
        await mediaCapture.StartPreviewAsync();
    

    ……

    SoftwareBitmapLuminanceSource luminanceSource = null;
            try
            {
                // Get preview 
                var frame = await mediaCapture.GetPreviewFrameAsync(videoFrame);
                // Create our luminance source
                luminanceSource = new SoftwareBitmapLuminanceSource(frame.SoftwareBitmap);
    

    ……

     ZXing.Result result = null;
            try
            {
                // Try decoding the image
                if (luminanceSource != null)
                    result = zxing.Decode(luminanceSource);
    

所以底层的流可以通过高斯模糊滤镜,而顶部的流将在屏幕中心清晰地显示为二次几何(没有失真,就像"剪出窗口")。

你可以先试试MediaCapture.CapturePhotoToStreamAsync,这里也有类似的讨论

如果你想在屏幕中央显示一个二次几何图形,你可以放置一个Canvas来包含这些几何对象,参见官方的Basic人脸跟踪示例

XAML:

 <CaptureElement Name="CamPreview" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stretch="Fill" Margin="0,10,0,0" />
 <Canvas Name="VisualizationCanvas" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,10,0,0" />

背后的代码:

private void SetupVisualization(Windows.Foundation.Size framePizelSize, IList<DetectedFace> foundFaces)
    {
            this.VisualizationCanvas.Children.Clear();
            double actualWidth = this.VisualizationCanvas.ActualWidth;
            double actualHeight = this.VisualizationCanvas.ActualHeight;
            if (this.currentState == ScenarioState.Streaming && foundFaces != null && actualWidth != 0 && actualHeight != 0)
            {
                double widthScale = framePizelSize.Width / actualWidth;
                double heightScale = framePizelSize.Height / actualHeight;
                foreach (DetectedFace face in foundFaces)
                {
                    // Create a rectangle element for displaying the face box but since we're using a Canvas
                    // we must scale the rectangles according to the frames's actual size.
                    Rectangle box = new Rectangle();
                    box.Width = (uint)(face.FaceBox.Width / widthScale);
                    box.Height = (uint)(face.FaceBox.Height / heightScale);
                    box.Fill = this.fillBrush;
                    box.Stroke = this.lineBrush;
                    box.StrokeThickness = this.lineThickness;
                    box.Margin = new Thickness((uint)(face.FaceBox.X / widthScale), (uint)(face.FaceBox.Y / heightScale), 0, 0);
                    this.VisualizationCanvas.Children.Add(box);
                }
            }
        }