You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用OpenCV提取图像所有目标?解决目标粘连分割问题

解决OpenCV粘连目标提取问题

我需要用OpenCV提取图像中的所有目标,当前代码在目标相互分离的图像上运行正常,但当目标彼此靠近粘连时,无法将它们分开,这影响了后续处理。

正常示例:
正常示例

异常示例:
异常示例

我知道正常示例也存在一些小问题,但并不关键。以下是我正在使用的代码:

int main(int argc, char** argv)
{
    cv::CommandLineParser parser(
        argc, argv, "{@input | | input image}");
    cv::Mat src =
        cv::imread(cv::samples::findFile(parser.get<cv::String>("@input")),
                   cv::IMREAD_UNCHANGED);
    if (src.empty())
    {
        std::cout << "Could not open or find the image!\n" << std::endl;
        std::cout << "usage: " << argv[0] << " <Input image>" << std::endl;
        return -1;
    }

    cv::Mat gray;
    cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);

    cv::Mat filtred;
    cv::bilateralFilter(gray, filtred, 11, 17, 17);

    cv::Mat canny;
    cv::Canny(filtred, canny, 40., 120.);
    cv::imshow("canny", canny);
    cv::waitKey(0);

    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2));
    cv::Mat closed;
    cv::morphologyEx(canny, closed, cv::MORPH_CLOSE, kernel);

    cv::imshow("morph", closed);

    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(closed, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);

    cv::Mat with_contours;
    src.copyTo(with_contours);

    for (int i = 0; i < contours.size(); i++)
        if (cv::contourArea(contours[i]) > 100.)
        {
            cv::Rect rect = cv::boundingRect(contours[i]);
            cv::rectangle(with_contours,
                          rect,
                          cv::Scalar(0, 255, 0),
                          2);
        }

    imshow("contours", with_contours);
}

实用改进方案

1. 距离变换+分水岭算法(针对类圆形粘连目标)

如果你的目标是类圆形,这个方法能精准分离粘连区域:

  • 先通过二值化得到前景/背景分割图
  • 距离变换计算每个前景像素到最近背景的距离,距离越大越接近目标中心
  • 阈值提取目标中心作为种子,再用分水岭算法分割粘连目标

代码示例:

// 替换原有的轮廓检测流程
cv::Mat binary;
// Otsu自动阈值二值化,适配不同亮度的图像
cv::threshold(gray, binary, 0, 255, cv::THRESH_BINARY_INV + cv::THRESH_OTSU);

// 距离变换
cv::Mat dist;
cv::distanceTransform(binary, dist, cv::DIST_L2, 5);
cv::normalize(dist, dist, 0, 1.0, cv::NORM_MINMAX);

// 提取种子点(目标中心区域)
cv::Mat seeds;
cv::threshold(dist, seeds, 0.5, 255, cv::THRESH_BINARY);
seeds.convertTo(seeds, CV_8U);

// 标记种子连通域
std::vector<std::vector<cv::Point>> seedContours;
cv::findContours(seeds, seedContours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

cv::Mat markers = cv::Mat::zeros(binary.size(), CV_32S);
for (int i = 0; i < seedContours.size(); i++) {
    cv::drawContours(markers, seedContours, i, cv::Scalar(i+1), -1);
}

// 执行分水岭分割
cv::watershed(src, markers);

// 可视化结果
cv::Mat result = src.clone();
for (int i = 1; i <= seedContours.size(); i++) {
    cv::Mat mask = (markers == i);
    // 用随机颜色标记不同目标
    result.setTo(cv::Scalar(rand()%255, rand()%255, rand()%255), mask);
}
cv::imshow("分割结果", result);
cv::waitKey(0);

2. 替换形态学操作:用腐蚀代替闭运算

原代码的闭运算(膨胀+腐蚀)会让粘连目标更紧密,改成腐蚀可以先断开粘连:

// 替换原有的morphologyEx代码
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2));
cv::Mat eroded;
cv::erode(canny, eroded, kernel); // 腐蚀断开粘连
cv::imshow("腐蚀后", eroded);

注意:腐蚀核的大小需要根据粘连程度调整,过大可能会把小目标腐蚀掉。

3. 调整Canny边缘检测参数

原代码的Canny阈值(40,120)可能让边缘过度连接,尝试降低高阈值或拉大阈值差:

cv::Canny(filtred, canny, 30., 90.); // 调整后的阈值,边缘更细致

4. 凸缺陷分割(针对有凹陷的粘连目标)

如果粘连处有明显凹陷,可以通过凸缺陷找到分割点:

// 针对单个粘连轮廓的分割示例
for (auto& cnt : contours) {
    if (cv::contourArea(cnt) < 100) continue;

    std::vector<cv::Point> hull;
    cv::convexHull(cnt, hull);

    std::vector<cv::Vec4i> defects;
    cv::convexityDefects(cnt, cv::convexHull(cnt, false), defects);

    // 筛选深度足够的凸缺陷(深度>阈值,比如10)
    for (auto& d : defects) {
        float depth = d[3] / 256.0;
        if (depth > 10) {
            int startIdx = d[0];
            int endIdx = d[1];
            // 用start和end点分割轮廓(具体分割逻辑需根据目标形状调整)
            cv::line(with_contours, cnt[startIdx], cnt[endIdx], cv::Scalar(0,0,255), 2);
        }
    }
}

代码小修正

原代码中std::vector<contour>是笔误,应该改为std::vector<std::vector<cv::Point>>;另外最后需要加cv::waitKey(0);否则程序会直接退出,看不到结果。

内容的提问来源于stack exchange,提问作者SabakaSamson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:57:35