图像分割-水平集(CV模型、RSF模型)opencv3代码

// 水平集_图像分割.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include 


#include 
#include 
#include 
#include 


using namespace cv;
using namespace std;
#define pi 3.14159265

#define CVTerm 1


//显示图像和轮廓
void ImgShow(Mat LSF, Mat Image)
{
	Mat src = (LSF > 0); //先得到二值图
	imshow("src", src); //imwrite("new_cv_src.jpg", src);
	Image.convertTo(Image, CV_8UC1);//转化类型
	imshow("8UC1_img", Image);// cout << Image.type() << endl << Image.channels()<
	vector <vector<Point> > contours;
	vector <Vec4i> hierarchy;
	findContours(src, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
	drawContours(Image, contours, -1, Scalar(0, 0, 255), 1);
	imshow("分割结果", Image);
	waitKey(100);
}

//NeumannBound条件,处理边界
void NeumannBoundCond(Mat& LSF)
{
	int w = LSF.cols - 1;
	int h = LSF.rows - 1;
	LSF.at<float>(0, 0) = LSF.at<float>(2, 2);
	LSF.at<float>(h, 0) = LSF.at<float>(h - 2, 2);
	LSF.at<float>(0, w) = LSF.at<float>(2, w - 2);
	LSF.at<float>(h, w) = LSF.at<float>(h - 2, w - 2);

	for (int i = 0; i <= w; i++)
	{
		LSF.at<float>(0, i) = LSF.at<float>(2, i);
		LSF.at<float>(h, i) = LSF.at<float>(h - 2, i);
	}
	for (int i = 0; i <= h; i++)
	{
		LSF.at<float>(i, 0) = LSF.at<float>(i, 2);
		LSF.at<float>(i, w) = LSF.at<float>(i, w - 2);
	}
}

//计算矩阵的反三角函数
Mat atan(Mat LSF)
{
	Mat dst(LSF.size(), LSF.type());
	for (int k = 0; k < LSF.rows; k++) //遍历
	{
		const float* inData = LSF.ptr<float>(k);//使用指针获取
		float* outData = dst.ptr<float>(k);
		for (int i = 0; i < LSF.cols; i++)
			outData[i] = atan(inData[i]);
	}
	return dst;
}

Mat gradient_x(Mat input)
{
	Mat Ix(input.size(), input.type());
	for (int ncol = 0; ncol < input.cols; ncol++)
	{
		for (int nrow = 0; nrow < input.rows; nrow++)
		{
			if (ncol == 0) {
				Ix.at<float>(nrow, ncol) = input.at<float>(nrow, 1) - input.at<float>(nrow, 0);
			}
			else if (ncol == input.cols - 1) {
				Ix.at<float>(nrow, ncol) = input.at<float>(nrow, ncol) - input.at<float>(nrow, ncol - 1);

			}
			else
				Ix.at<float>(nrow, ncol) = (input.at<float>(nrow, ncol + 1) - input.at<float>(nrow, ncol - 1)) / 2;
		}
	}
	return Ix;
}

Mat gradient_y(Mat input)
{
	Mat Iy(input.size(), input.type());
	for (int nrow = 0; nrow < input.rows; nrow++)
	{
		for (int ncol = 0; ncol < input.cols; ncol++)
		{
			if (nrow == 0) {
				Iy.at<float>(nrow, ncol) = input.at<float>(1, ncol) - input.at<float>(0, ncol);
			}
			else if (nrow == input.rows - 1) {
				Iy.at<float>(nrow, ncol) = input.at<float>(nrow, ncol) - input.at<float>(nrow - 1, ncol);
			}
			else
				Iy.at<float>(nrow, ncol) = (input.at<float>(nrow + 1, ncol) - input.at<float>(nrow - 1, ncol)) / 2;
		}

	}
	return Iy;
}

#if CVTerm

int claBitMaps(Mat img)
{
	//Mat tmp = img.reshape(1, 1); imshow("aa", tmp);
	Mat sorted;
	img.reshape(1, 1).copyTo(sorted); //imshow("sorted", sorted);
	//sort(sorted, sorted, CV_SORT_EVERY_ROW + CV_SORT_ASCENDING);
	//sort(tmp, sorted, CV_SORT_EVERY_ROW+CV_SORT_ASCENDING);
	uchar * aa = sorted.ptr<uchar>(0);
	for (int i = 0; i < sorted.cols; i++)
	{
		for (int j = 0; j < sorted.cols - 1 - i; j++)
		{
			if (aa[j] >= aa[j + 1])
			{
				int temp = aa[j];
				aa[j] = aa[j + 1];
				aa[j] = temp;
			}
		}

	}
	int meddata = aa[sorted.cols / 2];// cout << endl << meddata << endl;
	return meddata;
}
void CV(Mat& LSF, Mat Img, float mu, float nu, float epison, float step)
{
	NeumannBoundCond(LSF); //边界条件

	Mat Drc = (epison / pi) / (epison*epison + LSF.mul(LSF)); //Dirac 函数

	Mat Hea = 0.5*(1 + (2 / pi)*atan(LSF / epison)); //Heaviside 函数

	//计算曲率
	Mat Ix, Iy;
	Ix = gradient_x(LSF);
	Iy = gradient_y(LSF);
	Mat s;
	magnitude(Ix, Iy, s);//梯度的模
	Mat Nx = Ix / s;
	Mat Ny = Iy / s;
	Mat Nxx, Nyy;
	Nxx = gradient_x(Nx);
	Nyy = gradient_y(Ny);
	Mat cur = Nxx + Nyy;

	//长度项
	Mat Length = nu * Drc.mul(cur);  //nu = 0.15*255*255

	//惩罚项
	Mat Lap;
	Laplacian(LSF, Lap, CV_32FC1);//拉普拉斯运算
	Mat Penalty = mu * (Lap - cur); // mu = 1

	//面积项
	Mat Square = mu * Hea;

	//CV项,驱动闭合曲线朝目标边界演化
	Scalar S1;
	S1 = sum(Hea.mul(Img));
	Scalar S2;
	S2 = sum(Hea);
	float C1 = S1.val[0] / S2.val[0];//曲线外的全局灰度均值
	Scalar S3;
	S3 = sum((1 - Hea).mul(Img));
	Scalar S4;
	S4 = sum((1 - Hea));
	float C2 = S3.val[0] / S4.val[0];//曲线内的全局灰度均值
	//Mat CVterm = Drc.mul((-1 * (Img - C1).mul(Img - C1) + 1 * (Img - C2).mul(Img - C2)));

	Mat hea_img = Hea.mul(Img);
	float k1_med = claBitMaps(hea_img);
	Mat de_hea_img = (1 - Hea).mul(Img);
	float k2_med = claBitMaps(de_hea_img);
	Mat CVterm_1 = Drc.mul(0.7 *(Img - (C1 + C2) / 2) + 0.3*(abs(Img - k1_med) - abs(Img - k2_med)));

	//三项相加
	LSF = LSF + step * (0.3 * Length + CVterm_1);
}

//RSF模型
#else
void RSF(Mat LSF, Mat Img, Mat kernal, float mu, float nu, float epison, float step, int lambda1, int lambda2)
{
	NeumannBoundCond(LSF); //边界条件

	Mat Drc = (epison / pi) / (epison*epison + LSF.mul(LSF)); //Dirac 函数

	Mat Hea = 0.5*(1 + (2 / pi)*atan(LSF / epison)); //Heaviside 函数

	//计算曲率
	Mat Ix, Iy;
	Ix = gradient_x(LSF);
	Iy = gradient_y(LSF);
	Mat s;
	magnitude(Ix, Iy, s);//梯度的模
	Mat Nx = Ix / s;
	Mat Ny = Iy / s;
	Mat Nxx, Nyy;
	Nxx = gradient_x(Nx);
	Nyy = gradient_y(Ny);
	Mat cur = Nxx + Nyy;

	//长度项
	Mat Length = nu * Drc.mul(cur);

	//惩罚项
	Mat Lap;
	Laplacian(LSF, Lap, CV_32FC1);//拉普拉斯运算
	Mat Penalty = mu * (Lap - cur);

	Mat KIH;
	filter2D(Hea.mul(Img), KIH, -1, kernal);//输入图像与卷积核作卷积,输出图像与输入图像深度一致
	Mat KH;
	filter2D(Hea, KH, -1, kernal);
	Mat f1 = KIH / KH;

	Mat KIH1;
	filter2D((1 - Hea).mul(Img), KIH1, -1, kernal);
	Mat KH1;
	filter2D((1 - Hea), KIH1, -1, kernal);
	Mat f2 = KIH1 / KH1;

	Mat R1 = (lambda1 - lambda2)*Img.mul(Img);
	Mat R2;
	filter2D(lambda1*f1 - lambda2 * f2, R2, -1, kernal);
	Mat R3;
	filter2D(lambda1*f1.mul(f1) - lambda2 * f2.mul(f2), R3, -1, kernal);
	Mat RSFterm = -Drc.mul(R1 - 2 * R2.mul(Img) + R3);

	Mat term1, term2;
	filter2D(((Img - f1).mul(Img - f1)).mul(Hea), term1, -1, kernal);
	filter2D(((Img - f2).mul(Img - f2)).mul(1 - Hea), term2, -1, kernal);
	Mat RSFterm_1 = -Drc.mul(term1 + term2);

	LSF = LSF + step * (Length + Penalty + RSFterm_1);
}
#endif
//主程序
int main()
{
	Mat Img = imread("5.bmp", 0); //读入图像
	//Mat bgrchannels[3];
	//split(Img, bgrchannels);
	//Img = bgrchannels[1];
	//resize(Img,Img,Size(100,65));
	imshow("yuantu", Img);
	Img.convertTo(Img, CV_32FC1);//转化类型
	imshow("32fc1_img", Img); //cout << Img.type()<
								 //初始轮廓
	Mat LSF = Mat::ones(Img.size(), CV_32FC1);
	Rect roi(60, 40, 10, 10);
	LSF(roi) = -1;
	LSF = -LSF;
	imshow("lsf", LSF);
	ImgShow(LSF, Img);
	waitKey(1000);

	double time0 = static_cast<double>(getTickCount());//计时起点

	//参数设置
	float mu = 1;                  //惩罚项系数
	float nu = 0.15 * 255 * 255;  //长度项参数
	int num = 50;                  //迭代次数

	float epison = 1;
	float step = 0.1;               //时间步长
	int lambda1 = 1;
	int lambda2 = 1;
	//后面四行涉及RSF模型
	float sig = 3;
	Mat kernalX = getGaussianKernel(int(sig * 2) * 2 + 1, sig);
	cout << endl << kernalX << endl;
	Mat kernal = kernalX * kernalX.t();


	for (int n = 0; n < num; n++)
	{
		CV(LSF, Img, mu, nu, epison, step);//迭代
		//RSF(LSF, Img, kernal, mu, nu, epison, step, lambda1, lambda2);RSF模型
		if (n % 1 == 0) {
			ImgShow(LSF, Img);
			cout << endl << "第" << n << "次迭代" << endl;
		}
	}
	time0 = ((double)getTickCount() - time0) / getTickFrequency();//计时终点

	std::cout << "finsh" << endl << "runtime:" << time0 << "s";
	waitKey();
	//_CrtDumpMemoryLeaks();
	return 0;
}

你可能感兴趣的:(图像分割-水平集(CV模型、RSF模型)opencv3代码)