目录
前言
这里将会介绍一种图像增强的算法——retinex算法。在查找资料的过程中,我发现对于这一部分的讲解并不是很清楚,所以这里我觉得有必要写一篇通俗且清晰的介绍。这里主要介绍三种retinex算法的变种,它们在原有的retinex算法的基础上做了进一步的改进和优化。
概念介绍
retinex算法理论
retinex的理论基础是三色理论和颜色恒常性。
这意味着物体的颜色是由它对红、绿、蓝三种光线的反射能力来决定的,而不是由反射光强度的绝对值来决定的。同时,物体的颜色也不会受到光照不均匀性的影响,具有一致性。
retinex模型利用这种颜色恒常性,可以在动态范围压缩、边缘增强和颜色恒常三个方面打到平衡,因此可以对各种不同类型的图像进行自适应的增强,不同于传统的只能增强图像某一类特征的方法。
retinex理论认为图像是由照度图像与反射图像组成。照度图像指的是物体的入射分量的信息,用表示;反射图像指的是物体的反射部分,用
表示。公式:
同时,由于对数形式与人类在感受亮度的过程属性最相近,因此将上述过程转换到对数域进行处理,这样做也将复杂的乘法转换为加法:
当然,上面的流程是retinex基本框架,不同的retinex算法可能会有不同的细节处理方式。
单尺度retinex(ssr)
单尺度视网膜算法是 retinex 算法中最基础的一个算法。运用的就是上面的方法:
- 将输入图像转换为对数空间:
其中,为输入图像,
为对数图像。
- 对对数图像进行高斯平滑:
其中,为平滑后的对数图像,
为高斯滤波核。
- 计算照度图像:
其中,为照度图像,即物体的入射分量信息。
- 计算反射图像:
其中,为反射图像,即物体的反射部分。
- 将照度图像和反射图像进行指数变换:
其中,和
分别为指数变换后的照度图像和反射图像。
- 对输出图像进行亮度调整:
其中,为输出图像,
为反射图像中的最大值。通过将反射图像归一化到[0,1]区间,再将其放大到[0, 255]区间,可以增强图像的对比度和细节。
需要注意的是,ssr算法中只使用了一个固定的高斯滤波尺度(没有使用高斯滤波,只是高斯核),因此称为单尺度retinex。虽然算法简单,但在一些场景下仍能取得较好的效果。
多尺度retinex(msr)
1.将原始图像分解为多个尺度的图像
......
其中为高斯滤波器,
表示第
层尺度的高斯核尺度,
表示第
层尺度的图像。
2.对每一层尺度图像进行 retinex 处理
其中表示第
层尺度的反射分量,
表示第
层尺度的光照分量,
表示第
层尺度的增强后的图像。
3.将各层增强后的图像进行加权融合,得到最终的增强图像
其中表示第
层尺度的权重。
综上所述,多尺度retinex算法与单尺度retinex算法的不同之处在于对图像的分解方式,它将原始图像分解为多个尺度的图像,然后对每一层尺度的图像进行retinex处理,最后进行加权融合得到最终的增强图像。
多尺度自适应增益retinex(msrcr)
msrcr算法是在msr算法的基础上进一步改进而来的,主要是通过自适应增益控制算法的方式来实现对图像的增强。相对于msr算法,msrcr算法主要增加了以下步骤:
- 多尺度分解:将原始图像分解成不同尺度的子图像。
- 对数域操作:对每个尺度下的子图像进行对数变换,得到对数域图像。
- 自适应增益控制:对于每个尺度下的对数域图像,通过计算每个像素点周围像素点的标准差,来确定该像素点的增益系数,即:
其中,表示像素点
的增益系数,
表示像素点
周围的像素点的标准差,
为一个常数,用于控制增益系数的大小。
- 增强处理:对每个尺度下的对数域图像进行乘法增强,即:
其中,为增强后的像素值,
为原始对数域图像的像素值。
- 逆对数变换:对每个尺度下的增强后的对数域图像进行逆对数变换,得到增强后的子图像。
- 尺度合成:将所有增强后的子图像进行合成,得到最终增强后的图像。
需要注意的是,msrcr算法中的增益系数计算公式与msr算法不同,增加了常数,这样可以控制增益系数的大小,避免增益系数过大导致图像的过度增强。此外,msrcr算法中还增加了多尺度分解、增强处理和尺度合成等步骤,进一步提高了对不同尺度、不同光照条件下图像的增强效果。
opencv实现retinex算法
在python中是没有集成的第三方库的函数(可能调查不到位),这里我们就根据它的这个原理来实现这三种retinex算法。
在我这里我讲详细一点,尽量让大家去理解,而不是只是套代码去用。
ssr算法
def ssr(img, sigma):
img_log = np.log1p(np.array(img, dtype="float") / 255)
img_fft = np.fft.fft2(img_log)
g_recs = sigma // 2 + 1
result = np.zeros_like(img_fft)
rows, cols, deep = img_fft.shape
for z in range(deep):
for i in range(rows):
for j in range(cols):
for k in range(1, g_recs):
g = np.exp(-((np.log(k) - np.log(sigma)) ** 2) / (2 * np.log(2) ** 2))
result[i, j] += g * img_fft[i, j]
img_ssr = np.real(np.fft.ifft2(result))
img_ssr = np.exp(img_ssr) - 1
img_ssr = np.uint8(cv2.normalize(img_ssr, none, 0, 255, cv2.norm_minmax))
return img_ssr
实现思路:
mcr算法
def msr(img, scales):
img_log = np.log1p(np.array(img, dtype="float") / 255)
result = np.zeros_like(img_log)
img_light = np.zeros_like(img_log)
r, c, deep = img_log.shape
for z in range(deep):
for scale in scales:
kernel_size = scale * 4 + 1
# 高斯滤波器的大小,经验公式kernel_size = scale * 4 + 1
sigma = scale
img_smooth = cv2.gaussianblur(img_log[:, :, z], (kernel_size, kernel_size), sigma)
img_detail = img_log[:, :, z] - img_smooth
result[:, :, z] += cv2.resize(img_detail, (c, r))
img_light[:, :, z] += cv2.resize(img_smooth, (c, r))
img_msr = np.exp(result+img_light) - 1
img_msr = np.uint8(cv2.normalize(img_msr, none, 0, 255, cv2.norm_minmax))
return img_msr
实现思路:
关于尺度选择
msrcr算法
def msrcr(img, scales, k):
img_log = np.log1p(np.array(img, dtype="float") / 255)
result = np.zeros_like(img_log)
img_light = np.zeros_like(img_log)
r, c, deep = img_log.shape
for z in range(deep):
for scale in scales:
kernel_size = scale * 4 + 1
# 高斯滤波器的大小,经验公式kernel_size = scale * 4 + 1
sigma = scale
g_ratio=sigma**2/(sigma**2+k)
img_smooth = cv2.gaussianblur(img_log[:, :, z], (kernel_size, kernel_size), sigma)
img_detail = img_log[:, :, z] - img_smooth
result[:, :, z] += cv2.resize(img_detail, (c, r))
result[:, :, z]=result[:, :, z]*g_ratio
img_light[:, :, z] += cv2.resize(img_smooth, (c, r))
img_msrcr = np.exp(result+img_light) - 1
img_msrcr = np.uint8(cv2.normalize(img_msrcr, none, 0, 255, cv2.norm_minmax))
return img_msrcr
实现思路:
效果展示
上(左)原图,上(右)ssr,下(左)msr,下(右)msrcr
if __name__=="__main__":
path=r'./images/ai2.png'
img=cv2.imread(path)
imgssr=ssr(img,7)
imgmsr=msr(img, [1, 3, 5])
imgmsrcr=msrcr(img,[1,3,5],12)
imgstack=zjr.stackimages(0.6,([img,imgssr],[imgmsr,imgmsrcr]))
cv2.imshow("retinex",imgstack)
cv2.waitkey(0)
总结
在尝试实现像retinex这种没有集成函数的算法时,我遇到了一些困难。这些算法需要深入理解其原理和流程,并在代码具体实现。为了解决这些问题,我参考了其他大佬的代码,但大多数代码并不完整,经常出现报错。我也只能依照自己对算法的理解来实现其功能,可能存在部分错误。因此,我希望可以与大家共同讨论,一起学习和进步。
参考文章
(6条消息) retinex 算法_chaiky的博客-csdn博客
(7条消息) retinex算法详解_chenlee_1的博客-csdn博客
(6条消息) retinex图像增强算法——ssr,msr,msrcr,msrcp,automsrcr_chaoy6565的博客-csdn博客
传统图像处理——图像增强retinex - 知乎 (zhihu.com)
发表评论