一、引言

本人初次接触HDR方面的知识,有描述不正确的地方烦请见谅。

为方便文章描述,引用部分百度中的文章对HDR图像进行简单的描述。

高动态范围图像(High-Dynamic Range,简称HDR),相比普通的图像,可以提供更多的动态范围和图像细节,根据不同的曝光时间的LDR(Low-Dynamic Range)图像,利用每个曝光时间相对应最佳细节的LDR图像来合成最终HDR图像,能够更好的反映人真实环境中的视觉效果。

现实真正存在的亮度差,即最亮的物体亮度,和最小的物体亮度之比为108, 而人类的眼睛所能看到的范围是105左右,但是一般的显示器,照相机能表示的只有256种不同的亮度,计算一般的显示器,照相机能表示的只有256种不同的亮度机在表示图象的时候是用8bit(256)级或16bit(65536)级来区分图象的亮度的,但这区区几百或几万无法再现真实自然的光照情况。HDR文件是一种特殊图形文件格式,它的每一个像素除了普通的RGB信息,还有该点的实际亮度信息。普通的图形文件每个象素只有0 -255的灰度范围,这实际上是不够的。想象一下太阳的发光强度和一个纯黑的物体之间的灰度范围或者说亮度范围的差别,远远超过了256个级别。因此,一张普通的白天风景图片,看上去白云和太阳可能都呈现是同样的灰度/亮度,都是纯白色,但实际上白云和太阳之间实际的亮度不可能一样,他们之间的亮度差别是巨大的。因此,普通的图形文件格式是很不精确的,远远没有纪录到现实世界的实际状况。而HDR格式则记录了很广范围内的亮度信息。

但是最终,HDR图像要在显示器中显示,还是需要对其数据进行处理的,如何处理即能充分利用这些数据,又能使得图像的显示尽量不丢失细节,是多年来不少图像工作者研究的重点。

简单的说,就是现在有一堆离散的数据,数据的分布范围可能很广,如何把这些离散的数据隐射到0到255之间。

二、相关算法的实现

最简单的当然是线性隐射,先算出离散数据的最大值和最小值,然后将数据线性的拉升至0到255之间,这种直接的操作往往无法得到满意的效果,会导致大量细节丢失,表现在视觉上就是一大块黑色或者一大块白色的,如下图所示:

     

上面两幅图要么是暗部太暗,要么是亮部太亮,整体对比度太强,导致细节信息大量丢失。

针对这一问题,很多人提出了不少相当不错的解决方案,比如基于全局操作符的,其中本文作者实现其中的基于快速双边滤波技术的HDR显示过程。

本文对应的参考论文地址: Fast Bilateral Filtering for the Display of High-Dynamic-Range Images

论文的细路很简单,首先他将原始的HDR数据分解成两个层:base layer 和 detail layer,然后降低base layer的对比度,不改变detail layer的数据,在将这两层合并。

其中:base layer的数据用 HDR原始数据进行双边滤波获取。

算法的简单流程入下所示:

    1、input intensity= 1/61*(R*20+G*40+B)

    2、r=R/(input intensity), g=G/input intensity, B=B/input intensity

    3、log(base)=Bilateral(log(input intensity))

    4、log(detail)=log(input intensity)-log(base)

    5、log (output intensity)=log(base)*compressionfactor+log(detail) - log_absolute_scale

    6、R output = r*10^(log(output intensity)), etc.

上述过程中的变量compressionfactor,log_absolute_scale原文作者的建议取值为:

      compressionfactor = targetContrast/(max(log(base)) - min(log(base))) 对于很多图像,targetContrast使用log(5)能获得较为理想的值。

      而log_absolute_scale= max(log(base))*compressionfactor;

在进行双边的时候,SigmaS一般取值为0.02*Max(Width,Height)比较合适,而SigmaR取值0.4较为理想(这里是指数据量化到了0-1之间的)。

  所以都取优化的参数,则上述过程可以自动进行。

作者提到上述log操作都是以10为底进行的,我觉得以e为底实际效果也没啥区别的。

  三、效果

按照这个思路编制程序后,确实能取得很不错的效果,比如上述两幅图像,按照前面讲的参数取值,解码后得到的图像如下:

 

可见,图像的细节较为完美的体现出来了。

当然,自动的参数不一定能调处最好的效果,比如还是这两幅图,手工选择一些参数,可以调出如下效果:

 

  特别是第一幅图,很有种蒙太奇的感觉。

在看看几张长出现在论文中的图像的结果:

 

 

 

 

          线性解码图                                              双边滤波解码图

  有些图线性解码啥都看不到,双边滤波解码后细节表现的就很清晰了。

