《OpenCv视觉之眼》Python图像处理七 :Opencv图像处理之高通滤波和低通滤波原理及构造

56
0
2021年2月17日 09时33分

本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的、不同方法的处理,以达到对图像进行去噪、锐化等一系列的操作。同时,希望观看本专栏的小伙伴可以理解到OpenCv进行图像处理的强大哦,如有转载,请注明出处(原文链接和作者署名),感谢各位小伙伴啦!

 

前文参考:


《OpenCv视觉之眼》Python图像处理一 :Opencv-python的简介及Python环境搭建
《OpenCv视觉之眼》Python图像处理二 :Opencv图像读取、显示、保存基本函数原型及使用
《OpenCv视觉之眼》Python图像处理三 :Opencv图像属性、ROI区域获取及通道处理
《OpenCv视觉之眼》Python图像处理四 :Opencv图像灰度处理的四种方法及原理
《OpenCv视觉之眼》Python图像处理五 :Opencv图像去噪处理之均值滤波、方框滤波、中值滤波和高斯滤波
《OpenCv视觉之眼》Python图像处理六 :Opencv图像傅里叶变换和傅里叶逆变换原理及实现

 

上一章节,林君学长介绍了图像的傅里叶变换和逆变换,图傅里叶变换和逆变换并不是对图像处理的目的,只是图像处理过程的中间步骤,而我们需要通过图像的傅里叶变换得到图像的频域图,然后对图像的频域进行操作,例如构造高通滤波和低通滤波对图像频域进行过滤,然后再通过傅里叶逆变换将频域图还原为时域图进行显示,达到图像去噪、图像轮廓提取、图像锐化的目的。

 

本次博客,林君学长主要介绍在傅里叶变换的基础上,如何构造高通滤波和低通滤波来进行图像简单轮廓提取和图像去噪,高通和低通滤波的主要难点理解就是傅里叶变换和逆变换,上次博客已经介绍过,而对于高通和低通滤波的构造还是比较简单的,一起学习吧!

 

[Python图像处理七] :Opencv图像处理之高通滤波和低通滤波原理及构造

 

  • 一、高通滤波
    • 1、高通滤波简介
    • 2、图像高通滤波原理
    • 3、图像高通滤波构造
  • 二、低通滤波
    • 1、低通滤波简介
    • 2、低通滤波原理
    • 3、图像低通滤波构造

一、高通滤波

 

  • 高通滤波一般用来提取图像轮廓

 

1、高通滤波简介

 

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

 

2、图像高通滤波原理

 

1)、图像高通滤波原理首先应该了解高通滤波应该除掉的是什么滤波,高通滤波,意思就是让高频部分通过,留下低频部分;而衍生到图像上面来理解,一张图片的像素一般来说,在轮廓的地方像素值高,而在其他部分像素值低,例如一张图像上面的人像,人像的轮廓之所以我们能够看出来就是因为与周围像素值相差过大,频率高,周围像素值低,频率低,形成像素差,从而我们肉眼可以分辨;

 

2)、而对于傅里叶变换来说,它将一张图像高频部分显示在外围,而低频部分显示在中间;因此,高通滤波就是将傅里叶变换之后的频谱图的中间部分过滤;过滤方法就是将中间部分区域的低频对应的像素值给设置为0,设置为黑色,如下图所示:

 

在这里插入图片描述

 

而这个黑色区域就是需要我们构造的区域,尺寸是通过我们自定义的,接下来,了解如何构造高通滤波吧!

 

注意:该出是将低频处对应的像素值设置为黑色,而不是将频域图的中间部分变黑,相反的,频域图而言,像素值越低,频率越低,中间部分也就越亮

 

3、图像高通滤波构造

 

