4

我想计算只有黑白的背景图像中白点的数量。我有这样的代码:

int count = 0; 
for ( int j = 0; j < Image.rows; j ++ )
    {
    for ( int i = 0; i < Image.cols; i ++ )
        {
            if ( Image.at<int>(i,j) >= 150 )
            {
                count ++ ;
            }
        }
    }

由于某种原因,上面的代码不起作用,它只是停止反应。我检查了一下,“if (Image.at(i,j) >= 150)”这行导致了问题。我的“图像”是“cv::Mat”,类型为“CV_8UC3”。有人可以帮助我吗?谢谢你。

4

6 回答 6

11

除了我对罗宾回答的评论之外,您的错误是您尝试将 CV_8UC3 类型的图像作为整数访问。如果你想检查灰度,做这样的事情(注意“unsigned char”而不是“int”,如罗宾的回答)。

cv::Mat greyscale;
cv::cvtColor(image,grayscale,CV_RGB2GRAY);
// either, most elegant:
int count = cv::countNonZero(greyscale >= 150);
// or, copied from Robin's answer:
int count = 0;
for(int i = 0; i < greyscale.rows; ++i) {
    const unsigned char* row = greyscale.ptr<unsigned char>(i);
    for(int j = 0; j < greyscale.cols; j++) {
        if (row[j] >= 150)
            ++count;
    }
}
于 2012-08-22T11:10:00.310 回答
5

我相信这更整洁:

Mat result;
threshold(Image,result,150,255,THRESH_BINARY);
int white_count = countNonZero(result);
于 2012-08-22T10:50:01.227 回答
3

如果您使用 i 表示列,使用 j 表示行,Image.at<unsigned char>(j,i)则不要写。Image.at<unsigned char>(i,j)

于 2012-08-22T09:45:13.717 回答
2

我认为您必须访问列之前的行,这意味着您应该交换 i 和 j。
替换if ( Image.at<int>(i,j) >= 150 )if ( Image.at<int>(j,i) >= 150 )

不过,有更简单的方法可以访问 Mat。
OpenCV 提供了一个类似 STL 的迭代器,它易于使用,如果您想访问所有元素,则非常易于使用。例子:

int count = 0;
MatConstIterator_<int> it = Image.begin<int>(), it_end = Image.end<int>();
for(; it != it_end; ++it)
    if ((*it) >= 150)
        ++count;

最后但同样重要的是,您还可以获得指向每一行的指针并通过普通 [] 运算符访问数据:

int count = 0;
for(int i = 0; i < Image.rows; ++i) {
    const int* Ii = Image.ptr<int>(i);
    for(int j = 0; j < Image.cols; j++) {
        if (Ii[j] >= 150)
            ++count;
    }
}
于 2012-08-22T09:46:52.397 回答
1

您可以使用 opencv 字节向量(无符号字符像素)访问 CV_8UC3 像素!在这种情况下,您可以进行以下操作(现在您还可以使用一些特殊的颜色阈值)

int channel = 0;
Image.at<Vec3b>( row , col )[channel]
于 2012-08-22T11:47:01.087 回答
1

访问 cv::Mat 图像的方法有很多,如果要直接访问彩色图像(CV_8UC3),可以通过以下方式实现:

int count = 0;
int threshold = 150;
for(int j = 0; j < img.rows; j++) {
   for(int i = 0; i < img.cols; i++) {
      //white point which means that the point in every channel(BGR)
      //are all higher than threshold!
      if(img.ptr<cv::Vec3b>(j)[i][0] > threshold && 
         img.ptr<cv::Vec3b>(j)[i][1] > threshold 
         img.ptr<cv::Vec3b>(j)[i][2] > threshold ) {
             count++;
         }

    }
 }

但我建议如果您只想计算白点,您可以将图像转换为灰度(CV_8UC1),然后执行以下操作:

cv::Mat img;
cv::cvtColor(src,img,CV_BGR2RGB);
int count = 0;
int threshold = 150;
for(int j = 0; j < img.rows; j++) {
   for(int i = 0; i < img.cols; i++) {
      if(img.ptr<uchar>(j)[i] > threshold) {
            count++;
      }
   }
}

最后要注意的是,通过img.ptr< Imagetype >访问cv::Mat图像不会检查访问点是否正确,所以如果你肯定知道图像的范围,那么通过ptr访问图像就可以了,否则,你可以这样做通过img.at< Imagetype>(),它会在每次调用时检查每个点是否正确,为什么通过 ptr 访问图像更快 ,所以如果有无效的访问点,它会断言你!

于 2014-01-25T04:49:30.207 回答