【opencv】示例-connected_components.cpp 连通组件检测

dbed73fadf2418fd42eab6bcff063167.png

4a6b33528b1435732151b2f158bb1561.png

#include <opencv2/core/utility.hpp> // 包含OpenCV核心功能相关的头文件
#include "opencv2/imgproc.hpp" // 包含OpenCV图像处理相关的头文件
#include "opencv2/imgcodecs.hpp" // 包含OpenCV图像编码解码相关的头文件
#include "opencv2/highgui.hpp" // 包含OpenCV的GUI相关的头文件
#include <iostream> // 包含标准输入输出流相关的头文件


using namespace cv; // 使用cv命名空间,简化代码中OpenCV函数的书写
using namespace std; // 使用std命名空间


Mat img; // 声明一个Mat类型的变量img用来存储图像数据
int threshval = 100; // 定义一个阈值变量并初始化为100


// 声明回调函数on_trackbar用于滑动条的回调
static void on_trackbar(int, void*)
{
    // 根据阈值将图像进行二值化处理
    Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);
    // 声明并初始化连通组件标记图
    Mat labelImage(img.size(), CV_32S);
    // 调用connectedComponents函数计算连通组件并返回组件数量
    int nLabels = connectedComponents(bw, labelImage, 8);
    // 定义颜色向量数组,用于存储每个连通组件的颜色
    std::vector<Vec3b> colors(nLabels);
    // 第一个组件(背景)颜色设为黑色
    colors[0] = Vec3b(0, 0, 0);
    // 为每个连通组件生成随机颜色
    for(int label = 1; label < nLabels; ++label){
        colors[label] = Vec3b( (rand()&255), (rand()&255), (rand()&255) );
    }
    // 声明存储最终结果的彩色图像
    Mat dst(img.size(), CV_8UC3);
    // 遍历每个像素,将连通组件对应的颜色填充到dst图像中
    for (int r = 0; r < dst.rows; ++r) { // 使用for循环遍历每一行
        for (int c = 0; c < dst.cols; ++c) { // 内层for循环遍历每一列
            int label = labelImage.at<int>(r, c); // 获取当前像素位置的标签值
            Vec3b& pixel = dst.at<Vec3b>(r, c); // 获取待赋值的目标图像的当前像素位置的引用
            pixel = colors[label]; // 将对应标签的颜色赋给当前像素位置
        }
    }
    // 显示连通组件的结果图像
    imshow( "Connected Components", dst );
}


// 主函数
int main( int argc, const char** argv )
{
    // 解析命令行参数
    CommandLineParser parser(argc, argv, "{@image|stuff.jpg|image for converting to a grayscale}");
    // 打印程序相关信息
    parser.about("\nThis program demonstrates connected components and use of the trackbar\n");
    parser.printMessage();
    // 输出相关提示信息
    cout << "\nThe image is converted to grayscale and displayed, another image has a trackbar\n"
            "that controls thresholding and thereby the extracted contours which are drawn in color\n";
    
    // 获取输入的图像文件名
    String inputImage = parser.get<string>(0);
    // 读取图像文件为灰度图
    img = imread(samples::findFile(inputImage), IMREAD_GRAYSCALE);
    
    // 检查图像是否读取成功
    if(img.empty())
    {
        cout << "Could not read input image file: " << inputImage << endl;
        // 图像读取失败,返回退出码
        return EXIT_FAILURE;
    }


    // 显示原始图片窗口
    imshow( "Image", img );


    // 创建一个新的窗口用于显示连通组件处理的结果
    namedWindow( "Connected Components", WINDOW_AUTOSIZE);
    // 创建滑动条并关联到on_trackbar回调函数
    createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar );
    // 初始调用滑动条的回调函数进行处理
    on_trackbar(threshval, 0);


    // 等待用户按键
    waitKey(0);
    // 正常退出程序
    return EXIT_SUCCESS;
}

此段代码展示了如何使用OpenCV库进行连通组件检测,并将结果显示在带有滑动条的窗口中,用户可以通过滑动条调整阈值,以改变连通组件检测的结果。代码分别包括了图像的读取、窗口的创建、滑动条的创建及其回调函数的编写,并在窗口中展示原始图像和连通组件的结果。使用Trackbar(滑动条)可以动态地控制图像的二值化阈值,进而观察到不同阈值下连通组件的变化。

Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);

6f3487e74f9ad6e4743cb16acb28f4d2.png

1db75f941fcdd2439cc270c8406305bf.png

int nLabels = connectedComponents(bw, labelImage, 8);

da35ae41e62c0c438e33a3535e588038.png

The End

