OpenCV:读取矩阵值

时间:2012-08-22 09:29:36

标签: c++ opencv matrix background-image pixel

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

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)&gt; = 150)”这一行导致了问题。我的“图像”是“cv :: Mat”,带有“CV_8UC3”类型。有人可以帮助我吗?谢谢。

6 个答案:

答案 0 :(得分:11)

除了我对Robin的答案的评论之外,您的错误是您尝试以int为单位访问CV_8UC3类型的图像。如果你想检查灰度级别,可以这样做(注意“unsigned char”而不是“int”,如Robin的答案)。

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

答案 1 :(得分:5)

我相信这更整洁:

Mat result;
threshold(Image,result,150,255,THRESH_BINARY);
int white_count = countNonZero(result);

答案 2 :(得分:3)

如果您将i用于cols而j用于行,则将Image.at<unsigned char>(j,i)写为Image.at<unsigned char>(i,j)

答案 3 :(得分: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;

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

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

答案 4 :(得分:1)

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

int channel = 0;
Image.at<Vec3b>( row , col )[channel]

答案 5 :(得分: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&lt;访问cv :: Mat图像Imagetype&gt; 不会检查访问点是否正确,因此如果您确定知道图像的范围,则通过ptr访问图像会很好,否则,您可以通过 img来完成。在&LT; Imagetype&gt;(),它会在每次调用时检查每个点是否正确,why access image by ptr is faster 所以如果有无效的访问点,它会断言你!