筛选最大连通域

本文介绍了一种使用OpenCV进行图像处理的方法,通过cv::connectedComponents找到图像中的最大连通域。首先读取图像并进行边缘检测,然后通过连接组件找出轮廓,过滤掉面积过小或宽高比不满足条件的轮廓。最后,提取并显示最大连通域,并将其保存到文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <opencv2/opencv.hpp>  

#include <opencv2/highgui/highgui.hpp>  

#include <opencv2/ml/ml.hpp>  
#include <io.h>
#include <direct.h>
#include<Windows.h>
using namespace std;
using namespace cv;
/*采用cvFindContours提取轮廓,并过滤掉小面积轮廓,最后将轮廓保存*/
RNG rng;
static int getContoursByCplus(string Imgname, double minarea, double whRatio)

{

    cv::Mat src, dst, canny_output;

    /// Load source image and convert it to gray

    src = imread(Imgname, 0);
    if (!src.data)

    {
        std::cout << "read data error!" << std::endl;

        return -1;
    }

    blur(src, src, Size(3, 3));
    //the pram. for findContours,

    vector<vector<Point> > contours;

    vector<Vec4i> hierarchy;

    /// Detect edges using canny

    Canny(src, canny_output, 80, 255, 3);

    /// Find contours

    findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    //CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE
    double maxarea = 0;

    int maxAreaIdx = 0;

    for (int i = 0; i < contours.size(); i++)

    {
        double tmparea = fabs(contourArea(contours[i]));

        if (tmparea > maxarea)

        {
            maxarea = tmparea;

            maxAreaIdx = i;

            continue;

        }

        if (tmparea < minarea&&tmparea>20000)
        {

            //删除面积小于设定值的轮廓

            contours.erase(contours.begin() + i);

            std::wcout << "delete a small area" << std::endl;

            continue;
        }

        //计算轮廓的直径宽高

        Rect aRect = boundingRect(contours[i]);
        

        if ((aRect.width / aRect.height) < whRatio)

        {
            //删除宽高比例小于设定值的轮廓

            contours.erase(contours.begin() + i);

            std::wcout << "delete a unnomalRatio area" << std::endl;

            continue;

        }
        Mat hsv, mask;
        Mat roi = src(aRect);
        Mat person=roi.clone();
        imshow("hsv", roi);
        drawContours(person,contours[i],i,Scalar(255),0);

function connected_bw = connectbw(bw) cc = bwconncomp(bw); props = regionprops(cc, ‘BoundingBox’, ‘PixelList’); connected_bw = bw; % 右端 左端 rightmost_points = []; leftmost_points = []; for i = 1:length(props) rightmost = max(props(i).PixelList(:,1)); right_y = props(i).PixelList(props(i).PixelList(:,1) == rightmost, 2); leftmost = min(props(i).PixelList(:,1)); left_y = props(i).PixelList(props(i).PixelList(:,1) == leftmost, 2); rightmost_points = [rightmost_points; rightmost, mean(right_y)]; leftmost_points = [leftmost_points; leftmost, mean(left_y)]; end % 初始化 connected = false(1, length(props)); current_idx = 1; connected(current_idx) = true; % 循环遍历 while sum(connected) < length(props) right_point = rightmost_points(current_idx, :); min_dist = Inf; % 小距离 next_idx = -1; for i = 1:length(props) if ~connected(i) % 只考虑未连接的连通域 left_point = leftmost_points(i, :); dist = sqrt((right_point(1) - left_point(1))^2 + (right_point(2) - left_point(2))^2); if dist < min_dist % 找到更近的连通域 min_dist = dist; next_idx = i; end end end if next_idx ~= -1 right_point = rightmost_points(current_idx, :); left_point = leftmost_points(next_idx, :); x_coords = [right_point(1), left_point(1)]; y_coords = [right_point(2), left_point(2)]; % 插值连接 line_points = round([linspace(x_coords(1), x_coords(2), 200)', ... linspace(y_coords(1), y_coords(2), 200)']); for k = 1:size(line_points, 1) connected_bw(line_points(k,2), line_points(k,1)) = 1; end % 已连接标志 connected(next_idx) = true; % 更新连通域索引 current_idx = next_idx; end end 如何修改代码,只对大的五个连通域进行操作,使其能够从大连开始,优先连接左右距离近的连通域近的点,这个连通域可以是图中的任意一个连通域,不限于被操作的5个大连,也可能是图中的其他未被操作的连通域,只要这个连通域距离第一大连的一侧近,如果第二大连距离第一大连一侧近,则也连接第二大连,然后由于第二大连一侧已被连接,则在第一大连连完左右两侧后,再由第二大连开始,又因为第二大连的一侧可能会被上一步的第一大连连接,所以先判断第二大连两侧是否被连接,如果一侧已被第一大连连接,则只需要再寻找另一侧距离第二大连连通域近的点,直到两侧都被连接,再进行第三大连的连接,依此类推,确保这些被操作的连通域左右两端都被连接,提供完整的修改后的代码
03-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值