在OpenCV二值图像中高效地计算“白色”像素数量

11

我正在尝试计算OpenCV二进制图像中所有白色像素的数量。 我目前的代码如下:

  whitePixels = 0;
  for (int i = 0; i < height; ++i)
    for (int j = 0; j < width; ++j)
      if (binary.at<int>(i, j) != 0)
        ++whitePixels;

然而,通过使用gprof进行分析后,我发现这段代码非常缓慢,是程序中的一个重要瓶颈。

是否有一种方法可以更快地计算相同的值?


你尝试过改变高度和宽度吗?我的意思是先循环宽度,然后再循环高度?这可能会改善循环,具体取决于图像在内存中的布局。 - Yochai Timmer
2
你能直接访问图像数据而不是通过这个at()函数吗? - jrok
按照jrok的建议做可能会更快。我想知道这个常见问题解答条目是否相关。 - Brian
谢谢大家,我觉得直接访问数据是正确的方法。而且有种感觉告诉我改变循环的顺序会更快。我会试一试的。 - Bill Cheatham
2
在调试模式下,at()函数非常慢,尽管在发布模式下几乎与直接指针访问一样快。它包含一个CV_DbgAssert()来检查边界,这是一种懒惰的方法。 - Sam
很好的评论@vasile,我确实处于调试模式。很好知道。 - Bill Cheatham
4个回答

29

cv::CountNonZero。通常情况下,OpenCV实现的任务都经过了大量优化。


3
@karlphillip 你是指cv::countNonZero吗? - Josh Bleecher Snyder
完美,一个优化的内置函数。正是我在寻找的。 - Bill Cheatham
在答案中添加了当前文档链接(可以在将来进行更新,不像此评论)。 - handle

0

你可以使用并行计算。将图像分成N个部分,在不同的线程中运行代码,然后获取每个线程的结果,最后将这些结果相加以获得最终的结果。


1
如果正确实现,Bill的算法应该是内存绑定而不是CPU绑定。在普通台式电脑上,通常并行化对于内存绑定任务没有帮助。 - Brian

-2

实际上,binary.at<int>(i, j) 是一种较慢的访问方式!

这里有一个简单的代码,比你的访问速度更快。

for (int i = 0; i < height; ++i)
{
uchar * pixel = image.ptr<uchar>(i);
    for (int j = 0; j < width; ++j)
{
  if(pixel[j]!=0)
   {
      //do your job
   }
}
}

-2

在一行中的最后一个像素通常会跟随着下一行中的第一个像素(C 代码):

limit=width*height;
i=0;
while (i<limit)
{
  if (binary.at<int>(0,i) != 0) ++whitePixels;
  ++i;
}

或者将其实现为滑动指针,这将消除索引。 - Olof Forshell
同时测试[i]和[i+1]处的两个值,并将索引/指针加2。这样可以减少一半的循环次数。 - Olof Forshell
在使用isContinuous()方法之前,应该对矩阵进行连续性测试。如果矩阵不连续,这个方法就会失败。 - Jean-Philippe Jodoin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接