countNonZero函数在openCV中出现断言错误

20

我尝试使用countNonZero()函数获取水平投影,如下所示。

Mat src = imread(INPUT_FILE, CV_LOAD_IMAGE_COLOR);
Mat binaryImage = src.clone();
cvtColor(src, src, CV_BGR2GRAY);

Mat horizontal = Mat::zeros(1,binaryImage.cols, CV_8UC1);

for (int i = 0; i<binaryImage.cols; i++)
{
    Mat roi = binaryImage(Rect(0, 0, 1, binaryImage.rows));

    horizontal.at<int>(0,i) = countNonZero(roi);
    cout << "Col no:" << i << " >>" << horizontal.at<int>(0, i);
}

但在调用countonZero()函数的那一行出现了错误。错误如下。

    OpenCV Error: Assertion failed (src.channels() == 1 && func != 0) in cv::countNo
    nZero, file C:\builds\2_4_PackSlave-win32-vc12-shared\opencv\modules\core\src\st
    at.cpp, line 549

有人能指出错误吗?


4
binaryImage是src的副本,src是一个3通道彩色图像。尝试使用cvtColor(src, binaryImage, CV_BGR2GRAY)将其转换为灰度图像。 - Micka
2
还有一个错误:将switch horizontal.at<int>(0,i)更改为horizontal.at<unsigned char>(0,i),因为您创建了8位数据类型。 - Micka
我已经进行了更改,错误已经解决。谢谢你。但是现在我发现countNonZero(roi)函数返回的值始终为零。我还确认了binaryImage不是完全黑色的图像。(它在任何地方都有黑色和白色像素) - Samitha Chathuranga
@Mika 我刚刚打印了countNonZero(roi)的值,代码如下:for (int i = 0; i < binaryImage.cols; i++) { Mat roi = binaryImage(Rect(0, 0, 1, binaryImage.rows)); cout << "\t列号:" << i << "=" << countNonZero(roi); } - Samitha Chathuranga
1
你的输入矩阵的第一列是否完全为零?在每次迭代中,您都会读取相同的列!尝试使用Mat roi = binaryImage(Rect(i, 0, 1, binaryImage.rows)); - Micka
显示剩余4条评论
3个回答

26

Assertion src.channels() == 1 表示该图像应该只有1个通道,即它必须为灰度图像,而不是彩色图像。你正在对roi调用countNonZero,它是binaryImage的子图像,而binaryImagesrc的克隆,最初是彩色的。

我想你想写的是cvtColor(binaryImage,binaryImage,CV_BGR2GRAY)。在这种情况下是有意义的。然而,我没有看到你再次使用src,因此也许你不需要这个中间图像。如果确实需要,请不要称之为“binary”,因为在计算机视觉中,“binary”通常表示黑白图像,仅有两种颜色。你的图像是“gray”,因为它具有所有黑色和白色的阴影。

关于你的原始任务,Miki是正确的,你应该使用cv::reduce来完成。他已经给了你一个如何使用它的例子。


谢谢你的回答。除了上述需要改变的事情之外,我还需要修改Mat roi = binaryImage(Rect(0, 0, 1, binaryImage.rows));为Mat roi = binaryImage(Rect(i, 0, 1, binaryImage.rows));我只是在迭代同一列。 - Samitha Chathuranga

0

顺便提一下,你可以使用reduce计算水平投影,将CV_REDUCE_SUM作为参数传入即可。

以下是一个最简示例:

Mat1b mat(4, 4, uchar(0));
mat(0,0) = uchar(1);
mat(0,1) = uchar(1);
mat(1,1) = uchar(1);

// mat is: 
//
// 1100
// 0100
// 0000
// 0000

// Horizontal projection, result would be a column matrix
Mat1i reducedHor;
cv::reduce(mat, reducedHor, 1, CV_REDUCE_SUM);

// reducedHor is:
//
// 2
// 1
// 0
// 0

// Vertical projection, result would be a row matrix
Mat1i reducedVer;
cv::reduce(mat, reducedVer, 0, CV_REDUCE_SUM);

// reducedVer is:
//
// 1200


// Summary
//
// 1100 > 2
// 0100 > 1
// 0000 > 0
// 0000 > 0
// 
// vvvv
// 1200

您可以像这样使用它来处理您的图像:

// RGB image
Mat3b img = imread("path_to_image");

// Gray image, contains values in [0,255]
Mat1b gray;
cvtColor(img, gray, CV_BGR2GRAY);

// Binary image, contains only 0,1 values
// The sum of pixel values will equal the count of non-zero pixels
Mat1b binary;
threshold(gray, binary, 1, 1, THRESH_BINARY);

// Horizontal projection
Mat1i reducedHor;
cv::reduce(binary, reducedHor, 1, CV_REDUCE_SUM);

// Vertical projection
Mat1i reducedVer;
cv::reduce(binary, reducedVer, 0, CV_REDUCE_SUM);

你能否详细说明一下你的答案?reduce是什么?它是一个函数吗?如果是,如何使用它来实现目的? - Samitha Chathuranga
抱歉,这仍然没有任何意义。至少您甚至没有使用黑白图像来获取其水平投影。 - Samitha Chathuranga
@SamithaChathuranga 我更新了我的回答,希望它对你更有意义。 - Miki
这似乎更容易,尽管这不是我的方法。我会很快检查并回复结果。谢谢Miki。 - Samitha Chathuranga

0

将图像转换为灰度,然后执行countNonZero()函数,它会起作用。

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
area = cv.countNonZero(gray)

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