[英]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.764
1频道PNG : 1.764
1.290
3频道PNG : 1.290
4 Channel PNG : 1.336
4频道PNG : 1.336
1 Channel BMP : 1.384
1频道BMP : 1.384
1.099
3频道BMP : 1.099
4 Channel BMP : 1.809
4频道BMP : 1.809
3 Channel JPG : 2.816
(Example image) 3频道JPG : 2.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: 我试过的其他事情:
Other details: 其他详情:
The results seem kind of counter intuitive, but it sure seems like in this particular scenario OpenCV is simply slower. 结果似乎有点反直觉,但在这种特殊情况下,OpenCV看起来确实比较慢。
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. 我希望这能使它成为一个有效的测试。
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.