什么是圖像分割
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; }