1)、构造高通滤波函数

 

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#高通滤波构造
def highPassFiltering(img,size):#传递参数为傅里叶变换后的频谱图和滤波尺寸
    h, w = img.shape[0:2]#获取图像属性
    h1,w1 = int(h/2), int(w/2)#找到傅里叶频谱图的中心点
    img[h1-int(size/2):h1+int(size/2), w1-int(size/2):w1+int(size/2)] = 0#中心点加减滤波尺寸的一半,刚好形成一个定义尺寸的滤波大小,然后设置为0
    return img

 

2)、步骤一:读取一张图像,转化为灰度图,然后通过傅里叶变换得到频谱图,然后调用高通滤波函数进行过滤,最后进行傅里叶逆变换观察结果

 

这里傅里叶变换我们直接用Numpy的傅里叶变换,用法比较简单

#Numpy库的傅里叶变换
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取图像
img = cv.imread('my.jpg',0)
#傅里叶变换
f = np.fft.fft2(img)
#将左上角低频部分移动到中间
fshift = np.fft.fftshift(f)
#调用高通滤波函数
img1=highPassFiltering(fshift,80)
#复数化整,方便观察频谱图
res = np.log(np.abs(img1))
#傅里叶逆变换
ishift = np.fft.ifftshift(img1)
iimg = np.fft.ifft2(ishift)
iimg = np.abs(iimg)
#展示结果
plt.subplot(131), plt.imshow(img,'gray'), plt.title('原图像')
plt.axis('off')
plt.subplot(132), plt.imshow(res,'gray'), plt.title('高通滤波')
plt.axis('off')
plt.subplot(133), plt.imshow(iimg,'gray'), plt.title('高通滤波结果')
plt.axis('off')
plt.show()

 

在这里插入图片描述

 

我们可以看到,通过调节尺寸的大小,我们可以提取明显度不同的图像轮廓,对于高通滤波的尺寸大小,主要看实际操作中对图像的要求而设置

 

注意:该出是将低频处对应的像素值设置为黑色,而不是将频域图的中间部分变黑,相反的,频域图而言,像素值越低,频率越低,中间部分也就越亮

 

3)、以上我们是对灰度图像进行高通滤波处理,那么很多小伙伴会疑惑,如何对彩色图像进行高通滤波处理呢?步骤也是同样如此,只不过,我们需要用到的傅里叶变换为彩色图像的傅里叶变换而已,上次博客林君学长也已经讲过哦,只不过,在现实的图像处理中,傅里叶变换一般是针对灰度图像而言,因为对弈灰度图像,有较好的频域,比较可观的频域图像,一般的图像图像不管是提取轮廓、还是阈值化都是转化为灰度图像进行处理的哈,完整代码如下:

 

#彩色图像的高通滤波
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#自定义傅里叶变换功能函数
def dft(img):
    #获取图像属性
    H,W,channel=img.shape
    #定义频域图,从公式可以看出为求出结果为复数,因此,需要定义为复数矩阵
    F = np.zeros((H, W,channel), dtype=np.complex)
    # 准备与原始图像位置相对应的处理索引
    x = np.tile(np.arange(W), (H, 1))
    y = np.arange(H).repeat(W).reshape(H, -1)
    #通过公式遍历
    for c in range(channel):
        for u in range(H):
            for v in range(W):
                F[u, v, c] = np.sum(img[..., c] * np.exp(-2j * np.pi * (x * u / W + y * v / H))) / np.sqrt(H * W)
    return F
#傅里叶反变换
def idft(G):
    H, W, channel = G.shape
    #定义空白时域图像
    out = np.zeros((H, W, channel), dtype=np.float32)
    # 准备与原始图像位置相对应的处理索引
    x = np.tile(np.arange(W), (H, 1))
    y = np.arange(H).repeat(W).reshape(H, -1)
    #通过公式遍历
    for c in range(channel):
        for u in range(H):
            for v in range(W):
                out[u, v, c] = np.abs(np.sum(G[..., c] * np.exp(2j * np.pi * (x * u / W + y * v / H)))) / np.sqrt(W * H)
    # 剪裁
    out = np.clip(out, 0, 255)
    out = out.astype(np.uint8)
    return out
