【fishing-pan:https://blog.csdn.net/u013921430 转载请注明出处】

前言

  在实际的拍照过程中,常常会遇到,光线不足的情况。这时候单反用户一般会调大感光度,调大光圈,以让照片整体更清晰,更亮。那么如果照片已经被拍的很暗了,怎么办呢?这时候我们可以利用算法来提升图像整体的光照情况,让图像更清晰。

  2013年这篇《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images》发表在了IEEE上,如题目所说,文章提到将高动态图像在低动态范围显示设备上进行显式时,会面临信息丢失的问题。因此结合传统的CENTER/SURROUND RETINEX 技术提出了全局自适应和局部自适应的HDR实现过程,对HDR image 进行色调映射。而文中的全局自适应方法对于低照度图像具有很好的照度提升效果。作者将他的Matlab脚本上传到了Github,有兴趣的可以点击这里去查看。

全局自适应原理

  全局自适应方法的原理很简单,就是两个公式;
Lg(x,y)=log(Lw(x,y)/Lwˉ+1)log(Lwmax/Lwˉ+1)L_{g}(x,y)=\frac{log(L_{w}(x,y)/\bar{L_{w}}+1)}{log(L_{wmax}/\bar{L_{w}}+1)} Lg​(x,y)=log(Lwmax​/Lw​ˉ​+1)log(Lw​(x,y)/Lw​ˉ​+1)​
  上述式子中,Lg(x,y)L_{g}(x,y)Lg​(x,y) 代表全局自适应处理的输出结果;Lw(x,y)L_{w}(x,y)Lw​(x,y) 表示输入图像的亮度值;LwmaxL_{wmax}Lwmax​ 表示输入图像亮度的最大值;Lwˉ\bar{L_{w}}Lw​ˉ​ 表示输入图像的亮度值的对数平均值;由以下公式求得;
Lwˉ=exp(1m∗n∑log(σ+Lw(x,y)))\bar{L_{w}}=exp\left ( \frac{1}{m*n}\sum log(\sigma +L_{w}(x,y))\right ) Lw​ˉ​=exp(m∗n1​∑log(σ+Lw​(x,y)))
  其中,m∗nm*nm∗n 代表图像的尺寸。σ\sigmaσ 是一个很小的值,为了防止遇到图像中亮度为0的黑点的情况;

  文中提到“随着对数均值趋近于高值,函数的形状从对数趋势转换为线性趋势,因此对低对数均值的图像具有更好的提升效果。”这个方法利用到了图像的对数均值,这就是自适应的体现。

  我在Matlab中分别简单的画了一下曲线,发现在对数均值比较大的时候曲线确实非常接近直线。

代码&结果

   我根据自己的理解以及作者的Matlab脚本,分别利用OpenCV实现了全局自适应方法。两者有很多细节不一样,结果也有一些差异;
   首先是作者的matlab 代码;

function outval = ALTM_Retinex(I)
II = im2double(I);
Ir=double(II(:,:,1)); Ig=double(II(:,:,2)); Ib=double(II(:,:,3));
% Global Adaptation
Lw = 0.299 * Ir + 0.587 * Ig + 0.114 * Ib;% input world luminance values
Lwmax = max(max(Lw));% the maximum luminance value
[m, n] = size(Lw);
Lwaver = exp(sum(sum(log(0.001 + Lw))) / (m * n));% log-average luminance
Lg = log(Lw / Lwaver + 1) / log(Lwmax / Lwaver + 1);
gain = Lg ./ Lw;
gain(find(Lw == 0)) = 0;
outval = cat(3, gain .* Ir, gain .* Ig, gain .* Ib);
figure;
imshow(outval)

   接着是我参考作者提供的脚本实现的C++ 代码