<think> 我们正在解决的是在Python中使用OpenCV 4.11.0时调用连通组件分析函数出现的错误: 错误信息:OpenCV(4.11.0) ... error: (-215:Assertion failed) L.channels() == 1 && I.channels() == 1 in function 'cv::connectedComponents_sub1' 这个错误的原因是:函数`cv.connectedComponents`要求输入的图像必须是单通道(即灰度图),但实际传入的图像可能是多通道图像(例如BGR三通道图像)。 在Python中,我们通常使用OpenCV的`cv2`模块。以下是解决步骤: 1. **确保输入图像是单通道**: - 如果图像是彩色的,需要先转换为灰度图。 - 使用`cv2.cvtColor`函数,参数为`cv2.COLOR_BGR2GRAY`(如果是从`cv2.imread`读取的默认BGR格式)或`cv2.COLOR_RGB2GRAY`(如果是其他RGB格式)。 2. **验证图像通道数**: - 可以通过`image.ndim`查看维度,如果是2,则是单通道;如果是3,则是多通道。 - 或者使用`image.shape`,如果是单通道,则形状为`(height, width)`;如果是三通道,则为`(height, width, 3)`。 3. **连通组件分析函数调用**: - 正确用法:`retval, labels = cv2.connectedComponents(binary_image)` - 注意:`binary_image`必须是二值图像(单通道,且通常为0和255)或者至少是单通道的8位图像。 4. **完整示例代码**: ```python import cv2 # 读取图像,使用IMREAD_GRAYSCALE直接读为灰度图(单通道) image = cv2.imread('input_image.png', cv2.IMREAD_GRAYSCALE) # 如果图像不是单通道,则转换 # 例如,如果以彩色方式读取,则: # image = cv2.imread('input_image.png') # gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 检查图像是否成功读取 if image is None: print("Could not open or find the image") exit() # 二值化处理(如果需要) # 注意:连通组件分析通常用于二值图像,但也可以用于非二值图像(此时会以0为背景,非0为前景) # 这里使用Otsu二值化 _, binary = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 连通组件分析 num_labels, labels = cv2.connectedComponents(binary) # 显示结果(注意:labels是整数矩阵,需要转换为8U才能显示) labels_show = cv2.convertScaleAbs(labels, alpha=(255.0/labels.max()) if labels.max()>0 else 1) cv2.imshow('Connected Components', labels_show) cv2.waitKey(0) cv2.destroyAllWindows() ``` 5. **注意事项**: - 如果图像已经是单通道,则无需转换。 - 如果图像是二值化的,确保其数据类型是`np.uint8`(8位无符号整数)。 - 连通组件分析的输入图像可以是二值图像,也可以是灰度图像,但必须是单通道。 6. **错误情况分析**: - 如果使用彩色图像(3通道)直接调用`cv2.connectedComponents`,就会触发上述错误。 - 如果使用4通道(带透明通道)的图像,同样会出错。 如果按照上述步骤操作,应该可以解决该错误。 --- ### 相关问题 1. OpenCV中如何将多通道图像转换为单通道图像? 2. 连通组件分析的结果如何可视化? 3. 除了`cv2.connectedComponents`,OpenCV还有哪些连通组件分析函数? 4. 如何获取连通组件的统计信息(如面积、质心等)? [^1]: OpenCV官方文档中关于`cv2.connectedComponents`的说明 [^2]: OpenCV图像处理教程示例 </think> ### Python OpenCV 4.11.0 `cv::connectedComponents_sub1` 报错解决方案 在 Python 中使用 OpenCV 4.11.0 时出现 `(-215:Assertion failed) L.channels() == 1 && I.channels() == 1` 错误,原因是 **输入图像不符合单通道要求**。以下是详细解决方法: #### 核心解决步骤 1. **检查图像通道数** 在处理前确认图像是单通道: ```python import cv2 image = cv2.imread('input.jpg') print(f"图像通道数: {image.shape[2] if len(image.shape) > 2 else 1}") # 输出应为 1 ``` 2. **转换为单通道灰度图** 使用 `cv2.COLOR_BGR2GRAY` 转换多通道图像: ```python # 方法1:读入时直接转为灰度 gray = cv2.imread('input.jpg', cv2.IMREAD_GRAYSCALE) # 方法2:转换现有彩色图像 if len(image.shape) > 2: gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ``` 3. **二值化处理(必需步骤)** 连通组件算法需要二值输入: ```python _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) ``` 4. **正确调用连通组件函数** 使用单通道二值图像作为输入: ```python num_labels, labels = cv2.connectedComponents(binary) # 不再报错 ``` #### 完整代码示例 ```python import cv2 import numpy as np # 读取图像并确保单通道 src = cv2.imread('input.jpg', cv2.IMREAD_GRAYSCALE) # 关键步骤 if src is None: print("错误:无法读取图像") exit() # 二值化处理 _, binary = cv2.threshold(src, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 连通组件分析 num_labels, labels = cv2.connectedComponents(binary) # 正确调用 print(f"找到 {num_labels} 个连通区域") # 可视化结果(可选) output = cv2.applyColorMap( np.uint8(255 * labels / num_labels), cv2.COLORMAP_JET ) cv2.imshow('Result', output) cv2.waitKey(0) ``` #### 错误原因详解 该断言失败的根本原因是函数要求输入矩阵 $L$ (标签图) 和 $I$ (输入图) 必须满足: $$ \text{channels}(L) = 1 \quad \land \quad \text{channels}(I) = 1 $$ 在 OpenCV 4.11.0 中强化了通道数验证机制: 1. 连通组件算法基于像素邻接关系计算,多通道数据会导致距离计算错误 2. 函数内部会检查 `image.type() == CV_8UC1` 3. 彩色图像(如 BGR 三通道或 RGBA 四通道)直接传入会触发断言[^1] #### 进阶调试技巧 ```python # 检查图像类型 assert binary.dtype == np.uint8, "需为8位无符号整数类型" assert binary.ndim == 2, "需为二维单通道矩阵" # 安全封装函数 def safe_connected_components(img): if img.ndim != 2: img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) return cv2.connectedComponents(binary) ``` #### 注意事项 1. 视频流处理时需对每帧转换通道格式(参考引用[1]) 2. 多通道图像算术操作前需统一通道数(参考引用[2]) 3. 可使用 `cv2.COLOR_RGBA2GRAY` 处理含 Alpha 通道的图像 --- ### 相关问题 1. 如何获取连通组件的统计信息(面积、质心等)? 2. OpenCV 中 `connectedComponentsWithStats` 和 `connectedComponents` 有什么区别? 3. 如何处理带有噪声的二值图像以提高连通组件分析准确性? 4. 在视频流处理中如何优化连通组件分析性能? [^1]: OpenCV 官方文档 - 连通组件分析要求 [^2]: OpenCV 4.11.0 图像处理模块源码解析
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值