简体   繁体   English

为什么OpenCV加载图像需要比.NET长得多?

[英]Why does OpenCV take much longer to load an image than .NET?

I was looking into using OpenCV in a performance critical application, so I decided to start with the basics and test image loading speed. 我正在考虑在性能关键应用程序中使用OpenCV,所以我决定从基础开始并测试图像加载速度。 To my surprise, image loading (something we do a lot of) takes ~1.5 times longer with OpenCV when compared to .NET. 令我惊讶的是,与.NET相比,使用OpenCV时,图像加载(我们做了很多工作)需要大约1.5倍。

Here is my code: 这是我的代码:

CvDll.cpp

#include "stdafx.h"
#include <opencv2\opencv.hpp>

#define CVDLL_API __declspec(dllexport)

extern "C"
{
    CVDLL_API void CvLoadImage(const char* imagePath);
    CVDLL_API void CvCreateMat(int width, int height, int stride, int channels, void* pBuffer);
}

CVDLL_API void CvLoadImage(const char* imagePath)
{
    cv::Mat image = cv::imread(imagePath, CV_LOAD_IMAGE_UNCHANGED);
}

CVDLL_API void CvCreateMat(int width, int height, int stride, int channels, void* pBuffer)
{
    int type = CV_MAKETYPE(CV_8U, channels);
    cv::Mat image(cv::Size(width, height), type, pBuffer, stride);
}

