OpenCV学习笔记5

图像变换

傅里叶变换

这里可以先学习一下卷积分,了解清除卷积的过程和实际意义,在看这一章节的内容。

原理:

傅里叶变换经常被用来分析不同滤波器的频率特性。我们可以使用 2D 离散傅里叶变换 (DFT) 分析图像的频域特性。实现 DFT 的一个快速算法被称为快速傅里叶变换(FFT)。关于傅里叶变换的细节知识可以在任意一本图像处理或信号处理的书中找到。请查看本小节中更多资源部分。 对于一个正弦信号:x (t) = A sin (2πf t), 它的频率为 f,如果把这个信号转到它的频域表示,我们会在频率 f 中看到一个峰值。如果我们的信号是由采样产生的离散信号好组成,我们会得到类似的频谱图,只不过前面是连续的,现在是离散。你可以把图像想象成沿着两个方向采集的信号。所以对图像同时进行 X 方向和 Y 方向的傅里叶变换,我们就会得到这幅图像的频域表示(频谱图)。 更直观一点,对于一个正弦信号,如果它的幅度变化非常快,我们可以说他是高频信号,如果变化非常慢,我们称之为低频信号。你可以把这种想法应用到图像中,图像那里的幅度变化非常大呢?边界点或者噪声。所以我们说边界和噪声是图像中的高频分量(注意这里的高频是指变化非常快,而非出现的次数多)。如果没有如此大的幅度变化我们称之为低频分量。 现在我们看看怎样进行傅里叶变换

Numpy 中的傅里叶变换

首先我们看看如何使用 Numpy 进行傅里叶变换。Numpy 中的 FFT 包可以帮助我们实现快速傅里叶变换。函数 np.fft.fft2() 可以对信号进行频率转换,输出结果是一个复杂的数组。本函数的第一个参数是输入图像,要求是灰度格式。第二个参数是可选的, 决定输出数组的大小。输出数组的大小和输入图像大小一样。如果输出结果比输入图像大,输入图像就需要在进行 FFT 前补0。如果输出结果比输入图像小的话,输入图像就会被切割。 现在我们得到了结果,频率为 0 的部分(直流分量)在输出图像的左上角。如果想让它(直流分量)在输出图像的中心我们还需要将结果沿两个方向平移 N/2 。函数 np.fft.fftshift() 可以帮助我们实现这一步。(这样更容易分析)。 进行完频率变换之后,我们就可以构建振幅谱了。

import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread('../img/fooot.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 逆变换。同样又得到一堆复杂的数字,我们可以对他们取绝对值:

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('../img/fooot.png',0)
# 进行傅里叶变化
f = np.fft.fft2(img)
# 平移中心点
fshift = np.fft.fftshift(f)
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.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 格式。我们来看看如何操作。

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('../img/fooot.png',0)
# 使用dft来进行傅里叶转化 sin(2πft)
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()

注意:你可以使用函数 cv2.cartToPolar(),它会同时返回幅度和相位。

现在我们来做逆 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.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()

OpenCV 中的函数 cv2.dft() 和 cv2.idft() 要比 Numpy 快。但是Numpy 函数更加用户友好。

DFT 的性能优化

当数组的大小为某些值时 DFT 的性能会更好。当数组的大小是 2 的指数时 DFT 效率最高。当数组的大小是 2,3,5 的倍数时效率也会很高。所以如果你想提高代码的运行效率时,你可以修改输入图像的大小(补 0)。对于OpenCV 你必须自己手动补 0。但是 Numpy,你只需要指定 FFT 运算的大 小,它会自动补 0。那我们怎样确定最佳大小呢?

OpenCV 提供了一个函数:cv2.getOptimalDFTSize()。它可以同时被 cv2.dft() 和 np.fft.fft2() 使用。让我们一起使用 jupyter的魔法命令%timeit 来测试一下吧。

import cv2
import numpy as np
img = cv2.imread('../img/fooot.png',0)
rows,cols = img.shape
print(rows,cols)
nrows = cv2.getOptimalDFTSize(rows)
ncols = cv2.getOptimalDFTSize(cols)
print(nrows, ncols)

输出结果:(326 520)(360 540)可以看出数组大小发生变化,现在为它补零,然后看看性能有没有提升.

# 创建一个大的0数组
nimg = np.zeros((nrows,ncols))
# 然后把数据拷贝过去
nimg[:rows,:cols] = img
# 使用函数 cv2.copyMakeBoder()
right = ncols - cols
bottom = nrows - rows
bordertype = cv2.BORDER_CONSTANT
nimg = cv2.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)

下面是numpy和opencv的对比:

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

速度提高了 4 倍。我们再看看 OpenCV 的表现:

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

也提高了 4 倍,同时我们也会发现 OpenCV 的速度是 Numpy 的 3 倍。

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

对不同的算子进行傅里叶变换并分析它们:

import cv2
import numpy as np
from matplotlib import pyplot as plt# simple averaging filter without scaling parameter
mean_filter = np.ones((3, 3))
# creating a guassian filter
x = cv2.getGaussianKernel(5, 10)
# x.T 为矩阵转置
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 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。

转载于:https://www.cnblogs.com/TimVerion/p/11385203.html

