zoukankan      html  css  js  c++  java
  • 基于距离变换与分水岭的图像分割 (一)

    什么是图像分割

    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;
    }

     

     

     

     

     

     

  • 相关阅读:
    django xadmin 集成DjangoUeditor富文本编辑器
    docker学习笔记
    02-创建 TLS CA证书及密钥
    01-集群环境及组件介绍
    使用Filebeat和Logstash集中归档日志
    FastDFS分布式存储实战
    [转]JVM内存模型
    jcmd
    jstack Dump 日志文件中的线程状态
    cpu占用过高排查
  • 原文地址:https://www.cnblogs.com/wangtianning1223/p/13443261.html
Copyright © 2011-2022 走看看