【16位RAW图像处理三】直方图均衡化及局部直方图均衡用于16位图像的细节增强。
通常我们生活中遇到的图像,无论是jpg、还是png或者bmp格式,一般都是8位的(每个通道的像素值范围是0-255),但是随着一些硬件的发展,在很多行业比如医疗、红外、航拍等一些场景下,拥有更宽的量化范围的图像也越来越常见,比如10位(带宽1024)、12位(带宽4096)、14位(带宽16384)以及16位(带宽32768)的图像,当然还有以浮点数保存的高动态图像(hdr格式的那种),但是目前大部分的显示器还是只支持8位图像的显示,因此,对于这一类图像,一个很重要的问题就是如何将他们的数据量化到0到255之间,而且尽量的保留更多的细节信息,这也就是常见的HDR到LDR的过程。 在我前面的博客里其实也有讲到这方面的信息,本文再尝试将直方图均衡化引入到这个过程中。
首先,我们统一一下由一组ushort数据(带宽是10、12、14、16的Raw图像,都可以用ushort数据类型表示)直接量化为8位显示的函数,这样我们的处理就可以集中在原始的ushort数据经过算法处理后得到新的ushort数据的过程。这个函数简单如下所示:
// 这个只是个辅助用来显示的函数
int IM_ConvetUshortToByte(unsigned short *Src, unsigned char *Dest, int Width, int Height, int Stride, int WindowWidth, int WindowLevel)
{
int Channel = Stride / Width;
int Min = WindowLevel - WindowWidth / 2;
int Max = WindowLevel + WindowWidth / 2;
if (Min < 0) Min = 0;
if (Max > 65535) Max = 65535;
int Diff = Max - Min;
if (Diff == 0)
{
memset(Dest, Max, Height * Stride * sizeof(unsigned char));
}
else
{
unsigned char Table[65536];
for (int X = 0; X < 65536; X++)
{
if (X < Min)
Table[X] = 0;
else if (X > Max)
Table[X] = 255;
else
Table[X] = IM_ClampToByte((X - Min) * 255 / Diff);
}
for (int Y = 0; Y < Height; Y++)
{
unsigned short *LinePS = Src + Y * Width * Channel;
unsigned char *LinePD = Dest + Y * Stride;
for (int X = 0; X < Width * Channel; X++)
{
LinePD[X] = Table[LinePS[X]];
}
}
}
return IM_STATUS_OK;
}
其中的WindowWidth表示窗宽,WindowLevel表示窗位,这个其实是借助了医学图像上的一些概念,对于普通的RAW图像,比如12位,我们通常就认为WindowWidth = 1 << 12 = 4096,而WindowLevel则就为窗宽的一半。
一般来说,RAW图像中的数据每一行是没有冗余量的,即没有BMP位图中所谓的扫描行对齐的概念。所以可以直接遍历每一个数据。
那么我们来看看如何把普通的直方图均衡化算法利用到RAW图像中来。
以灰度图为例,如果已经统计了图像的直方图,则直方图均衡化的新的隐射曲线由以下代码获取:
for (int Y = 0, Num = 0; Y < 256; Y++)
{
Num = Num + Histgram[Y];
Table[Y] = (unsigned char)(((float)Num * 255) / (Width * Height)); // 注意(float)强制转换的位置,否则对于大图就溢出了,2014.11.1修正
}
简单的,扩展到ushort类型的RAW图像,我们也可以用以下的类似代码搞定:
for (int Y = 0, Num = 0; Y < WindowWidth; Y++)
{
Num = Num + Histgram[Y];
Table[Y] = (unsigned short)(((float)Num * WindowWidth) / (Width * Height)); // 注意(float)强制转换的位置,否则对于大图就溢出了,2014.11.1修正
}
关于这个WindowWidth,我觉得一般可以由两种方法得到,一个是我们已经知道了这个硬件生成的图像是多少位的,常见的就是10、12、14、16等,这个时候WindowWidth可以直接指定,而如果只有RAW数据,一种方式就是根据数据的最大值来确定WindowWidth,即取大于最大值的2的整数次幂的那个值。
如下代码所示:
ushort MaxValue = IM_GetMaxValue(ImageData, ImageWidth * ImageHeight * ImageChannel);
int ProperWindowWidth = 1;
while (ProperWindowWidth < MaxValue)
ProperWindowWidth *= 2;
WindowWidth = ProperWindowWidth;
WindowLevel = WindowWidth / 2;
这个简单的数据范围的调整,我们看下一些效果:


