欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

opencv 分水岭算法区域的分割和合并

程序员文章站 2022-05-16 11:23:01
...

使用直方图相似性合并相似区域

#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
using namespace cv;

Mat display(Mat& markers, int noOfSegment)
{
	vector<Vec3b> colorTab;
	for (int i = 0; i < noOfSegment; i++)
	{
		int b = theRNG().uniform(0, 255);
		int g = theRNG().uniform(0, 255);
		int r = theRNG().uniform(0, 255);
		colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
	}

	Mat watershedImage(markers.size(), CV_8UC3);
	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 == -1)
				watershedImage.at<Vec3b>(i, j) = Vec3b((uchar)255, (uchar)255, (uchar)255);
			else if (index <= 0 || index > noOfSegment)
				watershedImage.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
			else
				watershedImage.at<Vec3b>(i, j) = colorTab[index - 1];
		}
	}
	
	return watershedImage;
}

//分水岭图像分割
Mat watershedSrgment(Mat src, int& noOfSegment)//noOfSegment表示分割的类别数
{
	Mat grayMat;
	Mat otsuMat;
	cvtColor(src, grayMat, CV_BGR2GRAY);
	threshold(grayMat, otsuMat, 0, 255, CV_THRESH_BINARY_INV + CV_THRESH_OTSU);
	imshow("src", src);
	imshow("otsuMat", otsuMat);
	//形态学
	morphologyEx(otsuMat, otsuMat, MORPH_OPEN, Mat::ones(9, 9, CV_8SC1), Point(4, 4), 2);//2表示迭代的次数,Point(4,4)表示结构元素的原点
	imshow("Mor-open", otsuMat);
	//距离变换
	Mat disTranMat(otsuMat.rows, otsuMat.cols, CV_32FC1);
	distanceTransform(otsuMat, disTranMat, CV_DIST_L2, 3);
	//归一化
	normalize(disTranMat, disTranMat, 0.0, 1, NORM_MINMAX);
	imshow("DisTranMat", disTranMat);
	//阈值分割
	threshold(disTranMat, disTranMat, 0.1, 1, CV_THRESH_BINARY);
	normalize(disTranMat, disTranMat, 0, 255, NORM_MINMAX);
	disTranMat.convertTo(disTranMat, CV_8UC1);
	imshow("TDisTranMat", disTranMat);
	//计算标记的分割块
	int i, j, compCount = 0;
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	findContours(disTranMat, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
	Mat markers(disTranMat.size(), CV_32S);
	markers = Scalar::all(0);
	int idx = 0;
	//绘制区域块
	for (; idx >= 0; idx = hierarchy[idx][0], compCount++)
	{
		drawContours(markers, contours, idx, Scalar::all(compCount + 1), -1, 8, hierarchy, INT_MAX);
	}
	imshow("markers", markers * 255);
	double t = (double)getTickCount();
	watershed(src, markers);
	t = (double)getTickCount() - t;
	cout << "time: " << t * 1000 / getTickFrequency() << endl;

	Mat wash = display(markers, compCount);
	imshow("watershedSrgment", wash);
	noOfSegment = compCount;
	waitKey(0);
	return markers;
}


//分水岭图像合并
void segMerge(Mat src, Mat& segments, int& numSeg)
{
	vector<Mat> samples;//每个分割区域
	//统计区域更新
	int newNumSeg = numSeg;
	//初始化samples
	for (int i = 0; i <= numSeg; i++)
	{
		Mat sampleImage;
		samples.push_back(sampleImage);
	}
	//计算每个像素的归属
	for (int i = 0; i < segments.rows; i++)
	{
		for (int j = 0; j < segments.cols; j++)
		{
			int index = segments.at<int>(i,j);
			if (index >= 0 && index < numSeg)
				samples[index].push_back(src(Rect(j,i,1,1)));
		}
	}

	//创建直方图
	vector<MatND> hist_bases;
	Mat hsv_base;
	int h_bins = 35;
	int s_bins = 30;
	int hist_size[] = {h_bins,s_bins};
	float h_ranges[] = {0,256};
	float s_ranges[] = {0,180};
	const float* ranges[] = { h_ranges,s_ranges };
	int channels[] = {0,1};
	MatND hist_base;
	for (int i = 0; i <= numSeg; i++)
	{
		if (samples[i].dims > 0)
		{
			cvtColor(samples[i], hsv_base, CV_BGR2HSV);
			calcHist(&hsv_base, 1, channels, Mat(), hist_base, 2, hist_size, ranges);
			normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());
			hist_bases.push_back(hist_base);
		}
		else
			hist_bases.push_back(Mat());
		hist_base.release();
	}

	//计算各直方图之间的相似性
	double similarity = 0;
	vector<bool> merged;
	for (int k = 0; k < hist_bases.size(); k++)
	{
		merged.push_back(false);
	}

	for (int c = 0; c < hist_bases.size(); c++)
	{
		for (int q = c + 1; q < hist_bases.size(); q++)
		{
			if (!merged[q])
			{
				if (hist_bases[c].dims > 0 && hist_bases[q].dims>0)
				{
					similarity = compareHist(hist_bases[c],hist_bases[q],CV_COMP_BHATTACHARYYA);
					if (similarity > 0.8)
					{
						merged[q] = true;
						if (q != c)
						{
							newNumSeg--;
							for (int i = 0; i < segments.rows; i++)
							{
								for (int j = 0; j < segments.cols; j++)
								{
									int index = segments.at<int>(i, j);
									if (index == q)
										segments.at<int>(i, j) = c;
								}
							}
						}
					}
				}
			}
		}
	}
	numSeg = newNumSeg;
	Mat wash=display(segments, numSeg);
	imshow("segMerge", wash);
	waitKey(0);

}


int main()
{
	//imread中0表示灰度返回,1表示原图返回
	Mat srcImage = imread("E:\\研究生\\学习材料\\学习书籍\\OpenCV图像处理编程实例-源码-20160801\\《OpenCV图像处理编程实例-源码-20160801\\images\\flower.jpg");
	if (!srcImage.data)
		return -1;
	int noOfSegment = 0;
	Mat segments=watershedSrgment(srcImage, noOfSegment);
	segMerge(srcImage, segments, noOfSegment);
	return 0;
}