行业知识
Retinex图像增强算法——SSR,MSR,MSRCR,MSRCP,autoMSRCR
系列文章目录
关于OpenCV���一些图像处理函数
图象基本操作(读取、显示、通道提取、边界填充、融合、保存)
Retinex图像增强算法——SSR,MSR,MSRCR,MSRCP,autoMSRCR
文章目录
- 系列文章目录
- 前言
- 一、Retinex理论
- 二、算法目的:
- 三、Retinex基础算法
- 四、算法介绍及流程
- 4.1 SSR算法介绍
- 4.2 SSR操作流程
- 4.3 MSR算法介绍
- 4.4 MSR操作流程
- 4.5 MSRCR算法介绍
- 4.6 MSRCR操作流程
- 4.7 MSRCP算法介绍
- 4.8 MSRCP操作流程
- 4.9 automatedMSRCR算法
- 4.10 automatedMSRCR算法流程
- 4.11 线性量化公式
- 4.12 自动色阶平衡
- 总代码
- 五、结果分析
- 总结
前言
其实这是我的数字图像分析与处理的大作业。
一、Retinex理论
始于Edwin Herbert Land(埃德温·赫伯特·兰德)于1971年提出的一种被称为色彩恒常的理论,并基于此理论的图像增强方法。Retinex 这个词由视网膜(Retina)和大脑皮层(Cortex)合成而来.之所以这样设计,表明Land他也不清楚视觉系统的特性究竟取决于此两个生理结构中的哪一个,抑或两者都有关系。其基本思想是人感知到某点的颜色和亮度不仅仅取决于该点进入人眼的绝对光线,还和周围的颜色和亮度有关。不同于传统的图像增强算法,如线性、非线性变换、图像锐化等只能增强图像的某一类特征,如压缩图像的动态范围,或增强图像的边缘等,Retinex可以在动态范围压缩、边缘增强和颜色恒常三方面达到平衡,可以对各种不同类型的图像进行自适应性地增强,在很多方面得到了广泛的应用。
Retinex理论的基本内容是物体的颜色是由物体对长波(红)、中波(绿)和短波(蓝)光线的反射能力决定的,而不是由反射光强度的绝对值决定的;物体的色彩不受光照非均性的影响,具有一致性,即Retinex理论是以色感一致性(颜色恒常性)为基础的。如下图所示,观察者所看到的物体的图像S是由物体表面对入射光L反射得到的,反射率R由物体本身决定,不受入射光L变化。40多年来,研究人员模仿人类视觉系统发展了Retinex算法,从单尺度Retinex算法,MSR改进成多尺度加权平均的MSR算法,再发展成彩色恢复多尺度MSRCR算法和色彩增益加权的AutoMSRCR算法。
二、算法目的:
去除环境照度,抽取反射光,从而得到物体真实图像。更好的利用图像中的原像素点去估计原始照度。解决由环境等因素影响导致对比度不足、细节不充分、色彩偏差、噪声过大等问题。
三、Retinex基础算法
如下图所示,图像可以看做是由入射图像和反射图像构成,入射光照射在反射物体上,通过反射物体的反射形成反射光进入人眼,就是人类所看到的图像。最后形成的图像可以用公式表示为:S(x,y)=R(x,y)L(x,y)
其中,L(x,y)表示亮度分量,R(x,y)表示物体反射分量,S(x,y)表示观测到的图像S(x,y)表示观测到的图像。Retinex理论的基本思想就是在原始图像中,通过某种方法去除或者降低入射图像的影响,从而尽量的保留物体本质的反射属性图像。其一般的处理过程如下所示:
Retinex理论增强算法的思想就是利用式S(x,y)=R(x,y)L(x,y),去除亮度分量 L求得反射分量R,从而达到图像增强效果。两边取对数
**log(S(x,y))=log(L(x,y))+log(R(x,y))** **log(R(x,y))=log(S(x,y))-log(L(x,y))**由上面两个公式可知,只需要估计亮度分量L就能求得反射分量,因此L的估计直接决定图像恢复效果.Jobson等论证了高斯卷积函数可以从已知图像SS中更好地估计出亮度分量,即L(x,y)=S(x,y)G(x,y)
其中‘’代表卷积操作,高斯函数G(x,y)=k⋅exp(-(x2+y2)/σ^2 ),σ是高斯函数尺度参数,k为归一化因子,使∬G(x,y)dxdy=1。
四、算法介绍及流程
4.1 SSR算法介绍
SSR(Single Scale Retinex)的思想:在原始图像中,通过某种办法抑制入射图像L的影响,尽可能保留反映物体本质特征的反射属性。
SSR假设原始图像中光照图像是缓慢变换的,即入射图像L可以看做图像的低频成分(使用高斯低通滤波将低频成分滤出)。用原始图像减去入射图像即可得到表明图像内在属性的发射图像。公式可参考上面介绍。
4.2 SSR操作流程
1.将图像进行log变换。
2.然后将log图像进行高斯模糊 (即得到低频成分),也就是求出L(x,y)=S(x,y)*G(x,y)。
3.利用原图和模糊之后的log图像做差分,也就是得到log(R(x,y))=log(S(x,y))-log(L(x,y)),求出物体SSR图像R。
4. 将R数据放缩到0-255,转为jpg图片格式,即为MSR图像。(这个步骤只是为了显示图像,后面其他算法调用此函数没有放缩这一步骤。)
4.3 MSR算法介绍
MSR(Multi Scale Retinex)是在SSR基础上发展来的,优点是可以同时保持图像高保真度与对图像的动态范围进行压缩的同时,MSR也可实现色彩增强、颜色恒常性、局部动态范围压缩、全局动态范围压缩,也可以用于X光图像增强。多尺度增强算法MSR(Multi-Scale Retinex)最为经典的就是3尺度的,大、中、小,既能实现图像动态范围的压缩,又能保持色感的一致性较好。在SSR基础上改进,能够保持图像的高保真度和对图像的动态范围进行压缩。其实就是将多个SSR做平均,区别在于高斯模糊部分选择了不同的sigma。公式如下:
log(R(x,y))=Weight1⋅log(Rσ1(x,y))+Weight2⋅log(Rσ2(x,y))+Weight3⋅log(Rσ3(x,y))4.4 MSR操作流程
1.对原始图像R、G、B三个维度分别进行三次不同sigma参数的SSR操作。
2.高斯模糊选择15,80,200作为高斯模糊sigma参数。
3.对三次的SSR结果加权求平均,然后把三个维度合并,得到R。
4.将R数据放缩到0-255,转为jpg图片格式,即为MSR图像。
4.5 MSRCR算法介绍
由于R是对数域的输出,要转换为数字图像,必须将他们量化为[0,255]的数字图像范畴,关于这个量化的算法,有这极为重要的意义,他的好坏直接决定了最终输出的图像的品质。在前面的增强过程中,图像也可能会因为增加了噪声,而使得图像的局部细节色彩失真,不能显现出物体的真正颜色,整体视觉效果变差。针对这一点不足,MSRCR(Multi-Scale Retinex with Color Restoration)在MSR的基础上,加入了色彩恢复因子C来调节由于图像局部区域对比度增强而导致颜色失真的缺陷,从而把相对较暗区域的信息凸显出来,达到了消除图像色彩失真的缺陷。处理后的图像局部对比度提高,亮度与真实场景相似,在人们视觉感知下,图像显得更加逼真,但是MSRCR算法处理图像后,像素值一般会出现负值。所以从对数域r(x, y)转换为实数域R(x, y)后,需要通过改变增益G,偏差b对图像进行修正。
I(x,y)表示第i个通道的图像,C_i表示第i个通道的彩色回复因子,用来调节3个通道颜色的比例,f(·)表示颜色空间的映射函数,β是增益常数,α是受控制的非线性强度,G和b为经验参数。
4.6 MSRCR操作流程
1.使用高斯函数对原始图像进行低通滤波。
2.将原始图像与滤波后图像转换到对数域做差(即将图像中的低频成分减掉),得到对数域的反射图像。
3.多尺度重复1,2步骤,将对数域的反射图像在像素层面上进行图像求和(即MSR的步骤),得到MSR结果。
4.在通道层面,对原始图像求和,作为各个通道的归一化因子,权重矩阵归一化,并转换到对数域,得到图像颜色增益,MSR结果按照权重矩阵与颜色增益重新组合(连乘)。
5.图像恢复:颜色恢复后的图像乘以图像像素值改变范围的增益,加图像像素值改变范围的偏移量,通过色阶自动平衡得到最终结果。
4.7 MSRCP算法介绍
对于一些原始图像HUE较为合理的图,如果用经典的MSRCR算法,会导致处理后的图容易偏色,为了解决这一现象提出了对图像的Intensity数据进行MSR处理,然后再把数据根据原始的RGB的比例映射到每个通道,这样就能在保留原始颜色分布的基础上增强图像。
4.8 MSRCP操作流程
1.首先对图像每个像素点进行分量相加求均值,然后使用高斯函数对原始图像进行低通滤波。
2.将原始图像与滤波后图像转换到对数域做差(即将图像中的低频成分减掉),得到对数域的反射图像。
3.将对数域的反射图像在像素层面上进行图像求和(即MSR的步骤),得到MSR结果,然后进行线性处理和自动色阶平衡。
4. 然后再把数据根据原始的RGB的比例映射到每个通道,最终整合输出图像。
4.9 automatedMSRCR算法
色彩增益加权的autoMSRCR算法,这个算法我没有查到太多资料,只找到了一段程序。看过代码之后,我认为autoMSRCR算法是先对图片进行了SMR算法,由于Retinex数据处理后的高动态特性,数据分布很广,会出现严重的两极化现象,一般难以获得满意的结果。所以autoMSRCR算法这里对SMR的结果是数组进行色彩增益加权,这里是对R 、G、B三个维度分别根据各自像素值设定不同的上下限阈值,去除较小和较大的像素值,防止两极化现象出现。
4.10 automatedMSRCR算法流程
1、首先对图片进行了SMR算法,生成SMR算法的像素值数组(维度为三维)。
2、对不同维度的像素进行去重之后、从小到大排序并统计不同元素的个数。筛选出最小值和最大值和像素等于0值的个数。
3、对每个维度的SMR像素值进行缩放,具体操作为先确定下限和上限(下限确定:像素值小于0且这个像素值的个数小于0像素的个数的十分之一。上限确定:像素值大于0且这个像素值的个数小于0像素的个数的十分之一。然后依次遍历每一个维度的每一个像素值,确定每一个维度的上限和下限。)
4、把SMR像素数组里超过上限和低于下限的值用上限值和下限值替换。线性放缩到0-255,取整可视化图形。
4.11 线性量化公式
还是直接看代码吧 ,对着代码看公式比较好懂。
4.12 自动色阶平衡
Simplest Color Balance 自动色阶平衡
按照一定的百分比去除最小和最大的部分,然后中间的部分重新线性量化到0和255之间。
def simplestColorBalance(img, low_clip, high_clip): # 这里 low_clip和high_clip 是经验值为认为设定的 0.01、0.99 total = img.shape[0] * img.shape[1] # 多少个像素点 for i in range(img.shape[2]): # 维度 # np.unique对数据去重后从小到大排序 # unique为从小到大排序的数组 # counts不同元素的个数 unique, counts = np.unique(img[:, :, i], return_counts=True) current = 0 # 这个for循环 求出 下限 low_val 和 上限 high_val # 具体的原理我也不清楚 # 从输出来讲缩小了像素值的范围 ,防止出现两极化现象。 for u, c in zip(unique, counts): if float(current) / total
总代码
代码几乎每一行我都写了注释,这里就不解释了。
import numpy as npimport cv2#------------------------------------------------------------## SSR# retinex SSR# # 用data数组里的最小数替代0# np.nonzero(a) 取出a里面非零的数 # -----------------------------------------------------------#def replaceZeroes(data): min_nonzero = min(data[np.nonzero(data)]) # 取data数组里除0外最小的数 data[data == 0] = min_nonzero # 把data数组里的0的数用 min_nonzero 替换掉 return datadef SSR(src_img, size): L_blur = cv2.GaussianBlur(src_img, (size, size), 0) # 高斯函数 img = replaceZeroes(src_img) # 去除0 这里为什么要去0 呢 我个人认为是后面有log运算 0不能运算 L_blur = replaceZeroes(L_blur) # 去除0 dst_Img = cv2.log(img/255.0) # 归一化取log dst_Lblur = cv2.log(L_blur/255.0) # 归一化取log dst_IxL = cv2.multiply(dst_Img, dst_Lblur) # 乘 L(x,y)=S(x,y)*G(x,y) log_R = cv2.subtract(dst_Img, dst_IxL) # 减 log(R(x,y))=log(S(x,y))-log(L(x,y)) dst_R = cv2.normalize(log_R,None, 0, 255, cv2.NORM_MINMAX) # 放缩到0-255 log_uint8 = cv2.convertScaleAbs(dst_R) # 取整 return log_uint8def SSR_image(image): size = 3 b_gray, g_gray, r_gray = cv2.split(image) # 拆分三个通道 # 分别对每一个通道进行 SSR b_gray = SSR(b_gray, size) g_gray = SSR(g_gray, size) r_gray = SSR(r_gray, size) result = cv2.merge([b_gray, g_gray, r_gray]) # 通道合并。 return result#------------------------------------------------------##------------------------------------------------------## MSR# retinex MSR#------------------------------------------------------#def MSR(img, scales): weight = 1 / 3.0 # 不同ssr的权重 scales_size = len(scales) # 做多少次ssr h, w = img.shape[:2] # 宽高 log_R = np.zeros((h, w), dtype=np.float32) # 创建0数组 for i in range(scales_size): # img = replaceZeroes(img) # 去0值 L_blur = cv2.GaussianBlur(img, (scales[i], scales[i]), 0) # 高斯函数 L_blur = replaceZeroes(L_blur) # 去0值 dst_Img = cv2.log(img/255.0) # 归一化取log dst_Lblur = cv2.log(L_blur/255.0) # 归一化取log dst_Ixl = cv2.multiply(dst_Img, dst_Lblur) # 乘 L(x,y)=S(x,y)*G(x,y) # 公式如下 也就是求三次 ssr 结果乘权重然后相加在一起。 # log(R(x,y))=log(S(x,y))-log(L(x,y)) # log(R(x,y))=Weight1⋅log(Rσ1(x,y))+Weight2⋅log(Rσ2(x,y))+Weight3⋅log(Rσ3(x,y)) log_R += weight * cv2.subtract(dst_Img, dst_Ixl) dst_R = cv2.normalize(log_R,None, 0, 255, cv2.NORM_MINMAX) # 0-1 缩放到0-255 log_uint8 = cv2.convertScaleAbs(dst_R) # 取整 return log_uint8def MSR_image(image): scales = [15, 101, 301] # 卷积核大小 b_gray, g_gray, r_gray = cv2.split(image) # 拆分通道 r g b b_gray = MSR(b_gray, scales) g_gray = MSR(g_gray, scales) r_gray = MSR(r_gray, scales) result = cv2.merge([b_gray, g_gray, r_gray]) return result#-----------------------------------------------------------## 这个求出来数据没有转换不能直接显示 MSRCR MSRCP调用#-----------------------------------------------------------## SSRdef singleScaleRetinex(img, sigma): # SSR # L(x,y)=S(x,y)*G(x,y) # log(R(x,y))=log(S(x,y))-log(L(x,y)) retinex = np.log10(img) - np.log10(cv2.GaussianBlur(img, (0, 0), sigma)) return retinex#-----------------------------------------------------------## MSR MSRCR MSRCP调用def multiScaleRetinex(img, sigma_list): retinex = np.zeros_like(img) # 创建0数组 for sigma in sigma_list: # 循环 retinex += singleScaleRetinex(img, sigma) # 高斯模糊 # log(R(x,y))=Weight1⋅log(Rσ1(x,y))+Weight2⋅log(Rσ2(x,y))+Weight3⋅log(Rσ3(x,y)) # 加权求均值 retinex = retinex / len(sigma_list) return retinex#-----------------------------------------------------------## 这个函数求的是 色彩恢复因子Cidef colorRestoration(img, alpha, beta): img_sum = np.sum(img, axis=2, keepdims=True) # 按通道求和 color_restoration = beta * (np.log10(alpha * img) - np.log10(img_sum)) return color_restoration# Simplest Color Balance 自动色阶平衡# 按照一定的百分比去除最小和最大的部分,然后中间的部分重新线性量化到0和255之间。def simplestColorBalance(img, low_clip, high_clip): # 这里 low_clip和high_clip 是经验值为认为设定的 0.01、0.99 total = img.shape[0] * img.shape[1] # 多少个像素点 for i in range(img.shape[2]): # 维度 # np.unique对数据去重后从小到大排序 # unique为从小到大排序的数组 # counts不同元素的个数 unique, counts = np.unique(img[:, :, i], return_counts=True) current = 0 # 这个for循环 求出 下限 low_val 和 上限 high_val # 具体的原理我也不清楚 # 从输出来讲缩小了像素值的范围 ,防止出现两极化现象。 for u, c in zip(unique, counts): if float(current) / total 0 and c
程序参数
#----------------------------------------------------#
#“sigma_list”: [15, 80, 200],多尺度高斯模糊sigma值
#“G” : 5.0,增益
#“b” : 25.0,偏差
#“alpha” : 125.0,
#“beta” : 46.0,
#“low_clip” : 0.01,
#“high_clip” : 0.99
#---------------------------------------------------#
可视化代码
import sysimport osimport cv2import jsonimport numpy as np import matplotlib.pyplot as plt# plt显示挂内核 添加下面两行代码import os # 添加代码①os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # 添加代码②def cv_show1(name, img): # 长宽高 cv2.imshow(name, img) cv2.waitKey(0) cv2.destroyAllWindows()image = cv2.imread("D:/code/data/test2.jpg") # -----------------------------------------------------## SSRimg_ssr = SSR_image(image)#cv_show1('SSR',img_ssr)cv2.imwrite("D:/code/data/SSR.jpg",img_ssr) # MSRimg_msr = MSR_image(image)#cv_show1('MSR',img_msr)cv2.imwrite("D:/code/data/MSR.jpg",img_msr)# MSRCRimg_msrcr = MSRCR(image,[15, 80, 200],5,25,125,46,0.01,0.99)#cv_show1('MSRCR',img_msrcr)cv2.imwrite("D:/code/data/MSRCR.jpg",img_msrcr)# MSRCPimg_msrcp = MSRCP(image,[15, 80, 200],0.01,0.99) #cv_show1('MSRCP',img_msrcp)cv2.imwrite("D:/code/data/MSRCP.jpg",img_msrcp)# automatedMSRCRimg_amsrcr = automatedMSRCR(image,[15, 80, 200])#cv_show1('automatedMSRCR',img_amsrcr)cv2.imwrite("D:/code/data/automatedMSRCR.jpg",img_amsrcr)#---------------------------------------------------------## 显示plt.subplot(2,3,1),plt.imshow(image),plt.title("原图",fontname="SimHei")plt.subplot(2,3,2),plt.imshow(img_ssr),plt.title("SSR",fontname="SimHei")plt.subplot(2,3,3),plt.imshow(img_msr),plt.title("MSR",fontname="SimHei")plt.subplots_adjust(top=0.8)plt.subplot(2,3,4),plt.imshow(img_msrcr),plt.title("MSRCR",fontname="SimHei")plt.subplots_adjust(top=0.8)plt.subplot(2,3,6),plt.imshow(img_amsrcr),plt.title("automatedMSRCR",fontname="SimHei")plt.subplots_adjust(top=0.8)plt.subplot(2,3,5),plt.imshow(img_msrcp),plt.title("MSRCP",fontname="SimHei")plt.subplots_adjust(top=0.8)#-----------------------------------------------------#五、结果分析
SSR能够较好地完成动态范围的压缩,暗区域的细节能得到较好地增强,但也明显出现了色差。同单尺度相比,MSR既能实现图像动态范围的压缩,又能保持色感的一致性较好。从图中可以看出MSR比SSR还原出的原图更清晰一点,虽然不太明显。MSRCR效果要比MSR好很多,MSRCR利用彩色恢复因子C,调节原始图像中3个颜色通道之间的比例关系基本消除了色偏,结果图也没有跟SSR和MSR一样发白。MSRCP的结果图更具色彩感,图中的车灯和房间里的光线都得到了很好的还原。autoMSRCR的结果图是最贴近自然图片的,很好的把图片暗黑色的部分展现了出来且没有色偏。
Retinex算法的效果对于一些正常的图像处理后的效果并不佳,我们可以认为他就是为那些在外界环境不理想的状态下拍摄的图像增强而设计的,特别的,对于航拍的雾天图片,医学上的成像图片等成像条件恶劣的图有很明显的效果。
总结
额,,,终于水完了 。