直方图均衡化(HE)是一种很常用的直方图类方法,基本思想是通过图像的灰度分布直方图确定一条映射曲线,用来对图像进行灰度变换,以达到提高图像 对比度的目的。该映射曲线其实就是图像的累计分布直方图(CDF)(严格来说是呈正比例关系)。然而HE是对图像全局进行调整的方法,不能有效地提高局部 对比度,而且某些场合效果会非常差。如:

上述原图和HE结果图的直方图分别为:

因为从原图的直方图中求取的映射函数(CDF)形状为:

将它作用于原图像会导致直方图被整体右移,没有充分利用整个灰度动态范围。

为了提高图像的局部对比度,有人提出将图像分成若干子块,对子块进行HE处理,这便是AHE(自适应直方图均衡化),使用AHE处理上图得到:

结果直方图:

可 以看出结果图像的灰度较好地分布在了全部动态范围上。从结果图像上也可以看出,局部对比度的确得到了提高,视觉效果要优于HE。但是仍然有个问题:AHE 对局部对比度提高过大,导致图像失真。看看背景区,本来的黑色背景现在已经变成白色了,原因是因为背景区中的局部子块统计得到的直方图在0灰度处幅值太高 (实际上全黑子图基本上就集中在0灰度处),这样导致映射曲线斜率过高,将所有灰度值都映射到整个灰度轴的右侧,所以结果图中背景偏白(另外局部对比度过 高还会放大图像中的噪声,不过上图并没有体现这一点)。

为了解决这个问题,我们必须对局部对比度进行限制,这就是我们今天的主题:CLAHE

从HE中我们知道,映射曲线T与CDF关系为:(M为最高灰度值,N为像素个数)

限制对比度,其实就是限制CDF的斜率,又因累计分布直方图CDF是灰度直方图Hist的积分:

反过来:

也就是说限制CDF的斜率就相当于限制Hist的幅度。

因此我们需要对子块中统计得到的直方图进行裁剪,使其幅值低于某个上限,当然裁剪掉的部分又不能扔掉,我们还需要将这部分裁剪值均匀地分布在整个灰度区间上,以保证直方图总面积不变,如下图:

可以看到,这时直方图又会整体上升了一个高度,貌似会超过我们设置的上限。其实在具体实现的时候有很多解决方法,你可以多重复几次裁剪过程,使得上升的部分变得微不足道,或是用另一种常用的方法:

设 裁剪值为ClipLimit,求直方图中高于该值的部分的和totalExcess,此时假设将totalExcess均分给所有灰度级,  求出这样导致的直方图整体上升的高度L=totalExcess/N,以upper= ClipLimit-L为界限对直方图进行如下处理:

(1)若幅值高于ClipLimit,直接置为ClipLimit;

(2)若幅值处于Upper和ClipLimit之间,将其填补至ClipLimit;

(3)若幅值低于Upper,直接填补L个像素点;

经过上述操作,用来填补的像素点个数通常会略小于totalExcess,也就是还有一些剩余的像素点没分出去,这个剩余来自于(1)(2)两处。这时我们可以再把这些点均匀地分给那些目前幅值仍然小于ClipLimit的灰度值。

这里给出一段代码:(摘自Matlab的adapthisteq.m),描述的就是上述过程:

% total number of pixels overflowing clip limit in each bin
totalExcess = sum(max(imgHist - clipLimit,)); % clip the histogram and redistribute the excess pixels in each bin
avgBinIncr = floor(totalExcess/numBins);
upperLimit = clipLimit - avgBinIncr; % bins larger than this will be
% set to clipLimit % this loop should speed up the operation by putting multiple pixels
% into the "obvious" places first
for k=:numBins
if imgHist(k) > clipLimit
imgHist(k) = clipLimit;
else
if imgHist(k) > upperLimit % high bin count
totalExcess = totalExcess - (clipLimit - imgHist(k));
imgHist(k) = clipLimit;
else
totalExcess = totalExcess - avgBinIncr;
imgHist(k) = imgHist(k) + avgBinIncr;
end
end
end % this loops redistributes the remaining pixels, one pixel at a time
k = ;
while (totalExcess ~= )
%keep increasing the step as fewer and fewer pixels remain for
%the redistribution (spread them evenly)
stepSize = max(floor(numBins/totalExcess),);
for m=k:stepSize:numBins
if imgHist(m) < clipLimit
imgHist(m) = imgHist(m)+;
totalExcess = totalExcess - ; %reduce excess
if totalExcess ==
break;
end
end
end k = k+; %prevent from always placing the pixels in bin #
if k > numBins % start over if numBins was reached
k = ;
end
end

