均值滤波器可以一定程度降低高斯噪声,但对椒盐噪声效果不好,并且平滑也会带来图像模糊化。
椒盐噪声是灰度值过大或过小的噪声,对均值的影响较大,所以滤波效果不好。
# 方法1
img_smooth = cv.blur(img_org, ksize=(3, 3))
# 方法2
kernel = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])/9
img_smooth = cv.filter2D(img_org, -1, kernel)
高斯滤波构造二维高斯分布的核函数,可以有效的出去图像的高斯噪声。
# 方法1
img_smooth = cv.GaussianBlur(img,(5,5),0.6)
# 方法2
kernel = cv.getGaussianKernel(ksize=3, sigma=0.6) * cv.getGaussianKernel(ksize=3, sigma=0.6).T
img_smooth = cv.filter2D(img_org, -1, kernel)
双边滤波希望在非边缘部分,让图像平滑(高斯滤波); 在边缘部分,让图像变得锐化(让模板中与中心像素差值大的权重更小),可以有效保留边缘。
img_smooth = cv.bilateralFilter(img_org,r,差值,差值)
中值滤波用模板中像素值的中位像素值来确定当前像素值, 可以有效去除椒盐噪声。
11 blur = cv.medianBlur(img_org,5)
拉普拉斯算子可以突现出图像中小的细节信息。
kernel0 = np.array([[0, -1, 0],
[-1, 4, -1],
[0, -1, 0]])
kernel1 = np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]])
dst = cv.filter2D(img_smooth, -1, kernel0)
img_sharpen = img_org + dst
kernel0 = np.array([[-1, 0], [0, -1]])
kernel1 = np.array([[0, -1], [-1, 0]])
dst0 = cv.filter2D(img_smooth, -1, kernel0)
dst1 = cv.filter2D(img_smooth, -1, kernel1)
dst = dst0 + dst1
img_sharpen = img_org + dst
sobel算子可以产生较好的边缘检测效果,而且对噪声具有平滑抑制作用,但是得到的边缘较粗,可能出现伪边缘现象。
kernel0 = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
kernel1 = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
dst0 = cv.filter2D(img_org, -1, kernel0)
dst1 = cv.filter2D(img_org, -1, kernel1)
dst = dst0 + dst1
img_sharpen = img_org + dst
灰度变换平滑锐化等方法组合起来使用
傅里叶变换可以在全局运算,获取图像的灰度变换情况,并把这种灰度变换情况对应到频率域。通常图像的边缘区域对应频率域的高频部分,平滑区域对应频率域的低频部分。
低通滤波一般实现的是图像平滑,仅保留图像的平滑区域。
def filter(img, d_th, N=1, type='lp', filter='butterworth'):
'''
img: 单通道图片
d_th: 截止频率
N: butterworth的阶数
type: lp-低通 hp-高通
filter:滤波器类型:巴特沃斯、理想、高斯滤波器
'''
# 离散快速傅里叶变换
# dft = cv.dft(np.float32(img), flags=cv.DFT_COMPLEX_OUTPUT) # 注意这里实部一个通道,虚部一个通道
dft = np.fft.fft2(img) # 复数
dtf_shift = np.fft.fftshift(dft) # 复数
rows, cols = img.shape
mask = np.zeros((rows, cols)) # 生成rows行cols列的二维矩阵
y_shift, x_shift = np.meshgrid(np.arange(-cols // 2, cols // 2), np.arange(-rows // 2, rows // 2))
d_uv = np.sqrt(x_shift ** 2 + y_shift ** 2)
if filter.lower() == 'butterworth': # 巴特沃斯滤波器
if type == 'lp':
mask = 1 / (1 + (d_uv / d_th) ** (2 * N))
elif type == 'hp':
mask = 1 / (1 + (d_th / d_uv) ** (2 * N))
else:
assert 'type error'
elif filter.lower() == 'ideal': # 理想滤波器
if type == 'lp':
mask[d_uv <= d_th] = 1
elif type == 'hp':
mask[d_uv > d_th] = 1
else:
assert 'type error'
elif filter.lower() == 'gaussian': # 高斯滤波器
if type == 'lp':
mask = np.exp(-(d_uv * d_uv) / (2 * d_th * d_th))
elif type == 'hp':
mask = 1 - np.exp(-(d_uv * d_uv) / (2 * d_th * d_th))
else:
assert 'type error'
fshift = dtf_shift * mask
# 逆傅里叶变换
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift) # 复数
img_back = np.abs(img_back) # 实数
img_back = (img_back - np.amin(img_back)) / (np.amax(img_back) - np.amin(img_back)) # 灰度值:0-1
img_back = np.uint8(255 * img_back) # 灰度值:0-255
return img_back
img_lp = filter(img_org, 30, type="lp", filter="gaussian")
高通滤波一般可以获得图像的边缘,与微分算子类似,与原图像求和,可以锐化图像。
img_hp = filter(img_org, 10, type="hp", filter="gaussian")
同态滤波基本的思想是分离图像的照射分量和反射分量,对照射分量和反射分量进行不同的处理。
一般的同态滤波的步骤主要是:对数变换;傅里叶变换;低频高频分别处理(一般低频抑制,高频增强);逆傅里叶变换;反对数变换。
关于同态滤波的输入灰度级:对有些图像灰度级为[0,255],处理结果会更好;有些图像灰度级为[0,1],处理结果会更好。
def homomorphic_filter(gray_f, d_th=30, rl=0.5, rh=1.5, c=1.0, result_type='abs'):
# 对数变换:0-255 to 0-1 to 0-0.693
gray = np.log(gray_f/255.0 + 1.0)
#gray = np.log(gray_f/1.0 + 1.0)
# 快速傅里叶变换
gray_fft = np.fft.fft2(gray)
gray_fftshift = np.fft.fftshift(gray_fft)
# 创建频率域的坐标矩阵
rows, cols = gray_f.shape
y_shift, x_shift = np.meshgrid(np.arange(-cols // 2, cols // 2), np.arange(-rows // 2, rows // 2)) # 注意,//就是除法
# 计算图像中各个位置的频率值
d_uv = np.sqrt(x_shift ** 2 + y_shift ** 2)
# 滤波函数
mask = (rh - rl) * (1 - np.exp(-c * (d_uv * d_uv) / (d_th * d_th))) + rl
dst_fftshift = gray_fftshift * mask
# 傅里叶反变换
dst_ifftshift = np.fft.ifftshift(dst_fftshift)
dst_ifft = np.fft.ifft2(dst_ifftshift)
# 选取复数的幅值
if result_type == 'abs':
dst_ifft_amplitude = np.abs(dst_ifft)
else:
dst_ifft_amplitude = np.real(dst_ifft)
# 归一化后再反变换:可有可无。如果dst_ifft_abs.max() < 1, 会让图更暗;如果dst_ifft_abs.max() > 1, 会让图更亮。(不一定对)
if dst_ifft_amplitude.max() > 1:
dst_ifft_amplitude = (dst_ifft_amplitude - dst_ifft_amplitude.min()) / (dst_ifft_amplitude.max() - dst_ifft_amplitude.min())
# 对数反变换:压缩灰度空间(图像会偏暗)
dst = np.exp(dst_ifft_amplitude)-1
#dst = dst_ifft_amplitude# 不用对数反变换,图像会亮一些
dst = (dst - np.min(dst)) / (np.max(dst) - np.min(dst)) # 灰度值:0-1
dst = np.uint8(255 * dst) # 灰度值:0-255
return dst
img_homomorphic = homomorphic_filter(img_org, result_type="abs")