如何使用网络摄像头在 WinUI 3 中扫描二维码?

问题描述 投票:0回答:1

我正在尝试在 WinUI 3 中从网络摄像头扫描二维码。我已经安装了 ZXing 和 AForge Video,但这些库在 WinUI 3 中无法正常工作。是否有任何解决方案或更兼容的替代方案?

c# qr-code webcam zxing winui-3
1个回答
0
投票

ZXing(ZXing.NET是一个端口)完全与平台无关,因此只要您可以捕获某种“位图”(RGB等),无论它在给定平台上意味着什么,它都可以很好地与任何技术一起使用.

这是 WinUI3(确保您安装了最新的 WinUI3 nuget)示例应用程序,它执行两件事:

  • 它捕获(PC 上的第一个)网络摄像头输出并将其显示在 WinUI3 MediaPlayerElement 中。
  • 对于每一帧,它都会运行 ZXing 条形码阅读器解码,尝试查找 QR 码,并在找到时显示它。

可以轻松更改代码以读取 XZing 支持的任何条形码(EAN13 等)。它包含 XZing 和 WinRT 的 SoftwareBitmap 之间的薄适配层(我从 XZing.NET 代码复制):

这是 WinUI3 页面的 XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <Button Click="Button_Click">Toggle Capture</Button>
    <TextBox x:Name="textBox" Grid.Row="1" />
    <MediaPlayerElement
        x:Name="player"
        Grid.Row="2"
        Width="600"
        Height="600"
        AutoPlay="True" />
</Grid>

WinUI3页面中的代码(您需要安装XZing.NET nuget包):

public sealed partial class MainPage : Page
{
    private readonly SoftwareBitmapBarcodeReader _reader;
    private MediaCapture _capture;
    private MediaFrameReader _frameReader;
    private MediaSource _mediaSource;

    public MainPage()
    {
        InitializeComponent();

        // set various xzing options (beware, all formats like All_1D can divide perf by orders of magnitude)
        _reader = new SoftwareBitmapBarcodeReader
        {
            AutoRotate = true
        };
        _reader.Options.PossibleFormats = new[] { BarcodeFormat.QR_CODE };
        _reader.Options.TryHarder = true;
    }

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        if (_capture == null)
        {
            await InitializeCaptureAsync();
            return;
        }
        await TerminateCaptureAsync();
    }

    private async Task InitializeCaptureAsync()
    {
        // get first capture device (change this if you want)
        var sourceGroup = (await MediaFrameSourceGroup.FindAllAsync())?.FirstOrDefault();
        if (sourceGroup == null)
            return; // not found!

        // init capture & initialize
        _capture = new MediaCapture();
        await _capture.InitializeAsync(new MediaCaptureInitializationSettings
        {
            SourceGroup = sourceGroup,
            SharingMode = MediaCaptureSharingMode.SharedReadOnly,
            MemoryPreference = MediaCaptureMemoryPreference.Cpu, // to ensure we get SoftwareBitmaps
        });

        // initialize source
        var source = _capture.FrameSources[sourceGroup.SourceInfos[0].Id];

        // create reader to get frames & pass reader to player to visualize the webcam
        _frameReader = await _capture.CreateFrameReaderAsync(source, MediaEncodingSubtypes.Bgra8);
        _frameReader.FrameArrived += OnFrameArrived;
        await _frameReader.StartAsync();

        _mediaSource = MediaSource.CreateFromMediaFrameSource(source);
        player.Source = _mediaSource;
    }

    private void OnFrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
    {
        var bmp = sender.TryAcquireLatestFrame()?.VideoMediaFrame?.SoftwareBitmap;
        if (bmp == null)
            return;

        var result = _reader.Decode(bmp);
        if (result != null)
        {
            // found a QR CODE
            DispatcherQueue.TryEnqueue(() =>
            {
                textBox.Text = result.BarcodeFormat + ": " + result.Text;
            });
        }
    }

    private async Task TerminateCaptureAsync()
    {
        player.Source = null;

        _mediaSource?.Dispose();
        _mediaSource = null;

        if (_frameReader != null)
        {
            _frameReader.FrameArrived -= OnFrameArrived;
            await _frameReader.StopAsync();
            _frameReader?.Dispose();
            _frameReader = null;
        }

        _capture?.Dispose();
        _capture = null;
    }
}

// this is the thin layer that allows you to use XZing over WinRT's SoftwareBitmap
public class SoftwareBitmapBarcodeReader : BarcodeReader<SoftwareBitmap>
{
    public SoftwareBitmapBarcodeReader()
        : base(bmp => new SoftwareBitmapLuminanceSource(bmp))
    {
    }
}

// from https://github.com/micjahn/ZXing.Net/blob/master/Source/lib/BitmapLuminanceSource.SoftwareBitmap.cs
public class SoftwareBitmapLuminanceSource : BaseLuminanceSource
{
    protected SoftwareBitmapLuminanceSource(int width, int height)
      : base(width, height)
    {
    }

    public SoftwareBitmapLuminanceSource(SoftwareBitmap softwareBitmap)
        : base(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight)
    {
        if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Gray8)
        {
            using SoftwareBitmap convertedSoftwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Gray8);
            convertedSoftwareBitmap.CopyToBuffer(luminances.AsBuffer());
            return;
        }
        softwareBitmap.CopyToBuffer(luminances.AsBuffer());
    }

    protected override LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height)
        => new SoftwareBitmapLuminanceSource(width, height) { luminances = newLuminances };
}

这是编码“Hello World”的二维码的结果:

© www.soinside.com 2019 - 2024. All rights reserved.