[1] https://blog.csdn.net/qq_32808045/article/details/108855380
[2] https://blog.csdn.net/star_sky_sc/article/details/122371392
[3] 龚云,颉昕宇.一种改进同态滤波的井下图像增强算法[J/OL].煤炭科学技术:1-8[2022-12-09].DOI:10.13199/j.cnki.cst.2021-0774.
[4] https://blog.csdn.net/LaoYuanPython/article/details/120850922
同态滤波是一种全局增强算法,对于明暗差距很大的图像,在增强某部分像素时,会使一部分像素过增强,对高光区和阴影区增强效果不好。
伽马校正只用一个参数γ调节,缺乏自适应性,对明暗分布不均的图片容易造成过增强现象。
用一个补偿的累计分布函数(cdf)代替γ系数,即:
可以看到,公式中的校正系数1-cdf(l)<1,也就是说伽马校正中的γ<1,此时图像暗的地方被增强,图像整体变亮。在灰度值较低的区域(较暗的区域),cdf(l)较小,1-cdf(l)较大,增强效果明显;在灰度值较高的区域(较亮的区域)cdf(l)较大,1-cdf(l)较小,增强效果减弱。AGCWD通过对灰度进行拉伸,减少暗像元素,增加亮像元素,灰度级分布更平滑,缓解后续同态滤波因光暗分布不均而造成的过增强现象。
用于统计灰度值的直方图,x轴为灰度值0-255,y轴为灰度值对应的像素个数。
cv2.calcHist([img],[channels],mask,[histSize],range)
[img]:[]括起来,输入图像,uint8或者float32;
[channels]:[]括起来,灰度图——[0],彩图——[0]、[1]、[2]分别对应BGR;
mask:掩膜图像,对图像某一部分统计直方图,None表示对整幅图统计直方图;
histSize:[]括起来,BIN的数目。[256]表示0-255分为256份;[16]表示0-255均分为16份;
range:像素值范围,通常为[0,256]。
返回变换后的图像,将图像变换为指定的色彩模式,PIL有九种不同模式:1、L、P、RGB、RGBA、CMYK、YCbCr、I、F
"1"表示黑白图;注:黑点的密集程度可以表示不同灰度
"L"表示8位灰度图。
传统同态滤波算法滤波器(高斯型):
需要指定的参数:
rH高频增益
rL低频增益
c锐化系数
n滤波器阶数
对于一般的同态滤波器:
也有三个参数需要指定。其中rH、rL、n往往需要依靠经验选取。
单参数滤波器:
只有一个参数k需要选取。
原理:S型函数的剖面与同态滤波的剖面有相似结构;
优点:通过三维结构图可以看出,单参数同态滤波器由中心频率到高频的过渡较传统同态滤波器更平缓,斜率更小,滤波更加均匀。
输出与()中形状相同、元素全为零的张量(数组)
np.fft.fft()一维傅里叶变换
np.fft.fft2()二维傅里叶变换
np.fft.fftn()n维傅里叶变换
np.fft.shift()将FFT输出中的直流分量移动到频谱中央
np.fft.fftfreq()返回傅里叶变换采样频率
math.log(x [,base])
base表示基数,默认为e
np.real(val)返回复数参数的实部
经典直方图均衡化是一种全局算法,当只需对图像某一部分进行均衡化时不再适用
抑制直方图均衡化过程中由于部分灰度级被过多合并,部分灰度级丢失所引起的噪声过度增强,提高图像对比度的同时,使图像轮廓更清晰。
opencv中通过类CLAHE实现对比度受限的自适应直方图
retval = cv.creatCLAHE(clipLimit = 40,tilesGridSize = (8,8))
titlesGridSize 图像被分成称为tiles的小块,在opencv中tilesGridSize默认为(8,8)即将整个图分为8x8的64块,对每一块进行直方图均衡处理;
clipLimit 裁剪限制,与对比度受限相对应,将所有bins超出的像素数累加后平均分配到所有bins;
retval 返回创建的CLAHE类对象。
src 输入图像,8位或16位灰度图
dst 输出图像,8位或16位灰度图
获取当前CLAHE对象设置的ClipLimit值
设置当前CLAHE对象设置ClipLimit值
获取当前CLAHE对象设置的tilesGridSize值
设置当前CLAHE对象设置tilesGridSize值
这里仍然使用一般的同态滤波而不是单参数同态滤波
import os
import cv2
import numpy as np
#import matplotlib.pyplot as plt
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
def agcwd(image, w=1): #加权分布的自适应伽马校正,w就是公式里的alpha
is_colorful = len(image.shape) >= 3
img = extract_value_channel(image) if is_colorful else image
img_pdf = get_pdf(img)
max_intensity = np.max(img_pdf)
min_intensity = np.min(img_pdf)
w_img_pdf = max_intensity * (((img_pdf - min_intensity) / (max_intensity - min_intensity)) ** w) #加权分布后的概率密度函数
w_img_cdf = np.cumsum(w_img_pdf) / np.sum(w_img_pdf)
l_intensity = np.arange(0, 256)
l_intensity = np.array([255 * (e / 255) ** (1 - w_img_cdf[e]) for e in l_intensity], dtype=np.uint8) #变换后的灰度值
enhanced_image = np.copy(img)
height, width = img.shape
#对像素点依次进行处理
for i in range(0, height):
for j in range(0, width):
intensity = enhanced_image[i, j]
enhanced_image[i, j] = l_intensity[intensity]
enhanced_image = set_value_channel(image, enhanced_image) if is_colorful else enhanced_image
return enhanced_image
def extract_value_channel(color_image): #提取v通道
color_image = color_image.astype(np.float32) / 255.
hsv = cv2.cvtColor(color_image, cv2.COLOR_BGR2HSV)
v = hsv[:, :, 2]
return np.uint8(v * 255)
def get_pdf(gray_image): #获取概率密度函数
height, width = gray_image.shape
pixel_count = height * width
hist = cv2.calcHist([gray_image], [0], None, [256], [0, 256])
return hist / pixel_count
def set_value_channel(color_image, value_channel): #替换color_image中的v通道为value_channel,再把HSV变成RGB
value_channel = value_channel.astype(np.float32) / 255
color_image = color_image.astype(np.float32) / 255.
color_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2HSV)
color_image[:, :, 2] = value_channel
color_image = np.array(cv2.cvtColor(color_image, cv2.COLOR_HSV2BGR) * 255, dtype=np.uint8)
return color_image
def homomorphic_filter(src,d0=10,rl=0.5,rh=2,c=4,h=2.0,l=0.5): #同态滤波
gray = src
if len(src.shape) > 2:
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
gray = np.float64(gray)
rows, cols = gray.shape
gray_fft = np.fft.fft2(gray)
gray_fftshift = np.fft.fftshift(gray_fft)
M, N = np.meshgrid(np.arange(-cols // 2, cols // 2), np.arange(-rows // 2, rows // 2))
D = np.sqrt(M ** 2 + N ** 2)
Z = (rh-rl)*(1-np.exp(-c*(D**2/d0**2)))+rl
dst_fftshift = Z * gray_fftshift
dst_fftshift = (h - l) * dst_fftshift + l
dst_ifftshift = np.fft.ifftshift(dst_fftshift)
dst_ifft = np.fft.ifft2(dst_ifftshift)
dst = np.real(dst_ifft)
dst = np.uint8(np.clip(dst, 0, 255))
return dst
def clahe(image): #对比度受限的自适应直方图均衡化
clahe = cv2.createCLAHE(clipLimit=200, tileGridSize=(8, 8))
#cl2 = clahe.getClipLimit()
#clahe.setClipLimit(500)
#cl1 = clahe.getClipLimit()
#clahe.setTilesGridSize((3, 3))
dst = clahe.apply(image)
return dst
imageDir = "./test_img/"
saveDir_agcwd = "./AGCWD_results/"
saveDir_hf = "./AGCWD_HF_results/"
saveDir_clahe = "./AGCWD_HF_CLAHE_results/"
for name in os.listdir(imageDir):
img = cv2.imread(os.path.join(imageDir,name))
image_agcwd = agcwd(img)
#plt.hist(img.ravel(),256)
#plt.show()
#cv2.waitKey(0)
cv2.imwrite(os.path.join(saveDir_agcwd, name), image_agcwd)
image_hf = homomorphic_filter(img)
cv2.imwrite(os.path.join(saveDir_hf, name), image_hf)
image_clahe = cv2.equalizeHist(image_hf)
cv2.imwrite(os.path.join(saveDir_clahe, name), image_clahe)
从左到右依次为原图、同态滤波增强、本实验方法增强。可以看出本实验较同态滤波法的增强效果并没有明显改善,且程序更为复杂耗时。
尽管对于样本图片本实验没有获得较好的效果,但实验发现该算法以及构成该算法的AGCWD、单参数同态滤波、CLAHE方法在图像增强方面各有其适用的环境,可作为积累用于未来的相关研究。