【问题标题】:improving algorithm to be faster - scanning image from file改进算法更快 - 从文件中扫描图像
【发布时间】:2013-02-14 18:35:18
【问题描述】:

我的代码在这里可以工作,但需要几秒钟的时间,而对于较大的文件,需要的时间更长,我想知道是否有人可以查看我所拥有的内容并提出任何有助于加快速度的改进。

目的:

这是扫描一个pdf文件并搜索一个二维码的位图图像,它会返回它的代码(解码)

private void ScanQRPdf(string imagePath)
    {
        foreach (var item in Directory.GetFiles(imagePath))
        {
            if (Path.GetExtension(item).ToLower() == ".png")
            {
                Bitmap b = new Bitmap(imagePath);
                try
                {
                    QRCodeDecoder decoder = new QRCodeDecoder();
                    String decodedString = decoder.decode(new QRCodeBitmapImage(b));
                    rtbpdfData.Text += decodedString + "\n";
                }
                catch (Exception ex)
                {
                }
            }
        }
    }

 static void AddQRTag(PdfSharp.Drawing.XGraphics gfx, int xPosition, int yPosition, string QRdata, string HRdata)
    {
        gfx.DrawRectangle(XBrushes.White, xPosition, yPosition, xPosition + 55, yPosition + 85);

        PdfSharp.Drawing.XImage xImage =
            PdfSharp.Drawing.XImage.FromGdiPlusImage(BuildQR(QRdata.ToUpper(), 3,
                                            QRCodeEncoder.ENCODE_MODE.ALPHA_NUMERIC, 2, QRCodeEncoder.ERROR_CORRECTION.M));
        gfx.DrawImage(xImage, xPosition + 5, yPosition + 5, xImage.PixelWidth * .8, xImage.PixelWidth * .8);


        XFont font = new XFont("OCR B", 6);
        XTextFormatter tf = new XTextFormatter(gfx);
        tf.Alignment = XParagraphAlignment.Left;


        XRect layout = new XRect(xPosition + 5, yPosition + 55, 55, 30);
        tf.DrawString(HRdata.ToUpper(), font, XBrushes.Black, layout, XStringFormats.TopLeft);
    }

【问题讨论】:

  • 慢代码大概在QRCodeDecoder类。在这里您无能为力。
  • 要问自己的问题:解码器会处理您的Bitmaps 吗?
  • 1 建议:删除catch{}
  • 你能把链接发到QRCodeDecoder源代码吗? (我假设您使用的是 O/S 库)
  • 获取分析器。它会告诉你瓶颈在哪里。猜测通常是浪费时间。

标签: c# algorithm image-processing bitmap


【解决方案1】:

在代码中,您过去的一切都可以。问题一定出在 QRCodeDecoder.decode 函数中。如果您通过 Bitmap.GetPixel 函数逐像素扫描图像,则会浪费大量时间。更好的方法是使用不安全的代码并将位图转换为 BitmapData。

【讨论】:

  • +1 如果这是一个开源库,那么GetPixel 可能是 OP 的最佳选择(除非他/她想设计更好的算法)。
  • 感谢您的信息 - 有没有办法只扫描/检查文件的角落以获取位图?
  • 是的,当然。如果您知道图像的宽度和高度(您可以从位图对象中获取它们),那么您可以只扫描角落。看看这里:msdn.microsoft.com/en-us/library/… 你可以这样改变循环的一部分: //upper corner for (int counter = 2; counter
  • 顺便说一下 rgbValues[counter] - 是红色; rgbValues[counter+1] - 是绿色; rgbValues[counter+2] - 是模糊颜色;
  • 感谢您提供的所有信息!我现在在网上找,会告诉你的。只是为了清楚您正在谈论的角落是图像还是文件的角落?我想在扫描的 pdf 文件的角落搜索位图图像。
【解决方案2】:

根据您的cmets,如果您只需要处理图像的左上角,您可以使用Bitmap.Clone提取图像的那部分。

