- 一、Mat.type()函数
- 二、简单了解connectedComponentsWithStats函数
- 三、问题代码
- 第四行代码异常报错如下:
- 命令行窗口报错如下:
- 四、原因分析
- 五、解决方案
- 六、完整代码
- 七、部分引用
- 八、笔者想说的话
一、Mat.type()函数首先我们简单了解下Mat类型type()函数与connectedComponentsWithStats函数
命名规则为CV_(位数)+(数据类型)+(通道数)
U:代表unsigned int无符号整形
S:代表signed int有符号整形
F:代表float单精度浮点型
C(number of channels):代表一张图片的通道数
函数返回值与Mat类型对应如下:
| C1 | C2 | C3 | C4 | |
|---|---|---|---|---|
| CV_8U | 0 | 8 | 16 | 24 |
| CV_8S | 1 | 9 | 17 | 25 |
| CV_16U | 2 | 10 | 18 | 26 |
| CV_16S | 3 | 11 | 19 | 27 |
| CV_32S | 4 | 12 | 20 | 28 |
| CV_32F | 5 | 13 | 21 | 29 |
| CV_64F | 6 | 14 | 22 | 30 |
二、简单了解connectedComponentsWithStats函数
int connectedComponentsWithStats(InputArray image, OutputArray labels,
OutputArray stats, OutputArray centroids,int connectivity = 8, int
ltype = CV_32S);
前四个参数均为Mat类型,第一个参数为输入已有图片,第二三四参数为执行函数后有关图片的输出结果。以下为简易说明:
1.注意!第一参数image需输入一个二值化图片,且格式为CV_8UC1(可能只是单通道图片,有待考证)
2.输出labels是CV_32SC1类型的标签图,不同的连通域被赋该连通域的标签的值。
3.stats包含了标签为i的连通域的一些信息,可以如下访问标签为i的连通域的面积
stats.at(i, CC_STAT_AREA) //标签为i的连通域的面积
4.连通域的个数有两种得到方式
(1) 该函数返回值
(2) int labelNum = Imgcentriods.rows;
三、问题代码
Mat image;
image = imread("二值化图片.bmp");
Mat labels, stats, centriods;
int labelNum = connectedComponentsWithStats(image, labels, Imgstats, centriods, 8);
第四行代码异常报错如下:
0x00007FFC77EB4F69 处(位于 testcv.exe 中)有未经处理的异常: Microsoft C++ 异常: cv::Exception,位于内存位置 0x00000063B13FD840 处。
OpenCV(4.5.5) Error: Assertion failed (L.channels() == 1 &&
I.channels() == 1) in cv::connectedComponents_sub1, file C:buildmaster_winpack-build-win64-vc15opencvmodulesimgprocsrcconnectedcomponents.cpp, line 5623
四、原因分析
传递给该函数的图像image.type()是16,即image的Mat类型是CV_8UC3(三通道)。而该函数第一个参数应该是CV_8UC1的Mat类型(单通道)。
五、解决方案
修改image图片格式为CV_8UC1,因为image本身是二值化后三通道文件,所以BGR三者的值相等,要么为(ff,ff,ff)16,要么为(00,00,00)16.。修改为单通道图片只需(i,j)像素点的值取原图该点BGR其一的值即可。
代码如下:
Mat image;
image = imread("二值.bmp");
Mat img8bit = Mat::zeros(Size(image.cols, image.rows), CV_8UC1);//初始化CV_8UC1的Mat图片,初始值为0(黑色)
for (int i = 0; i < image.rows; i++)
{
uchar* data = image.ptr(i);
for (int j = 0; j < img.cols * 3; j = j + 3)
{
img8bit.at(i, j / 3) = data[j];
}
}
六、完整代码
#include#include using namespace cv; using namespace std; int main() { Mat image; image = imread("二值.bmp"); //cout << "image二值化文件类型值:" << image.type() << endl; Mat img8bit = Mat::zeros(Size(image.cols, image.rows), CV_8UC1); for (int i = 0; i < image.rows; i++) { uchar* data = image.ptr (i); for (int j = 0; j < image.cols * 3; j = j + 3) { img8bit.at (i, j / 3) = data[j]; } } //cout << "img8bit文件类型值:" << img8bit.type() << endl; Mat labels, stats, centriods; int labelNum = connectedComponentsWithStats(img8bit, labels, stats, centriods, 8); waitKey(0); return 0; }
两则cout执行结果:
image二值化文件类型值:16 img8bit文件类型值:0
对应:
image格式:CV_8UC3
img8bit格式:CV_8UC1
八、笔者想说的话https://blog.csdn.net/weixin_51326570/article/details/113932128
https://blog.csdn.net/qq_40119386/article/details/89085075
https://stackoverflow.com/questions/41257336/opencv-error-assertion-failed-l-channels-1-i-channels-1-in-conne
以上为笔者在学习opencv过程中总结所感,希望对大家有所帮助!(第一次发csdn有、、小激动,要是点个赞就更好了



