kongen kongen
首页
导航站
  • 学习教程

    • Opencv教程
    • C++基础教程
    • C++_Primer教程
    • CUDA编程
  • Opencv
  • CNN
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 面试题库

    • HTML
    • CSS
    • jQuery
    • Vue
    • 零碎
  • 面试心得

    • 杂言碎语
  • 十架道路

    • 十架七言系列
    • 基督徒生活观
    • 上帝的蓝图
  • 摘抄收录

    • ☆ 励志鸡汤
    • ❀ 人间烟火
  • 读书笔记

    • 《小狗钱钱》
    • 《穷爸爸富爸爸》
    • 《聪明人使用方格笔记本》
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Kongen

你好呀(✪ω✪)
首页
导航站
  • 学习教程

    • Opencv教程
    • C++基础教程
    • C++_Primer教程
    • CUDA编程
  • Opencv
  • CNN
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 面试题库

    • HTML
    • CSS
    • jQuery
    • Vue
    • 零碎
  • 面试心得

    • 杂言碎语
  • 十架道路

    • 十架七言系列
    • 基督徒生活观
    • 上帝的蓝图
  • 摘抄收录

    • ☆ 励志鸡汤
    • ❀ 人间烟火
  • 读书笔记

    • 《小狗钱钱》
    • 《穷爸爸富爸爸》
    • 《聪明人使用方格笔记本》
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • OpenCV简介

  • OpenCV中的 Gui特性

  • 核心操作

  • OpenCV中的图像处理

    • 改变颜色空间
    • 图像的几何变换
    • 图像阈值
    • 图像滤波
    • 形态变换
    • 图形梯度
    • Canny边缘检测
    • 图像金字塔
    • 轮廓:入门
    • 轮廓特征
    • 轮廓属性
    • 轮廓:更多函数
    • 轮廓:层次结构
    • 直方图1:查找,绘画,分析
    • 直方图2:均衡直方图
    • 直方图3:2D直方图
    • 反投影直方图
    • 傅里叶变换
      • 目标:
      • 理论
      • Numpy中的傅里叶变换
      • OpenCV中的傅里叶变换
      • DFT的性能优化
      • 为什么拉普拉斯算子是高通滤波器?
    • 模板匹配
    • 霍夫线变换
    • 霍夫圆变换
    • 基于GrabCut算法的交互式前景提取
    • 基于分水岭算法的图像分割
  • 特征检测和描述

  • 视频分析

  • 相机校准和3D重建

  • 机器学习

  • 计算摄影

  • 目标检测

  • Opencv基础原理
  • OpenCV中的图像处理
kongen
2019-06-11
目录

傅里叶变换

# 目标:

  • 使用OpenCV查找图像的傅立叶变换
  • 使用Numpy中提供的FFT函数
  • 傅立叶变换的一些应用
  • 我们将看到以下函数:cv.dft(),cv.idft()等

# 理论

傅立叶变换用于分析各种滤波器的频率特性。对于图像,2D离散傅里叶变换(DFT)用于找到频域。称为快速傅里叶变换(FFT)的快速算法用于计算DFT。有关这些的详细信息可以在任何图像处理或信号处理教科书中找到。

对于正弦信号,x(t)= Asin(2πft),我们可以说f是信号的频率,如果采用其频域,我们可以看到f处的尖峰。如果对信号进行采样以形成离散信号,则我们得到相同的频域,但在[-π,π]或[0,2π](或对于N点DFT的[0,N])范围内是周期性的。你可以将图像视为在两个方向上采样的信号。因此,在X和Y方向上进行傅里叶变换可以得到图像的频率表示。

更直观地说,对于正弦信号,如果幅度在短时间内变化如此之快,则可以说它是高频信号。如果变化缓慢,则为低频信号。你可以将相同的想法扩展到图像。幅度在图像中的幅度变化很大?在边缘点,或噪音。我们可以说,边缘和噪声是图像中的高频内容。如果幅度没有太大变化,则它是低频分量。 (一些链接被添加到Additional Resources_,它通过示例直观地解释了频率变换)。

现在我们将看到如何找到傅立叶变换。

# Numpy中的傅里叶变换

首先,我们将看到如何使用Numpy找到傅立叶变换。Numpy有一个FFT包来做到这一点。np.fft.fft2()为我们提供了一个复杂数组的频率变换。它的第一个参数是输入图像,它是灰度。第二个参数是可选的,它决定了输出数组的大小。如果它大于输入图像的大小,则在计算FFT之前用零填充输入图像。如果小于输入图像,则将裁剪输入图像。如果没有传递参数,则输出数组大小将与输入相同。

现在,一旦得到结果,零频率分量(DC分量)将位于左上角。如果要将其置于中心位置,则需要在两个方向上将结果移动$$\frac{N}{2}$$。这只是通过函数np.fft.fftshift()完成的。找到频率变换后,你可以找到幅度谱。

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

img = cv.imread('messi5.jpg',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()
1
2
3
4
5
6
7
8
9
10
11
12
13

窗口将如下图显示:

image57

请注意,你可以在中心看到更多更白的区域,显示低频内容更多。

所以你找到了频率变换现在你可以在频域做一些操作,比如高通滤波和重建图像,即找到逆DFT。 为此,你只需通过使用尺寸为60x60的矩形窗口进行遮罩来移除低频。 然后使用np.fft.ifftshift()应用反向移位,以便DC组件再次出现在左上角。 然后使用np.ifft2()函数找到逆FFT。 结果再次是一个复杂的数字。 你可以采取它的绝对价值。

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)
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()
1
2
3
4
5
6
7
8
9
10
11
12
13

