我正在考虑在性能关键应用程序中使用OpenCV,所以我决定从基础开始并测试图像加载速度.令我惊讶的是,与.NET相比,使用OpenCV时,图像加载(我们做了很多事情)需要大约1.5倍.
这是我的代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我用来测试的花卉图像的链接.
我的结果(CV时间/ .NET时间):
1.7641.2904频道PNG:1.336
1频道BMP:1.384
1.0994频道BMP:1.809
3频道JPG :( 2.816示例图片)
这些测试是在发布模式下编译完成的,没有使用官方OpenCV Windows库附加调试器.
我最初的想法是内存分配的速度,但看看不同频道图像之间的差异似乎暗示情况并非如此.
我试过的其他事情:
其他详情:
结果似乎有点反直觉,但在这种特殊情况下,OpenCV看起来确实比较慢.
感谢@πάνταῥεῖ指出操作不相同,编辑以在两种情况下创建Mat以隔离加载方法.我希望这能使它成为一个有效的测试.
修复了@B指出的问题,在使用CV_LOAD_IMAGE_UNCHANGED加载时修改了数字.
除非您另外指定(您没有指定),否则 OpenCv 将返回彩色图像。因此,对于 OpenCV,您需要支付颜色转换费用,而 .NET 可能不会发生这种情况。对于单色图像,您需要指定 CV_LOAD_IMAGE_GRAYSCALE,或将标志设置为 -1 以获取文件中的任何内容。
查看源代码,看起来 3 通道图像以 RGB 通道顺序从实际解码器(至少是 PNG 和 Jpeg)中出来,并且这些图像被交换为 OpenCV 在任何地方都期望的 BGR 顺序。如果您的 .NET 库按 RGB 顺序返回图像,那么如果要将图像传递给其他 OpenCV 函数,您可能需要转换为 BGR。然后你可能会失去速度优势。
公平地说,您需要将 RGB2BGR 转换添加到 .NET 加载代码中 - 请参阅将 BGR 位图转换为 RGB
另外,对于 4 通道 PNG,OpenCV 将丢弃 alpha 通道并返回 3 通道图像,除非您指定 flags = -1。
| 归档时间: |
|
| 查看次数: |
1795 次 |
| 最近记录: |