matlab分水岭分割算法不用内置函数_图像分割实战-分水岭分割方法和GrabCut 算法

1. 分水岭分割方法

它是依赖于形态学的,图像的灰度等级不一样,如果图像的灰度等级一样的情况下怎么人为的把它造成不一样?可以通过距离变换实现,这样它们的灰度值就有了阶梯状的变换。风水岭算法常见的有三种方法:(1)基于浸泡理论的分水岭分割方法;(2)基于连通图方法;(3)基于距离变换的方法。OpenCV 中是基于距离变换的分割方法,就相当于我们的小山头(认为造成的)。

基本的步骤:

7bf9c79221dd1f2d5b82ed9235710240.png

例子1 粘连对象分离和计数。

例子代码:

#include#includeusing namespace std;using namespace cv;void test(){    Mat srcImg;    srcImg = imread("pill_002.png");    if (srcImg.empty())    {        cout <>contours;    //找到 marker 的轮廓    findContours(distMaskImg, contours, RETR_EXTERNAL,                 CHAIN_APPROX_SIMPLE, Point(0, 0));    //create marker 填充 marker    Mat  markersImg = Mat::zeros(srcImg.size(), CV_32SC1);    for (int i = 0; i (i),                     Scalar::all(static_cast(i)+1), -1);     }    circle(markersImg, Point(5, 5), 3, Scalar(255), -1);    //形态学操作 - 彩色图像,目的是去掉干扰,让结果更好。    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));    morphologyEx(srcImg, srcImg, MORPH_ERODE, kernel);    //完成分水岭变换    watershed(srcImg, markersImg);    Mat mark = Mat::zeros(markersImg.size(), CV_8UC1);    markersImg.convertTo(mark, CV_8UC1);    bitwise_not(mark, mark, Mat());    namedWindow("watershed", CV_WINDOW_AUTOSIZE);    imshow("watershed", mark);    //下面的步骤可以不做,最好做出来让结果显示更美观。    //生成随机颜色    vectorcolors;    for (int i = 0; i (i, j);            if (index > 0 && index <= contours.size())            {                dstImg.at(i, j) = colors[index - 1];            }            else            {                dstImg.at(i, j) = Vec3b(0, 0, 0);            }        }    }    cout <
53b595c6823d946099d883cbd6d0cabe.png

总结:有时候会导致碎片化,过度分割,因为二值化中如果有很多小的黑点或碎片,在分割的时候导致很多 mask ,即小山头太多了,这个时候我们要考虑怎么去合并它,可以通过联通区域的直方图,或者像素值均值相似程度等。

例子2:图像分割

#include#includeusing namespace std;using namespace cv;//执行分水岭算法函数Mat watershedCluster(Mat &srcImg, int &numSegments);//结果显示函数void DisplaySegments(Mat &markersImg, int numSegments);void test(){    Mat srcImg;    srcImg = imread("toux.jpg");    if (srcImg.empty())    {        cout <>contours;    vectorhireachy;    findContours(distImg, contours, hireachy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);    if (contours.empty())    {        return Mat();    }    Mat markersImg(distImg.size(), CV_32S);    markersImg = Scalar::all(0);    for (int i = 0; i colors;    for (int i = 0; i (i, j);            if (index > 0 && index <= numSegments)            {                dstImg.at(i, j) = colors[index - 1];            }            else            {                dstImg.at(i, j) = Vec3b(255, 255, 255);            }        }    }    cout <

效果图:

acd16b313fb1b997258f93b9c7063b81.png

2. GrabCut 算法分割图像

GrabCut 算法的原理前面有介绍过,这里就不在介绍了,具体可以看下文章末尾往期推荐中阅读。下面例子实现图像中对象的抠图。

基本步骤:

3929cc252aa94166ccbab16ef4ab36fe.png

例子代码:

#include#includeusing namespace std;using namespace cv;int numRun = 0; //算法迭代次数bool init = false;Rect rect;Mat srcImg, MaskImg, bgModel, fgModel;//鼠标回调函数void onMouse(int event, int x, int y, int flags, void* param);void showImg();  //显示画的图片void setRoiMask();  //选择 ROI 的函数void runGrabCut();  //执行算法函数static void ShowHelpText();  //提示用户操作函数void test(){    srcImg = imread("toux.jpg");    if (srcImg.empty())    {        cout < 1 && rect.height > 1)        {            showImg();        }        break;    default:        break;    }}void showImg(){    Mat result, binMask;    binMask.create(MaskImg.size(), CV_8UC1);    binMask = MaskImg & 1;    if (init)    {        srcImg.copyTo(result,binMask);    }    else    {        srcImg.copyTo(result);    }    rectangle(result, rect, Scalar(0, 0, 255), 2, 8);    namedWindow("Original image", CV_WINDOW_AUTOSIZE);    imshow("Original image", result);}void setRoiMask(){    //GC_BGD = 0   明确属于背景的像素    //GC_FGD = 1   明确属于前景的像素    //GC_PR_BGD = 2  可能属于背景的像素    //GC_PR_FGD = 3  可能属于前景的像素    MaskImg.setTo(GC_BGD);      //为了避免选择越界    rect.x = max(0, rect.x);    rect.y = max(0, rect.y);    rect.width = min(rect.width, srcImg.cols - rect.x);    rect.height = min(rect.height, srcImg.rows - rect.y);    //把我们选取的那一块设为前景    MaskImg(rect).setTo(Scalar(GC_PR_FGD));}void runGrabCut(){    if (rect.width 

效果图:

d9535a7ebfc47ccd6fdbba003b16eeda.png
665bbb1079d04b75956b2c6ef4705dd5
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值