【OpenCV】拉普拉斯算子进行图像增强,以及算法优化

拉普拉斯算子进行图像增强,以及算法优化
环境:vs2017 + OpenCV3.4.1
步骤:
(1)新建工程LapFilter
在这里插入图片描述
(2)确定项目阶段
在这里插入图片描述
(3)FFT变换部分

	w = getOptimalDFTSize(gray_image.cols);//将输入图像延展到最佳尺寸,用0填充
	h = getOptimalDFTSize(gray_image.rows);//将输入图像延展到最佳尺寸,用0填充
	Mat padded;
	//将添加的像素用0填充
	copyMakeBorder(gray_image, padded, 0, h - gray_image.rows, 0, w - gray_image.cols, BORDER_CONSTANT, Scalar::all(0));
	padded.convertTo(padded, CV_32FC1);//转化为单通道浮点数
	//imshow("padded", padded);
	//将图像移到中心
	for (int i = 0; i < padded.rows; i++)
	{
		float *ptr = padded.ptr<float>(i);
		for (int j = 0; j < padded.cols; j++)	ptr[j] *= pow(-1, i + j);
	}
	//为傅里叶变换结果分配存储空间
	Mat plane[] = { padded,Mat::zeros(padded.size(),CV_32F) };
	Mat complexImg;
	//将plane数组合并成一个多通道数组complexImg
	merge(plane, 2, complexImg);
	//进行傅里叶变换
	dft(complexImg, complexImg);
	//laplace算子分配存储空间
	Mat laplace(padded.size(), CV_32FC2);

	for (int i = 0; i < padded.rows; i++)
	{
		float*k = laplace.ptr<float>(i);
		for (int j = 0; j < padded.cols; j++)
		{
			//laplace算子-4*PI*PI*(i-u/2)^2+(j-v/2)^2
			float d = pow(i - padded.rows / 2, 2) + pow(j - padded.cols / 2, 2);
			k[2 * j] = -4 * PI * PI * d;
			k[2 * j + 1] = -4 * PI * PI * d;
		}
	}
	//频域乘积H(u,v)*F(u,v)
	multiply(complexImg, laplace, laplace);
	//将多维数组拆分
	split(complexImg, plane);
	magnitude(plane[0], plane[1], plane[0]);//求幅值
	plane[0] += Scalar::all(1);
	//log(plane[0], plane[0]);
	normalize(plane[0], plane[0], 1, 0, CV_MINMAX);//归一化,形成能够显示的结构
	imshow("dft", plane[0]);//dft图像

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

(4)laplace算子部分

//将H(u,v)*F(u,v)多维数组拆分
	split(laplace, plane);
	magnitude(plane[0], plane[1], plane[0]);//求幅值
	plane[0] += Scalar::all(1);
	//log(plane[0], plane[0]);
	normalize(plane[0], plane[0], 1, 0, CV_MINMAX);//归一化,形成能够显示的结构
	imshow("laplace", plane[0]);//显示H(u,v)*F(u,v)

//将H(u,v)*F(u,v)做逆FFT
	idft(laplace, laplace);
	//将变换后的数组拆分
	split(laplace, plane);
	magnitude(plane[0], plane[1], plane[0]);//求幅值
	normalize(plane[0], plane[0], 1, 0, CV_MINMAX);//归一化,形成能够显示的结构
	temp = plane[0];
imshow("idft-laplace", temp );

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

(5)输出图像

temp.convertTo(out, CV_8UC1);
	copyMakeBorder(gray_image, temp1, 0, h - gray_image.rows, 0, w - gray_image.cols, BORDER_CONSTANT, Scalar::all(0));
	output = temp1 - out;//g(x,y)= f(x,y)-(idft-laplace)
	imshow("output", output);
	//计算峰值信噪比
	double snr;
	snr = getPSNR(temp1, output);
	cout << "laplace_PSNR:" << snr << endl

结果:
在这里插入图片描述
(6)通过幂次变换进行优化

Mat matDst2;
//幂次变换
matDst2 = PowerTranseform(output, 1.4, 1);
matDst2.convertTo(matDst2, CV_8UC1);
double snr;
//计算峰值信噪比
snr = getPSNR(temp1, matDst2);
cout << "mici_after_PSNR:" << snr << endl;
imshow("幂次变换 y=1.4", matDst2);

在这里插入图片描述
优化结果:
在这里插入图片描述
结论:经过幂次变换,峰值信噪比降为原laplace算子的三分之一左右。
附程序:

