opencv::分水岭图像分割
分水岭分割方法原理 (3种)
- 基于浸泡理论的分水岭分割方法 (距离)
- 基于连通图的方法
- 基于距离变换的方法 图像形态学操作:
- 腐蚀与膨胀
- 开闭操作 分水岭算法运用
- 分割粘连对象,实现形态学操作与对象计数
- 图像分割


#include <opencv2/opencv.hpp>
#include <iostream> using namespace cv;
using namespace std; int main(int argc, char** argv) {
Mat src = imread("D:/images/coins_001.jpg");
if (src.empty()) {
printf("could not load image...\n");
return -;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src); Mat gray, binary, shifted;
pyrMeanShiftFiltering(src, shifted, , );
//imshow("shifted", shifted); //灰度
cvtColor(shifted, gray, COLOR_BGR2GRAY);
threshold(gray, binary, , , THRESH_BINARY | THRESH_OTSU);
//imshow("binary", binary); // 距离变换
Mat dist;
distanceTransform(binary, dist, DistanceTypes::DIST_L2, , CV_32F);
normalize(dist, dist, , , NORM_MINMAX);
//imshow("distance result", dist); // 二值化
threshold(dist, dist, 0.4, , THRESH_BINARY);
//imshow("distance binary", dist); // markers
Mat dist_m;
dist.convertTo(dist_m, CV_8U);
vector<vector<Point>> contours;
findContours(dist_m, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(, )); // create markers
Mat markers = Mat::zeros(src.size(), CV_32SC1);
for (size_t t = ; t < contours.size(); t++) {
drawContours(markers, contours, static_cast<int>(t), Scalar::all(static_cast<int>(t) + ), -);
}
circle(markers, Point(, ), , Scalar(), -);
//imshow("markers", markers*10000); // 形态学操作 - 彩色图像,目的是去掉干扰,让结果更好
Mat k = getStructuringElement(MORPH_RECT, Size(, ), Point(-, -));
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 = ; i < contours.size(); i++) {
int r = theRNG().uniform(, );
int g = theRNG().uniform(, );
int b = theRNG().uniform(, );
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
} // 颜色填充与最终显示
Mat dst = Mat::zeros(markers.size(), CV_8UC3);
int index = ;
for (int row = ; row < markers.rows; row++) {
for (int col = ; col < markers.cols; col++) {
index = markers.at<int>(row, col);
if (index > && index <= contours.size()) {
dst.at<Vec3b>(row, col) = colors[index - ];
}
else {
dst.at<Vec3b>(row, col) = Vec3b(, , );
}
}
} imshow("Final Result", dst);
printf("number of objects : %d\n", contours.size()); waitKey();
return ;
}

