Smart Light Random Memory Sprays Retinex 传统图像增强 SLRMSR

文章目录

  • 前言
  • 1、Smart Light Random Memory Sprays Retinex概况
  • 2、Smart Light Random Memory Sprays Retinex的实现
    • 2.1、SLRMSR算法的伪代码
    • 2.2、初始化记忆喷雾(CreateInitialMemorySpray)
    • 2.3、更新记忆喷雾 (UpdateMemorySpray)
    • 2.4、计算颜色校正因子(ComputeColorCorrectionFactor)
    • 2.5、应用强度重映射(ApplyIntensityRemapping)
    • 2.6、应用引导滤波 (ApplyGuidedImageFiltering)
  • 3、Smart Light Random Memory Sprays Retinex效果


前言

  Smart Light Random Memory Sprays Retinex,即“智能光随机记忆喷雾Retinex”,简称SLRMSR。作为一种新的基于Retinex理论的图像增强算法,旨在解决图像亮度调整和颜色校正的问题。


1、Smart Light Random Memory Sprays Retinex概况

论文名称:
Smart light random memory sprays Retinex: a fast Retinex implementation for high-quality brightness adjustment and color correction
作者:
Nikola Banić,Sven Lončarić

  “智能光随机记忆喷雾Retinex”(Smart Light Random Memory Sprays Retinex,简称SLRMSR),该算法提出了记忆喷雾的概念,以减少每个像素操作的数量,从而实现了快速的Retinex基础的局部图像增强。同时提出了一种有效的图像强度重映射的方法,进一步显著地提高了图像的质量。最后通过使用引导滤波作为替代的光照处理方法,减少了原有LRSR算法的光晕效应。作为一种新的基于Retinex理论的图像增强算法,在解决图像亮度调整和颜色校正的问题上,具有显著优势。

2、Smart Light Random Memory Sprays Retinex的实现

2.1、SLRMSR算法的伪代码

在这里插入图片描述

2.2、初始化记忆喷雾(CreateInitialMemorySpray)

  图像第一个像素创建一个包含随机选择的邻近像素强度的记忆喷雾。
① 定义喷雾大小:
  确定记忆喷雾参数的大小n,作为预设值,决定了喷雾中包含像素的数量。
② 选择邻近像素:
  对于图像中每个像素,在其邻域定义一个包含n个随机选择的邻近像素区域。
③ 构建笛卡尔树:
  对于选定的每个邻近像素,收集其RGB强度值,进行笛卡尔树的构造,其每个节点包含子树的最大值。
④ 存储喷雾内容:
  构建好的笛卡尔树被作为存储记忆喷雾的数据结构,用于后续的像素处理。

2.3、更新记忆喷雾 (UpdateMemorySpray)

① 选择新像素:
  当处理新的像素时,算法会从当前像素的局部邻域中选择一个新的邻近像素。
② 更新笛卡尔树:
  新选定的像素强度值被添加到笛卡尔树中,同时,最旧的像素强度值被从树中移除。这种“先进先出”的更新机制确保了记忆喷雾始终反应最新的局部信息。
③ 计算最大值:
  通过笛卡尔树的根节点,可以快速获取当前记忆喷雾中所有像素强度的最大值。

//基于随机内存喷雾Retinex(Random Memory Sprays Retinex)算法对输入的彩色图像进行白平衡处理
void RandomMemorySpraysRetinexPerformWhiteBalance(Mat source, Mat& destination, int N, int n, double upperBound, int rowsStep, int colsStep, double rFactor) {

	int rows = source.rows;
	int cols = source.cols;

	int R = rFactor * sqrt((double)(rows * rows + cols * cols)) + 0.5;

	Mat normalized;
	source.convertTo(normalized, CV_64FC3);

	int outputRows = rows / rowsStep;
	int outputCols = cols / colsStep;
	destination = Mat(outputRows, outputCols, CV_64FC3);

	Vec3d* input = (Vec3d*)normalized.data;
	Vec3d* inputPoint = input;
	Vec3d* output = (Vec3d*)destination.data;
	Vec3d* outputPoint = output;

	RNG random;

	CartesianTree<double>** qhs;

	qhs = new CartesianTree<double>*[N];
	for (int i = 0; i < N; ++i) {
		qhs[i] = new CartesianTree<double>[3];
	}

	for (int outputRow = 0; outputRow < outputRows; ++outputRow) {
		for (int outputCol = 0; outputCol < outputCols; ++outputCol) {

			int row = outputRow * rowsStep;
			int col = outputCol * colsStep;

			inputPoint = input + row * cols + col;
			outputPoint = output + outputRow * outputCols + outputCol;

			Vec3d& currentPoint = *inputPoint;
			Vec3d& finalPoint = *outputPoint;
			finalPoint = Vec3d(0, 0, 0);

			for (int i = 0; i < N; ++i) {

				Vec3d max = Vec3d(0, 0, 0);

				while (qhs[i][0].Size() < n) {
					double angle = 2 * CV_PI * random.uniform(0.0, 1.0);
					double r = R * random.uniform(0.0, 1.0);

					int newRow = row + r * sin(angle);
					int newCol = col + r * cos(angle);

					if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols) {
						Vec3d& newPoint = input[newRow * cols + newCol];
						for (int k = 0; k < 3; ++k) {
							qhs[i][k].Push(newPoint[k]);
						}
					}
				}

				for (int k = 0; k < 3; ++k) {
					if (max[k] < qhs[i][k].Max()) {
						max[k] = qhs[i][k].Max();
					}

					qhs[i][k].Pop();

				}

				for (int k = 0; k < 3; ++k) {
					if (max[k] == 0) {
						max[k] = 1;
					}
					finalPoint[k] += currentPoint[k] / max[k];
				}

			}

			finalPoint /= N;

			for (int i = 0; i < 3; ++i) {
				if (finalPoint[i] > 1) {
					finalPoint[i] = 1;
				}
			}

		}
	}

	for (int i = 0; i < N; ++i) {
		delete[] qhs[i];
	}
	delete[] qhs;

	double scaleFactor = upperBound;

	if (rowsStep > 1 || colsStep > 1) {
		resize(destination, destination, source.size());
	}

	destination = destination * scaleFactor - 1;

	destination.convertTo(destination, source.type());

}

2.4、计算颜色校正因子(ComputeColorCorrectionFactor)

  颜色校正因子是基于当前像素亮度值和记忆喷雾的最大强度计算得出。其主要用于调整像素的颜色,以便在不同的光照条件下保持颜色的一致性。

//光照校正算法的实现
void ApplyIllumination(Mat source, Mat illumination, Mat& destination, double upperBound) {
	vector<Mat> destinationChannels;
	split(source, destinationChannels);
	vector<Mat> illuminationChannels;
	split(illumination, illuminationChannels);
	for (int i = 0; i < destinationChannels.size(); ++i) {
		destinationChannels[i].convertTo(destinationChannels[i], CV_64FC1);
		divide(destinationChannels[i], illuminationChannels[i], destinationChannels[i]);
	}

	merge(destinationChannels, destination);

	double* check = (double*)destination.data;
	for (int i = 0; i < destination.rows * destination.cols * 3; ++i) {
		if (check[i] >= upperBound) {
			check[i] = upperBound - 1;
		}
	}

	destination.convertTo(destination, source.type());

}

2.5、应用强度重映射(ApplyIntensityRemapping)

  强度重映射主要用于改善图像亮度调整和颜色校正的方法,特别是在处理高光细节处,以防止过度增强造成细节的丢失。即,在增强图像暗区域的同时,保持亮区域的高光细节,从而获得更为自然的视觉效果。
① 计算初始及LRSR的亮度:
  对于每个像素,首先计算其初始亮度Yi,及LRSR算法处理后的亮度Yo。
② 确定重映射的参数:
  引入重映射参数,用于调整亮度的增加强度。
③ 计算调整后的亮度:
  调整后的亮度是初始亮度Yi和处理后亮度Yo的凸组会。即:Yr = λi * Yi + (1 - λi) * Yo
  其中,λi 是一个介于0和1之间的权重因子,主要基于初始亮度Yi和一个调整参数a来计算。
④ 计算权重因子:
  权重因子λi,即:λi = (Yi / D) / (Yi / D + a)。
  其中,D是颜色通道的最大值(对于8bit颜色通道,D通常是255)。λi的值越大,表示保留的初始亮度越多,处理后亮度的影响越小。
⑤ 过滤处理:
  为了避免亮度增加的剧烈变化,对λi施以一个滤波器(例如使用5*5的均值核)进行平滑处理,得到平滑后的权重因子λ’i。
⑥ 计算最终亮度:
  最终的亮度值,即:OpIci = λ’i * Yo + (1 - λ’i) * Ici。
  其中OpIci是最终的输出亮度,Ici是原始图像中的像素亮度通道强度。

//基于随机内存喷雾Retinex算法对输入的彩色图像进行局部光照估计
void LightRandomMemorySpraysRetinexEstimateLocalIlumination(Mat source, Mat& destination, int N, int n, int inputKernelSize, int illuminantKernelSize, bool normalizeIlluminant = false, int rowsStep = 1, int colsStep = 1, double upperBound = 256.0, double rFactor = 1.0) {

	Mat retinex;
	RandomMemorySpraysRetinexPerformWhiteBalance(source, retinex, N, n, upperBound, rowsStep, colsStep, rFactor);

	Mat inputSource;
	Mat inputRetinex;

	source.convertTo(inputSource, CV_64FC3);
	retinex.convertTo(inputRetinex, CV_64FC3);

	Mat guidance;
	inputSource.copyTo(guidance);

	if (normalizeIlluminant) {
		Mat illuminant;
		divide(inputSource, inputRetinex, illuminant);
		vector<Mat> illuminantChannels;

		split(illuminant, illuminantChannels);
		Mat illuminantAverage = (illuminantChannels[0] + illuminantChannels[1] + illuminantChannels[2]) / 3;
		for (int i = 0; i < 3; ++i) {
			divide(illuminantChannels[i], illuminantAverage, illuminantChannels[i]);
		}
		merge(illuminantChannels, illuminant);

		inputSource = inputRetinex.mul(illuminant);
	}

	if (inputKernelSize > 1) {
		Mat averaging = Mat::ones(inputKernelSize, inputKernelSize, CV_64FC1) / (double)(inputKernelSize * inputKernelSize);
		boxFilter(inputSource, inputSource, -1, Size(inputKernelSize, inputKernelSize));
		boxFilter(inputRetinex, inputRetinex, -1, Size(inputKernelSize, inputKernelSize));
	}

	Mat illuminant;
	divide(inputSource, inputRetinex, illuminant);
	vector<Mat> illuminantChannels;

	if (illuminantKernelSize > 1) {
		Mat averaging = Mat::ones(illuminantKernelSize, illuminantKernelSize, CV_64FC1) / (double)(illuminantKernelSize * illuminantKernelSize);
		boxFilter(illuminant, illuminant, -1, Size(illuminantKernelSize, illuminantKernelSize));
	}

	illuminant.copyTo(destination);

}

2.6、应用引导滤波 (ApplyGuidedImageFiltering)

  使用引导滤波来处理重映射后的像素强度,以减少光晕效果并保留图像边缘。
其中,对图像进一步灰度化作为引导图像,进而采用引导滤波进行处理,最后输出目标图像。

//图像引导滤波
//对输入的图像img进行引导滤波,输出结果保存在result中。
void GuidedImageFilterC1(Mat img, Mat guidance, Mat& result, int r, double epsilon) {

	Mat p;
	img.convertTo(p, CV_64F);

	Mat I;
	guidance.convertTo(I, CV_64F);

	Mat meanI;
	boxFilter(I, meanI, -1, Size(r, r));

	Mat meanP;
	boxFilter(p, meanP, -1, Size(r, r));

	Mat corrI;
	boxFilter(I.mul(I), corrI, -1, Size(r, r));

	Mat corrIp;
	boxFilter(I.mul(p), corrIp, -1, Size(r, r));

	Mat varI = corrI - meanI.mul(meanI);
	Mat covIp = corrIp - meanI.mul(meanP);

	Mat a;
	divide(covIp, varI + epsilon, a);
	Mat b = meanP - a.mul(meanI);

	Mat meanA;
	boxFilter(a, meanA, -1, Size(r, r));

	Mat meanB;
	boxFilter(b, meanB, -1, Size(r, r));

	Mat q = meanA.mul(I) + meanB;

	q.convertTo(result, img.type());
}


//基于引导图像的彩色图像滤波方法
//基于引导图像guidance对输入的彩色图像img进行引导滤波,输出结果保存在result中。
void GuidedImageFilterC3(Mat img, Mat guidance, Mat& result, int r, double epsilon) {

	vector<Mat> imgChannels;
	vector<Mat> guidanceChannels;

	split(img, imgChannels);
	split(guidance, guidanceChannels);

	vector<Mat> resultChannels;

	for (int i = 0; i < imgChannels.size(); ++i) {
		Mat channelResult;
		GuidedImageFilterC1(imgChannels[i], guidanceChannels[i], channelResult, r, epsilon);
		resultChannels.push_back(channelResult);
	}

	merge(resultChannels, result);

}

//基于引导图像和随机内存喷雾Retinex算法的彩色图像局部光照估计方法
void GuidedLightRandomMemorySpraysRetinexEstimateLocalIlumination(Mat source, Mat& destination, int N, int n, int inputKernelSize, int illuminantKernelSize, bool normalizeIlluminant = false, int rowsStep = 1, int colsStep = 1, double upperBound = 256.0, double rFactor = 1.0) {

	Mat retinex;
	//白平衡化处理
	RandomMemorySpraysRetinexPerformWhiteBalance(source, retinex, N, n, upperBound, rowsStep, colsStep, rFactor);

	Mat inputSource;
	Mat inputRetinex;

	source.convertTo(inputSource, CV_64FC3);
	retinex.convertTo(inputRetinex, CV_64FC3);

	Mat guidance;
	inputSource.copyTo(guidance);

	//归一化处理
	if (normalizeIlluminant) {
		Mat illuminant;
		divide(inputSource, inputRetinex, illuminant);
		vector<Mat> illuminantChannels;

		split(illuminant, illuminantChannels);
		Mat illuminantAverage = (illuminantChannels[0] + illuminantChannels[1] + illuminantChannels[2]) / 3;
		for (int i = 0; i < 3; ++i) {
			divide(illuminantChannels[i], illuminantAverage, illuminantChannels[i]);
		}
		merge(illuminantChannels, illuminant);

		inputSource = inputRetinex.mul(illuminant);
	}

	double value = 40;
	double epsilon = value * value;

	if (inputKernelSize > 1) {
		//平滑图像
		GuidedImageFilterC3(inputSource, guidance, inputSource, inputKernelSize, epsilon);
		GuidedImageFilterC3(inputRetinex, guidance, inputRetinex, inputKernelSize, epsilon);
	}

	Mat illuminant;
	divide(inputSource, inputRetinex, illuminant);
	vector<Mat> illuminantChannels;

	if (illuminantKernelSize > 1) {
		GuidedImageFilterC3(illuminant, guidance, illuminant, illuminantKernelSize, epsilon);
	}

	illuminant.copyTo(destination);

}

3、Smart Light Random Memory Sprays Retinex效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/467148.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二十几岁的我们:在旷野中找寻自我

二十几岁&#xff0c;这是一个充满变数、充满机遇和挑战的年纪。它如同一片辽阔的旷野&#xff0c;每个人都在其中寻找自己的方向&#xff0c;摸索着自己的道路。这是一个既令人兴奋又令人迷茫的年纪&#xff0c;我们穿着不同的鞋子&#xff0c;注定要走不同的路。 在这个年纪里…

onnx 格式模型可视化工具

onnx 格式模型可视化工具 0. 引言1. 可视化工具2. 安装 Netron: Viewer for ONNX models 0. 引言 ONNX 是一种开放格式&#xff0c;用于表示机器学习模型。ONNX 定义了一组通用运算符&#xff08;机器学习和深度学习模型的构建基块&#xff09;和通用文件格式&#xff0c;使 A…

Unity引擎是否被过度吹嘘?

提到Unity&#xff0c;人们基本上持有以下几种观点&#xff1a; A. 很多人十分欣赏Unity在跨平台兼容性和大规模开放世界场景方面的出色表现。其渲染、环境特效以及AI系统为设计多样化沙盒游戏提供了强大支持。这使得Unity非常适合开发具有多种游戏玩法和互动系统的作品。 B. 一…

Java有哪些常用的集合?

1、典型回答 在 Java 中&#xff0c;常用的集合有以下几个&#xff1a; 列表(List)&#xff1a;有序集合&#xff0c;可以包含重复元素。常见实现类有 ArrayList、LinkedList、 Vector 等集合(Set)&#xff1a;无序集合&#xff0c;不允许包含重复元素。常见实现类有 HashSet、…

【复现】【免费】基于多时间尺度滚动优化的多能源微网双层调度模型

目录 主要内容 部分代码 结果一览 1.原文结果 2.程序运行结果 下载链接 主要内容 该模型参考《Collaborative Autonomous Optimization of Interconnected Multi-Energy Systems with Two-Stage Transactive Control Framework》&#xff0c;主要解决的是一个…

深入了解JVM底层原理

一、JVM内存结构 1、方法区&#xff1a;存储编译后的类、常量等&#xff08;.class字节码文件&#xff09; 2、堆内存&#xff1a;存储对象 3、程序计数器&#xff1a;存储当前执行的指令地址&#xff08;计算机处理器&#xff08;CPU&#xff09;正在执行的下一条指令在内存…

win修改图标自定义QQ桌面图标

当安装了TIM后&#xff0c;想把图标改成QQ 图标见顶部&#xff0c;或通过网盘下载 提取码&#xff1a;9Ayc 操作步骤&#xff1a; 1.桌面右键图标&#xff0c;点击属性 2.选择快捷方式-更改图标 3.浏览选择下载的ico图标即可

