Python气象数据处理与绘图:常见的10种图像滤波方法

2021-08-26 17:50:48 浏览数 (3)


一、准备工作

导入模块

代码语言:javascript复制
import numpy as np
import cv2
import matplotlib.pyplot as plt
import copy
import math
import warnings
warnings.filterwarnings('ignore')

展示原始图像(Origin)

代码语言:javascript复制
img = cv2.imread('airport/1.jpg')
b, g, r = cv2.split(img)
srcImage_new = cv2.merge([r, g, b])
plt.imshow(srcImage_new)

二、滤波方法

1.中值滤波(medianBlur) 中值滤波是非线性的图像处理方法,在去噪的同时可以兼顾到边界信息的保留。选一个含有奇数点的窗口,将这个窗口在图像上扫描,把窗口中所含的像素点按灰度级的升或降序排列,取位于中间的灰度值来代替该点的灰度值。

代码语言:javascript复制
medianBlur = cv2.medianBlur(srcImage_new, 7)
plt.imshow(medianBlur)

2.均值滤波(blur) 均值滤波采用线性的方法,平均整个窗口范围内的像素值,均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊。

代码语言:javascript复制
blur = cv2.blur(srcImage_new, (7, 7))
plt.imshow(blur)

3.高斯滤波(GaussianBlur) 在图像高斯平滑中,对图像进行平均时,不同位置的像素被赋予了不同的权重。高斯平滑与简单平滑不同,它在对邻域内像素进行平均时,给予不同位置的像素不同的权值。高斯滤波让临近的像素具有更高的重要度,对周围像素计算加权平均值,较近的像素具有较大的权重值。

代码语言:javascript复制
source = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
GaussianBlur = cv2.GaussianBlur(source, (7, 7), 0) 
plt.imshow(GaussianBlur)

4.双边滤波(bilateralFilter) 双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部处理的特点。之所以能够达到保边去噪的滤波效果是因为滤波器由两个函数构成:一个函数是由几何空间距离决定滤波器系数,另一个是由像素差值决定滤波器系数。

d:过滤时周围每个像素领域的直径 sigmaColor:在color space中过滤sigma。参数越大,临近像素将会在越远的地方mix。 sigmaSpace:在coordinate space中过滤sigma。参数越大,那些颜色足够相近的的颜色的影响越大。

代码语言:javascript复制
bilateralFilter = cv2.bilateralFilter(img, d=7, sigmaColor=20, sigmaSpace=20)
plt.imshow(bilateralFilter)

5.均值偏移滤波(MeanShiftFilter) 图像在色彩层面的平滑滤波,它可以中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域。

代码语言:javascript复制
MeanShiftFilter = cv2.pyrMeanShiftFiltering(img, sp=15, sr=20)
plt.imshow(MeanShiftFilter)

6.非局部平均滤波(NonLocalMeans) 借鉴了越多幅图像加权的效果越好的现象,那么在同一幅图像中对具有相同性质的区域进行分类并加权平均得到去噪后的图片,应该降噪效果也会越好。

代码语言:javascript复制
dst = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21)
b1, g1, r1 = cv2.split(dst)
NonLocalMeans = cv2.merge([r1, g1, b1])
plt.imshow(NonLocalMeans)

7.高通滤波(highpass_filter) 规则为高频信号能正常通过,而低于设定临界值的低频信号则被阻隔、减弱。但是阻隔、减弱的幅度则会依据不同的频率以及不同的滤波程序(目的)而改变。它有的时候也被叫做低频去除过滤(low-cut filter)。

代码语言:javascript复制
def high_pass_filtering(image, radius, n):
    """
    高通滤波函数
    :param image: 输入图像
    :param radius: 半径
    :param n: ButterWorth滤波器阶数
    :return: 滤波结果
    """
    # 对图像进行傅里叶变换,fft是一个三维数组,fft[:, :, 0]为实数部分,fft[:, :, 1]为虚数部分
    fft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
    # 对fft进行中心化,生成的dshift仍然是一个三维数组
    dshift = np.fft.fftshift(fft)

    # 得到中心像素
    rows, cols = image.shape[:2]
    mid_row, mid_col = int(rows / 2), int(cols / 2)

    # 构建ButterWorth高通滤波掩模

    mask = np.zeros((rows, cols, 2), np.float32)
    for i in range(0, rows):
        for j in range(0, cols):
            # 计算(i, j)到中心点的距离
            d = math.sqrt(pow(i - mid_row, 2)   pow(j - mid_col, 2))
            try:
                mask[i, j, 0] = mask[i, j, 1] = 1 / (1   pow(radius / d, 2*n))
            except ZeroDivisionError:
                mask[i, j, 0] = mask[i, j, 1] = 0
    # 给傅里叶变换结果乘掩模
    fft_filtering = dshift * mask
    # 傅里叶逆变换
    ishift = np.fft.ifftshift(fft_filtering)
    image_filtering = cv2.idft(ishift)
    image_filtering = cv2.magnitude(image_filtering[:, :, 0], image_filtering[:, :, 1])
    # 对逆变换结果进行归一化(一般对图像处理的最后一步都要进行归一化,特殊情况除外)
    cv2.normalize(image_filtering, image_filtering, 0, 1, cv2.NORM_MINMAX)
    return image_filtering
代码语言:javascript复制
highpass_filter_b = high_pass_filtering(img[:,:,0], 3, 1)
highpass_filter_g = high_pass_filtering(img[:,:,1], 3, 1)
highpass_filter_r = high_pass_filtering(img[:,:,2], 3, 1)
highpass_filter = cv2.merge([highpass_filter_r, highpass_filter_g, highpass_filter_b])
plt.imshow(highpass_filter)

8.低通滤波(lowpass_filter) 规则为低频信号能正常通过,而超过设定临界值的高频信号则被阻隔、减弱。但是阻隔、减弱的幅度则会依据不同的频率以及不同的滤波程序(目的)而改变。它有的时候也被叫做高频去除过滤(high-cut filter)或者最高去除过滤(treble-cut filter)。

代码语言:javascript复制
def low_pass_filtering(image, radius):
    """
    低通滤波函数
    :param image: 输入图像
    :param radius: 半径
    :return: 滤波结果
    """
    # 对图像进行傅里叶变换,fft是一个三维数组,fft[:, :, 0]为实数部分,fft[:, :, 1]为虚数部分
    fft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
    # 对fft进行中心化,生成的dshift仍然是一个三维数组
    dshift = np.fft.fftshift(fft)

    # 得到中心像素
    rows, cols = image.shape[:2]
    mid_row, mid_col = int(rows / 2), int(cols / 2)

    # 构建掩模,256位,两个通道
    mask = np.zeros((rows, cols, 2), np.float32)
    mask[mid_row - radius:mid_row   radius, mid_col - radius:mid_col   radius] = 1

    # 给傅里叶变换结果乘掩模
    fft_filtering = dshift * mask
    # 傅里叶逆变换
    ishift = np.fft.ifftshift(fft_filtering)
    image_filtering = cv2.idft(ishift)
    image_filtering = cv2.magnitude(image_filtering[:, :, 0], image_filtering[:, :, 1])
    # 对逆变换结果进行归一化(一般对图像处理的最后一步都要进行归一化,特殊情况除外)
    cv2.normalize(image_filtering, image_filtering, 0, 1, cv2.NORM_MINMAX)
    return image_filtering
代码语言:javascript复制
lowpass_filter_b = low_pass_filtering(img[:,:,0], 50)
lowpass_filter_g = low_pass_filtering(img[:,:,1], 50)
lowpass_filter_r = low_pass_filtering(img[:,:,2], 50)
lowpass_filter = cv2.merge([lowpass_filter_r, lowpass_filter_g, lowpass_filter_b])
plt.imshow(lowpass_filter)

9.带通滤波(bandpass_filter) 一个允许特定频段的波通过同时屏蔽其他频段的设备,比如RLC振荡回路就是一个模拟带通滤波器。一个理想的带通滤波器应该有一个完全平坦的通带,在通带内没有放大或者衰减,并且在通带之外所有频率都被完全衰减掉,另外,通带外的转换在极小的频率范围完成。

代码语言:javascript复制
def bandpass_filter(image, radius, w, n=1):
    """
    带通滤波函数
    :param image: 输入图像
    :param radius: 带中心到频率平面原点的距离
    :param w: 带宽
    :param n: 阶数
    :return: 滤波结果
    """
    # 对图像进行傅里叶变换,fft是一个三维数组,fft[:, :, 0]为实数部分,fft[:, :, 1]为虚数部分
    fft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
    # 对fft进行中心化,生成的dshift仍然是一个三维数组
    dshift = np.fft.fftshift(fft)

    # 得到中心像素
    rows, cols = image.shape[:2]
    mid_row, mid_col = int(rows / 2), int(cols / 2)

    # 构建掩模,256位,两个通道
    mask = np.zeros((rows, cols, 2), np.float32)
    for i in range(0, rows):
        for j in range(0, cols):
            # 计算(i, j)到中心点的距离
            d = math.sqrt(pow(i - mid_row, 2)   pow(j - mid_col, 2))
            if radius - w / 2 < d < radius   w / 2:
                mask[i, j, 0] = mask[i, j, 1] = 1
            else:
                mask[i, j, 0] = mask[i, j, 1] = 0

    # 给傅里叶变换结果乘掩模
    fft_filtering = dshift * np.float32(mask)
    # 傅里叶逆变换
    ishift = np.fft.ifftshift(fft_filtering)
    image_filtering = cv2.idft(ishift)
    image_filtering = cv2.magnitude(image_filtering[:, :, 0], image_filtering[:, :, 1])
    # 对逆变换结果进行归一化(一般对图像处理的最后一步都要进行归一化,特殊情况除外)
    cv2.normalize(image_filtering, image_filtering, 0, 1, cv2.NORM_MINMAX)
    return image_filtering