#高通滤波构造
def highPassFiltering(img,size):#传递参数为傅里叶变换后的频谱图和滤波尺寸
    h, w = img.shape[0:2]#获取图像属性
    h1,w1 = int(h/2), int(w/2)#找到傅里叶频谱图的中心点
    img[h1-int(size/2):h1+int(size/2), w1-int(size/2):w1+int(size/2)] = 0#中心点加减滤波尺寸的一半,刚好形成一个定义尺寸的滤波大小,然后设置为0
    return img
#读取图像
img=cv2.imread("my.jpg")
#进行图像裁剪,加快傅里叶运算速率。将原始尺寸缩放为100*100的尺寸
img = cv2.resize(img, (100, 100), interpolation=cv2.INTER_CUBIC)
#BGR转换为RGB显示格式,方便通过matplotlib进行图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#调用傅里叶变换函数
result =dft(img)
#将傅里叶频谱图从左上角移动到中心位置
fshift = np.fft.fftshift(result)
img1=highPassFiltering(fshift,30)
#将复数转为浮点数进行傅里叶频谱图显示
fimg = np.log(np.abs(img1))#复数转为整数,方便显示傅里叶频谱图
#将傅里叶频谱图从中心还原到左上角位置
ishift = np.fft.ifftshift(img1)
#调用傅里叶逆变换函数
result2=idft(ishift)
#图像显示
plt.subplot(131), plt.imshow(img), plt.title('原图像')
plt.axis('off')
plt.subplot(132), plt.imshow(fimg), plt.title('高通滤波')
plt.axis('off')
plt.subplot(133), plt.imshow(result2), plt.title('高通滤波结果')
plt.axis('off')
plt.show()

 

在这里插入图片描述

 

可以看到,高通滤波之后的结果,周围是存在BGR三通道的像素值的,这对我们需要达到目的也就是轮廓提取是干扰的,因此,在大多数情况下,高通滤波和低通滤波针对的对象都是灰度图像,对灰度图像提取轮廓!

 

二、低通滤波

 

  • 低通滤波一般用作图像去噪(模糊)

 

1、低通滤波简介

 

低通滤波可以简单的认为:设定一个频率点,当信号频率高于这个频率时不能通过,在数字信号中,这个频率点也就是截止频率,当频域高于这个截止频率时,则全部赋值为0。因为在这一处理过程中,让低频信号全部通过,所以称为低通滤波。低通过滤的概念存在于各种不同的领域,诸如电子电路,数据平滑,声学阻挡,图像模糊等领域经常会用到。在数字图像处理领域,从频域看,低通滤波可以对图像进行平滑去噪处理。

 

2、低通滤波原理

 

1)、低通滤波顾名思义就是低频可以通过,过滤掉高频部分,而对于图像的噪声,包括椒盐噪声和高斯噪声,他们的频率都是比较高的例如像素值为255,那么低通滤波就会将这些噪声过滤,但低通滤波并没有识别功能,图像中有些区域的像素同样为255,同理,低通滤波也会将其完全过滤,因此,通过这个原理,我们就可以简单了解,低通滤波其实就是将频域图中心部分保留,将外围部分过滤,衍生到图像中就是将高频区域对应的像素值设置为0,黑色,低频区域对应的像素值不改变

 

2)、那么如何实现呢?就需要和原图一模一样大小的黑色图像,将中间区域设置为白色,然后与频谱图一 一对应相乘,这样得到的结果就是中间部分不改变而过滤掉边上部分,如下图所示:

 

在这里插入图片描述

 

通过该原理,就可以构造图像的低频滤波了,一起来看吧!
注意:该出是将高频处对应的像素值设置为黑色,而不是将频域图的周围变黑,相反的,频域图而言,像素值越高,频率越高,周围部分也就越亮

 

3、图像低通滤波构造

 

1)、构造图像低频滤波函数

 

