如何运用16位RAW图像处理中的直方图均衡化与局部均衡化提升图像细节?

摘要:通常我们生活中遇到的图像,无论是jpg、还是png或者bmp格式,一般都是8位的(每个通道的像素值范围是0-255),但是随着一些硬件的发展,在很多行业比如医疗、红外、航拍等一些场景下,拥有更宽的量化范围的图像也越来越常见,比如10位(带宽
通常我们生活中遇到的图像,无论是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图像中来。
阅读全文