Image Smoothing via L0 Gradient Minimization基于C++的代码实现_铿锵的玫瑰的博客-程序员宅基地

技术标签: 图像的平滑处理  

论文解析

图像梯度L0范数最小化

图像梯度最小化平滑---一维信号

图像梯度最小化平滑---二维图像

源代码

//实现L0测度平滑
Mat L0Smoothing(Mat & image8UC3, double lambda = 2e-2, double kappa = 2.0)
{
	//将输入的图片转换为三通道的Double类型,按原来的像素值进行1:255的缩放
	Mat image64D3;
	image8UC3.convertTo(image64D3, CV_64FC3, 1.0 / 255.0);

	//定义roberts算子在x,y方向上的卷积核
	//Mat fx(1, 2, CV_64FC1);
	//Mat fy(2, 1, CV_64FC1);
	//fx.at<double>(0) = 1; fx.at<double>(1) = -1;
	//fy.at<double>(0) = 1; fy.at<double>(1) = -1;

	定义sobel算子在x、y方向上进行卷积的参数
	int scale = 1;
	int delta = 0;
	int ddepth = CV_64F;
	Mat fx(3, 3, CV_64FC1);
	Mat fy(3, 3, CV_64FC1);
	//构造在x方向上的卷积核
	fx.at<double>(0, 0) = -1; fx.at<double>(0, 1) = -2; fx.at<double>(0, 2) = -1;
	fx.at<double>(1, 0) = 0; fx.at<double>(1, 1) = 0; fx.at<double>(1, 2) = 0;
	fx.at<double>(2, 0) = 1; fx.at<double>(2, 1) = 2; fx.at<double>(2, 2) = 1;
	//构造在y方向上的卷积核
	fy.at<double>(0, 0) = -1; fy.at<double>(0, 1) = 0; fy.at<double>(0, 2) = 1;
	fy.at<double>(1, 0) = -2; fy.at<double>(1, 1) = 0; fy.at<double>(1, 2) = 2;
	fy.at<double>(2, 0) = -1; fy.at<double>(2, 1) = 0; fy.at<double>(2, 2) = 1;



	//把一个空间点扩散函数转换为频谱面的光学传递函数,即对图像进行FFT变换
	Mat otfFx = psf2otf(fx, image8UC3.size());
	Mat otfFy = psf2otf(fy, image8UC3.size());
	//定义DFT以后的输出图像,FNormal为两个通道
	Mat FNormin1[3];
	Mat single_channel[3];
	//分离为三个通道
	split(image64D3, single_channel);
	for (int k = 0; k < 3; k++) {
		// 离散傅里叶变换,指定输出复数格式(默认是CCS格式)
		dft(single_channel[k], FNormin1[k], DFT_COMPLEX_OUTPUT);
	}
	
	//F(∂x)∗F(∂x)+F(∂y)∗F(∂y);
	Mat Denormin2(image8UC3.rows, image8UC3.cols, CV_64FC1);
	for (int i = 0; i < image8UC3.rows; i++) {
		for (int j = 0; j < image8UC3.cols; j++) {
			Vec2f &c1 = otfFx.at<Vec2f>(i, j);
			Vec2f &c2 = otfFy.at<Vec2f>(i, j);
			// 0: Real, 1: Image
			Denormin2.at<double>(i, j) = pow(c1[0], 2) + pow(c1[1], 2) + pow(c2[0], 2) + pow(c2[1], 2);
		}
	}
	double beta = 2.0 * lambda;
	double betamax = 1e5;

	while (beta < betamax) {
		// F(1)+β(F(∂x)∗F(∂x)+F(∂y)∗F(∂y))
		Mat Denormin = 1.0 + beta * Denormin2;

		// h-v subproblem
		// 三个通道的 ∂S/∂x ∂S/∂y
		Mat dx[3], dy[3];
		for (int k = 0; k < 3; k++) {
			//利用Roberts算子进行求解
			//求解X方向上的梯度
			//Mat shifted_x = single_channel[k].clone();
			//circshift(shifted_x, 0, -1);
			//dx[k] = shifted_x - single_channel[k];
			求解Y方向上的梯度
			//Mat shifted_y = single_channel[k].clone();
			//circshift(shifted_y, -1, 0);
			//dy[k] = shifted_y - single_channel[k];

			利用Sobel算子进行求解
			//求解X方向上的梯度
			Mat shifted_x = single_channel[k].clone();
			Sobel(shifted_x, dx[k], ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
			//求解X方向上的梯度
			Mat shifted_y = single_channel[k].clone();
			Sobel(shifted_y, dy[k], ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
		}
		for (int i = 0; i < image8UC3.rows; i++) {
			for (int j = 0; j < image8UC3.cols; j++) {
				// (∂S/∂x)^2 + (∂S/∂y)^2
				double val = pow(dx[0].at<double>(i, j), 2) + pow(dy[0].at<double>(i, j), 2) +
					         pow(dx[1].at<double>(i, j), 2) + pow(dy[1].at<double>(i, j), 2) +
					         pow(dx[2].at<double>(i, j), 2) + pow(dy[2].at<double>(i, j), 2);
				// (∂S/∂x)^2 + (∂S/∂y)^2  < λ/β
				if (val < lambda / beta) {
					dx[0].at<double>(i, j) = dx[1].at<double>(i, j) = dx[2].at<double>(i, j) = 0.0;
					dy[0].at<double>(i, j) = dy[1].at<double>(i, j) = dy[2].at<double>(i, j) = 0.0;
				}
			}
		}

		// S subproblem
		for (int k = 0; k < 3; k++) {
			//利用Roberts算子求解二阶导数
			求解X方向上的梯度
			//Mat shift_dx = dx[k].clone();
			//circshift(shift_dx, 0, 1);
			//Mat ddx = shift_dx - dx[k];
			求解Y方向上的梯度
			//Mat shift_dy = dy[k].clone();
			//circshift(shift_dy, 1, 0);
			//Mat ddy = shift_dy - dy[k];

			//利用Sobel算子求解二阶导数
			//求解X方向上的梯度
			Mat shifted_dx = dx[k].clone();
			Mat ddx;
			Sobel(shifted_dx, ddx, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
			//求解X方向上的梯度
			Mat shifted_dy = dy[k].clone();
			Mat ddy;
			Sobel(shifted_dy, ddy, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);


			Mat Normin2 = ddx + ddy;
			Mat FNormin2;
			// 离散傅里叶变换,指定输出复数格式(默认是CCS格式)
			dft(Normin2, FNormin2, cv::DFT_COMPLEX_OUTPUT);
			// F(g)+β(F(∂x)∗F(h)+F(∂y)∗F(v))
			Mat FS = FNormin1[k] + beta*FNormin2;

			// 论文的公式(8):F^-1括号中的内容
			for (int i = 0; i < image8UC3.rows; i++) {
				for (int j = 0; j < image8UC3.cols; j++) {
					FS.at<Vec2d>(i, j)[0] /= Denormin.at<double>(i, j);
					FS.at<Vec2d>(i, j)[1] /= Denormin.at<double>(i, j);
				}
			}
			// 论文的公式(8):傅里叶逆变换
			Mat ifft;
			idft(FS, ifft, cv::DFT_SCALE | cv::DFT_COMPLEX_OUTPUT);
			for (int i = 0; i < image8UC3.rows; i++) {
				for (int j = 0; j < image8UC3.cols; j++) {
					single_channel[k].at<double>(i, j) = ifft.at<cv::Vec2d>(i, j)[0];
				}
			}
		}
		beta *= kappa;
	}

	创建显示图片的窗口
	//namedWindow("single_channel[0] Image", CV_WINDOW_AUTOSIZE);
	显示原始图片
	//imshow("single_channel[0] Image", single_channel[0]);
	创建显示图片的窗口
	//namedWindow("single_channel[1] Image", CV_WINDOW_AUTOSIZE);
	显示原始图片
	//imshow("single_channel[1] Image", single_channel[1]);
	创建显示图片的窗口
	//namedWindow("single_channel[2] Image", CV_WINDOW_AUTOSIZE);
	显示原始图片
	//imshow("single_channel[2] Image", single_channel[2]);

	//合并三个通道
	merge(single_channel, 3, image64D3);
	//创建显示图片的窗口
	namedWindow("L0 Smoothing Image", CV_WINDOW_AUTOSIZE);
	//显示原始图片
	imshow("L0 Smoothing Image", image64D3);
	return image64D3;
}

参考网址

http://www.cse.cuhk.edu.hk/~leojia/projects/L0smoothing/

https://blog.csdn.net/bluecol/article/details/48750561

https://blog.csdn.net/panda1234lee/article/details/52825113

https://www.cnblogs.com/quarryman/p/l0_gradient_smoothing.html

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/LYKymy/article/details/83963303

智能推荐

JavaOO综合练习题目 -- 宠物管理系统_江湖人称小明的博客-程序员宅基地

JavaOO综合练习题目 – 宠物管理系统题目要求:使用DAO模式开发宠物管理系统:在该宠物系统中,宠物分为狗和企鹅两种。狗的属性有:编号、名称、亲密值、健康值、品种、所属主人编号。企鹅的属性有:编号、名称、亲密值、健康值、性别、所属主人编号。该系统中主人可以领养宠物,主人的属性有:编号、用户名、密码、姓名、地址、电话。要求将狗和企鹅的数据保存到同一张表中,除品种、性别和所属主人编号外,其余列均不允

Java 利用反射机制获取内部类的私有属性和方法,并且修改私有属性的值_Missisy的博客-程序员宅基地_java反射获取私有属性,改变值

废话不多说直接贴代码,代码中有注释,如下:import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Test { @SuppressWarnings(&quot;unused&quot;) cla...

黑盒测试准备阶段_legend050709ComeON的博客-程序员宅基地

1. 概述 1.1.              黑盒测试的概念 黑盒测试(black box test)也称功能测试,它是通过测试来检测每个功能是否都能正常使用。在测试中,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确

使用CSS3 Cubic-Bezier创建动画链接悬停效果_普通网友的博客-程序员宅基地

我们将使用CSS3动画过渡来创建简单但引人入胜的链接悬停效果,将鼠标悬停在链接上时,会弹出一个小弹出框。我们还将看一下CSS3 Cubic-Bezier(贝塞尔)曲线,它是CSS过渡,为...

实用:使用caffe训练模型时solver.prototxt中的参数设置解析_jiongnima的博客-程序员宅基地

笔者之前发布了关于解析caffe的层的博客,解析caffe常用层的博客正在不断更新中。本篇博客是一个插播的博客,目的在彻底解决使用caffe训练模型时的参数设置问题,为什么要发这篇博客呢?是因为笔者最近在自定义网络时,需要构造自己的solver.prototxt,由于之前使用别人的网络时,很多设置参数都没有变,举个例子,下面是caffe官方例程中关于训练LeNet的配置参数文件:# The t

Android使用官方API分享内容到QQ和微信(非第三方集成)__H_JY的博客-程序员宅基地

最近在做分享功能,主要是实现QQ和微信分享,打算把自己实现过程跟大家分享一下,也是本人第一次发博客。好了,废话不多说,直接正题。我把各种分享封装到一个类ShareUtil中,打算通过调用这个类里面的方法来实现分享,不过在使用这个类之前,我们必须首先进行一系列配置和准备工作。一、注册官网帐号并登陆,审核应用并通过,下载签名工具获取你的应用的签名并填写到官方网站应用签名中1、在分享之前

随便推点

增长工程师修炼之道_weixin_30663391的博客-程序员宅基地

前言我的成长四步曲在我成长初期,我制定了一些计划来实现下面的一些能力:能做到你想做的: Tasking与学习能力用更好的方法来实现功能Better Code &amp; Architecture运营(Growth Hacker)除了第一步,每一个步骤都花费了相当长的时间来学习,光在学习方面就差不多一年了。能做到你想做的: Tasking与学习能力虽然这看...

php 请求的所有参数类型,post请求,xhr.send(data)函数的data参数类型有哪些?_猎豹白嘉丽的博客-程序员宅基地

平常项目中一般都是把对象类型的参数序列化之后再传给send,还要设置相应的头部:var params = {'name': 'json','age': 26};xhr.open('post', url, true);xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send(serialize...

Redis之延迟监控_一见的博客-程序员宅基地

延迟监控参考官方文档https://redis.io/topics/latency-monitor启用 redis 延迟监控CONFIG SET latency-monitor-threshold 100单位:毫秒,100表示一百毫秒。如果将 latency-monitor-threshold 的值设置为 0,则表示关闭延迟监控。子命令1)LATENCY LATEST返回所有事件的最新延迟样本2)LATENCY HISTORY event返回最多1

什么样的情况会导致网页不断的崩溃_weixin_30315435的博客-程序员宅基地

有許多種原因可能導致 Web 站點無法正常工作,這使得系統地檢查所有問題變得很困難。下面將集中分析總結導致 Web 站點崩潰的最常見的問題。如果可以解決這些常規問題,那麼也將有能力對付出現的一些意外情況。   磁片已滿  導致系統無法正常運行的最可能的原因是磁片已滿。一個好的網路管理員會密切關注磁片的使用情況,隔一定的時間,就需要將磁片上的一些負載轉存到備份存儲介質中 ( 例如磁帶 ) ...

sublime text3刚从官网下载安装后,Ctrl+B无法直接运行Python文件问题--解决方法_h200863057的博客-程序员宅基地

1.原因:ST3刚下载安装,Python环境没有配置,所以无法直接运行Python文件。2.由于网上很多这方面内容,这里省略基本配置。3.这时候直接在Build System中选择Python(ST3默认),然后在hello.py页面Ctrl+B只会看到,而看不到打印信息。因为没有配置自己的Python解析环境。4.添加自己的python解析环境如下:点击“New Build Sy

机器学习第四篇:详解决策树算法_简说Python的博客-程序员宅基地

↑↑↑关注后&#34;星标&#34;简说Python人人都可以简单入门Python、爬虫、数据分析简说Python推荐来源:俊红的数据分析之路作者:张俊红我的2020总结,戳图...

推荐文章

热门文章

相关标签