OpenCV图像变换之傅里叶变换的一些应用


Posted in Python onJuly 26, 2021

前言

这篇博客将介绍OpenCV中的图像变换,包括用Numpy、OpenCV计算图像的傅里叶变换,以及傅里叶变换的一些应用;

2D Discrete Fourier Transform (DFT)二维离散傅里叶变换
Fast Fourier Transform (FFT) 快速傅里叶变换

傅立叶变换用于分析各种滤波器的频率特性。对于图像采用二维离散傅立叶变换(DFT)求频域。一种称为快速傅立叶变换(FFT)的快速算法用于DFT的计算。

OpenCV使用cv2.dft()、cv2.idft() 实现傅里叶变换,效率更高一些(比OpenCV快3倍)

Numpy使用np.ifft2() 、np.fft.ifftshift() 实现傅里叶变换,使用更友好一些;

1. 效果图

灰度图 VS 傅里叶变换效果图如下:

可以看到白色区域大多在中心,显示低频率的内容比较多。

OpenCV图像变换之傅里叶变换的一些应用

傅里叶变换去掉低频内容后效果图如下:

可以看到使用矩形滤波后,效果并不好,有波纹的振铃效果;用高斯滤波能好点;

OpenCV图像变换之傅里叶变换的一些应用

傅里叶变换去掉高频内容后效果图如下:

删除图像中的高频内容,即将LPF应用于图像,它实际上模糊了图像。

OpenCV图像变换之傅里叶变换的一些应用

各滤波器是 HPF(High Pass Filter)还是 LPF(Low Pass Filter),一目了然:

拉普拉斯是高频滤波器;

OpenCV图像变换之傅里叶变换的一些应用

2. 原理

  • DFT的性能优化:在一定的阵列尺寸下,DFT计算的性能较好。当数组大小为2的幂时,速度最快。大小为2、3和5的乘积的数组也可以非常有效地处理。

为达到最佳性能,可以通过OpenCV提供的函数cv2.getOptimalDFTSize() 寻找最佳尺寸。
然后将图像填充成最佳性能大小的阵列,对于OpenCV,必须手动填充零。但是对于Numpy,可以指定FFT计算的新大小,会自动填充零。

通过使用最优阵列,基本能提升4倍的效率。而OpenCV本身比Numpy效率快近3倍;

拉普拉斯是高通滤波器(High Pass Filter)

3. 源码

3.1 Numpy实现傅里叶变换

# 傅里叶变换

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('ym3.jpg', 0)

# 使用Numpy实现傅里叶变换:fft包
# fft.fft2() 进行频率变换
# 参数1:输入图像的灰度图
# 参数2:>输入图像 用0填充;  <输入图像 剪切输入图像; 不传递 返回输入图像
f = np.fft.fft2(img)

# 一旦得到结果,零频率分量(直流分量)将出现在左上角。
# 如果要将其置于中心,则需要使用np.fft.fftshift()将结果在两个方向上移动。
# 一旦找到了频率变换,就能找到幅度谱。
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20 * np.log(np.abs(fshift))

plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(magnitude_spectrum, cmap='gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

# 找到了频率变换,就可以进行高通滤波和重建图像,也就是求逆DFT
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
fshift[crow - 30:crow + 30, ccol - 30:ccol + 30] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.abs(img_back)

# 图像渐变章节学习到:高通滤波是一种边缘检测操作。这也表明大部分图像数据存在于频谱的低频区域。
# 仔细观察结果可以看到最后一张用JET颜色显示的图像,有一些瑕疵(它显示了一些波纹状的结构,这就是所谓的振铃效应。)
# 这是由于用矩形窗口mask造成的,掩码mask被转换为sinc形状,从而导致此问题。所以矩形窗口不用于过滤,更好的选择是高斯mask。)
plt.subplot(131), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132), plt.imshow(img_back, cmap='gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133), plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])

plt.show()

3.2 OpenCV实现傅里叶变换

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('ym3.jpg', 0)
rows, cols = img.shape
print(rows, cols)

# 计算DFT效率最佳的尺寸
nrows = cv2.getOptimalDFTSize(rows)
ncols = cv2.getOptimalDFTSize(cols)
print(nrows, ncols)

nimg = np.zeros((nrows, ncols))
nimg[:rows, :cols] = img
img = nimg

# OpenCV计算快速傅里叶变换,输入图像应首先转换为np.float32,然后使用函数cv2.dft()和cv2.idft()。
# 返回结果与Numpy相同,但有两个通道。第一个通道为有结果的实部,第二个通道为有结果的虚部。
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))

plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(magnitude_spectrum, cmap='gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

rows, cols = img.shape
crow, ccol = rows // 2, cols // 2

# 首先创建一个mask,中心正方形为1,其他均为0
# 如何删除图像中的高频内容,即我们将LPF应用于图像。它实际上模糊了图像。
# 为此首先创建一个在低频时具有高值的掩码,即传递LF内容,在HF区域为0。
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow - 30:crow + 30, ccol - 30:ccol + 30] = 1

# 应用掩码Mask和求逆DTF
fshift = dft_shift * mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])

plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(img_back, cmap='gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

3.3 HPF or LPF?

import cv2
import numpy as np
from matplotlib import pyplot as plt

# 简单的均值滤波
mean_filter = np.ones((3, 3))

# 构建高斯滤波
x = cv2.getGaussianKernel(5, 10)
gaussian = x * x.T

# 不同的边缘检测算法Scharr-x方向
scharr = np.array([[-3, 0, 3],
                   [-10, 0, 10],
                   [-3, 0, 3]])
# Sobel_x
sobel_x = np.array([[-1, 0, 1],
                    [-2, 0, 2],
                    [-1, 0, 1]])
# Sobel_y
sobel_y = np.array([[-1, -2, -1],
                    [0, 0, 0],
                    [1, 2, 1]])
# 拉普拉斯
laplacian = np.array([[0, 1, 0],
                      [1, -4, 1],
                      [0, 1, 0]])

filters = [mean_filter, gaussian, laplacian, sobel_x, sobel_y, scharr]
filter_name = ['mean_filter', 'gaussian', 'laplacian', 'sobel_x', \
               'sobel_y', 'scharr_x']
fft_filters = [np.fft.fft2(x) for x in filters]
fft_shift = [np.fft.fftshift(y) for y in fft_filters]
mag_spectrum = [np.log(np.abs(z) + 1) for z in fft_shift]

for i in range(6):
    plt.subplot(2, 3, i + 1), plt.imshow(mag_spectrum[i], cmap='gray')
    plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])

plt.show()

参考

  • https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.html#fourier-transform

总结

到此这篇关于OpenCV图像变换之傅里叶变换的文章就介绍到这了,更多相关OpenCV图像变换傅里叶变换内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python中MySQLdb模块用法实例
Nov 10 Python
Python中的条件判断语句与循环语句用法小结
Mar 21 Python
python 获取当天每个准点时间戳的实例
May 22 Python
Python绘制KS曲线的实现方法
Aug 13 Python
浅谈python3发送post请求参数为空的情况
Dec 28 Python
Python面向对象程序设计OOP深入分析【构造函数,组合类,工具类等】
Jan 05 Python
实例详解python函数的对象、函数嵌套、名称空间和作用域
May 31 Python
Python列表对象实现原理详解
Jul 01 Python
PyQtGraph在pyqt中的应用及安装过程
Aug 04 Python
Python 找出出现次数超过数组长度一半的元素实例
May 11 Python
python 图像插值 最近邻、双线性、双三次实例
Jul 05 Python
教你使用Python pypinyin库实现汉字转拼音
May 27 Python
Python类方法总结讲解
pandas数值排序的实现实例
Jul 25 #Python
python非标准时间的转换
Jul 25 #Python
OpenCV 图像梯度的实现方法
Jul 25 #Python
ROS系统将python包编译为可执行文件的简单步骤
Jul 25 #Python
Pandas自定义选项option设置
Jul 25 #Python
Pandas 稀疏数据结构的实现
Jul 25 #Python
You might like
php递归实现无限分类生成下拉列表的函数
2010/08/08 PHP
延长phpmyadmin登录时间的方法
2011/02/06 PHP
php基于socket实现SMTP发送邮件的方法
2015/03/05 PHP
thinkphp集成前端脚手架Vue-cli的教程图解
2018/08/30 PHP
Laravel5.4框架使用socialite实现github登录的方法
2019/03/20 PHP
js使用递归解析xml
2014/12/12 Javascript
JavaScript使用FileSystemObject对象写入文本文件内容的方法
2015/08/05 Javascript
三种Node.js写文件的方式
2016/03/08 Javascript
浅谈jquery中的each方法$.each、this.each、$.fn.each
2016/06/23 Javascript
jQuery下拉框的简单应用
2016/06/24 Javascript
浅谈JSON.stringify()和JOSN.parse()方法的不同
2016/08/29 Javascript
JS正则表达式修饰符global(/g)用法分析
2016/12/27 Javascript
nodejs入门教程四:URL相关模块用法分析
2017/04/24 NodeJs
Vue.js在使用中的一些注意知识点
2017/04/29 Javascript
Angular使用Md5加密的解决方法
2017/09/16 Javascript
vue webuploader 文件上传组件开发
2017/09/23 Javascript
vue实现未登录跳转到登录页面的方法
2018/07/17 Javascript
Vue 第三方字体图标引入 Font Awesome的方法
2018/09/28 Javascript
layui实现下拉框三级联动
2019/07/26 Javascript
使用axios发送post请求,将JSON数据改为form类型的示例
2019/10/31 Javascript
js实现删除json中指定的元素
2020/09/22 Javascript
使用python将excel数据导入数据库过程详解
2019/08/27 Python
tensorflow中tf.slice和tf.gather切片函数的使用
2020/01/19 Python
Python列表倒序输出及其效率详解
2020/03/04 Python
利用python实现凯撒密码加解密功能
2020/03/31 Python
Python计算信息熵实例
2020/06/18 Python
Python远程linux执行命令实现
2020/11/11 Python
客服端调用EJB对象的几个基本步骤
2012/01/15 面试题
爱岗敬业演讲稿范文
2014/01/14 职场文书
公司接待方案
2014/03/08 职场文书
热爱祖国演讲稿
2014/05/04 职场文书
锦旗标语大全
2014/06/23 职场文书
科学发展观活动总结
2014/08/28 职场文书
2014年检验科工作总结
2014/11/22 职场文书
搭讪开场白台词大全
2015/05/28 职场文书
Golang gRPC HTTP协议转换示例
2022/06/16 Golang