//-------------------------------
//函数名:adaptHDR;参照作者脚本实现
//函数功能:全局自适应光照度提升
//参数:Mat &scr,输入图像
//参数:Mat &dst,输出图像
//------------------------------
bool adaptHDR(Mat &scr, Mat &dst)
{if (!scr.data)  //判断图像是否被正确读取;{cerr << "输入图像有误"<<endl;return false;}int row = scr.rows;int col = scr.cols;Mat ycc;                        //转换空间到YUV;cvtColor(scr, ycc, COLOR_RGB2YUV);vector<Mat> channels(3);        //分离通道,取channels[0];split(ycc, channels);Mat Luminance(row, col, CV_32FC1);for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){Luminance.at<float>(i, j) =(float)channels[0].at<uchar>(i, j)/ 255;}}double log_Ave = 0;double sum = 0;for (int i = 0; i < row; i++)                 //求对数均值{for (int j = 0; j < col; j++){sum += log(0.001 + Luminance.at<float>(i, j));}}log_Ave = exp(sum / (row*col));double MaxValue, MinValue;      //获取亮度最大值为MaxValue;minMaxLoc(Luminance, &MinValue, &MaxValue);Mat hdr_L (row,col,CV_32FC1);for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){hdr_L.at<float>(i, j) = log(1 + Luminance.at<float>(i, j) / log_Ave) / log(1 + MaxValue / log_Ave);if (channels[0].at<uchar>(i, j) == 0)   //对应作者代码中的gain = Lg ./ Lw;gain(find(Lw == 0)) = 0;  {hdr_L.at<float>(i, j) = 0;}else{hdr_L.at<float>(i, j) /= Luminance.at<float>(i, j);}}}vector<Mat> rgb_channels;        //分别对RGB三个通道进行提升split(scr, rgb_channels);for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){int r = rgb_channels[0].at<uchar>(i, j) *hdr_L.at<float>(i, j); if ( r> 255){r = 255; }rgb_channels[0].at<uchar>(i, j) = r;int g = rgb_channels[1].at<uchar>(i, j) *hdr_L.at<float>(i, j); if (g> 255){ g = 255; }rgb_channels[1].at<uchar>(i, j) = g;int b = rgb_channels[2].at<uchar>(i, j) *hdr_L.at<float>(i, j); if (b> 255){ b = 255; }rgb_channels[2].at<uchar>(i, j) = b;}}merge(rgb_channels, dst); return true;
}

  最后是我自己根据自己的理解实现代码