在这种情况下,我会将您的代码重构为:

private void ScanQRPdf(string imagePath)
{
    foreach (var decodedString in DecodeAllImagesInFolder(imagePath))
    {
        rtbpdfData.Text += decodedString + "\n";
    }
}

private static IEnumerable<string> DecodeAllImagesInFolder(string imagePath)
{
    foreach (var item in Directory.GetFiles(imagePath, "*.png"))
    {
        using (Bitmap b = new Bitmap(imagePath))
        {
            yield return DecodeTopLeftCorner(b);
        }
    }
}

private static string DecodeTopLeftCorner(Bitmap bitmap)
{
    var rect = new Rectangle(0, 0, 100, 100);
    using (var topLeft = bitmap.Clone(rect, bitmap.PixelFormat))
    {
        return new QRCodeDecoder().decode(new QRCodeBitmapImage(topLeft));
    }
}

【讨论】:

  • 只是尝试一下,我得到“检测到的 Finder 模式的数量无效”,我正在调试以查看源代码。
  • @BB987:请注意,我选择的矩形大小是完全任意的。您可能应该检查它是否裁剪了整个代码。而且,你之前吞下了异常(正如@Henk 在 cmets 中提到的那样),这通常是一种不好的做法。 decode 方法可能会在找不到代码时抛出此异常,但如果不查看其源代码,我无法判断。
  • 我明白了,我正在做一些改变和观察。也刚想到。因为我只查看用户传入的单个文件,我还需要有一个目录来获取所有文件吗?我不能只使用那个文件吗?
  • @BB987:当然,为什么不呢?如果您已经知道文件名,则无需使用Directory.GetFiles
  • 那么我可以省去删除 foreach 循环并将图像路径插入到 using 语句中吗? using(Bitmap b = new Bitmap(imagePath)?
【解决方案3】:

有几件事可以尝试:

  1. 按照 Carra 的建议,按扩展名过滤文件
  2. 只声明和实例化一次QRCodeDecoder
  3. 使用StringBuilder 附加文本并仅分配一次

应该是这样的:

private void ScanQRPdf(string imagePath)
{
    var files = Directory.GetFiles ( path, "*.png", SearchOption.AllDirectories );

    QRCodeDecoder decoder = new QRCodeDecoder();

    StringBuilder sb = new StringBuilder();

    foreach (var item in files)
    {

            Bitmap b = new Bitmap(imagePath);
            try
            {
                String decodedString = decoder.decode(new QRCodeBitmapImage(b));

                sb.AppendLine(decodedString);
            }
            catch (Exception ex)
            {
            }

    }

    rtbpdfData.Text = sb.ToString();
}

但我真的不认为它会解决你的问题,这都是一些小的改进,你的延迟必须在 QRCodeDecoderQRCodeBitmapImage 类中的某个地方,特别是在 decode 方法中,你应该尝试理解它们更好,并找出它在内部做什么,这样你就可以改进你的代码。

【讨论】:

  • 我认为不应该在没有分析的情况下提出这样的建议。在这种情况下,我很确定decode 方法至少占用了 95% 的执行时间。
  • 我刚试了一下,还是有点慢。我想知道我是否只能扫描/检查页面一角的二维码,如果这样会减少时间。二维码将始终位于左上角,如果我找不到它,我将旋转页面并检查。这听起来可行吗?
  • 是的,这是可行的,但您必须找到如何对 pdf 进行切片
【解决方案4】:

您可以使用带有类型的 GetFiles:

string[ ] files = Directory.GetFiles ( path, "*.png", SearchOption.AllDirectories ); 

【讨论】:

  • 我怀疑这是瓶颈。
  • 你是对的,这可能是一个小改进,取决于文件的数量。但瓶颈可能在解码器中,我们看不到那部分。
猜你喜欢
  • 2012-08-28
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
  • 2016-09-08
  • 2011-05-08
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多