OpenCV图像分割资料分享:贾志刚的OpenCV图像分割实战视频教程全套资料(包含配套视频、配套PPT的PDF文件、源码和用到的图片素材等)
分水岭分割方法概述
图像形态学操作:
腐蚀与膨胀
开闭操作
分水岭分割方法原理:
- 基于浸泡理论的分水岭分割方法
- 基于连通图的方法
- 基于距离变换的方法
分水岭算法的运用:
分割粘连对象,实现形态学操作与对象计数
图像分割
基于距离的分水岭分割流程:
API说明:
OpenCV3.x中
distanceTransform
watershed
实例6:基于距离变换的分水岭粘连对象分离与计数
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src = imread("pill_002.png");//pill_002.png coins_001.jpg
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
Mat gray, binary, shifted;
//边缘保留(空间、颜色差值<21、51) 减少差异化
pyrMeanShiftFiltering(src, shifted, 21, 51);
imshow("shifted", shifted);
cvtColor(shifted, gray, COLOR_BGR2GRAY);//转换为灰度图像
//灰度图像进行二值化
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);
// distance transform 距离变化
Mat dist;
distanceTransform(binary, dist, DistanceTypes::DIST_L2, 3, CV_32F);//使用3*3进行
normalize(dist, dist, 0, 1, NORM_MINMAX);
imshow("distance result", dist);
// binary
threshold(dist, dist, 0.4, 1, THRESH_BINARY);
imshow("distance binary", dist);
// markers 找到山峰的旗子
Mat dist_m;
dist.convertTo(dist_m, CV_8U);
vector<vector<Point>> contours;
//寻找轮廓contours
findContours(dist_m, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
// create markers 填充轮廓
Mat markers = Mat::zeros(src.size(), CV_32SC1);
for (size_t t = 0; t < contours.size(); t++) {
drawContours(markers, contours, static_cast<int>(t), Scalar::all(static_cast<int>(t) + 1), -1);
}
//左上角显示一个圆(可有可无)
circle(markers, Point(5, 5), 3, Scalar(255), -1);
//markers放大10000倍进行显示
imshow("markers", markers*10000);
// 形态学操作 - 彩色图像也可以,目的是去掉干扰,让结果更好
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(src, src, MORPH_ERODE, k);
// 完成分水岭变换
watershed(src, markers);
Mat mark = Mat::zeros(markers.size(), CV_8UC1);
markers.convertTo(mark, CV_8UC1);
bitwise_not(mark, mark, Mat());
//imshow("watershed result", mark);//中间是白色线进行分割
// generate random color 生成随机颜色
vector<Vec3b> colors;
for (size_t i = 0; i < contours.size(); i++) {
int r = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int b = theRNG().uniform(0, 255);
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
// 颜色填充与最终显示
Mat dst = Mat::zeros(markers.size(), CV_8UC3);
int index = 0;
for (int row = 0; row < markers.rows; row++) {
for (int col = 0; col < markers.cols; col++) {
index = markers.at<int>(row, col);
if (index > 0 && index <= contours.size()) {
dst.at<Vec3b>(row, col) = colors[index - 1];
} else {
dst.at<Vec3b>(row, col) = Vec3b(0, 0, 0);
}
}
}
imshow("Final Result", dst);
printf("number of objects : %d\n", contours.size());
waitKey(0);
return 0;
}
1 输入图像: 2 进行边缘保留的shifted转换:
3 灰度和二值化: 4 距离变换:
5 距离变换后进行二值化: 6 寻找种子,生产Marker:
7 分水岭变换并填充: 8 计数结果: