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效果
相关文章:

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、计算颜色校正因子…...
Oracle数据库实例概述
Oracle数据库实例是由内存结构(SGA和PGA)及后台进程这两大部分组成。 内存结构 SGA (System Global Area):这是数据库实例的共享内存区域,所有与该实例连接的进程都可以访问。SGA包含多个内存结构,例如: 数…...

Odoo17免费开源ERP开发技巧:如何在表单视图中调用JS类
文/Odoo亚太金牌服务开源智造 老杨 在Odoo最新V17新版中,其突出功能之一是能够构建个性化视图,允许用户以独特的方式与数据互动。本文深入探讨了如何使用 JavaScript 类来呈现表单视图来创建自定义视图。通过学习本教程,你将获得关于开发Odo…...

[RCTF2015]EasySQL ---不会编程的崽
今天也是sql注入的新类型---二次注入。不得不说花样真的多哦。 既然真的是sql注入了。那就不测试其他地方了。现在注册进去看一下界面 单纯的回显了名字。源代码里发现user.php。 可以修改密码?二次注入应该就在用户名这里了。因为修改密码时,用户名会被…...

Memcached-分布式内存对象缓存系统
目录 一、NoSQL 介绍 二、Memcached 1、Memcached 介绍 1.1 Memcached 概念 1.2 Memcached 特性 1.3 Memcached 和 Redis 区别 1.4 Memcached 工作机制 1.4.1 内存分配机制 1.4.2 懒惰期 Lazy Expiration 1.4.3 LRU(最近最少使用算法) 1.4.4…...
bash: sqlplus: command not found 问题解决方法
一、问题描述 在Linux中Oracle安装成功后,首次启动使用时,出现 sqlplus 命令不识别的问题,现象如下: $ sqlplus / as sysdba bash: sqlplus: command not found...二、问题分析 查看环境变量是否正确配置: $ vim .ba…...
大模型-Prompt
一、prompt是什么 在大型语言模型集成中,"prompt" 是指您向模型提供的输入文本或指令,以引导模型生成特定类型的响应。这个 prompt 可以是一个问题、一段描述、一个任务说明,甚至是一部分对话历史记录等。通过设计和优化 prompt&a…...
Python实战:SQLAlchemy ORM使用教程
一、SQLAlchemy ORM使用教程 SQLAlchemy是一个流行的Python SQL工具包和对象关系映射(ORM)框架,它为开发人员提供了一种高效、灵活的方式来与数据库进行交互。在本篇博客中,我们将深入探讨SQLAlchemy ORM的核心知识,并…...
能不能绕过c去学c++?
目前做工程开发,基本都是c/c混着用的,c/c是同源的,c/是在c的基础上发展起来的,它们之间有些联系和区别: 区别: 1.可用库不同 c基本是系统底层语言,一般系统底层开发用c(例如&…...
Python 小爬虫:爬取 bing 每日壁纸设为桌面壁纸
请求 URLJSON 版示例代码代码片段注意点headers 中的 User-Agent响应头中的 Content-Type终端通过代理API从 bing.com 找Bing 每日壁纸设置为桌面壁纸代码设定计划任务自动执行 python 脚本请求 URL 通过模仿必应(Bing)自己的 AJAX 调用方式获得请求 URL。 JSON 格式:...

利用textarea和white-space实现最简单的文章编辑器 支持缩进和换行
当你遇到一个非常基础的文章发布和展示的需求,只需要保留换行和空格缩进,你是否会犹豫要使用富文本编辑器?实际上这个用原生的标签两步就能搞定! 1.直接用textarea当编辑器 textarea本身就可以保存空格和换行符,示例如…...

总结mac下解决matplotlib中文显示问题的几种方法
一、前言: 使⽤matplotlib画图时,由于matplotlib默认没有中⽂,显⽰中文时会出现空⽩⼩⽅块。 二、方法: 2.1 matplotlib中使用SimHei字体 1)进入终端后查看matplotlib的字体路径: $ python >>&g…...

探索区块链世界:从加密货币到去中心化应用
相信提到区块链,很多人会想到比特币这样的加密货币,但实际上,区块链技术远不止于此,它正在深刻地改变我们的生活和商业。 首先,让我们来简单了解一下什么是区块链。区块链是一种分布式数据库技术,它通过将…...

GitLab/Github从头开始配置秘钥
1、下载git安装包 CNPM Binaries Mirrorhttps://registry.npmmirror.com/binary.html?pathgit-for-windows/ 拉到页面最底部选择 点进文件夹下载32位或者64位的版本,我的是64位就选择64的版本进行安装 2、傻瓜式安装 3、在相应的文件夹右键选择 UserName为你的用…...
uni.getlocation h5获取定位失败后,阻塞问题
uni.getlocation 在H5中,如果用户未开gps定位或者gps定位信号较差时,定位会失败。这种情况uni.getlocation也不会出现报错,也不会有后续执行,导致代码阻塞,体验极差。 解决方案1:拿不到定位或者定位失败这个…...

Flutter 运行 flutter doctor 命令长时间未响应
由于 Flutter 运行 flutter doctor 命令,会从 pub(https://pub.dev/ 类似于 Node.js 的 npm) 上进行资源的下载,如果没有配置国内镜像,可能会由于其服务器在国外导致资源下载慢或者下载不下来,所以出现了运行 flutter doctor 命令…...

【数据挖掘】练习2:数据管理2
课后作业2:数据管理2 一:上机实验2 # 编写函数stat,要求该函数同时计算均值,最大值,最小值,标准差,峰度和偏度。 install.packages("timeDate") library(timeDate) stat <- func…...

【iOS】——Blocks
文章目录 前言一、Blocks概要1.什么是Blocks 二、Block模式1.block语法2.block类型变量3.截获自动变量值4._Block修饰符5.截获的自动变量 三、Blocks的实现1.Block的实质2.截获自动变量值3._Block说明符4.Block存储域 前言 一、Blocks概要 1.什么是Blocks Blocks是C语言的扩…...

体验OceanBase OBD V2.5.0 组件内扩容和组件变更
背景 OBD 是OceanBase的命令行部署工具,在 obd V2.5.0 版本之前,其主要功能主要是部署各类组件,例如 oceanbase-ce,obproxy-ce,obagent 等。然而,它并不支持组件的变更操作以及组件内部的扩缩容调整。具体来说: 1、若…...

关于前端的学习
目录 前言: 1.初识HTML: 1.1超文本: 1.2标记语言: 2.关于html的基本框架: 3.HTML基本文字标签: 3.1.h标题标签: 3.3 文本内容: 3.4换行的和分割的: 3.5 特殊文字标签: 3.5.1表面上看着三对的结果呈现都是一样的: 3.5.2但是其背后的效果其实是不一样的: 3.6转义字符:…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...