程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

OpenCV使用分水岭算法实现图像分割

balukai 2025-01-01 17:58:10 文章精选 9 ℃

1、概述

  案例:使用分水岭算法实现图像的分割实现

  API:

watershed(src,markers);
src:原图像
markers:目标markers,生成markers是通过findContours边沿查找+drawContours来实现的。ps:这一步非常重要,有了marker就可以使用分水岭算法了。

  实现步骤:

    1.输入图像

    2.灰度化

    3.二值化

    4.执行距离变换

    5.归一化

    6.二值化

    7.生成marker:通过findContours+drawContours来创建一个marker

    8.将7生成的marker放入分水岭函数:watershed

    9.给marker着色

    10.输出着色后的图像

  ps:此算法关键点在于生成marker。生成marker之后其实已经完成了算法,后面的着色只是为了让输出更加好看。

2、代码样例

Mat src = imread(filePath);//输入原图
    if(src.empty()){
        //
        qDebug()<<"图像为空";
        return;
    }
    //图像灰度化
    Mat gray;
    cvtColor(src,gray,COLOR_BGR2GRAY);
    //图像二值化
    Mat binary;
    threshold(gray,binary,0,255,THRESH_BINARY|cv::THRESH_OTSU);
    imshow("binary",binary);
    qDebug()<<"binary....";
    //执行距离变换
    Mat dist;
    distanceTransform(binary,dist,DistanceTypes::DIST_L2,3,CV_32F);
    qDebug()<<"distanceTransform....";
    normalize(dist,dist,0.0,1.0,NORM_MINMAX);//归一化0~1之间
    qDebug()<<"normalize....";
    //重新二值化预值
    threshold(dist,dist,0.1,1.0,THRESH_BINARY);
    qDebug()<<"threshold....";
    normalize(dist,dist,0,255,NORM_MINMAX);
    qDebug()<<"normalize....";
    dist.convertTo(dist,CV_8UC1);//
    qDebug()<<"convertTo....";

    //开始生成marker并绘制出来
    vector<vector<Point>> contours;
    vector<Vec4i> heri;
    findContours(dist,contours,RETR_CCOMP,CHAIN_APPROX_SIMPLE);
    qDebug()<<"findContours....";

    Mat marker = Mat::zeros(dist.size(),CV_32S);
    for(size_t i = 0;i<contours.size();i++){
        drawContours(marker,contours,i,Scalar(i+1),-1, 8, heri, INT_MAX);
    }
    qDebug()<<"drawContours...."<<contours.size();
    circle(marker, Point(5, 5), 3, Scalar(255), -1);
    watershed(src,marker);
    qDebug()<<"watershed....";
//    marker.convertTo(marker,CV_8UC1);//ps:此处需要注意(到这里实际上已经完成了算法)。一旦不转换就不能用imshow,一旦转换了后面的marker着色就会出现异常
//    imshow("marker",marker);
    qDebug()<<"imshow(marker,marker);....";
    //生成颜色数组
    vector<Vec3b> colors;
    for (size_t i = 0; i < contours.size(); i++) {
        int r = theRNG().uniform(0, 255);
        int g = theRNG().uniform(0, 255);
        int b = theRNG().uniform(0, 255);
        colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
    }

    //给marker着色
    Mat finalResult = Mat::zeros(dist.size(),CV_8UC3);//三通道彩色图像
    int index = 0;
    for(int row = 0;row<marker.rows;row++){
        for(int col = 0;col<marker.cols;col++){
            index = marker.at<int>(row,col);
            if(index>0&&index<=contours.size()){
                finalResult.at<Vec3b>(row,col)  = colors[index-1];
            }else{
                finalResult.at<Vec3b>(row,col) = Vec3b(255,255,255);
            }
        }
    }
    imshow("finalResult",finalResult);

3、图片演示

案例1:分割蚕茧

案例2:分割任意图像

QT开发交流君羊:714620761

最近发表
标签列表