Program.cs

   static class Cv
    {
        [DllImport("CvDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "CvLoadImage")]
        public static extern void LoadImage(string imagePath);

        [DllImport("CvDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "CvCreateMat")]
        public static extern void CreateMat(int width, int height, int stride, int channels, IntPtr pBuffer);
    }

    static void Main(string[] args)
    {
        if (args.Length < 1)
        {
            Console.WriteLine("Usage: {0} (path to image)", Path.GetFileName(System.Reflection.Assembly.GetCallingAssembly().Location));
            Console.Write("Press any key to continue...");
            Console.ReadKey();
            return;
        }

        string imagePath = args[0];

        try
        {
            if (!File.Exists(imagePath)) throw new ApplicationException("Image file does not exist.");

            // Time .NET
            Console.Write(".NET Loading {0} Bitmaps: ", ITERATIONS);
            TimeSpan timeDotNet = TimeIt(
                () =>
                {
                    using (Bitmap img = new Bitmap(imagePath))
                    {
                        int width = img.Width;
                        int height = img.Height;
                        int channels = Image.GetPixelFormatSize(img.PixelFormat) / 8; // Assumes 1 byte per channel

                        BitmapData bd = img.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, img.PixelFormat);

                        // Create a Mat from the bitmap data to make the operation equivalent
                        Cv.CreateMat(width, height, Math.Abs(bd.Stride), channels, bd.Scan0);

                        img.UnlockBits(bd);
                    }
                }
                , ITERATIONS
            );
            Console.WriteLine("{0}", timeDotNet);

            // Time OpenCV
            Console.Write("OpenCV Loading {0} Mats: ", ITERATIONS);
            TimeSpan timeCv = TimeIt(
                () => Cv.LoadImage(imagePath)
                , ITERATIONS
            );
            Console.WriteLine("{0}", timeCv);

            // Show ratio
            Console.WriteLine("CV / .NET: {0:0.000}", timeCv.TotalMilliseconds / timeDotNet.TotalMilliseconds);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception caught: {0}{1}", ex.Message, Environment.NewLine);
        }

        // End
        Console.Write("Press any key to continue...");
        Console.ReadKey();
    }

    static TimeSpan TimeIt(Action action, int iterations)
    {
        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < iterations; ++i)
        {
            action();
        }
        return sw.Elapsed;
    }
}

Here is a link to the flower image I've been using to test. 是我用来测试的花卉图像的链接。

My results (CV time / .NET time): 我的结果(CV时间/ .NET时间):

  • 1 Channel PNG : 1.764 1频道PNG1.764
  • 3 Channel PNG : 1.290 3频道PNG1.290
  • 4 Channel PNG : 1.336 4频道PNG1.336

  • 1 Channel BMP : 1.384 1频道BMP1.384

  • 3 Channel BMP : 1.099 3频道BMP1.099
  • 4 Channel BMP : 1.809 4频道BMP1.809

  • 3 Channel JPG : 2.816 (Example image) 3频道JPG2.816 (示例图片)

These tests were done compiled in Release mode without the debugger attached using the official OpenCV Windows libs. 这些测试是在发布模式下编译完成的,没有使用官方OpenCV Windows库附加调试器。

My initial thought was the speed of memory allocation, but looking at the difference between different channel images seems to imply this is not the case. 我最初的想法是内存分配的速度,但看看不同频道图像之间的差异似乎暗示情况并非如此。

Other things I've tried: 我试过的其他事情:

  • Moving loop into C++ function : No change 将循环移动到C ++函数 :没有变化
  • Turn on all the optimization options I could find in VS : No change 打开我在VS中找到的所有优化选项 :无变化
  • Second machine : Tried on an AMD Phenom II machine and the color images started giving around 1.25 and grayscale around 1.5. 第二台机器 :在AMD Phenom II机器上试用,彩色图像开始提供大约1.25和灰度大约1.5。 So while different, still in .NET's favor. 所以虽然不同,但仍然受到.NET的青睐。

Other details: 其他详情:

  • Windows 7 x64 Windows 7 x64
  • Visual Studio 2013 Visual Studio 2013
  • OpenCV 2.4.9 OpenCV 2.4.9
  • .NET 4.5 .NET 4.5

The results seem kind of counter intuitive, but it sure seems like in this particular scenario OpenCV is simply slower. 结果似乎有点反直觉,但在这种特殊情况下,OpenCV看起来确实比较慢。

EDIT: 编辑:

Thanks to @πάντα ῥεῖ for pointing out that the operations weren't equivalent, edited to create a Mat in both scenarios to isolate the loading method. 感谢@πάνταῥεῖ指出操作不相同,编辑以在两种情况下创建Mat以隔离加载方法。 I hope this makes it a valid test. 我希望这能使它成为一个有效的测试。

EDIT2: EDIT2:

Fixed issue pointed out by @B, revised the numbers when loading with CV_LOAD_IMAGE_UNCHANGED. 修复了@B指出的问题,在使用CV_LOAD_IMAGE_UNCHANGED加载时修改了数字。

Unless you specify otherwise, which you haven't, OpenCv returns a color image. 除非您另外指定,否则OpenCv将返回彩色图像。 Therefore for OpenCV you are paying for a color conversion which probably isn't occurring for .NET. 因此,对于OpenCV,您需要支付可能不会出现在.NET中的颜色转换。 For the one color image you need to specify CV_LOAD_IMAGE_GRAYSCALE, or set the flags to -1 to get whatever is in the file. 对于单色图像,您需要指定CV_LOAD_IMAGE_GRAYSCALE,或将标志设置为-1以获取文件中的任何内容。

Looking at the source code, it looks like 3 channel images come out of the actual decoder (PNG and Jpeg, at least) in RGB channel order and these are swapped to the BGR order that OpenCV expects everywhere. 看一下源代码,看起来3个通道图像以RGB通道顺序从实际解码器(至少是PNG和Jpeg)出来,并且这些图像被交换到OpenCV期望的BGR顺序。 If your .NET library is returning the images in RGB order, then you might need to do a conversion to BGR if you are going to pass the images to other OpenCV functions. 如果您的.NET库以RGB顺序返回图像,那么如果要将图像传递给其他OpenCV函数,则可能需要转换为BGR。 ANd then you would probably lose the speed advantage. 那么你可能会失去速度优势。

To be fair, you need to add a RGB2BGR conversion to your .NET load code - see Converting a BGR bitmap to RGB 公平地说,您需要将RGB2BGR转换添加到.NET加载代码中 - 请参阅将BGR位图转换为RGB

Also, for the 4 channel PNG, OpenCV will discard the alpha channel and return a 3 channel image unless you specify flags = -1. 此外,对于4通道PNG,除非指定flags = -1,否则OpenCV将丢弃Alpha通道并返回3通道图像。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么写入Excel范围比在C#.NET中花费更长的时间? - Why does writing to an Excel range take much longer than expected in C# .NET? 为什么 ConcurrentDictionary 的第一次访问时间比后续访问时间长得多? - Why does the first access time for ConcurrentDictionary take so much longer than consequent accesses? 为什么通过ASP.NET方法运行查询比原生SQL需要更长的时间? - Why does running a query through ASP.NET method take longer than native SQL? 为什么重载++比仅增加值要花费更长的时间? - Why does overloading ++ take significantly longer than incrementing just the value? 在SoapUI中进行测试时,请求比在代码中进行的请求要花费更长的时间。 为什么? - When testing in SoapUI, requests take much longer than requests made in code. Why? 为什么在WinForm中隐藏控件比使它们可见更长? - Why does hiding controls in WinForm take longer than making them visible? 为什么访问先前创建的变量所需的时间比刚刚声明的变量要长? - Why does it take longer to access to a previously created variable than a variable just declared? 为什么运行一百个异步任务比运行一百个线程需要更长的时间? - Why does running a hundred async tasks take longer than running a hundred threads? 为什么在Image上旋转比使用BitmapEncoder快得多? - Why is rotation much faster on Image than using BitmapEncoder? 为什么列表容量的大小调整到超出所需的大小? - Why does List Capacity resize to much more than is needed?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM