OpenCV官方教程中文版 —— 傅里叶变换

OpenCV官方教程中文版 —— 傅里叶变换

  • 前言
  • 一、原理
  • 二、Numpy 中的傅里叶变换
  • 三、OpenCV 中的傅里叶变换
  • 四、为什么拉普拉斯算子是高通滤波器?

前言

本小节我们将要学习:

使用 OpenCV 对图像进行傅里叶变换

使用 Numpy 中 FFT(快速傅里叶变换)函数

傅里叶变换的一些用处

我们将要学习的函数有:cv2.dft(),cv2.idft() 等

一、原理

傅里叶变换经常被用来分析不同滤波器的频率特性。我们可以使用 2D 离散傅里叶变换 (DFT) 分析图像的频域特性。实现 DFT 的一个快速算法被称为快速傅里叶变换(FFT)。关于傅里叶变换的细节知识可以在任意一本图像处理或信号处理的书中找到。请查看本小节中更多资源部分。

对于一个正弦信号:x (t) = A sin (2πft), 它的频率为 f,如果把这个信号转到它的频域表示,我们会在频率 f 中看到一个峰值。如果我们的信号是由采样产生的离散信号好组成,我们会得到类似的频谱图,只不过前面是连续的,现在是离散。你可以把图像想象成沿着两个方向采集的信号。所以对图像同时进行 X 方向和 Y 方向的傅里叶变换,我们就会得到这幅图像的频域表示(频谱图)。

更直观一点,对于一个正弦信号,如果它的幅度变化非常快,我们可以说他是高频信号,如果变化非常慢,我们称之为低频信号。你可以把这种想法应用到图像中,图像那里的幅度变化非常大呢?边界点或者噪声。所以我们说边界和噪声是图像中的高频分量(注意这里的高频是指变化非常快,而非出现的次数多)。如果没有如此大的幅度变化我们称之为低频分量。

现在我们看看怎样进行傅里叶变换。

二、Numpy 中的傅里叶变换

首先我们看看如何使用 Numpy 进行傅里叶变换。Numpy 中的 FFT 包可以帮助我们实现快速傅里叶变换。函数 np.fft.fft2() 可以对信号进行频率转换,输出结果是一个复杂的数组。本函数的第一个参数是输入图像,要求是灰度格式。第二个参数是可选的, 决定输出数组的大小。输出数组的大小和输入图像大小一样。如果输出结果比输入图像大,输入图像就需要在进行 FFT 前补0。如果输出结果比输入图像小的话,输入图像就会被切割。

现在我们得到了结果,频率为 0 的部分(直流分量)在输出图像的左上角。如果想让它(直流分量)在输出图像的中心,我们还需要将结果沿两个方向平移 N/2 。函数 np.fft.fftshift() 可以帮助我们实现这一步。(这样更容易分析)。进行完频率变换之后,我们就可以构建振幅谱了。

# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('ball.png', 0)
f = np.fft.fft2(img)
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 的逆变换)。比如我们可以使用一个60x60 的矩形窗口对图像进行掩模操作从而去除低频分量。然后再使用函数np.fft.ifftshift() 进行逆平移操作,所以现在直流分量又回到左上角了,左后使用函数 np.ifft2() 进行 FFT 逆变换。同样又得到一堆复杂的数字,我们可以对他们取绝对值:

rows, cols = img.shape
crow, ccol = int(rows / 2), int(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)
plt.figure()
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()

结果如下:
在这里插入图片描述
上图的结果显示高通滤波其实是一种边界检测操作。这就是我们在前面图像梯度那一章看到的。同时我们还发现图像中的大部分数据集中在频谱图的低频区域。我们现在已经知道如何使用 Numpy 进行 DFT 和 IDFT 了,接着我们来看看如何使用 OpenCV 进行这些操作。

如果你观察仔细的话,尤其是最后一章 JET 颜色的图像,你会看到一些不自然的东西(如我用红色箭头标出的区域)。看上图那里有些条带装的结构,这被成为振铃效应。这是由于我们使用矩形窗口做掩模造成的。这个掩模被转换成正弦形状时就会出现这个问题。所以一般我们不适用矩形窗口滤波。最好的选择是高斯窗口。

三、OpenCV 中的傅里叶变换

OpenCV 中相应的函数是 cv2.dft()cv2.idft()。和前面输出的结果一样,但是是双通道的。第一个通道是结果的实数部分,第二个通道是结果的虚数部分。输入图像要首先转换成 np.float32 格式。我们来看看如何操作。

plt.figure()
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()