窗口将如下图显示:

image58

结果显示高通滤波是边缘检测操作。这是我们在Image Gradients章节中看到的。这也表明大多数图像数据存在于光谱的低频区域。无论如何,我们已经看到如何在Numpy中找到DFT,IDFT等。现在让我们看看如何在OpenCV中完成它。

如果你仔细观察结果,特别是JET颜色的最后一个图像,你可以看到一些文物(我用红色箭头标记的一个实例)。它在那里显示出一些类似波纹的结构,它被称为振铃效应。它是由我们用于遮蔽的矩形窗口引起的。此蒙版转换为sinc形状,这会导致此问题。因此矩形窗口不用于过滤。更好的选择是高斯Windows。

# OpenCV中的傅里叶变换

OpenCV为此提供了cv.dft()和cv.idft()函数。它返回与之前相同的结果,但有两个通道。第一个通道将具有结果的实部,第二个通道将具有结果的虚部。输入图像应首先转换为np.float32。我们将看到如何做到这一点。

import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv.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()
1
2
3
4
5
6
7
8
9
10
11

注意:你还可以使用cv.cartToPolar(),它可以一次性返回幅度和相位

所以,现在我们必须进行逆DFT。 在之前的会话中,我们创建了一个HPF,这次我们将看到如何去除图像中的高频内容,即我们将LPF应用于图像。 它实际上模糊了图像。 为此,我们首先在低频处创建具有高值(1)的掩模,即我们传递LF内容,并且在HF区域传递0。

rows, cols = img.shape
crow,ccol = rows/2 , 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 = cv.idft(f_ishift)
img_back = cv.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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

窗口将如下图显示:

image59

注意:像往常一样,OpenCV函数cv.dft()和cv.idft()比Numpy函数更快。 但是Numpy功能更加用户友好。 有关性能问题的更多详细信息,请参阅以下部分。

# DFT的性能优化

对于某些阵列大小,DFT计算的性能更好。 当阵列大小为2的幂时,它是最快的。 尺寸为2,3和5的乘积的阵列也可以非常有效地处理。 因此,如果你担心代码的性能,可以在找到DFT之前将数组的大小修改为任何最佳大小(通过填充零)。 对于OpenCV,你必须手动填充零。 但对于Numpy,你可以指定FFT计算的新大小,它会自动为你填充零。

那么我们如何找到这个最佳尺寸? OpenCV为此提供了一个函数cv.getOptimalDFTSize()。 它适用于cv.dft()和np.fft.fft2()。 让我们使用IPython magic命令timeit检查它们的性能。

In [16]: img = cv.imread('messi5.jpg',0)
In [17]: rows,cols = img.shape
In [18]: print("{} {}".format(rows,cols))
342 548
In [19]: nrows = cv.getOptimalDFTSize(rows)
In [20]: ncols = cv.getOptimalDFTSize(cols)
In [21]: print("{} {}".format(nrows,ncols))
360 576
1
2
3
4
5
6
7
8

看,大小(342,548)被修改为(360,576)。 现在让我们用零填充它(对于OpenCV)并找到它们的DFT计算性能。 你可以通过创建一个新的大零数组并将数据复制到它,或使用cv.copyMakeBorder()来实现。

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

或者

right = ncols - cols
bottom = nrows - rows
bordertype = cv.BORDER_CONSTANT #just to avoid line breakup in PDF file
nimg = cv.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)
1
2
3
4

现在我们计算Numpy函数的DFT性能比较:

In [22]: %timeit fft1 = np.fft.fft2(img)
10 loops, best of 3: 40.9 ms per loop
In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols])
100 loops, best of 3: 10.4 ms per loop
1
2
3
4

它显示了4倍的加速。现在我们将尝试使用OpenCV函数。

In [24]: %timeit dft1= cv.dft(np.float32(img),flags=cv.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 13.5 ms per loop
In [27]: %timeit dft2= cv.dft(np.float32(nimg),flags=cv.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 3.11 ms per loop
1
2
3
4

它还显示了4倍的加速。 你还可以看到OpenCV函数比Numpy函数快3倍。这也可以进行逆FFT测试,这可以作为练习。

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

在论坛中提出了类似的问题。 问题是,为什么拉普拉斯算子是高通滤波器? 为什么Sobel是HPF? 第一个答案就是傅立叶变换。 只需将拉普拉斯算子的傅里叶变换用于更高尺寸的FFT。 分析一下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# simple averaging filter without scaling parameter
mean_filter = np.ones((3,3))
# creating a gaussian filter
x = cv.getGaussianKernel(5,10)
gaussian = x*x.T
# different edge detecting filters
# scharr in x-direction
scharr = np.array([[-3, 0, 3],
                   [-10,0,10],
                   [-3, 0, 3]])
# sobel in x direction
sobel_x= np.array([[-1, 0, 1],
                   [-2, 0, 2],
                   [-1, 0, 1]])
# sobel in y direction
sobel_y= np.array([[-1,-2,-1],
                   [0, 0, 0],
                   [1, 2, 1]])
# laplacian
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 xrange(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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

窗口将如下图显示:

image60

编辑 (opens new window)
反投影直方图
模板匹配

← 反投影直方图 模板匹配→

最近更新
01
附录L_CUDA底层驱动API
02-08
02
附录K_CUDA计算能力
02-08
03
附录J纹理获取
02-08
更多文章>
Theme by Vdoing | Copyright © 2024-2025 Kongen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×