Python中的迭代器与生成器提高性能的秘密武器【第143篇—迭代器与生成器】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python中的迭代器与生成器&#xff1a;提高性能的秘密武器 在Python编程中&#xff0c;迭代…

17双体系Java学习之数组的长度

数组的长度 //获取数组长度 arrays.lengthfor (int i 0; i <nums.length; i) {sum sum nums[i];}System.out.println("总和为&#xff1b;"sum);

心灵治愈交流平台|基于springboot框架+ Mysql+Java+B/S结构的心灵治愈交流平台设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 用户功能模块 心理咨询师功能 系统功能设计 数据库…

Linux下使用ntpdate进行时间同步

1.简介 ntpdate是Linux下用于从NTP服务器同步时间的命令行工具。 2.安装 大多数Linux发行版已预装ntpdate。未安装的可使用以下命令&#xff1a; # Ubuntu/Debian sudo apt-get install ntpdate # CentOS/Fedora/RHEL sudo yum install ntpdate 3.手工同步网络时间 执行以下命…

操作系统原理与实验——实验七固定分区的分配与回收

实验指南 运行环境&#xff1a; Dev c 算法思想&#xff1a; 本实验是模拟存储管理方式中的固定分区分配与回收算法&#xff0c;系统在作业装入前预分将整个用户区划分为若干个大小确定的分区&#xff0c;然后根据待装入作业的名称和大小到分区列表中查找满足要求的空闲分区&am…

鸿蒙Next-TextInput制作简易登录页面

Entry Component struct EventCase {State username: string State password: string build() {Row() {Column({ space: 30 }) {TextInput({ placeholder: 请输入用户名, text: $$this.username }).height(40)TextInput({ placeholder: 请输入密码, text: $$this.password })…

【网络原理】TCP协议详细解析

文章目录 &#x1f332;TCP协议的概念&#x1f338;TCP协议段格式&#x1f338;TCP的特性 &#x1f333;TCP原理详解&#x1f338;确认应答机制&#xff08;安全机制&#xff09;&#x1f338;超时重传机制&#xff08;安全机制&#xff09;&#x1f338;连接管理&#xff08;安…

电脑缺少dll文件一键修复的方法,如何快速修复dll文件

如果你遇到了电脑缺少dll文件&#xff0c;那么也不要慌&#xff0c;要解决也是比较简单的&#xff0c;下面我们一起来了解一下电脑缺少dll文件一键修复的方法&#xff0c;教教大家快速修复。 一.什么是dll文件 DLL 文件全称为“Dynamic Link Library”文件&#xff0c;翻译为中…

美国科技行业今年裁员超 5 万人;宁德时代一年净赚超 440 亿丨 RTE 开发者日报 Vol.167

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real Time Engagement&#xff09; 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「…

Docker部署Django项目——基础

1.服务器配置 1.1centos7 系统的安装 centos-7-isos-x86_64安装包下载) VMware安装自定义配置 选择对应的系统镜像 一般选择内核4核、内存8g、硬盘80g 相关配置 1.2.网络配置 1.2.1查看win电脑虚拟机VMnet8的ip 使用ipconfig查看虚拟机的ip 1.2.2配置虚拟机VMnet8的ip…

膨胀 卷积

1.作用 Dilated convolution、Atrous convolution 增大感受野保持原输入大小 2.膨胀因子 描述的是相邻元素之间的距离 r 2 3.gridding effect 不合理的多个膨胀卷积之前&#xff0c;设计的膨胀因子不合理导致&#xff0c;在增大感受野的同时丢失了细节信息。 丢失&…

计算机组成原理-1-计算系统概论

1. 计算系统概论 文章目录 1. 计算系统概论1.0 课程概貌1.1 计算机系统简介1.2 计算机的硬件框图1.3 计算机的工作步骤1.4 计算机硬件的主要技术指标 本笔记参考哈工大刘宏伟老师的MOOC《计算机组成原理&#xff08;上&#xff09;_哈尔滨工业大学》、《计算机组成原理&#xf…

简历信息泄露?如何用图数据库技术解决简历泄露事件的反欺诈挑战

“金三银四”&#xff0c;又到了春招黄金期&#xff0c;但个人简历泄露的数据安全问题诸见报端&#xff0c;甚至在此前的3.15晚会报道中就揭露过招聘平台上的简历信息被泄露&#xff0c;不法分子通过各种渠道获取到简历&#xff0c;并用于欺诈活动&#xff0c;形成了一套庞大的…
最新文章