OpenCV学习笔记5相关推荐

  1. OpenCV 学习笔记03 boundingRect、minAreaRect、minEnclosingCircle、boxPoints、int0、circle、rectangle函数的用法...

    函数中的代码是部分代码,详细代码在最后 1 cv2.boundingRect 作用:矩形边框(boundingRect),用于计算图像一系列点的外部矩形边界. cv2.boundingRect(arr ...

  2. opencv学习笔记(二):基于肤色的人手检测

    opencv学习笔记(二):基于肤色的人手检测 原文:http://blog.csdn.net/wzmsltw/article/details/50849810 先写了人手的检测程序,下一步基于检测程 ...

  3. python做直方图-python OpenCV学习笔记实现二维直方图

    本文介绍了python OpenCV学习笔记实现二维直方图,分享给大家,具体如下: 官方文档 – https://docs.opencv.org/3.4.0/dd/d0d/tutorial_py_2d ...

  4. OpenCV学习笔记大集锦

    转载自: OpenCV学习笔记大集锦 – 视觉机器人 http://www.cvrobot.net/collect-opencv-resource-learn-study-note-chinese/ ...

  5. OpenCV学习笔记(五十六)——InputArray和OutputArray的那些事core OpenCV学习笔记(五十七)——在同一窗口显示多幅图片 OpenCV学习笔记(五十八)——读《Mast

    OpenCV学习笔记(五十六)--InputArray和OutputArray的那些事core 看过OpenCV源代码的朋友,肯定都知道很多函数的接口都是InputArray或者OutputArray ...

  6. OpenCV学习笔记(五十一)——imge stitching图像拼接stitching OpenCV学习笔记(五十二)——号外:OpenCV 2.4.1 又出来了。。。。。 OpenCV学习笔记(五

    OpenCV学习笔记(五十一)--imge stitching图像拼接stitching stitching是OpenCV2.4.0一个新模块,功能是实现图像拼接,所有的相关函数都被封装在Stitch ...

  7. OpenCV学习笔记(四十六)——FAST特征点检测features2D OpenCV学习笔记(四十七)——VideoWriter生成视频流highgui OpenCV学习笔记(四十八)——PCA算

    OpenCV学习笔记(四十六)--FAST特征点检测features2D 特征点检测和匹配是计算机视觉中一个很有用的技术.在物体检测,视觉跟踪,三维常年关键等领域都有很广泛的应用.这一次先介绍特征点检 ...

  8. OpenCV学习笔记(四十一)——再看基础数据结构core OpenCV学习笔记(四十二)——Mat数据操作之普通青年、文艺青年、暴力青年 OpenCV学习笔记(四十三)——存取像素值操作汇总co

    OpenCV学习笔记(四十一)--再看基础数据结构core 记得我在OpenCV学习笔记(四)--新版本的数据结构core里面讲过新版本的数据结构了,可是我再看这部分的时候,我发现我当时实在是看得太马 ...

  9. OpenCV学习笔记(三十六)——Kalman滤波做运动目标跟踪 OpenCV学习笔记(三十七)——实用函数、系统函数、宏core OpenCV学习笔记(三十八)——显示当前FPS OpenC

    OpenCV学习笔记(三十六)--Kalman滤波做运动目标跟踪 kalman滤波大家都很熟悉,其基本思想就是先不考虑输入信号和观测噪声的影响,得到状态变量和输出信号的估计值,再用输出信号的估计误差加 ...

  10. OpenCV学习笔记(三十一)——让demo在他人电脑跑起来 OpenCV学习笔记(三十二)——制作静态库的demo,没有dll也能hold住 OpenCV学习笔记(三十三)——用haar特征训练自己

    OpenCV学习笔记(三十一)--让demo在他人电脑跑起来 这一节的内容感觉比较土鳖.这从来就是一个老生常谈的问题.学MFC的时候就知道这个事情了,那时候记得老师强调多次,如果写的demo想在人家那 ...

最新文章

  1. 算法的时间与空间复杂度详解
  2. 面向接口编程详解(一)—— 思想基础
  3. Sqlite c/c++ api 学习
  4. 92. Leetcode 63. 不同路径 II (动态规划-路径规划)
  5. 哇靠靠,这也行?零基础DIY无人驾驶小车(一)
  6. Linux stmac网卡代码分析----probe
  7. Qt 生成bin文件
  8. 面向小姐姐的编程——JAVA面向对象之多态
  9. 嵌入式设备中支持国密算法的方法
  10. 提高应用程序可用性的五个要点
  11. CruiseControl 安装配置
  12. python入门区块链技术_区块链教程
  13. 读《IPD华为研发之道》笔记
  14. 维生素D与肠道菌群的互作
  15. tumblr android app,6 Best Tumblr Apps for Android and iOS (2018)
  16. 中国移动发布物联网操作系统 OneOS
  17. webuploader+上传文件夹
  18. SQLMAP-Tamper之较为通用的双写绕过
  19. 电脑桌面壁纸更换后不一会就变成黑屏
  20. val和var的区别

热门文章

  1. Win7怎么卸载微软输入法?
  2. 微信小程序 java四六级英语学习助手系统app
  3. [作业] 六角填数问题
  4. RAB/RB/RL/RRC的概念
  5. Win10环境下基于Hexo的静态博客环境搭建,及其阿里云部署
  6. 服务器拒绝连接怎么修复服务器,服务器拒绝了连接怎么修复
  7. Inventor制作动画
  8. MPB:南农韦中组-植物根际土壤样品的非破坏性连续采集
  9. php 7编译安装mysql5.6_CentOS7上编译安装MySQL5.6.23_MySQL
  10. 谷歌浏览器调用打印机不预览