CLAHE和AHE中另一个重要的问题:插值。

将图像进行分块处理,若每块中的像素点仅通过该块中的映射函数进行变换,则会导致最终图像呈块状效应:

为了解决这个问题,我们需要利用插值运算,也就是每个像素点出的值由它周围4个子块的映射函数值进行双线性插值得到,如下图:

上图中,为了求蓝色像素点处的值,需要利用它周围四个子块的映射函数分别做变换得到四个映射值,再对这四个值做双线性插值即可。

当 然对于边界处的像素点则不是通过四个子块进行插值,如上图红色像素点直接以一个子块的映射函数做变换,绿色像素则以两个子块做映射函数做线性插值。这里讲 的边界处像素是指落在图像左上角,左下角、右上角,右下角的四个子块中心像素点围成的四边形之外的像素。如下图,将图像分为8x8子块,边界像素即落在灰 色区域的像素点。

利用插值对图像进行处理的整体架构如下:

for (Y = ; Y <= TileY; Y++) //TileY为Y方向网格数
{
if (Y == )
{
SubY = TileYDim >> ; YU = ; YB = ;
}
else if (Y == TileY)
{
SubY = TileYDim >> ; YU = TileY-; YB = YU;
}
else
{
SubY = TileYDim; YU = Y - ; YB = Y;
}
for (X = ; X <= TileX; X++) //TileX为X方向网格数
{
if (X == )
{
SubX = TileXDim >> ; XL = ; XR = ;
}
else if (X == TileX)
{
SubX = TileXDim >> ; XL = TileX - ; XR = XL;
}
else
{
SubX = TileXDim; XL = X - ; XR = X;
}
MapLU = &pMapArray[numBins * (YU * TileX + XL)];//左上角映射函数
MapRU = &pMapArray[numBins * (YU * TileX + XR)];//右上角映射函数
MapLB = &pMapArray[numBins * (YB * TileX + XL)];//左下角映射函数
MapRB = &pMapArray[numBins * (YB * TileX + XR)];//右下角映射函数
Interpolate(pImPointer,Stride,Channel,MapLU,MapRU,MapLB,MapRB,SubX,SubY,aLUT);//插值
pImPointer += SubX;
}
pImPointer+=(SubY-)*Stride;
}

注意的是,上述循环需要(TileX+1)*(TileY+1)次,而不是TileX*TileY次。,原因很简单,以X方向为例,两侧边界处的半宽子块(灰色区)也各需要处理一次,如下图:

通过双线性插值可以基本消除块状效应:


于彩色图像,三通处理分开处理会导致严重的偏色,故我们可以将其进行颜色空间转换(如RGB转为HSV),然后仅对亮度分量处理,再反变换回RGB空间。
不过网上有高手将R、G、B统一处理[2](也就相当于把一个像素点拆成三个像素点),这样得到的效果也不错,而且省去了颜色空间转换的时间,我们这里也
仿照他来吧:

另外,CLAHE对雾天图像处理效果也不错:

至于编程,我基本就是翻译adaphisteq.m,另外还有一些参考资源:CLAHE代码(MATLAB)

这里给出编译好的文件,有兴趣的朋友可以下载看看:ImageProcess(CLAHE)

参考:

[1]https://en.wikipedia.org/wiki/Adaptive_histogram_equalization

[2]http://www.cnblogs.com/Imageshop/archive/2013/04/07/3006334.html

