基於距離變換與分水嶺的圖像分割 (一)


什么是圖像分割

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

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM