【问题标题】:Iterate over pixels of an image with emgu cv使用 emgu cv 迭代图像的像素
【发布时间】:2011-07-03 09:15:36
【问题描述】:

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

更新:

我用 C# 编写了我的函数,它运行良好,但是太慢了!我已经有一个用 c 语言翻译成 C# 的算法。 C# 比 c 慢 3 到 4 倍! (我的函数几乎遍历图像的每个像素以寻找图像中的形状。-> Hugh 变换)

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

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

【问题讨论】:

    标签: c# image loops


    【解决方案1】:

    我想用另一种解决方案来补充@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])));
        }
    }
    

    我机器上的平均时间:(676ms)

    或者,我可以在原始的蓝色通道上调用转换,将其他两个通道作为参数传递,以及相应签名的委托方法来执行我的计算:

    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)));
    }
    

    我机器上的平均时间:(674ms)

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

    【讨论】:

      【解决方案2】:

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

      安全(慢)方式

      假设您正在处理Image&lt;Bgr, Byte&gt;。 您可以通过调用获取第y行第x列的像素

      Bgr color = img[y, x];
      

      在第y行第x列设置像素也很简单

      img[y,x] = color;
      

      快捷方式

      图像像素值存储在 3D 数组的 Data 属性中。 好的,这是真的,但没有说明如何在真实场景中做到这一点。所以让我们看一些工作代码,然后讨论性能和优化:

      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...

      因此,循环和设置像素数等于 1024*768 的平均时间为 1021 毫秒。我们可以通过逐行循环来做得更好

      所以让我们稍微重构一下我们的代码,让我们使用更快的方式直接使用 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)

      【讨论】:

      • 非常感谢您的详细回答!我不知道那个规则,不要在循环中使用属性。另一个问题:这是什么意思:“不安全的数据属性”。以什么方式不安全?有什么风险?
      • 使用数据属性没有什么不安全的。开发人员在指定正确的索引以获取或设置正确的值时需要更多注意,因为 Data 属性是一个 3 维数组
      • 如果你能分享最后一个需要多长时间(不使用属性),我将不胜感激
      • @Ali Veli:我编辑答案并添加最后一个示例需要多长时间
      • 你为什么要翻转范围?即在第一个 sn-p 中,您从 [0 到 rows] 进行迭代,然后从 [row to 0] 进行迭代
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-24
      • 2012-04-02
      • 2017-12-10
      • 2015-03-08
      • 2016-08-11
      • 2015-07-19
      相关资源
      最近更新 更多