#include <opencv2/opencv.hpp>
#include <iostream> using namespace cv;
using namespace std; Mat watershedCluster(Mat &image, int &numSegments);
void createDisplaySegments(Mat &segments, int numSegments, Mat &image);
int main(int argc, char** argv) {
Mat src = imread("D:/images/cvtest.png");
if (src.empty()) {
printf("could not load image...\n");
return -;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src); int numSegments;
Mat markers = watershedCluster(src, numSegments);
createDisplaySegments(markers, numSegments, src);
waitKey();
return ;
} Mat watershedCluster(Mat &image, int &numComp) {
// 二值化
Mat gray, binary;
cvtColor(image, gray, COLOR_BGR2GRAY);
//阈值
threshold(gray, binary, , , THRESH_BINARY | THRESH_OTSU);
// 形态学与距离变换
Mat k = getStructuringElement(MORPH_RECT, Size(, ), Point(-, -));
morphologyEx(binary, binary, MORPH_OPEN, k, Point(-, -));
Mat dist;
distanceTransform(binary, dist, DistanceTypes::DIST_L2, , CV_32F);
normalize(dist, dist, 0.0, 1.0, NORM_MINMAX); // 开始生成标记
threshold(dist, dist, 0.1, 1.0, THRESH_BINARY);
normalize(dist, dist, , , NORM_MINMAX);
dist.convertTo(dist, CV_8UC1); // 标记开始
vector<vector<Point>> contours;
vector<Vec4i> hireachy;
findContours(dist, contours, hireachy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
if (contours.empty()) {
return Mat();
} Mat markers(dist.size(), CV_32S);
markers = Scalar::all();
for (int i = ; i < contours.size(); i++) {
drawContours(markers, contours, i, Scalar(i + ), -, , hireachy, INT_MAX);
}
//填充
circle(markers, Point(, ), , Scalar(), -); // 分水岭变换
watershed(image, markers);
numComp = contours.size();
return markers;
} void createDisplaySegments(Mat &markers, int numSegments, Mat &image) {
// generate random color
vector<Vec3b> colors;
for (size_t i = ; i < numSegments; i++) {
int r = theRNG().uniform(, );
int g = theRNG().uniform(, );
int b = theRNG().uniform(, );
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
} // 颜色填充与最终显示
Mat dst = Mat::zeros(markers.size(), CV_8UC3);
int index = ;
for (int row = ; row < markers.rows; row++) {
for (int col = ; col < markers.cols; col++) {
index = markers.at<int>(row, col);
if (index > && index <= numSegments) {
dst.at<Vec3b>(row, col) = colors[index - ];
}
else {
dst.at<Vec3b>(row, col) = Vec3b(, , );
}
}
}
imshow("分水岭图像分割-演示", dst);
return;
}
opencv::分水岭图像分割的更多相关文章
- Opencv分水岭算法——watershed自动图像分割用法
分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭算法的一个重要特 ...
- OpenCV 1 图像分割--分水岭算法代码
// watershed_test20140801.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" // // ch9_watershed ...
- opencv分水岭算法对图像进行切割
先看效果 说明 使用分水岭算法对图像进行切割,设置一个标记图像能达到比較好的效果,还能防止过度切割. 1.这里首先对阈值化的二值图像进行腐蚀,去掉小的白色区域,得到图像的前景区域.并对前景区域用255 ...
- OpenCV 之 图像分割 (一)
1 基于阈值 1.1 基本原理 灰度阈值化,是最简单也是速度最快的一种图像分割方法,广泛应用在硬件图像处理领域 (例如,基于 FPGA 的实时图像处理). 假设输入图像为 f,输出图像为 g,则经 ...
- Opencv 分水岭分割图片
#include <iostream>#include <opencv2/opencv.hpp> using namespace std;using namespace cv; ...
- opencv::KMeans图像分割
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...
- opencv 金字塔图像分割
我所知的opencv中分割函数:watershed(只是看看效果,不能返回每类pixel类属),cvsegmentImage,cvPyrSegmentation(返回pixel类属) 金字塔分割原理篇 ...
- OpenCV——分水岭算法
分水岭算法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形 ...
- opencv kmeans 图像分割
利用kmeans算法,将彩色图像的像素点作为样本,rgb值作为样本的属性, 对图像所有的像素点进行分类,从而实现对图像中目标的分割. c++代码(openCV 2.4.11) Scalar color ...
随机推荐
- MD5 加密工具类MD5Util
我们在使用MD5 在线加密的时候,会发现下面情况,大小写的区别就不说啦,那么16位和32位有啥区别呢,其实16 位实际上是从 32 位字符串中,取中间的第 9 位到第 24 位的部分,就是str.su ...
- Android 蓝牙开发(3)——蓝牙的详细介绍
前面的两篇文章,主要是在 Android 官网关于蓝牙介绍的基础上加上自己的理解完成的.主要针对的是 Android 开发中的一些 API 的使用. 第一篇文章 Android 蓝牙开发(1) 主要是 ...
- 【转】HTTPS建立连接的过程
原文链接:https://www.cnblogs.com/shiqi17/p/9756880.html https://www.jianshu.com/p/bd75ab32ae57 HTTP建立连接的 ...
- PHP常用数字函数以及排序函数
一:数字函数 .ceil() 进一取整 示例:ceil(0.9) 结果为1 .abs() 绝对值 示例:abs(-1) 结果为1 .rand() 随机数 示例:rand(1. 100) 1到100 以 ...
- LSTM容易混淆的地方
1 如果只是学习怎么用LSTM,那么可以这么理解LSTM LSTM可以看成一个仓库,而这个仓库有三个门卫,他们的功能分别是 遗忘门.决定什么样的物品需要从仓库中丢弃. 输入门.决定输入的什么物品用来存 ...
- backbone 路由传参(可选)
因为维护公司的老项目而接触到backbone.以前是只闻其名,未见其码. 因为其他项目需要跳转到本项目的某个页面,但是需要UI改变. 考虑的方法是给路由添加一个可选参数.代码如下: 正常路由: rou ...
- iOS应用卡顿分析
1.屏幕显示图像的原理 显示器按照从上到下的方式,一行行扫描,扫描完成后显示器就呈现一帧画面,随后电子枪回到初始位置继续下一次扫描.为了把显示器的显示过程和系统的视频控制器进行同步,显示器(或者其他硬 ...
- ubuntu / zsh shell / oh-my-zsh / 常用插件
记录一下 zsh 的下载与配置,省得每次重装系统都要上网到处查. 安装 zsh shell sudo apt install zsh 切换 shell chsh -s /bin/zsh 安装 oh-m ...
- php中in_array函数的坑
由于PHP是弱类型语言,所以有自动类型转换 例子 $array = [0, 1, 2, '3']; var_dump(in_array('abc', $array)); //true var_dump ...
- ICP&TPS:最近邻
经过了一段时间的研bai究gei...终于可以偷得几天闲了. 这里来补个档. 无论是ICP还是TPS,缺乏锚点的前提下.你总是要通过找另一个曲面的最近的点来实现你的work beimat:点数*3,f ...