为什么这不起作用? ZXing、位图、ImageSource

Why isnt this working? ZXing, Bitmap, ImageSource

我正在尝试从 WPF 中的相机扫描二维码(使用 Zxing - ZXing 的解码方法仅适用于位图)。这是我拥有的:

void Window2_Loaded(object sender, RoutedEventArgs e)
    {
        System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
        dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
        dispatcherTimer.Interval = new TimeSpan(0, 5, 0);
        LoaclWebCamsCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
        LocalWebCam = new VideoCaptureDevice(LoaclWebCamsCollection[1].MonikerString);
        LocalWebCam.NewFrame += new NewFrameEventHandler(Cam_NewFrame);
        LocalWebCam.Start();
        dispatcherTimer.Start();
    }

转换方法(位图源到位图)- 从另一个线程获取:

Bitmap GetBitmap(BitmapSource source)
    {
        Bitmap bmp = new Bitmap(
          source.PixelWidth,
          source.PixelHeight,
          System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
        BitmapData data = bmp.LockBits(
          new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size),
          ImageLockMode.WriteOnly,
          System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
        source.CopyPixels(
          Int32Rect.Empty,
          data.Scan0,
          data.Height * data.Stride,
          data.Stride);
        bmp.UnlockBits(data);
        return bmp;
    }

和定时器方法:

private void dispatcherTimer_Tick(object sender, EventArgs e)
    {

        BarcodeReader Reader = new BarcodeReader();

        if (frameHolder.Source != null)
        {
            Result result = Reader.Decode(GetBitmap((BitmapSource)frameHolder.Source));
            decoded = result.ToString().Trim();
            hey.Text = decoded;

        }

    }

和新的框架方法:

void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {

        try
        {
            System.Drawing.Bitmap img = (Bitmap)eventArgs.Frame.Clone();
            MemoryStream ms = new MemoryStream();
            img.Save(ms, ImageFormat.Bmp);
            ms.Seek(0, SeekOrigin.Begin);
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.StreamSource = ms;
            bi.EndInit();
            bi.Freeze();
            Dispatcher.BeginInvoke(new ThreadStart(delegate
            {
                frameHolder.Source = bi;
            }));

        }
        catch (Exception ex)
        {
        }
    }

frameHolder is my Image Control.

我做错了什么?。我很确定他不能从 frameHolder 中得到 Bitmap 但我不知道为什么。

您需要将二维码设置为可能的格式,否则它不会搜索任何内容。

下面的代码应该可以帮助您传递图像路径:

public static string Find(string fileName)
{
    if (File.Exists(fileName)) {

        using (var bitmap = (Bitmap)Image.FromFile(fileName))
        {
           return Decode(bitmap, false, new List<BarcodeFormat> {BarcodeFormat.QR_CODE});
        }            

    }
    return null;
}

并解码:

private static string Decode(Bitmap bitmap, bool tryMultipleBarcodes, IList<BarcodeFormat> possibleFormats)
{

    BarcodeReader barcodeReader = new BarcodeReader();            
    var previousFormats = barcodeReader.Options.PossibleFormats;

    if (possibleFormats != null)
        barcodeReader.Options.PossibleFormats = possibleFormats;

    barcodeReader.Options.TryHarder = true;
    barcodeReader.TryInverted = true;
    barcodeReader.AutoRotate = true;

    var result = barcodeReader.Decode(bitmap);

    if (result != null) {
        return result.ToString();
    } else {
        return null;
    }
}

首先

你知道这个方法有效吗?您是否使用从原始 Cam_NewFrame 方法保存的位图对其进行了测试。

为了您的理智,这是您应该做的第一件事。例如

void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
   ...
   img.Save("some path");

然后用它测试BarcodeReader

其次

为什么要麻烦地转换位图,然后再转换回来?

克隆位图时只需复制位图即可。然后在您的计时器方法中使用该克隆(显然使线程安全并正确处理它们)。

最后,阅读关于 BarcodeReader 的文档,您显然缺少很多配置(根据 Matt Beldons)回答

ZXing.Net 提供了一个特殊版本的 BarcodeReader class,它使用 BitmapSource 实例。 通常,如果您通过 nuget 将 ZXing.Net 包添加到您的项目中,应该会有对 zxing.presentation.dll 的引用。如果不是从二进制分发版手动添加它。 特殊的 BarcodeReader 位于命名空间 ZXing.Presentation 中。 您的方法的以下修改版本应该有效:

private void dispatcherTimer_Tick(object sender, EventArgs e)
{
    BarcodeReader Reader = new ZXing.Presentation.BarcodeReader();

    if (frameHolder.Source != null)
    {
        Result result = Reader.Decode((BitmapSource)frameHolder.Source);
        decoded = result?.Text;
        hey.Text = decoded;
    }
}

不要忘记检查 "result == null",如果没有找到条形码,就会发生这种情况。

顺便说一句,忘掉你的 DispatcherTimer 解决方案,把所有的工作都放在 Cam_NewFrame 里。

void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{

    try
    {
        System.Drawing.Bitmap img = (Bitmap)eventArgs.Frame.Clone();
        // TODO: add some kind of mutex or similar here so that you don't start a new Decode before the previous one is finished
        Dispatcher.BeginInvoke(new ThreadStart(delegate
        {
            // use the original BarcodeReader because we are using the bitmap instance directly
            BarcodeReader Reader = new ZXing.BarcodeReader();

            Result result = Reader.Decode(img);
            decoded = result?.Text;
            hey.Text = decoded;
        }));

        MemoryStream ms = new MemoryStream();
        img.Save(ms, ImageFormat.Bmp);
        ms.Seek(0, SeekOrigin.Begin);
        BitmapImage bi = new BitmapImage();
        bi.BeginInit();
        bi.StreamSource = ms;
        bi.EndInit();
        bi.Freeze();
        Dispatcher.BeginInvoke(new ThreadStart(delegate
        {
            frameHolder.Source = bi;
        }));

    }
    catch (Exception ex)
    {
    }
}

扔掉以下

...
    System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
    dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
    dispatcherTimer.Interval = new TimeSpan(0, 5, 0);
...
    dispatcherTimer.Start();
...
Bitmap GetBitmap(BitmapSource source)
{
...
}
...
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
...
}
...

我没有编译或测试代码。把它当作正确方向的提示。