在这里插入图片描述
现在我们来做逆 DFT。在前面的部分我们实现了一个 HPF(高通滤波),现在我们来做 LPF(低通滤波)将高频部分去除。其实就是对图像进行模糊操作。首先我们需要构建一个掩模,与低频区域对应的地方设置为 1, 与高频区域对应的地方设置为 0。

rows, cols = img.shape
crow, ccol = int(rows / 2), int(cols / 2)
# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# apply mask and inverse DFT
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.figure()
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()

在这里插入图片描述

四、为什么拉普拉斯算子是高通滤波器?

我在论坛中遇到了一个类似的问题。为什么拉普拉斯算子是高通滤波器?为什么 Sobel 是 HPF?等等。对于第一个问题的答案我们以傅里叶变换的形式给出。我们一起来对不同的算子进行傅里叶变换并分析它们:

# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as pltmean_filter = np.ones((3, 3))  # simple averaging filter without scaling parameter
x = cv2.getGaussianKernel(5, 10)  # creating a guassian filter
gaussian = x * x.T  # x.T 为矩阵转置
# different edge detecting filters
scharr = np.array([[-3, 0, 3],[-10, 0, 10],[-3, 0, 3]])  # scharr in x-direction
sobel_x = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])  # sobel in x direction
sobel_y = np.array([[-1, -2, -1],[0, 0, 0],[1, 2, 1]])  # sobel in y direction
laplacian = np.array([[0, 1, 0],[1, -4, 1],[0, 1, 0]])  # laplacian
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 = [20 * 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()

在这里插入图片描述
从图像中我们就可以看出每一个算子允许通过那些信号。从这些信息中我们就可以知道那些是 HPF 那是 LPF。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/121353.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多线程线程池

线程安全问题 当多个线程同时操作同一个共享资源的时候,可能会出现结果不符合预期的问题 解决安全问题 方式一: 同步代码块 作用: 把访问共享资源的核心代码给上锁,以此保证线程安全 格式: synchronized(同步锁) { 访问共享资源的核心代…

202310-MetaPhlAn4安装和使用方法-Anaconda3- centos9 stream

MetaPhlAn 4是一种基于DNA序列的微生物组分析工具,它能够从宏基因组测序数据中识别和分离微生物的组成。以下是安装和使用MetaPhlAn 4的步骤: 安装MetaPhlAn 4: 裸机环境,手动安装( 1. 安装依赖项: Met…

unocss和tailwindcss css原子引擎

第一种tailwindcss: tailwindcss官网 https://tailwindcss.com/docs/grid-column 基本介绍及优点分析 Tailwind CSS 中文文档 - 无需离开您的HTML,即可快速建立现代网站 PostCss 处理 Tailwind Css 基本流程 PostCSS - 是一个用 JavaScript 工具和插…

SM3加密udf

SM3加密udf maven xml <dependencies> <!-- 配置日志 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.5</version> </dep…

67 内网安全-域横向smbwmi明文或hash传递

#知识点1: windows2012以上版本默认关闭wdigest&#xff0c;攻击者无法从内存中获取明文密码windows2012以下版本如安装KB2871997补丁&#xff0c;同样也会导致无法获取明文密码针对以上情况&#xff0c;我们提供了4种方式解决此类问题 1.利用哈希hash传递(pth&#xff0c;ptk等…

读书笔记:c++对话系列,Visitor模式

需要在类体系中加入一个新的虚函数&#xff0c;但不允许改动。 Visitor模式&#xff0c;核心是&#xff1a;将操作作为数据对象传递给类体系预留的Accept函数。 class Personnel{ public:virtual void Pay () 0;virtual void Promote() 0;virtual void Accept(Visitor &…

缓冲channel和限制goroutine并发数

文章目录 3.7.1 用作计数信号量3.7.2 使用缓存channelsync.WaitGroup限制并发数&#xff08;类似上小节&#xff09; 要限制住goroutine的并发, 一定要阻塞住main的goroutine! 一定要阻塞住main的goroutine! 一定要阻塞住main的goroutine! 可以看最后一个例子。 由于带缓冲cha…

尚未解决:use_python()和use_virtualenv()的使用

reticulate包为Python和R之间的互操作性提供了一套全面的工具。该包包含以下功能&#xff1a; 以多种方式从R调用Python&#xff0c;包括RMarkdown、获取Python脚本、导入Python模块以及在R会话中交互使用Python。 R和Python对象之间的转换&#xff08;例如&#xff0c;R和Pan…

2023年中国调音台产业链、产量及市场规模分析[图]

调音台是一种专业音频设备&#xff0c;用于混音、处理和控制音频信号。它通常用于音乐制作、现场演出、录音室以及广播等场景中。调音台允许用户调整不同声音来源的音频信号&#xff0c;使其在混音过程中达到理想的音质和平衡。调音台按信号出来方式可分为&#xff1a;模拟式调…

UVa10976 Fractions Again?!(分数拆分)

1、题目 2、题意 输入正整数 k k k&#xff0c;找到所有正整数 x ≥ y x \ge y x≥y&#xff0c;使得 1 k 1 x 1 y \frac{1}{k} \frac{1}{x} \frac{1}{y} k1​x1​y1​。 3、分析 既然要求找出所有的 x , y x,y x,y&#xff0c;枚举对象自然是 x , y x,y x,y了。可…

LeetCode每日一题——2558. Take Gifts From the Richest Pile

文章目录 一、题目二、题解 一、题目 2558. Take Gifts From the Richest Pile You are given an integer array gifts denoting the number of gifts in various piles. Every second, you do the following: Choose the pile with the maximum number of gifts. If there …

名词解释 MongoDB

MongoDB 是一个面向文档的数据库管理系统&#xff0c;它不使用传统的表格结构&#xff0c;而是将数据组织成类似文档的形式&#xff0c;通常使用JSON格式。 文档数据库&#xff1a;数据以文档的形式存储&#xff0c;每个文档可以包含不同的字段&#xff0c;就像一个文件可以包…

day36(http协议 服务器软件的使用 PHP的简单了解 前后端交互 ajax 同步和异步)

一.http协议 1.http1&#xff09;前后端交互&#xff1a;前端发数据给后端&#xff0c;后端获取前端数据&#xff0c;经过解析&#xff0c;返回需要的数据2&#xff09;数据如何交互&#xff1f;请求响应3&#xff09;概念&#xff1a;http&#xff08;超文本传输协议&#xf…

C# 基于腾讯云人脸核身和百度云证件识别技术相结合的 API 实现

目录 腾讯云人脸核身技术 Craneoffice.net 采用的识别方式 1、活体人脸核身(权威库)&#xff1a; 2、活体人脸比对&#xff1a; 3、照片人脸核身(权威库)&#xff1a; 调用成本 百度云身份证识别 调用成本 相关结合点 核心代码 实现调用人脸核身API的示例 实现调用身…

拓世大模型 | 立足行业所需,发力终端,缔造智能无限可能

蒸汽机的发明为人类工业革命揭开序幕&#xff0c;引领了近现代产业变革。众所周知&#xff0c;而今AI技术的革命性突破&#xff0c;站在了时代舞台的中心&#xff0c;特别是大模型的崛起&#xff0c;无疑是第四次产业革命的焦点&#xff0c;它的地位可与当年的“蒸汽机”相提并…

性能诊断工具对比+Prometheus(普罗米修斯)监控系统学习

【精选】Prometheus&#xff08;普罗米修斯&#xff09;监控系统_普罗米修斯监控_愿许浪尽天涯的博客-CSDN博客 Java 性能诊断工具 &#x1f3cd;️... Java自带的工具 JConsoleJVisualVMjmapjstackjcmd单机图形化诊断工具 YourKitJProfilerVisualVMArthas分布式诊断工具 Zipk…

Jenkins发布windows服务器jar

一、背景 之前是linux服务器部署的项目&#xff0c;现在转为windows服务器部署。jenkins和git都已经部署好了。所以本文只会重点讲Jenkins调用windows服务器bat命令及bat命令的编写概况。 二、详情操作 1、Jenkins调用windows bat文件 首先在Jenkins项目配置"高级项目选…

【git命令】删除分支

1. 删除本地分支 使用git branch -d命令删除本地分支 git branch -d branch_name其中&#xff0c;branch_name是分支名。如果有未合并的更改&#xff0c;Git会阻止你删除分支。 使用git branch -D命令强制删除本地分支 git branch -D branch_name这个命令会强制删除分支&am…

JAVA排序

目录 再看各种排序前我们先了解一下什么叫 稳定性 插入排序&#xff1a; 希尔排序:(插入排序的优化) 测试插入排序和希尔排序(插入排序的优化)排序时间对比 选择排序: 选择排序的优化: 正确的 选择排序优化 快速排序(挖坑法:未优化) 快速排序的优化1 快速排序优化2 优化快速排序…

mysql4

创建表并插入数据&#xff1a; 字段名 数据类型 主键 外键 非空 唯一 自增 id INT 是 否 是 是 否 primary key name VARCHAR(50) 否 否 是 否 否 not null glass VARCHAR(50) 否 否 是 否 否 not nullsch 表内容 id name glass 1 xiaommg glass 1 2 xiaojun …