HDR格式的原始数据的解码可以借助FreeImage来实现,FreeImage似乎已经讲这些数据量化到了0和1之间(不一定正确)。一段简单的实现代码如下:

  1. public Bitmap LoadHdrFormFreeImage(string FileName)
  2. {
  3. Bitmap Bmp = null;
  4. FREE_IMAGE_FORMAT fif = FREE_IMAGE_FORMAT.FIF_UNKNOWN; ;
  5. if (FreeImage.IsAvailable() == true)
  6. {
  7. fif = FreeImage.GetFileType(FileName, );
  8. if (fif != FREE_IMAGE_FORMAT.FIF_HDR)
  9. {
  10. MessageBox.Show("不是Hdr格式的图像.");
  11. return null;
  12. }
  13. fif = FreeImage.GetFIFFromFilename(FileName);
  14. FIBITMAP Dib = FreeImage.Load(fif, FileName, FREE_IMAGE_LOAD_FLAGS.DEFAULT);
  15. uint Bpp = FreeImage.GetBPP(Dib);
  16.  
  17. if (Bpp != )
  18. {
  19. MessageBox.Show("无法支持的Hdr格式.");
  20. FreeImage.Unload(Dib);
  21. return null;
  22. }
  23. uint Width = FreeImage.GetWidth(Dib); // 图像宽度
  24. uint Height = FreeImage.GetHeight(Dib); // 图像高度
  25. uint Stride = FreeImage.GetPitch(Dib); // 图像扫描行的大小,必然是4的整数倍
  26. IntPtr Bits = FreeImage.GetBits(Dib);
  27.  
  28. float* Data = (float*)Bits;
  29. int Speed, Index;
  30. byte* Pixel;
  31. float Value;
  32.  
  33. if (RawData != null) Marshal.FreeHGlobal((IntPtr)RawData);
  34. RawData = (float*)Marshal.AllocHGlobal((int)Width * (int)Height * * sizeof(float));
  35. CopyMemory(RawData, Data, (int)Width * (int)Height * * sizeof(float));
  36.  
  37. Bmp = new Bitmap((int)Width, (int)Height, PixelFormat.Format24bppRgb);
  38. BitmapData BmpData = Bmp.LockBits(new Rectangle(, , Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
  39. Pixel = (byte*)BmpData.Scan0;
  40.  
  41. for (int Y = ; Y < Height; Y++)
  42. {
  43. Speed = Y * BmpData.Stride;
  44. Index = Y * (int)Width * ;
  45. for (int X = ; X < Width; X++)
  46. {
  47. Value = (Data[Index + ] * );
  48. if (Value > )
  49. Value = ;
  50. else if (Value < )
  51. Value = ;
  52. Pixel[Speed] = (byte)Value;
  53. Value = (Data[Index + ] * );
  54. if (Value > )
  55. Value = ;
  56. else if (Value < )
  57. Value = ;
  58. Pixel[Speed + ] = (byte)Value;
  59. Value = (Data[Index + ] * );
  60. if (Value > )
  61. Value = ;
  62. else if (Value < )
  63. Value = ;
  64. Pixel[Speed + ] = (byte)Value;
  65. Index += ;
  66. Speed += ;
  67. }
  68. }
  69. FreeImage.Unload(Dib);
  70. Bmp.UnlockBits(BmpData);
  71. Bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
  72. return Bmp;
  73. }
  74. else
  75. return null;
  76. }

  以上采用的是线性解码。

  附一个解码的调用程序:http://files.cnblogs.com/Imageshop/ReadHdrTest.rar

更多的源码可参考:http://people.csail.mit.edu/sparis/code/src/tone_mapping

http://people.csail.mit.edu/fredo/PUBLI/Siggraph2002/

一些常见的用于测试的HDR图像可以从这里下载:http://www.pauldebevec.com/Research/HDR/

同样,这种 tone mapping算法也可以用在普通的RGB图像上,效果如下所示:

  

              原图                                    增加base layer的对比度

 

            原图                                    降低base layer的对比度

对于普通的整体偏暗的图像,该方式也能取得相当理想的效果,一些测试结果如下:

  

  

  

很多其他的算法也能起到类似上述的效果,不过他们一般很容易产生halo现象。

相信对于偏亮的普通照片,也可以有同样的处理能力(未找到合适的测试图片)。

*********************************作者: laviewpbt   时间: 2013.11.18   联系QQ:  33184777  转载请保留本行信息************************

基于Fast Bilateral Filtering 算法的 High-Dynamic Range(HDR) 图像显示技术。的更多相关文章

  1. Tone Mapping算法系列一:基于Fast Bilateral Filtering 算法的 High-Dynamic Range(HDR) 图像显示技术。

    一.引言 本人初次接触HDR方面的知识,有描述不正确的地方烦请见谅. 为方便文章描述,引用部分百度中的文章对HDR图像进行简单的描述. 高动态范围图像(High-Dynamic Range,简称HDR ...

  2. Unity Lighting - High Dynamic Range (HDR) 高动态范围(五)

      High Dynamic Range (HDR) 高动态范围 As well as Color Space, the ‘dynamic range’ of your camera needs to ...

  3. 阅读Real-Time O(1) Bilateral Filtering 一文的相关感受。

    研究双边滤波有很长一段时间了,最近看了一篇Real-Time O(1) Bilateral Filtering的论文,标题很吸引人,就研读了一番,经过几天的攻读,基本已理解其思想,现将这一过程做一简单 ...

  4. paper 72 :高动态范围(HDR)图像 HDR (High Dynamic Range)

    In standard rendering, the red, green and blue values for a pixel are each represented by a fraction ...

  5. Computer Vision_33_SIFT:Fast Adaptive Bilateral Filtering——2018

    此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...

  6. 学习《Hardware-Efficient Bilateral Filtering for Stereo Matching》一文笔记。

    个人收藏了很多香港大学.香港科技大学以及香港中文大学里专门搞图像研究一些博士的个人网站,一般会不定期的浏览他们的作品,最近在看杨庆雄的网点时,发现他又写了一篇双边滤波的文章,并且配有源代码,于是下载下 ...

  7. Bilateral Filtering(双边滤波) for SSAO(转)

    原文链接:http://blog.csdn.net/bugrunner/article/details/7170471 另外一篇相似的英文资料:http://homepages.inf.ed.ac.u ...

  8. Bilateral Filtering(双边滤波) for SSAO

    原网址:http://blog.csdn.net/bugrunner/article/details/7170471 1. 简介 图像平滑是一个重要的操作,而且有多种成熟的算法.这里主要简单介绍一下B ...

  9. 简单易学的机器学习算法——基于密度的聚类算法DBSCAN

    一.基于密度的聚类算法的概述     最近在Science上的一篇基于密度的聚类算法<Clustering by fast search and find of density peaks> ...

随机推荐

  1. C#基础知识五之abstract virtual关键字

    abstract 用关键字abstract修饰的类叫做抽象类,且只能作为基类,也不能实例化. 用abstract定义的抽象类中不一定只包含抽象方法 ,可以包含非抽象方法. abstract定义的方法一 ...

  2. 多个提高C#编程能力的建议

    1.总是用属性 (Property) 来代替可访问的数据成员 2.在 readonly 和 const 之间,优先使用 readonly 3.在 as 和 强制类型转换之间,优先使用 as 操作符 4 ...

  3. C#入门经典Lambda

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Lamb ...

  4. 增加删除字段修改字段名,修改表结构,非常用SQL语句技巧总结

    1.为数据表添加一个新字段 Alter TABLE [dbo].[CustomerBackupConfig] Add [Stamp] [timestamp] NULL GO 2.为数据表添加两个新字段 ...

  5. 连接输出 如果存在在php中多次echo输出js的时候

  6. 【开发软件】推荐一款MAC OS X 下php集成开发环境mamp

      这里给大家推荐一款在mac上搭建WEB服务器环境的集成环境安装软件,非常的好用,需要的朋友可以拿去,不用谢 ^_^   之前苦于mac上搭建本地服务器之艰辛,找寻好久都没找到一款类似windows ...

  7. Lind.DDD.Events事件总线~自动化注册

    回到目录 让大叔兴奋的自动化注册 对于领域事件之前说过,在程序启动时订阅(注册)一些事件处理程序,然后在程序的具体位置去发布(触发)它,这是传统的pub/sub模式的体现,当然也没有什么问题,为了让它 ...

  8. 【转】微信小程序给程序员带来的可能是一个赚钱的机遇

    自上周被微信小程序刷屏之后,这周大家都在谈微信小程序能够带来哪些红利的话题,其实我想从程序员的角度来谈谈,带给我们程序员来的红利,或许是我们程序员创业或者赚钱的机遇. 其实我从<作为移动开发程序 ...

  9. GIT 基本操作

    git 流程:1.查看自己所在分支 git branch 2.切换到开发分支 git checkout develop3.把代码拉下来 git fetch4.合并到自己本地 git merge5.切换 ...

  10. SQL 常识

    1.varchar 与 nvarchar 的区别? varchar(n):长度为 n 个字节的可变长度且非 Unicode 的字符数据.n 必须是一个介于 1 和 8,000 之间的数值.存储大小为输 ...