基于距离变换与分水岭的图像分割 (一)

什么是图像分割

image segmentation 直观含义就是将图像从背景中分离开

图像分割是图像处理最重要的处理手段之一

图像分割的目标是将图像中的像素根据一定的规则分为若干个cluster几何,每个集合包含一类像素

根据算法分为监督学习方法和无监督学习方法,图像分割的算法多数都是无监督的学习方法(K-Means)

 

距离变换分水岭介绍

距离变换常见算法有两种

一种是不断膨胀/腐蚀得到

另一种是倒角距离

 

将图像灰度值看作山峰,按照高度进行区域划分就是分水岭算法

常见的分水岭算法是基于浸泡理论实现的

 

API

距离变换API

cv::distanceTransform(InputArray src,OutputArray dst,OutputArray labels,int distanceType,int maskSize,int labelType=DIST_LABEL_CCOMP)

distancdType=DIST_L1/DIST_L2

maskSize=3x3最新的可以5x5,推荐3,3

labels离散维诺图输出

dst输出8位或者32位浮点数,大小与输入图像一致

 

分水岭API

cv::watershed(InputArray image,InputOutputArray markers)

markers就是标线

 

处理流程

1.将白色背景变为黑色,为后续变换做准备

2.使用filter2D与拉普拉斯算子实现图像对比度提高,sharp

3.转为二值图像通过threshold

4.距离变换

5.对距离变换得到的结果进行归一化,[0,1]之间

6.使用阈值,再次二值化,得到标记

7.腐蚀得到每个Peak-erode

8.发现轮廓-findContours

9.绘制轮廓-drawContours

10.分水岭变换watershed

11.对每个分割区域进行着色输出结果

 

Demo

#include"pch.h"
#include<iostream>
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
    Mat src,gray;
    src = imread("water.jpg");
    imshow("input img", src);
    //cvtColor(src, gray, COLOR_BGR2GRAY);
    //反转背景
    for(int row=0;row<src.rows;++row)
        for (int col = 0; col < src.cols; ++col)
        {
            if (src.at<Vec3b>(row, col) == Vec3b(255, 255, 255))
            {
                src.at<Vec3b>(row, col)[0] = 0;
                src.at<Vec3b>(row, col)[1] = 0;
                src.at<Vec3b>(row, col)[2] = 0;
            }
        }
    imshow("black background", src);


    //锐化
    Mat imgLaplance;
    Mat sharp = src;
    src.convertTo(sharp, CV_32F);
    Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
    filter2D(src, imgLaplance, CV_32F, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
    Mat resultImg = sharp - imgLaplance;

    resultImg.convertTo(resultImg, CV_8UC3);
    imgLaplance.convertTo(imgLaplance, CV_8UC3);
    imshow("sharp", resultImg);


    //二值距离变换
    Mat binaryImg;
    cvtColor(resultImg, resultImg, COLOR_BGR2GRAY);
    threshold(resultImg, binaryImg, 40, 255, THRESH_BINARY | THRESH_OTSU);
    imshow("binary", binaryImg);

    //距离变换
    Mat dstImg;
    distanceTransform(binaryImg, dstImg, DIST_L1, 3, 5);
    normalize(dstImg, dstImg, 0, 1, NORM_MINMAX);
    imshow("dist img", dstImg);
    threshold(dstImg, dstImg, 0.4, 1, THRESH_BINARY);
    imshow("threshold", dstImg);

    //二值腐蚀
    Mat Kernel1 = Mat::ones(13, 13, CV_8UC1);
    erode(dstImg, dstImg, Kernel1, Point(-1, -1));
    imshow("erode", dstImg);
    waitKey();
    return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-08-05 22:30  Wangtn  阅读(1468)  评论(0编辑  收藏  举报