代码语言:javascript复制
bandpass_filter_b = bandpass_filter(img[:,:,0], 50, 3, n=1)
bandpass_filter_g = bandpass_filter(img[:,:,1], 50, 3, n=1)
bandpass_filter_r = bandpass_filter(img[:,:,2], 50, 3, n=1)
bandpass_filter = cv2.merge([bandpass_filter_r, bandpass_filter_g, bandpass_filter_b])
plt.imshow(bandpass_filter)

10.带阻滤波(bandstop_filter) 通过大多数频率分量、但将某些范围的频率分量衰减到极低水平的滤波器,与带通滤波器的概念相对。

代码语言:javascript复制
def bandstop_filter(image, radius, w, n=1):
    """
    带阻滤波函数
    :param image: 输入图像
    :param radius: 带中心到频率平面原点的距离
    :param w: 带宽
    :param n: 阶数
    :return: 滤波结果
    """
    # 对图像进行傅里叶变换,fft是一个三维数组,fft[:, :, 0]为实数部分,fft[:, :, 1]为虚数部分
    fft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
    # 对fft进行中心化,生成的dshift仍然是一个三维数组
    dshift = np.fft.fftshift(fft)

    # 得到中心像素
    rows, cols = image.shape[:2]
    mid_row, mid_col = int(rows / 2), int(cols / 2)

    # 构建掩模,256位,两个通道
    mask = np.zeros((rows, cols, 2), np.float32)
    for i in range(0, rows):
        for j in range(0, cols):
            # 计算(i, j)到中心点的距离
            d = math.sqrt(pow(i - mid_row, 2)   pow(j - mid_col, 2))
            if radius - w / 2 < d < radius   w / 2:
                mask[i, j, 0] = mask[i, j, 1] = 0
            else:
                mask[i, j, 0] = mask[i, j, 1] = 1

    # 给傅里叶变换结果乘掩模
    fft_filtering = dshift * np.float32(mask)
    # 傅里叶逆变换
    ishift = np.fft.ifftshift(fft_filtering)
    image_filtering = cv2.idft(ishift)
    image_filtering = cv2.magnitude(image_filtering[:, :, 0], image_filtering[:, :, 1])
    # 对逆变换结果进行归一化(一般对图像处理的最后一步都要进行归一化,特殊情况除外)
    cv2.normalize(image_filtering, image_filtering, 0, 1, cv2.NORM_MINMAX)
    return image_filtering
代码语言:javascript复制
bandstop_filter_b = bandstop_filter(img[:,:,0], 7, 3, n=1)
bandstop_filter_g = bandstop_filter(img[:,:,1], 7, 3, n=1)
bandstop_filter_r = bandstop_filter(img[:,:,2], 7, 3, n=1)
bandstop_filter = cv2.merge([bandstop_filter_r, bandstop_filter_g, bandstop_filter_b])
plt.imshow(bandstop_filter)

三、汇总绘图

代码语言:javascript复制
fig = plt.figure(figsize=(18,18))
plt.subplot(431)
#plt.title('原始图像', fontsize=15)
plt.title('Origin (7×7)', fontsize=15)
plt.imshow(srcImage_new)

plt.subplot(432)
#plt.title('中值滤波 (7×7)', fontsize=15)
plt.title('medianBlur (7×7)', fontsize=15)
plt.imshow(medianBlur) 

plt.subplot(433)
#plt.title('均值滤波 (7×7)', fontsize=15)
plt.title('blur (7×7)', fontsize=15)
plt.imshow(blur) 

plt.subplot(434)
#plt.title('高斯滤波 (7×7)', fontsize=15)
plt.title('GaussianBlur (7×7)', fontsize=15)
plt.imshow(GaussianBlur) 

plt.subplot(435)
#plt.title('双边滤波 (7×7)', fontsize=15)
plt.title('bilateralFilter (7×7)', fontsize=15)
plt.imshow(bilateralFilter) 

plt.subplot(436)
#plt.title('均值偏移滤波', fontsize=15)
plt.title('MeanShiftFilter', fontsize=15)
plt.imshow(MeanShiftFilter)

plt.subplot(437)
#plt.title('非局部平均法', fontsize=15)
plt.title('NonLocalMeans', fontsize=15)
plt.imshow(NonLocalMeans)

plt.subplot(438)
#plt.title('高通滤波', fontsize=15)
plt.title('highpass_filter', fontsize=15)
plt.imshow(highpass_filter)

plt.subplot(439)
#plt.title('低通滤波', fontsize=15)
plt.title('lowpass_filter', fontsize=15)
plt.imshow(lowpass_filter)

plt.subplot(4,3,10)
#plt.title('带通滤波', fontsize=15)
plt.title('bandpass_filter', fontsize=15)
plt.imshow(bandpass_filter)

plt.subplot(4,3,11)
#plt.title('带阻滤波', fontsize=15)
plt.title('bandstop_filter', fontsize=15)
plt.imshow(bandstop_filter)

plt.show()

1 人点赞