w = getOptimalDFTSize(gray_image.cols);//将输入图像延展到最佳尺寸,用0填充
	h = getOptimalDFTSize(gray_image.rows);//将输入图像延展到最佳尺寸,用0填充
	Mat padded;
	//将添加的像素用0填充
	copyMakeBorder(gray_image, padded, 0, h - gray_image.rows, 0, w - gray_image.cols, BORDER_CONSTANT, Scalar::all(0));
	padded.convertTo(padded, CV_32FC1);//转化为单通道浮点数
	//imshow("padded", padded);
	//将图像移到中心
	for (int i = 0; i < padded.rows; i++)
	{
		float *ptr = padded.ptr<float>(i);
		for (int j = 0; j < padded.cols; j++)	ptr[j] *= pow(-1, i + j);
	}
	//为傅里叶变换结果分配存储空间
	Mat plane[] = { padded,Mat::zeros(padded.size(),CV_32F) };
	Mat complexImg;
	//将plane数组合并成一个多通道数组complexImg
	merge(plane, 2, complexImg);
	//进行傅里叶变换
	dft(complexImg, complexImg);
	//laplace算子分配存储空间
	Mat laplace(padded.size(), CV_32FC2);

	for (int i = 0; i < padded.rows; i++)
	{
		float*k = laplace.ptr<float>(i);
		for (int j = 0; j < padded.cols; j++)
		{
			//laplace算子-4*PI*PI*(i-u/2)^2+(j-v/2)^2
			float d = pow(i - padded.rows / 2, 2) + pow(j - padded.cols / 2, 2);
			k[2 * j] = -4 * PI * PI * d;
			k[2 * j + 1] = -4 * PI * PI * d;
		}
	}
	//频域乘积H(u,v)*F(u,v)
	multiply(complexImg, laplace, laplace);
	//将多维数组拆分
	split(complexImg, plane);
	magnitude(plane[0], plane[1], plane[0]);//求幅值
	plane[0] += Scalar::all(1);
	//log(plane[0], plane[0]);
	normalize(plane[0], plane[0], 1, 0, CV_MINMAX);//归一化,形成能够显示的结构
	imshow("dft", plane[0]);//dft图像
	//将H(u,v)*F(u,v)多维数组拆分
	split(laplace, plane);
	magnitude(plane[0], plane[1], plane[0]);//求幅值
	plane[0] += Scalar::all(1);
	//log(plane[0], plane[0]);
	normalize(plane[0], plane[0], 1, 0, CV_MINMAX);//归一化,形成能够显示的结构
	imshow("laplace", plane[0]);//显示H(u,v)*F(u,v)
	//将H(u,v)*F(u,v)做逆FFT
	idft(laplace, laplace);
	//将变换后的数组拆分
	split(laplace, plane);
	magnitude(plane[0], plane[1], plane[0]);//求幅值
	normalize(plane[0], plane[0], 1, 0, CV_MINMAX);//归一化,形成能够显示的结构
	temp = plane[0];
imshow("idft-laplace", temp );
	temp1;
	temp.convertTo(out, CV_8UC1);
	copyMakeBorder(gray_image, temp1, 0, h - gray_image.rows, 0, w - gray_image.cols, BORDER_CONSTANT, Scalar::all(0));
	output = temp1 - out;//g(x,y)= f(x,y)-(idft-laplace)
	imshow("output", output);
	//计算峰值信噪比
	double snr;
	snr = getPSNR(temp1, output);
	cout << "laplace_PSNR:" << snr << endl;
Mat matDst2;
	//幂次变换
	matDst2 = PowerTranseform(output, 1.4, 1);
	matDst2.convertTo(matDst2, CV_8UC1);
	double snr;
	//计算峰值信噪比
	snr = getPSNR(temp1, matDst2);
	cout << "mici_after_PSNR:" << snr << endl;
	imshow("幂次变换 y=1.4", matDst2);
}
幂次变换函数:PowerTranseform
Mat CLapFilterDlg::PowerTranseform(Mat &src, double gamma, int parameter)
{ 
	Mat dst;
	dst.create(src.size(), src.type());
	vector<double> value;
	for (int r = 0; r < src.rows; r++)
	{
		uchar* srcRowData = src.ptr<uchar>(r);
		for (int c = 0; c < src.cols; c++)
		{
			//幂次变换的公式为 s = c * r ^ v	r为输入图像像素
			value.push_back(parameter * pow((double)srcRowData[c], gamma));
		}
	}
	double max = 0.0;
	double min = 0.0;
	for (int i = 0; i < value.size(); i++)
	{
		if (value[i] > max)
			max = value[i];
		if (value[i] < min)
			min = value[i];
	}
	int index = 0;
	for (int r = 0; r < dst.rows; r++)
	{
		uchar* dstRowData = dst.ptr<uchar>(r);
		for (int c = 0; c < dst.cols; c++)
		{
			dstRowData[c] = (uchar)(255 * ((value[index++] - min) * 1.0 / (max - min)));
		}
	}
	return dst;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值