对比度受限的自适应直方图均衡化(CLAHE)的更多相关文章

  1. 图像增强 | CLAHE 限制对比度自适应直方图均衡化

    1 基本概述 CLAHE是一个比较有意思的图像增强的方法,主要用在医学图像上面.之前的比赛中,用到了这个,但是对其算法原理不甚了解.在这里做一个复盘. CLAHE起到的作用简单来说就是增强图像的对比度 ...

  2. 【图像增强】CLAHE 限制对比度自适应直方图均衡化

    文章目录: 目录 1 基本概述 2 竞赛中的CLAHE实现 3 openCV绘制直方图 4 对比度Contrast 5 Contrast Stretching 6 Histogram Equaliza ...

  3. 机器学习进阶-直方图与傅里叶变化-直方图均衡化 1.cv2.equalizeHist(进行直方图均衡化) 2. cv2.createCLAHA(用于生成自适应均衡化图像)

    1. cv2.equalizeHist(img)  # 表示进行直方图均衡化 参数说明:img表示输入的图片 2.cv2.createCLAHA(clipLimit=8.0, titleGridSiz ...

  4. opencv —— equalizeHist 直方图均衡化实现对比度增强

    直方图均匀化简介 从这张未经处理的灰度图可以看出,其灰度集中在非常小的一个范围内.这就导致了图片的强弱对比不强烈. 直方图均衡化的目的,就是把原始的直方图变换为在整个灰度范围(0~255)内均匀分布的 ...

  5. S0.6 直方图均衡化

    S0.6 直方图均衡化 直方图均衡化能提高图像的质量 累积直方图 这是后面均衡化所要知道的先验知识. 如果说直方图统计的是等于像素值的数量,那么累积直方图统计的就是小于等于像素值的数量 均衡化步骤 我 ...

  6. OpenCV计算机视觉学习(9)——图像直方图 & 直方图均衡化

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 1, ...

  7. OpenCV2马拉松第9圈——再谈对照度(对照度拉伸,直方图均衡化)

    收入囊中 lookup table 对照度拉伸 直方图均衡化 葵花宝典 lookup table是什么东西呢? 举个样例,假设你想把图像颠倒一下,f[i] = 255-f[i],你会怎么做? for( ...

  8. 【16位RAW图像处理三】直方图均衡化及局部直方图均衡用于16位图像的细节增强。

    通常我们生活中遇到的图像,无论是jpg.还是png或者bmp格式,一般都是8位的(每个通道的像素值范围是0-255),但是随着一些硬件的发展,在很多行业比如医疗.红外.航拍等一些场景下,拥有更宽的量化 ...

  9. 图像增强算法(直方图均衡化、拉普拉斯、Log、伽马变换)

    一.图像增强算法原理 图像增强算法常见于对图像的亮度.对比度.饱和度.色调等进行调节,增加其清晰度,减少噪点等.图像增强往往经过多个算法的组合,完成上述功能,比如图像去燥等同于低通滤波器,增加清晰度则 ...

随机推荐

  1. 解决echart在IE中使用时,在div中加入postion后图表不显示问题

    <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="height:400px;width:1 ...

  2. oracle技术总结

    http://www.cnblogs.com/jimeper/ http://blog.csdn.net/dragonxiangfu http://www.boobooke.com/bbs/threa ...

  3. Linux pipe 源代码分析

    Linux pipe 源代码分析      管道pipe作为Unix中历史最悠久的IPC机制,存在各个版本号的Unix中,主要用于父子进程之间的通信(使用fork,从而子进程会获得父进程的打开文件表) ...

  4. Python爬虫开发【第1篇】【机器视觉及Tesseract】

    ORC库概述 在读取和处理图像.图像相关的机器学习以及创建图像等任务中,Python 一直都是非常出色的语言.虽然有很多库可以进行图像处理,但在这里我们只重点介绍:Tesseract 1.Tesser ...

  5. 【iOS系列】-UINavigationController的使用(Segue传递数据)

    [iOS系列]-UINavigationController的使用 UINavigationController是以以栈(先进后出)的形式保存子控制器, 常用属性: UINavigationItem有 ...

  6. 【MongoDB】The description of procedure in MongoDB

    In this blog the procedure of mongodb will be described in details. It is known that mongodb has pro ...

  7. 2016-2017 ACM-ICPC Southwestern European Regional Programming Contest (SWERC 2016) E.Passwords AC自动机+dp

    题目链接:点这里 题意: 让你构造一个长度范围在[A,B]之间 字符串(大小写字母,数字),问你有多少种方案 需要满足条件一下: 1:构成串中至少包含一个数字,一个大写字母,一个小写字母:   2:不 ...

  8. 更改android studio AVD 位置

  9. Test redis

    单机测试: public class RedisClient{ private Jedis jedis; private JedisPool jedisPool; private ShardedJed ...

  10. Lightoj 1029 - Civil and Evil Engineer

    1029 - Civil and Evil Engineer    PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limi ...