图像分割系列6_基于距离变换的分水岭粘连对象分离与计数

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 计数结果:

                       

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亦我飞也

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值