opencv之基于距离变换与分水岭的图像分割

相关知识
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
相关程序

#include "stdafx.h"

//本节讲述 图像处理之 图像分割:Image Segmentaion;
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace std;
using namespace cv;

void contours_Callback(int, void*);
Mat src, test1, test2, dst, gray_src, temp;
char input_title[] = "原图";
char output_title[] = "结果图";
void tiaojie(int, void*);


int value = 50;
int max_value = 255;

int main(int argc, char**argv)
{
	//src = imread("C:/Users/Rubison.DELL/Desktop\\杂物/壁纸/热气球2.png");    //待检测图 
	src = imread("C:/Users/Rubison.DELL/Desktop\\杂物/壁纸/扑克牌.jpg");
	if (src.empty())
	{
		printf("could not load image...\r\n");
		return -1;
	}

	namedWindow(input_title, CV_WINDOW_AUTOSIZE);
	imshow(input_title, src);

	for (int x = 0; x < src.rows; x++)                      //将白色背景变为黑色,为后续变换做准备       1)
	{              //本例程中的扑克牌不是纯白(255,255,255),因此不会变黑
		for (int y = 0; y < src.cols; y++)
		{
			if (src.at<Vec3b>(x, y) == Vec3b(255, 255, 255)) 
			{
				src.at<Vec3b>(x, y)[0] = 0;
				src.at<Vec3b>(x, y)[1] = 0;
				src.at<Vec3b>(x, y)[2] = 0;
			}
		}
	}
	// Show output image
	imshow("黑色背景图", src);
	// Create a kernel that we will use for accuting/sharpening our image
	Mat kernel = (Mat_<float>(3, 3) <<                               //实现图像对比度提高--锐化sharp      2)
		1, 1, 1,
		1, -8, 1,
		1, 1, 1); // an approximation of second derivative, a quite strong kernel
					// do the laplacian filtering as it is
					// well, we need to convert everything in something more deeper then CV_8U
					// because the kernel has some negative values,
					// and we can expect in general to have a Laplacian image with negative values
					// BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
					// so the possible negative number will be truncated
	Mat imgLaplacian;
	Mat sharp = src;           //复制原图
	//imshow("另一复制",sharp);  
	filter2D(sharp, imgLaplacian, CV_32F, kernel,Point(-1,-1),0,BORDER_CONSTANT);
	src.convertTo(sharp, CV_32F);
	//imshow("类型转换32F", sharp);
	//imshow("拉普拉斯卷积图", imgLaplacian);
    Mat imgResult = sharp - imgLaplacian;

	//imshow("差值锐化图", imgResult);   //注意 在类型没有转化成CV_8UC3时,扑克牌上的方块时空心的
	// convert back to 8bits gray scale      
	imgResult.convertTo(imgResult, CV_8UC3);
	imgLaplacian.convertTo(imgLaplacian, CV_8UC3);
    imshow( "Laplace Filtered Image", imgLaplacian );
	imshow("New Sharped Image", imgResult);
	                                                       //将sharp后的图像二值化然后进行距离变换       3)
	//src = imgResult; // copy back
	// Create binary image from source image
	Mat binaryImage;
	cvtColor(imgResult, binaryImage, CV_BGR2GRAY);
	threshold(binaryImage, binaryImage, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
	imshow("二值图", binaryImage);
	// Perform the distance transform algorithm
	Mat dist;
	distanceTransform(binaryImage, dist, CV_DIST_L2, 3);
	// Normalize the distance image for range = {0.0, 1.0}
	// so we can visualize and threshold it 
	normalize(dist, dist, 0, 1, NORM_MINMAX);
	imshow("Distance Transform Image", dist);               // Threshold to obtain the peaks
	threshold(dist, dist, 0.4, 1, CV_THRESH_BINARY);       // This will be the markers for the foreground objects
	imshow("阈值化", dist);

	// Dilate a bit the dist image
	Mat kernel1 = Mat::ones(7, 7, CV_8UC1);
	//dilate(dist, dist, kernel1);
	erode(dist,dist,kernel1);                    //   腐蚀
	imshow("erode", dist);        // Create the CV_8U version of the distance image
	                              // It is needed for findContours()               标记                   4)
	Mat dist_8u;                                      
	dist.convertTo(dist_8u, CV_8U); 
	                                 // Find total markers
	vector<vector<Point> > contours;
	findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
	// Create the marker image for the watershed algorithm
	Mat markers = Mat::zeros(dist.size(), CV_32SC1);                     //创建mark图片
	// Draw the foreground markers
	for (size_t i = 0; i < contours.size(); i++)
	{
		drawContours(markers, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i)+1), -1);
	}
	// Draw the background marker
	circle(markers, Point(5, 5), 3, Scalar(255, 255, 255), -1);    // -1表示填充
	imshow("Markers", markers * 1000);             //乘1000是因为灰度级别很低

	// Perform the watershed algorithm                     
	watershed(src, markers);                            //                     分水岭变换                5)
	Mat mark = Mat::zeros(markers.size(), CV_8UC1);
	markers.convertTo(mark, CV_8UC1);
	bitwise_not(mark, mark);     //   取反
	imshow("分水岭", mark); // uncomment this if you want to see how the mark 
	// image looks like at that point
	// Generate random colors             //到上一步已经结束,但为了将分水岭后的图片填充颜色,提高辨识度
	vector<Vec3b> colors;
	for (size_t i = 0; i < contours.size(); i++)
	{
		int b = theRNG().uniform(0, 255);
		int g = theRNG().uniform(0, 255);
		int r = theRNG().uniform(0, 255);
		colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
	}
	// Create the result image
	Mat dst = Mat::zeros(markers.size(), CV_8UC3);
	// Fill labeled objects with random colors
	for (int i = 0; i < markers.rows; i++)
	{
		for (int j = 0; j < markers.cols; j++)
		{
			int index = markers.at<int>(i, j);
			if (index > 0 && index <= static_cast<int>(contours.size()))
				dst.at<Vec3b>(i, j) = colors[index - 1];
			else
				dst.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
		}
	}
	// Visualize the final image
	imshow("Final Result", dst);


	waitKey(0);
	destroyAllWindows();
	return 0;

}

运行结果:
在这里插入图片描述

备注
1.OpenCV距离变换函数介绍distanceTransform()
2.opencv中的Circle函之线宽类型为负则代表填充
3.OpenCV库中watershed函数(分水岭算法)的详细使用例程分水岭算法
watershed自动图像分割用法分水岭算法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

w5875895

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

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

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

打赏作者

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

抵扣说明:

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

余额充值