//-------------------------------
//函数名:my_AdaptHDR;自己理解实现
//函数功能:全局自适应光照度提升
//参数:Mat &scr,输入图像
//参数:Mat &dst,输出图像
//------------------------------bool my_AdaptHDR(Mat &scr, Mat &dst)
{if (!scr.data)  //判断图像是否被正确读取;{cerr << "输入图像有误" << endl;return false;}int row = scr.rows;int col = scr.cols;Mat ycc;                        //转换空间到YUV;cvtColor(scr, ycc, COLOR_RGB2YUV);vector<Mat> channels(3);        //分离通道,取channels[0];split(ycc, channels);double log_Ave = 0;double sum = 0;for (int i = 0; i < row; i++)   //求对数均值{for (int j = 0; j < col; j++){sum += log(0.001 + channels[0].at<uchar>(i, j));}}log_Ave = exp(sum / (row*col));double MaxValue, MinValue;      //获取亮度最大值为MaxValue;minMaxLoc(channels[0], &MinValue, &MaxValue);Mat hdr_L(row, col, CV_32FC1);for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){hdr_L.at<float>(i, j) = log(1 + channels[0].at<uchar>(i, j) / log_Ave) / log(1 + MaxValue / log_Ave);}}double L_MaxValue, L_MinValue;            //获取亮度最大值为MaxValue;minMaxLoc(hdr_L, &L_MinValue, &L_MaxValue);for (int i = 0; i < row; i++)            //对亮度通道进行提升;{for (int j = 0; j < col; j++){channels[0].at<uchar>(i, j) = floor(0.5 + 255 * (hdr_L.at<float>(i, j) - L_MinValue) / (L_MaxValue - L_MinValue));}}merge(channels, ycc);cvtColor(ycc, dst, COLOR_YUV2RGB);return true;}

   两种思路的区别主要在于,我的方法是先把图像重RGB空间转换到YUV空间,然后对亮度进行提升,然后转换回RGB空间。这样做有一个问题,只提升了图像的亮度,而没有提高色度和浓度,图像会显得很亮,但是色彩不够鲜艳。而从作者提供的代码的思路来看,他用新得到的图像亮度除以原始图像亮度,得到一个亮度增益,然后将这个增益附加在每个颜色通道上。这样做三通道可以得到同样程度的亮度增强,但是这种方法可能会让图像色彩过饱和。

  来看看结果;


总结

   到底谁的思路好,我觉得我还是尊重作者的思路。但是也许有些情况下,我的方法会取得更好的效果,也可能存在更好的思路。但是最主要的方法还是在上面的两个公式中。而作者在文中主要介绍的是局部的映射方法,全局自适应是为后面做局部自适应进行铺垫的,当然,这篇博客中,不会讲到局部的方法了。

   对于低照度图像的计处理,我并不在行,这也是第一次接触,有些原理上面的东西还没摸清楚,只是觉得有意思就去实现了一下,有些不足的地方,还请大家指针(指正)。

参考

  1. Ahn H, Keum B, Kim D, et al. Adaptive local tone mapping based on retinex for high dynamic range images[C]//Consumer Electronics
    (ICCE), 2013 IEEE International Conference on. IEEE, 2013:
    153-156.

  2. https://github.com/IsaacChanghau/OptimizedImageEnhance/tree/master/matlab/ALTMRetinex

【图像处理】一种低光照图像的亮度提升方法(Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images)相关推荐

  1. matlab图像最暗,一种暗图像的亮度增强方法与流程

    本发明属于图像处理技术领域,涉及图像增强方法,具体涉及一种暗图像的亮度增强方法. 背景技术: 图像增强算法用于增强图像中的有用信息,其目的是要改善图像的视觉效果.目前图像增强常用算法有:直方图均衡化. ...

  2. c#图像处理入门(-bitmap类和图像像素值获取方法)

    c#图像处理入门 -bitmap类和图像像素值获取方法 一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义 ...

  3. 一种新型分割图像中人物的方法,基于人物动作辨认

    想要进行图像分割,传统方法是先检测图中物体,在进行分离.在本文中,来自清华大学.腾讯AI研究室和英国卡迪夫大学的研究者们提出了一种新型分割图像中人物的方法,基于人物动作辨认.以下是论智对原文的编译. ...

  4. loss低但精确度低_低光照图像增强网络-RetinexNet(model.py解析【2】)

    论文地址:https://arxiv.org/pdf/1808.04560.pdf 代码地址:https://github.com/weichen582/RetinexNet 解析目录:https:/ ...

  5. matlab提取遥感图像的点DN值,一种高分辨率遥感图像去雾霾方法

    4 实验验证与分析 实验对象为两颗国产亚米级高分辨率遥感卫星图像, 即GF-2和Superview-1图像.两颗卫星参数如表1所示.其中, GSD为地面采样距离, 即空间分辨率; PAN表示全色谱段; ...

  6. 一种基于协作表示的特征提取投影方法(A collaborative representation based projections method for feature extraction)

    1.CRP简介 文章全称为"A collaborative representation based projections method for feature extraction&qu ...

  7. 图像融合亮度一致_博文精选 | 基于深度学习的低光照图像增强方法总结

    光照估计(illumination estimation)和低光照增强(low-light enhancement)的区别:光照估计是一个专门的底层视觉任务,它的输出结果可以被用到其它任务中,例如图像 ...

  8. python去除图像光照不均匀_CVPR 2020 | 从重建质量到感知质量:用于低光照增强的半监督学习方法...

    CVPR 2020 | 从重建质量到感知质量: 用于低光照增强的半监督学习方法 Code: https://github.com/flyywh/CVPR-2020-Semi-Low-Light 1 背 ...

  9. 低光照图像增强算法汇总

    目录 1.场景需求 2.Retinex算法 2.1 Retinex算法简介 2.2 Retinex核心代码实现 2.3 Retinex算法效果展示与分析 3.LIME算法 3.1.LIME算法简介 3 ...

最新文章

  1. Ubuntu su 认证失败
  2. 速腾雷达客户端软件使用说明
  3. Noip 2016 愤怒的小鸟 题解
  4. 深井软岩巷道群支护技术与应用_引领支护创新,促进行业发展
  5. C++容器的insert()函数有以下三种用法: 最终*it=val;
  6. 腾讯暑期日常实习前端面试
  7. 改变Linux的DNS解析顺序(DNS到hosts)
  8. HDU 2685 I won't tell you this is about number theory
  9. mysql 更新删除数据,MYSQL数据的插入、删除、更新
  10. 冲击IPO:达达的负“重”上市之路
  11. WIN7下如何删除需要管理员权限才能删除的文件夹
  12. centos7时间校准
  13. Epicor 调试 customization
  14. springboot整合jwt_springboot整合jwt实现身份验证
  15. 帆软报表列表_动态图表 - FineReport报表官网
  16. 修改登录页面Login
  17. 清华大学(深圳)吕帅课题组招收计算机领域博士后
  18. StoneDB 团队成员与 MySQL 之父 Monty 会面,共话未来数据库形态
  19. 公共基础知识题库 计算机考点,公共基础知识考点
  20. Java 并发编程实战演练

热门文章

  1. 约翰·钱伯斯 创新想法
  2. Serverless 实战 —— 利用OneIndex-Serverless无成本搭建属于你自己的网盘
  3. NGINX配置邮件代理服务器
  4. Centos7使用Docker创建Oracle11g
  5. 界面发布2019中国最富1000人榜:凛冬望春,马云问鼎中国首富
  6. 持续交付之软件包管理maven篇
  7. html5和flash播放器
  8. 函数式编程 -- 函子(Functor)
  9. C#LeetCode刷题之#203-删除链表中的节点(Remove Linked List Elements)
  10. Jmeter获取性能指标