a、RAW数据直接ConvetUshortToByte的8位结果图 b、直方图均衡后的RAW数据转换为8位的效果图 c、对8位的a图直接在直方图均衡后的结果图
通过比较可以看到确实还是有明显的增强效果的,但是似乎有过曝的现象。
我们可以仿照一种强化的基于局部直方图裁剪均衡化的对比度调节算法 或者限制对比度自适应直方图均衡化算法原理、实现及效果 文中的方法将局部直方图均衡化引入到16位中,尝试看看效果是否有改善,这里不多谈,只说下我遇到的几个问题。
一个是在ClipHistogram 这个函数的过程中,我们发现往往会出现这个函数陷入死循环的结果,特备是对于12位以上的图像,因此,这个可能需要其他的一些改进方案。
二个是我们还可以学习【算法随记四】自动色阶、对比度、直方图均衡等算法的一些小改进 一文中的getWeightedValue函数,即对获取的直方图数据开平方,起到一定的压缩作用,这个可以明显的改善上述的曝光效果。
另外,同样的道理,在局部算法里,还可以不用直方图均衡化算法,可以使用任何其他的基于直方图的调整基数,比如自动色剂等等。

a、RAW数据直接ConvetUshortToByte的8位结果图 b、局部压缩直方图均衡后的RAW数据转换为8位的效果图
很明显这样处理后的效果要好很多。细节、曝光等等都较为合适。
关于16位RAW图像,本人开发了一个简易的增强和处理程序,可在https://files.cnblogs.com/files/Imageshop/Optimization_Demo_16.rar下载测试。

