介绍
红外热像仪在采集图像时由于ADC、放大电路、读出电路的影响,会产生非均匀的竖条纹噪声,大部分人的做法是对红外机芯做标定,也就是两点校正和单点校正。
但是也存在校正后还会出现竖条纹噪声的情况,可能是由于硬件性能的影响,或者是温漂的影响,再或者是被摄物体温度范围超出标定范围,积分时间不匹配等等原因。
出现竖条纹噪声会影响使用者的观感,一般会采用单点校正来使画面变得均匀,但毕竟单点校正只对像元变化的偏置做改变,而没有对斜率还是之前的,所以再换环境后依旧会出现竖条纹。当然也可以使用基于场景的非均匀校正,已经有好多人介绍过了。
我看到Effective Strip Noise Removal for Low-Textured Infrared Images Based on 1-D Guided Filtering这篇文章,就尝试用python实现了一下
python实现一维引导滤波去除竖条纹
对8bit的红外图像进行竖条纹噪声去除
#定义函数
import numpy as np
import cv2
import matplotlib.pyplot as plt
def Normalize_img(img):
min_n = np.min(img)
max_n = np.max(img)
Normalize_image = ((img-min_n)/(max_n-min_n))
return Normalize_image
def guideFilter(I, p, winSize, eps):
mean_I = cv2.blur(I, winSize) # I的均值平滑
mean_p = cv2.blur(p, winSize) # p的均值平滑
mean_II = cv2.blur(I * I, winSize) # I*I的均值平滑
mean_Ip = cv2.blur(I * p, winSize) # I*p的均值平滑
var_I = mean_II - mean_I * mean_I # 方差
cov_Ip = mean_Ip - mean_I * mean_p # 协方差
a = cov_Ip / (var_I + eps) # 相关因子a
b = mean_p - a * mean_I # 相关因子b
mean_a = cv2.blur(a, winSize) # 对a进行均值平滑
mean_b = cv2.blur(b, winSize) # 对b进行均值平滑as
q = mean_a * I + mean_b
return q
进行行列的一维引导滤波
image = cv2.imread(r'test.bmp', cv2.COLOR_BGR2GRAY)
image= image[:, :, 0]
plt.figure(figsize=(5, 5))
plt.imshow(image,cmap="gray")
#-----------------------------------------------------------#
row_guideFilter_img=np.zeros((len(image),len(image[0])))
col_guideFilter_img=np.zeros(((len(image),len(image[0]))))
#-------------------行-----------------------------------#
I = image/255.0 #将图像归一化
p =I
eps =20
winSize = (9,1)
row_guideFilter_img = guideFilter(I, p, winSize, eps)
row_guideFilter_img = p-row_guideFilter_img
plt.figure(figsize=(5, 5))
plt.imshow(row_guideFilter_img,cmap="gray")
#------------------列------------------------------------#
eps =20
winSize = (1,15)
guideFilter_img_lie = guideFilter(p ,row_guideFilter_img, winSize, eps)
col_guideFilter_img=p-guideFilter_img_lie
guideFilter_img_lie = Normalize_img(guideFilter_img_lie)
plt.figure(figsize=(5, 5))
plt.imshow(guideFilter_img_lie,cmap="gray")
#---------------还原为8bit------------------------------#
col_guideFilter_img = Normalize_img(col_guideFilter_img) * 255
col_guideFilter_img [col_guideFilter_img > 255] = 255
col_guideFilter_img = np.round(col_guideFilter_img )
final_img = col_guideFilter_img.astype(np.uint8)
plt.figure(figsize=(5, 5))
plt.imshow(final_img,cmap="gray")
结果
原图:
行滤波:
列滤波提取竖条纹噪声:
去除竖条纹:
保留竖边信息
可以看到处理完的图片完全没有了竖条纹,但同时也竖边细节也没有了,所以作者用sobel提取了图像中竖边细节信息,在一维引导滤波的时候将判断为细节的竖条纹保留下来了。我也尝试了一下,有一点效果,但不知道是不是理解的不对,结果没那么明显。可能还要再调调参数?
//提取竖条纹细节,参数固定了,要改自己改
def shuDetail(img):
img_blur = cv2.GaussianBlur(img, (11, 55), 0)
# x梯度
xgrad = cv2.Sobel(img_blur, cv2.CV_16SC1, 1, 0)
# y梯度
ygrad = cv2.Sobel(img_blur, cv2.CV_16SC1, 0, 1)
edge1 = cv2.Canny(xgrad, ygrad, 9,50)
return edge1
sobel提取的竖边信息:
加一段这个,也可能不对,仅供参考吧
img_shu = shuDetail(image)
guideFilter_img_shu = guideFilter(I, img_shu, winSize, eps)
guideFilter_img_shu = I-guideFilter_img_shu
guideFilter_img_shu = Normalize_img(guideFilter_img_shu)
plt.figure(figsize=(5, 5))
plt.imshow(guideFilter_img_hang+guideFilter_img_shu,cmap="gray")
row_guideFilter_img = guideFilter_img_hang+guideFilter_img_shu
没加sobel提取细节:
有竖边细节:
其他图片尝试
讨论
感觉有效果,但被滤掉的竖边细节确实不好恢复,滤波完的图像亮度对比度都会变低,可以再用直方图均衡一下,也可以用细节增强再增强一下边缘。
这个方法在8bit红外图像的处理中还可以,我也尝试了16bit图像,直接处理的话调整参数后,再动态范围压缩和细节增强,在竖条纹噪声不强时是有些用的。但还是转为8bit再用可能更明显一点