#低通滤波构造
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def lowPassFiltering(img,size):#传递参数为傅里叶变换后的频谱图和滤波尺寸
    h, w = img.shape[0:2]#获取图像属性
    h1,w1 = int(h/2), int(w/2)#找到傅里叶频谱图的中心点
    img2 = np.zeros((h, w), np.uint8)#定义空白黑色图像,和傅里叶变换传递的图尺寸一致
    img2[h1-int(size/2):h1+int(size/2), w1-int(size/2):w1+int(size/2)] = 1#中心点加减滤波尺寸的一半,刚好形成一个定义尺寸的滤波大小,然后设置为1,保留低频部分
    img3=img2*img #将定义的低通滤波与传入的傅里叶频谱图一一对应相乘,得到低通滤波
    return img3

 

2)、读取图像添加噪声并灰度化,进行傅里叶变换后调用低通滤波函数,然后通过傅里叶逆变换还原观察图像变化

 

#Numpy库的傅里叶变换
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#读取图像
img = cv.imread('my.jpg')
h, w = img.shape[0:2]#获取图像属性
#加噪声
for i in range(3000):    #添加3000个噪声点
    x = np.random.randint(0, h) 
    y = np.random.randint(0, w)    
    img[x,y] = 255
#图像灰度化
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#傅里叶变换
f = np.fft.fft2(img)
#将左上角低频部分移动到中间
fshift = np.fft.fftshift(f)
#调用低通滤波函数
img1=lowPassFiltering(fshift,100)
#复数化整,方便观察频谱图
res = np.log(np.abs(img1))
#傅里叶逆变换
ishift = np.fft.ifftshift(img1)
iimg = np.fft.ifft2(ishift)
iimg = np.abs(iimg)
#展示结果
plt.subplot(131), plt.imshow(img,'gray'), plt.title('原图像')
plt.axis('off')
plt.subplot(132), plt.imshow(res,'gray'), plt.title('低通滤波')
plt.axis('off')
plt.subplot(133), plt.imshow(iimg,'gray'), plt.title('低通滤波结果')
plt.axis('off')
plt.show()

 

在这里插入图片描述

 

注意:该出是将高频处对应的像素值设置为黑色,而不是将频域图的周围变黑,相反的,频域图而言,像素值越高,频率越高,周围部分也就越亮

 

上图可能不是太明显,这是由于jupyter通过matplotlib显示图像不是太大,而且设置的1行3张,当我们只对比原图和低通滤波结果时,就会发现还是很明显的,如下所示:

 

在这里插入图片描述

 

通过上图可以知道,图像的噪声基本去掉,也就是说,低通滤波消除噪声的强度取决于你构造低通滤波的尺寸大小,尺寸越大,消除越不好,图像越清晰;尺寸越小,消除越好,图像越模糊

 

3)、同样的,彩色图像低通滤波无意义,但这里给一个显示结果,不要陷入太深哦;值得注意的是,彩色图像低通滤波的构造方法有点不一样,因为彩色是3通道图,因此,在构造低通滤波时,应该将滤波模板设置为3通道img2 = np.zeros((h, w,3), np.uint8),彩色图像低通滤波完整代码如下所示:

 

#彩色图像低通滤波
#彩色图像的高通滤波
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
#自定义傅里叶变换功能函数
def dft(img):
    #获取图像属性
    H,W,channel=img.shape
    #定义频域图,从公式可以看出为求出结果为复数,因此,需要定义为复数矩阵
    F = np.zeros((H, W,channel), dtype=np.complex)
    # 准备与原始图像位置相对应的处理索引
    x = np.tile(np.arange(W), (H, 1))
    y = np.arange(H).repeat(W).reshape(H, -1)
    #通过公式遍历
    for c in range(channel):
        for u in range(H):
            for v in range(W):
                F[u, v, c] = np.sum(img[..., c] * np.exp(-2j * np.pi * (x * u / W + y * v / H))) / np.sqrt(H * W)
    return F