其他相关链接:
【16位RAW图像处理一】:基于Fast Bilateral Filtering 算法的 High-Dynamic Range(HDR) 图像显示技术。
【16位RAW图像处理二】:一种自适应对数映射的高对比度图像显示技术及其速度优化。
【16位RAW图像处理三】直方图均衡化及局部直方图均衡用于16位图像的细节增强。的更多相关文章
- 图像处理之直方图均衡化及C源码实现
1 直方图均衡化(Histogram Equalization)简介 图像对比度增强的方法可以分成两类:一类是直接对比度增强方法;另一类是间接对比度增强方法.直方图拉伸和直方图均衡化是两种最常见的间接 ...
- OpenCV-跟我一起学数字图像处理之直方图均衡化
从这篇博文开始,小生正式从一个毫不相干专业转投数字图像处理.废话不多说了,talk is cheap. show me the code. 直方图均衡化目的 由于一些图像灰度的分布过于集中,这样会导致 ...
- 机器学习进阶-直方图与傅里叶变化-直方图均衡化 1.cv2.equalizeHist(进行直方图均衡化) 2. cv2.createCLAHA(用于生成自适应均衡化图像)
1. cv2.equalizeHist(img) # 表示进行直方图均衡化 参数说明:img表示输入的图片 2.cv2.createCLAHA(clipLimit=8.0, titleGridSiz ...
- 彩色图像的直方图均衡化matlab代码
彩色图像的直方图均衡化 - YangYudong2014的专栏 - CSDN博客 http://blog.csdn.net/yangyudong2014/article/details/4051503 ...
- 16位/32位/64位CPU的位究竟是说啥
平时,我们谈论CPU,都会说某程序是32位编译,可以跑在32位机或64位机,或则是在下载某些开源包时,也分32位CPU版本或64CPU位版本,又或者在看计算机组成相关书籍时,特别时谈到X86 CPU时 ...
- [Effective JavaScript 笔记] 第7条:视字符串为16位的代码单元序列
Unicode编码,基础:它为世界上所有的文字系统的每个字符单位分配一个唯一的整数,该整数介于0~1114111之间,在Unicode术语中称为代码点(code point). 和其它字符编码几乎没有 ...
- 16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16
一.Intel 32 位处理器的工作模式 如上图所示,Intel 32 位处理器有3种工作模式. (1)实模式:工作方式相当于一个8086 (2)保护模式:提供支持多任务环境的工作方式,建立保护机制 ...
- opencv——图像的灰度处理(线性变换/拉伸/直方图/均衡化)
实验内容及实验原理: 1.灰度的线性变换 灰度的线性变换就是将图像中所有的点的灰度按照线性灰度变换函数进行变换.该线性灰度变换函数是一个一维线性函数:f(x)=a*x+b 其中参数a为线性函数的斜率, ...
- 图像处理 Matlab实现线性点运算、非线性点运算、点运算与直方图、直方图均衡化
今天,我们学习了直方图.于是乎,回来我就用matlab代码实现一下.昨天受到道路检测老师课上一个内容的影响(对于道路裂缝的检测,我突发奇想,如果对于道路图像进行操作,是否能够让裂缝与道路分离,使得图像 ...
随机推荐
- 基于区域的CNN(R-CNN)
基于区域的CNN(R-CNN) Region-based CNNs (R-CNNs) 基于区域的卷积神经网络或具有CNN特征的区域(R-CNN)是一种将深度模型应用于目标检测的开创性方法.在本节中,将 ...
- 【译】.NET 5 中的诊断改进
基于我们在 .NET Core 3.0 中引入的诊断改进,我们一直在努力进一步改进这个领域.我很高兴介绍下一波诊断改进. 诊断工具不再需要 .NET SDK 直到最近,.NET 诊断工具套件还只能作为 ...
- VNC 相关
vncserver启动报错root A VNC server is already running as :1 [root@42 ~]# service vncserver startStarting ...
- 性能工具之Jmeter小白入门系列之一
一.简单了解 Apache JMeter The Apache JMeter application is open source software, a 100% pure Java applica ...
- 【题解】hdu2044一只小蜜蜂
斐波拉契数列的应用 题目 有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数.其中,蜂房的结构如下所示. Input输入数据的第一行是一个整数N,表 ...
- ES6中的Generator函数
今天小编发现一个es6中的新概念,同时也接触到了一个新关键字yeild,下面我就简单和大家聊聊es6中的generator函数.大家还可以关注我的微信公众号,蜗牛全栈. 一.函数声明:在functio ...
- 教你用python搭建一个「生活常识解答」机器人
今天教大家如何用Python爬虫去搭建一个「生活常识解答」机器人. 思路:这个机器人主要是依托于"阿里达摩院发布的语言模型PLUG",通过爬虫的方式,发送post请求(提问),然后 ...
- Netty 框架学习 —— 基于 Netty 的 HTTP/HTTPS 应用程序
通过 SSL/TLS 保护应用程序 SSL 和 TLS 安全协议层叠在其他协议之上,用以实现数据安全.为了支持 SSL/TLS,Java 提供了 javax.net.ssl 包,它的 SSLConte ...
- google protobuf的原理和思路提炼
之前其实已经用了5篇文章完整地分析了protobuf的原理.回过头去看,感觉一方面篇幅过大,另一方面过于追求细节和源码,对protobuf的初学者并不十分友好,因此这篇文章将会站在"了解.使 ...
- uniapp 微信小程序扫码处理
1.view 代码 <view class="v-main-scan"> <uni-icons @click="scanCode" clas ...