基于距离变换和分水岭的图像分割

第一步:读取图片

Mat img = imread("../img/cards.png", CV_LOAD_IMAGE_COLOR);
if(img.empty())
    return -1;
namedWindow( "input", CV_WINDOW_AUTOSIZE );
imshow("input", img);

所读取的图片如下:
基于距离变换和分水岭的图像分割_第1张图片
第二步:将图片的白色的背景变为黑色的背景

for(int i = 0; i < img.rows; i++){
        for(int j = 0; j < img.cols; j++){
            if(img.at(i,j) == Vec3b(255,255,255)){
                img.at(i,j)[0] = 0;
                img.at(i,j)[1] = 0;
                img.at(i,j)[2] = 0;
            }
        }
    }

结果如下:
基于距离变换和分水岭的图像分割_第2张图片第四步:为了使图像的边界更加清晰,使用filter2d和拉普拉斯算子来得到图像的边界

    Mat filter2d_img;
    Mat kernel = (Mat_(3,3) << 1,1,1,1,-8,1,1,1,1);
    filter2D(img,filter2d_img,CV_32F,kernel);
    filter2d_img.convertTo(filter2d_img,CV_8UC3);
    imshow("filter2d_img",filter2d_img);

filter2d_img图片如下:
基于距离变换和分水岭的图像分割_第3张图片
第五步:将源图像减去filter_2d的图像可以得到边界更加清晰的图像

    Mat result_img;
    result_img = img  - filter2d_img;
    imshow("result_img",result_img);

基于距离变换和分水岭的图像分割_第4张图片第六步:将图像转换为二值化图像
首先将图像转化为灰度图像,然后对图像使用自适应阈值变为二值化图像

    Mat gray;
    cvtColor(result_img,gray,CV_BGR2GRAY);
    imshow("gray",gray);
//    我们使用自适应阈值,将图片变为黑白图像
    Mat binary_img;
    threshold(gray,binary_img,0,255,THRESH_BINARY | THRESH_OTSU);
    imshow("binary",binary_img);

二值化图像的结果:
基于距离变换和分水岭的图像分割_第5张图片第七步:确定背景区域
对图片进行膨胀,膨胀会消除黑色的噪音。膨胀后仍为黑色的区域,即为背景区域。

//确定图像的背景区域
    Mat sure_bg;
    Mat kernel1 = getStructuringElement(MORPH_RECT,Size(9,9),Point(-1,-1));
    dilate(binary_img,sure_bg,kernel1,Point(-1,-1),3);
    sure_bg.convertTo(sure_bg,CV_8UC1);
    imwrite("sure_bg.jpg",sure_bg);

背景区域的图片如下所示:
基于距离变换和分水岭的图像分割_第6张图片第八步:确定前景区域
首先对二值图像进行距离变换,距离大于0.4的均认为是前景图像

//确定前景区域
    Mat sure_fg;
    //距离变换:计算源像素的每个像素到最近的零像素的距离
    Mat dist_img;
    distanceTransform(binary_img,dist_img,DIST_L1,3,5);
    //我们将距离变换的图像进行归一化
    normalize(dist_img,dist_img,0,1,NORM_MINMAX);
    //距离大于0.4的皆为前景
    threshold(dist_img,sure_fg,0.4,1,THRESH_BINARY);
    normalize(sure_fg,sure_fg,0,255,NORM_MINMAX);
    sure_fg.convertTo(sure_fg,CV_8UC1);
    imwrite("sure_fg.jpg",sure_fg);

前景区域的图片如下
基于距离变换和分水岭的图像分割_第7张图片
第九步:背景区域减去前景区域,即我们不确定的区域,该区域中包含了图像分割的边界点

    Mat unknown;
    unknown = sure_bg-sure_fg;
    imwrite("unknown.jpg",unknown);

基于距离变换和分水岭的图像分割_第8张图片第十步:我们对这些区域进行标记,其中不确定区域标记为0,背景区域标记为1。前景区域借助于connectedComponents函数进行标记,该函数会将前景区域从1开始进行标记
我们对前景区域从1开始标记

//前景对象标记是从1开始的整数
    Mat marker1;
    connectedComponents(sure_fg,marker1);

然后我们将标记的marker1每个值都加上1。相当于前景区域从2开始标记,除了前景区域的其他区域的值均为1。

    Mat markers = Mat::ones(marker1.size(),marker1.type());
    markers = marker1 +markers;
    markers.convertTo(markers,CV_8UC1);

我们将未知区域标记为0

//我们将图像中的未知区域标记为0
    for(int row = 0; row < unknown.rows; row++){
        for(int col = 0; col < unknown.cols; col++){
            uchar c = unknown.at(row,col);
            if(c == 255)
                markers.at(row,col) = 0;
        }
    }
    normalize(markers,markers,0,255,NORM_MINMAX);
    imwrite("markers.jpg",markers);

标记的图像如下所示:
基于距离变换和分水岭的图像分割_第9张图片第十一步:实施分水岭算法

 //实施分水岭算法,标签图像将会被修改便捷区域的标记为-1
    markers.convertTo(markers,CV_32SC1);
    watershed(img,markers);
    Mat mark = Mat::zeros(markers.size(),CV_8UC1);
    markers.convertTo(mark,CV_8UC1);
//    bitwise_not(mark,mark);
    imshow("water_img",mark);

实施分水岭算法之后mark结果如下所示:
基于距离变换和分水岭的图像分割_第10张图片最后一步:根据mark,对图片进行着色

    vector pixes;
    vector colors;
    RNG rng;
    Mat final_rst(mark.size(),CV_8UC3);
    for(int i = 0; i< markers.rows; i++){
        for(int j = 0;j< markers.cols;j++){
            uchar c = mark.at(i,j);
            bool target = false;
            for(int k = 0; k(i,j) = colors[k];
                    target = true;
                    break;
                }
            }
            if(target == false){
                pixes.push_back(c);
                int r = rng.uniform(0,255);
                int g = rng.uniform(0,255);
                int b = rng.uniform(0,255);
                Vec3b color = Vec3b((uchar)b,(uchar)g,(uchar)r);
                final_rst.at(i,j) = color;
                colors.push_back(color);
            }


        }
    }

着色结果如下:
基于距离变换和分水岭的图像分割_第11张图片

你可能感兴趣的:(opencv,分水岭,图像分割,距离变换)