代码之家  ›  专栏  ›  技术社区  ›  Adri1511

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

  •  0
  • Adri1511  · 技术社区  · 6 年前

    我正在尝试扫描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 是我的图像控件。

    我做错了什么?。我很肯定他不能得到 Bitmap 超出 框架支架 但我不知道为什么。

    3 回复  |  直到 6 年前
        1
  •  2
  •   user9401448 user9401448    6 年前

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

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

    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;
        }
    }
    
        2
  •  0
  •   Michael    6 年前

    ZXing。Net提供了使用BitmapSource实例的BarcodeReader类的特殊版本。 通常,如果您添加ZXing。Net包通过nuget到您的项目应该有一个zxing的参考。演示dll。如果没有,请从二进制分发中手动添加它。 特殊的条形码阅读器位于名称空间ZXing中。演示 您的方法的以下修改版本应该可以使用:

    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”,如果没有找到条形码,就会出现这种情况。

    顺便说一下,忘记Dispatchermer解决方案,在Cam\u 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)
    {
    ...
    }
    ...
    

    我没有编译或测试代码。更像是向正确的方向暗示。

        3
  •  0
  •   TheGeneral    6 年前

    首先

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

    为了你的理智,这是你应该做的第一件事。E、 g级

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

    然后测试 BarcodeReader 用它。

    其次

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

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

    最后,阅读上的文档 条形码阅读器 很明显,您缺少了很多配置(根据Matt Beldons)的答案