ACE 算法源自 retinex 算法,可以调整图像的对比度,实现人眼色彩恒常性和亮度恒常性,通过差分来计算目标点与周围像素点的相对明暗关系来校正最终像素值,有很好的增强效果。但是计算复杂度非常高,本文提出一种有效的快速实现方法。
为叙述方便,这里假设后面的图像都是归一化到 [0,1] 之间的浮点数图像。
ACE 算法的计算公式为:
Y = ∑(g(I(x0)-I(x))w(x0,x)) / ∑(w(x0,x)) x 属于 I (1)
其中,w 是权重参数,离中心点像素越远 w 值越小,可以直接取值欧氏距离。g() 是相对对比度调节参数,非线性的,简单取如下计算方法:
g(x) = max(min(ax, 1.0), -1.0) (2)
这里 a 是控制参数,值越大,细节增强越明显。计算完后,还要对 Y 进行一次归一化即可得到最终的增强图像。
ACE 的增强效果普遍与 retinex 好。需要注意的是,ACE 中当前像素是与整个图像的其他像素做差分比较,计算复杂度非常非常高,这也是限制它应用的最主要原因,本文主要基于两个假设:(1)对一副图像 ACE 增强后得到输出 Y,如果对 Y 再进行一次 ACE 增强,输出仍然是 Y 本身;(2)对一副图像的 ACE 增强结果进行尺寸缩放得到 Y,对 Y 进行 ACE 增强,输出仍然是 Y 本身。这两个假设我没法证实,呵呵,就算臆想的吧。
如果上面假设成立,我们就可以对图像进行缩放得到 I1,对 I1 的 ACE 增强结果进行尺度放大(与 I 尺寸一样)得到 Y1,那么 Y 和 Y1 是非常接近的,我们只需要在 Y1 基础上进一步处理即可。这里就又引申了两个细节问题:1)如何快速的求 I1 的 ACE 增强结果? 其实很简单,对它再次缩放得到 I2,求 I2 的增强结果,依次类推,就是金字塔结构思想。2) 如何在 Y1 基础上进一步处理得到 Y? 因为是在整个图像域进行差分比较运算,与近处邻域像素的比较构成了 Y 的细节信息,与远处像素的比较构成了 Y 的全局背景信息,那么我们合理假设,Y 和 Y1 的全局背景信息相同,只更新细节信息即可,也就是,我们需要在 Y1 基础上加上 I 中邻近像素的差分结果,并减去 Y1 中邻近像素的差分结果就是最终的输出 Y。
上面说的有点绕,慢慢看吧。
下面是 python 代码
- import cv2 import numpy as np import math def stretchImage(data, s = 0.005, bins = 2000) : #线性拉伸,去掉最大最小0.5 % 的像素值,然后线性拉伸至 [0, 1] ht = np.histogram(data, bins);
- d = np.cumsum(ht[0]) / float(data.size) lmin = 0;
- lmax = bins - 1
- while lmin < bins: if d[lmin] >= s: break lmin += 1
- while lmax >= 0 : if d[lmax] <= 1 - s: break lmax -= 1
- return np.clip((data - ht[1][lmin]) / (ht[1][lmax] - ht[1][lmin]), 0, 1) g_para = {}
- def getPara(radius = 5) : #根据半径计算权重参数矩阵global g_para m = g_para.get(radius, None) if m is not None: return m size = radius * 2 + 1 m = np.zeros((size, size)) for h in range( - radius, radius + 1) : for w in range( - radius, radius + 1) : if h == 0 and w == 0 : continue m[radius + h, radius + w] = 1.0 / math.sqrt(h * *2 + w * *2) m /= m.sum() g_para[radius] = m
- return m def zmIce(I, ratio = 4, radius = 300) : #常规的ACE实现para = getPara(radius) height,
- width = I.shape zh,
- zw = [0] * radius + range(height) + [height - 1] * radius,
- [0] * radius + range(width) + [width - 1] * radius Z = I[np.ix_(zh, zw)] res = np.zeros(I.shape) for h in range(radius * 2 + 1) : for w in range(radius * 2 + 1) : if para[h][w] == 0 : continue res += (para[h][w] * np.clip((I - Z[h: h + height, w: w + width]) * ratio, -1, 1)) return res def zmIceFast(I, ratio, radius) : #单通道ACE快速增强实现height,
- width = I.shape[: 2]
- if min(height, width) <= 2 : return np.zeros(I.shape) + 0.5 Rs = cv2.resize(I, ((width + 1) / 2, (height + 1) / 2)) Rf = zmIceFast(Rs, ratio, radius)#递归调用Rf = cv2.resize(Rf, (width, height)) Rs = cv2.resize(Rs, (width, height)) return Rf + zmIce(I, ratio, radius) - zmIce(Rs, ratio, radius)
- def zmIceColor(I, ratio = 4, radius = 3) : #rgb三通道分别增强,ratio是对比度增强因子,radius是卷积模板半径res = np.zeros(I.shape) for k in range(3) : res[: , :, k] = stretchImage(zmIceFast(I[: , :, k], ratio, radius)) return res
- if __name__ == '__main__': m = zmIceColor(cv2.imread('p4.bmp') / 255.0) * 255 cv2.imwrite('zmIce.jpg', m)
下面是实验结果, 上边是原图,下边是增强结果。
来源: http://www.bubuko.com/infodetail-1861092.html