#傅里叶反变换
def idft(G):
    H, W, channel = G.shape
    #定义空白时域图像
    out = np.zeros((H, W, channel), dtype=np.float32)
    # 准备与原始图像位置相对应的处理索引
    x = np.tile(np.arange(W), (H, 1))
    y = np.arange(H).repeat(W).reshape(H, -1)
    #通过公式遍历
    for c in range(channel):
        for u in range(H):
            for v in range(W):
                out[u, v, c] = np.abs(np.sum(G[..., c] * np.exp(2j * np.pi * (x * u / W + y * v / H)))) / np.sqrt(W * H)
    # 剪裁
    out = np.clip(out, 0, 255)
    out = out.astype(np.uint8)
    return out
#低通滤波构造
def lowPassFiltering(img,size):#传递参数为傅里叶变换后的频谱图和滤波尺寸
    h, w = img.shape[0:2]#获取图像属性
    h1,w1 = int(h/2), int(w/2)#找到傅里叶频谱图的中心点
    img2 = np.zeros((h, w,3), np.uint8)#定义空白黑色图像,和傅里叶变换传递的图尺寸一致
    img2[h1-int(size/2):h1+int(size/2), w1-int(size/2):w1+int(size/2)] = 1#中心点加减滤波尺寸的一半,刚好形成一个定义尺寸的滤波大小,然后设置为1,保留低频部分
    img3=img2*img #将定义的低通滤波与传入的傅里叶频谱图一一对应相乘,得到低通滤波
    return img3
#读取图像
img=cv2.imread("my.jpg")
h, w = img.shape[0:2]#获取图像属性
#加噪声
for i in range(3000):    #添加3000个噪声点
    x = np.random.randint(0, h) 
    y = np.random.randint(0, w)    
    img[x,y,:] = 255
#进行图像裁剪,加快傅里叶运算速率。将原始尺寸缩放为100*100的尺寸
img = cv2.resize(img, (100, 100), interpolation=cv2.INTER_CUBIC)
#BGR转换为RGB显示格式,方便通过matplotlib进行图像显示
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#调用傅里叶变换函数
result =dft(img)
#将傅里叶频谱图从左上角移动到中心位置
fshift = np.fft.fftshift(result)
img1=lowPassFiltering(fshift,30)
#将复数转为浮点数进行傅里叶频谱图显示
fimg = np.log(np.abs(img1))#复数转为整数,方便显示傅里叶频谱图
#将傅里叶频谱图从中心还原到左上角位置
ishift = np.fft.ifftshift(img1)
#调用傅里叶逆变换函数
result2=idft(ishift)
#图像显示
plt.subplot(131), plt.imshow(img), plt.title('原图像')
plt.axis('off')
plt.subplot(132), plt.imshow(fimg), plt.title('低通滤波')
plt.axis('off')
plt.subplot(133), plt.imshow(result2), plt.title('低通滤波结果')
plt.axis('off')
plt.show()

 

在这里插入图片描述

 

上面可以看出,彩色图像的低通滤波处理去噪效果比较明显啦,就是图像模糊较快,多用于图像平滑、去噪!

 

 

注意:在尺寸的设计中,不要超过图像的原尺寸,否则没有效果哦,以上代码自己将原图缩小成100×100尺寸的,只为了加快代码运行速度哦,大家记得对照修改!

 

以上就是本次博客的全部内容,遇到问题的小伙伴记得留言评论,学长看到会为大家进行解答的,这个学长不太冷!

 

趁我们都还年轻bai,多走几步路,多欣赏下沿途du的风景,zhi不要急于抵达目的地而错过了流年里温暖dao的人和物;趁我们都还年轻,多说些浪漫的话语,多做些幼稚的事情,不要嫌人笑话错过了生命中最美好的片段和场合;趁我们都还年轻,把距离缩短,把时间延长。趁我们都还年轻,多做些我们想要做的任何事

陈一月的又一天编程岁月^ _ ^

发表评论

后才能评论