使用emgu cv迭代图像的像素

时间:2011-02-24 08:14:34

标签: c# image loops

我想迭代图像的所有像素并与搜索模式进行比较。具有最佳性能并且在C#中。我找到了emgu cv,它是Intels opencv的包装器。但我不知道如何正确使用emgu。有人知道我怎么做吗?图像的数据属性是什么?这是imagedata吗?如果是,哪个值是什么?感谢

更新

我用C#编写了我的函数,但效果很好,但速度太慢了!我已经在c中使用了algorhytm,我将其翻译成C#。 C#比c慢3到4倍! (我的函数几乎遍历图像的每个像素以寻找图像中的形状。 - > Hugh Transformation)

好吧,我听说不安全的代码可能会更快,因为它不会检查数组边界和内容。真的吗?直接在物理机器上运行不安全的代码?

无论如何,我试图将不安全的代码放入我的函数中。但我无法获得指向我的3D数组的指针或使用指针访问3D数组。如何用不安全的代码重写上面的代码?这会带来额外的性能提升,甚至可以像c代码一样快速运行吗?

2 个答案:

答案 0 :(得分:48)

正如emgu网站所述,主要有两种策略:

安全(缓慢)

假设您正在使用Image<Bgr, Byte>。 您可以通过调用

获取第y行和第x列的像素
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毫秒)

也许只是个人喜好,但我希望这可能对某人有价值。