C# 为什么这不起作用?ZXing,位图,图像源

C# 为什么这不起作用?ZXing,位图,图像源,c#,wpf,bitmap,zxing,imagesource,C#,Wpf,Bitmap,Zxing,Imagesource,我正试图在WPF中从摄像头扫描二维码(使用Zxing-Zxing的解码方法仅适用于位图)。以下是我所拥有的: void Window2_Loaded(object sender, RoutedEventArgs e) { System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); dispatcherTi

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


我做错了什么?。我很确定他不能从
框架支架中取出
位图
,但我不知道为什么

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

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

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;
}
公共静态字符串查找(字符串文件名)
{
if(File.Exists(fileName)){
使用(var bitmap=(bitmap)Image.FromFile(文件名))
{
返回解码(位图、假、新列表{BarcodeFormat.QR_CODE});
}            
}
返回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;
    }
}
私有静态字符串解码(位图、bool-trymultipleBarcode、IList可能格式)
{
条码阅读器条码阅读器=新条码阅读器();
var previousFormats=barcodeReader.Options.PossibleFormats;
if(可能格式!=null)
条形码阅读器.Options.PossibleFormats=PossibleFormats;
barcodeReader.Options.TryHarder=true;
barcodeReader.TryInverted=true;
barcodeReader.AutoRotate=true;
var结果=条形码阅读器.Decode(位图);
如果(结果!=null){
返回result.ToString();
}否则{
返回null;
}
}

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

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

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;
}
公共静态字符串查找(字符串文件名)
{
if(File.Exists(fileName)){
使用(var bitmap=(bitmap)Image.FromFile(文件名))
{
返回解码(位图、假、新列表{BarcodeFormat.QR_CODE});
}            
}
返回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;
    }
}
私有静态字符串解码(位图、bool-trymultipleBarcode、IList可能格式)
{
条码阅读器条码阅读器=新条码阅读器();
var previousFormats=barcodeReader.Options.PossibleFormats;
if(可能格式!=null)
条形码阅读器.Options.PossibleFormats=PossibleFormats;
barcodeReader.Options.TryHarder=true;
barcodeReader.TryInverted=true;
barcodeReader.AutoRotate=true;
var结果=条形码阅读器.Decode(位图);
如果(结果!=null){
返回result.ToString();
}否则{
返回null;
}
}

首先

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

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

void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
   ...
   img.Save("some path");
然后用它测试条形码阅读器

其次

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

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


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

首先

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

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

void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
   ...
   img.Save("some path");
然后用它测试条形码阅读器

其次

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

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


最后,请阅读
BarcodeReader
上的文档,您显然缺少很多配置(根据Matt Beldons)答案ZXing.Net提供了使用BitmapSource实例的BarcodeReader类的特殊版本。 通常,如果您通过nuget将ZXing.Net包添加到项目中,则应该有对ZXing.presentation.dll的引用。如果没有,请从二进制发行版手动添加它。 特殊条形码阅读器位于名称空间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”,如果没有找到条形码,就会出现这种情况

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

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

ZXing.Net提供了一个使用BitmapSource实例的BarcodeReader类的特殊版本。 通常,如果您通过nuget将ZXing.Net包添加到项目中,则应该有对ZXing.presentation.dll的引用。如果没有,请从二进制发行版手动添加它。 特殊条形码阅读器位于名称空间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”,如果没有找到条形码,就会出现这种情况

顺便说一下,忘记你的Dispatchermer解决方案,在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)
{
...
}
...
我没有编译或测试代码。更像是向正确方向暗示。

我做错了什么?这里可能没有先知。只要你不说出你期望的结果和实际发生的事情,没有人能帮助你。你可能对学习和学习感兴趣。我做错了什么?这里可能没有先知。只要你不说出你期望的结果和实际发生的事情,没有人能帮助你。你可能对学习和学习感兴趣