我想迭代图像的所有像素并与搜索模式进行比较。具有最佳性能并且在C#中。我找到了emgu cv,它是Intels opencv的包装器。但我不知道如何正确使用emgu。有人知道我怎么做吗?图像的数据属性是什么?这是imagedata吗?如果是,哪个值是什么?感谢
我用C#编写了我的函数,但效果很好,但速度太慢了!我已经在c中使用了algorhytm,我将其翻译成C#。 C#比c慢3到4倍! (我的函数几乎遍历图像的每个像素以寻找图像中的形状。 - > Hugh Transformation)
好吧,我听说不安全的代码可能会更快,因为它不会检查数组边界和内容。真的吗?直接在物理机器上运行不安全的代码?
无论如何,我试图将不安全的代码放入我的函数中。但我无法获得指向我的3D数组的指针或使用指针访问3D数组。如何用不安全的代码重写上面的代码?这会带来额外的性能提升,甚至可以像c代码一样快速运行吗?
答案 0 :(得分:48)
正如emgu网站所述,主要有两种策略:
安全(缓慢)
假设您正在使用Image<Bgr, Byte>
。
您可以通过调用
Bgr color = img[y, x];
设置第y行和第x列的像素也很简单
img[y,x] = color;
快捷方式
图像像素值存储在Data属性(3D数组)中。 好的,这是真的,但没有说明如何在真实场景中做到这一点。那么让我们看一些工作代码,然后讨论性能和优化:
Image<Bgr, Byte> original = newImage<Bgr, byte>(1024, 768);
Stopwatch evaluator = newStopwatch();
int repetitions = 20;
Bgr color = newBgr(100, 40, 243);
evaluator.Start();
for (int run = 0; run < repetitions; run++)
{
for (int j = 0; j < original.Cols; j++)
{
for (int i = 0; i < original.Rows; i++)
{
original[i, j] = color;
}
}
}
evaluator.Stop();
Console.WriteLine("Average execution time for {0} iteration \n using column per row access: {1}ms\n", repetitions, evaluator.ElapsedMilliseconds / repetitions);
所以这是使用安全慢速设置图像像素的20次运行后的平均运行时间 在我的机器上需要 1021ms ......
因此,循环的平均时间为1021毫秒,设置的像素数等于1024 * 768。我们可以通过逐行循环来做得更好
因此,让我们重构一下我们的代码,让我们使用更快的方式直接使用Image.Data属性:
evaluator.Reset();
evaluator.Start();
for (int run = 0; run < repetitions; run++)
{
for (int i = 0; i < original.Rows; i++)
{
for (int j = 0; j < original.Cols; j++)
{
original.Data[i, j, 0] = 100;
original.Data[i, j, 1] = 40;
original.Data[i, j, 2] = 243;
}
}
}
evaluator.Stop();
Console.WriteLine("Average execution time for {0} iterations \n using Data property: {1}ms\n", repetitions, evaluator.ElapsedMilliseconds / repetitions);
在我的机器上需要 519ms 。 所以我们的性能提升了50%。执行时间减少了两倍。
仔细查看代码,记住我们正在使用C#,我们可以做一个小改动,这将大大提高我们的图像像素设置性能...... 我们不应该在循环中使用c#属性! !! 强>
evaluator.Reset();
evaluator.Start();
byte[,,] data = original.Data;
for (int run = repetitions - 1; run >= 0; run--)
{
for (int i = original.Rows - 1; i >= 0; i--)
{
for (int j = original.Cols - 1; j >= 0; j--)
{
data[i, j, 0] = 100;
data[i, j, 1] = 40;
data[i, j, 2] = 243;
}
}
}
evaluator.Stop();
使用这一最新代码,由于正确使用C#语言,您将获得巨大的性能提升(73ms)。
答案 1 :(得分:0)
我想用一种进一步的解决方案来补充@Luce Del Tongo和@ Dent7777的详尽答案,以便使用emgucv对图像数据进行按值运算。尽管我的测试(相同的方法)仅显示与上述最终解决方案相同的性能;我相信这是一个有价值的选择。
Image.Convert()方法具有许多强大的重载,可用于在调用图像上对每个值应用委托函数每个值,以返回相同或不同TDepth的结果图像。有关详情,请参见http://www.emgu.com/wiki/index.php/Working_with_Images上的“常规操作” 。
最重要的是能够将最多三张其他图像作为参数传递给Convert方法,其包含的数据将传递给委托。
例如,一个复杂的过滤器:
// From the input image "original"
Image<Bgr, Byte> original = new Image<Bgr, byte>(1024, 768);
// I wish to produce an image "result"
Image<Gray, double> result = new Image<Gray, double>(1024, 768);
// Whereby each "result" pixel is
Bgr originalPixel;
double resultPixel =
(0.5 + Math.Log(originalPixel.Green) -
(0.5 * Math.Log(originalPixel.Red)) -
(0.5 * Math.Log(originalPixel.Blue)));
要使用上一个答案中提供的解决方案:
byte[,,] sourceData = original.Data;
double[,,] resultData = result.Data;
for (int i = original.Rows - 1; i >= 0; i--)
{
for (int j = original.Cols - 1; j >= 0; j--)
{
resultData[i,j,0] =
(0.5 + Math.Log(sourceData[i, j, 1]) -
(0.5 * Math.Log(sourceData[i, j, 2])) -
(0.5 * Math.Log(sourceData[i, j, 0])));
}
}
我的计算机上的平均时间:(676毫秒)
或者,我可以在原始文件的蓝色通道上调用Convert,将其他两个通道作为参数传递,并带有相应签名的委托方法来执行计算:
result =
original[0].Convert<byte, byte, double>(
original[1],
original[2],
Compute);
位置:
private double Compute(byte B, byte G, byte R)
{
return (0.5 + Math.Log(G) - (0.5 * Math.Log(R)) - (0.5 * Math.Log(B)));
}
我的计算机上的平均时间:(674毫秒)
也许只是个人喜好,但我希望这可能对某人有价值。