OpenCV中的图像处理 —— 傅里叶变换+模板匹配

article/2025/11/9 16:29:38

OpenCV中的图像处理 —— 傅里叶变换+模板匹配

现在也在逐渐深入啦,希望跟大家一起进步越来越强

目录

    • OpenCV中的图像处理 —— 傅里叶变换+模板匹配
    • 1. 傅里叶变换
      • 1.1 Numpy实现傅里叶变换
      • 1.2 OpenCV实现傅里叶变换
      • 1.3 DFT的性能优化
    • 2. 模板匹配
      • 2.1 单对象的模板匹配
      • 2.2 多对象的模板匹配

1. 傅里叶变换

关于傅里叶变换最重要的两个概念:时域与频域。以时间作为参照来观察动态世界的方法我们称其为时域分析,而频域是什么呢,它是描述信号在频率方面特性时用到的一种坐标系,频域图显示了在一个频率范围内每个给定频带内的信号量。贯穿时域与频域的方法之一就是大名鼎鼎的傅里叶分析,它可以分为傅里叶级数和傅里叶变换,傅里叶变换也就是我们这一部分要说的东西

傅里叶变换是分析线性系统的一个有力工具。 它告诉我们任何周期函数,都可以看作是不同振幅,不同相位正弦波的叠加。从数学意义上说,傅里叶变换将一个任意的周期函数分解成为无穷个正弦函数的和的形式;从物理效果上看,傅里叶变换实现了将信号从空间域到频率域的转换

在计算机视觉中傅立叶变换用于分析各种滤波器的频率特性,对于图像,使用2D离散傅里叶变换(DFT)查找频域(还有一种称为快速傅立叶变换(FFT)的快速算法)这一段文字是不是不太好理解,因为里面涉及太多比较深奥的东西了,傅里叶变换本身是比较难的一个点,在这里我就不细说了,我们只说说在计算机视觉领域我们是怎么用它的,想要深入了解的同学来看看这篇文章:深入浅出的讲解傅里叶变换(真正的通俗易懂)

对于正弦信号,如果幅度在短时间内变化比较快,则可以说它是高频信号,如果变化缓慢,则为低频信号,我们可以将相同的想法扩展到图像,图像中的振幅在哪里急剧变化?当然是在边缘点或噪声,因此,可以说边缘和噪声是图像中的高频内容

1.1 Numpy实现傅里叶变换

Numpy提供了FFT软件包来查找傅里叶变换,np.fft.fft2()为我们提供了频率转换,它将是一个复杂的数组,它的第一个参数是输入图像(灰度图像),第二个参数是可选的,它决定输出数组的大小。如果它大于输入图像的大小,则在计算FFT之前用零填充输入图像。如果小于输入图像,将裁切输入图像。如果未传递任何参数,则输出数组的大小将与输入的大小相同,但是现在获得的结果它的零频率分量(DC分量)将位于左上角,为了便于分析我们要把它居中,居中处理关系到np.fft.fftshift()函数

import cv2 as cv
import numpy as np
from matplotlib import pyplot as pltimg = cv.imread(r'E:\image\test16.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,我们首先要用尺寸为60*60的矩形窗口遮罩抵消低频信号,然后使用np.fft.ifftshift()应用反向移位,以使DC分量再次出现在左上角。然后使用np.ifft2()函数找到逆FFT,结果同样是一个复数

import cv2 as cv
import numpy as np
from matplotlib import pyplot as pltimg = cv.imread(r'E:\image\test15.png', 0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20 * np.log(np.abs(fshift))
rows, cols = img.shape
crow, ccol = rows//2, cols//2
fshift[crow - 30:crow + 31, ccol - 30:ccol + 31] = 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(magnitude_spectrum, cmap='gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.subplot(133), plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

1.2 OpenCV实现傅里叶变换

OpenCV为此提供了cv.dft()和cv.idft()函数。它返回与前一个相同的结果,但是有两个通道。第一个通道是结果的实部,第二个通道是结果的虚部。输入图像首先应转换为np.float32

import cv2 as cv
import numpy as np
from matplotlib import pyplot as pltimg = cv.imread(r'E:\image\test17.png', 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()

在这里插入图片描述

这一块儿代码有几个难懂的地方,没关系我们来分析一下:第一次看这段代码会有几个疑问,cv.dft()函数的参数怎么传递?cv.magnitude()函数是怎么用的?

cv.dft()函数的作用是对一维或者二维浮点数数组进行正向或反向离散傅里叶变换,其中包括4个参数,第一个即源图像,第二个参数是OutputArray类型的dst,函数调用后返回的运算结果存在这里,它的尺寸和类型取决于第三个参数flags转换标识符,它的默认值为0(参考自:opencv:dft()函数详解)

cv.magnitude()函数用来计算二维矢量的幅值,其中包括3个参数,第一个是InputArray类型的x,表示矢量的浮点型X坐标值,也就是实部,第二个参数是InputArray类型的y,表示矢量的浮点型Y坐标值,也就是虚部,第三个参数是输出的幅值

接下来我们需要做OpenCV中DFT的逆变换,上一节用了高通滤波器HPF,这一部分我们会将低通滤波器LPF应用到图像中

注意:通常,OpenCV函数cv.dft()和cv.idft()比Numpy函数更快,大约快3倍,但是Numpy函数更容易使用

我们把这一部分的代码放在后面,与DFT的性能优化放在一起更容易理解

1.3 DFT的性能优化

对于某些数组尺寸,DFT的计算性能较好,例如当数组大小为2的幂时,速度最快,对于大小为2、3和5的乘积的数组,也可以非常有效地进行处理,关于代码的性能问题,我们可以在找到DFT之前将数组的大小修改为任何最佳大小(通过填充零),对于OpenCV,我们必须手动填充零,但是对于Numpy,指定FFT计算的新大小,它将自动为您填充零

关于寻找最优大小,OpenCV为此提供了一个函数:cv.getOptimalDFTSize()

import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread(r'E:\image\test17.png', 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()

在这里插入图片描述

版权声明:源码来自CSDN文章OpenCV中的图像变换——傅里叶变换

2. 模板匹配

模板匹配是一种用于在较大图像中搜索和查找模板图像位置的方法。为此,OpenCV带有一个函数cv.matchTemplate(), 它只是将模板图像滑动到输入图像上(就像在2D卷积中一样),然后在模板图像下比较模板和输入图像的拼图,它返回一个灰度图像,其中每个像素表示该像素的邻域与模板匹配的程度。但是在这个方法的内涵中,到底是用什么样的方法去做做匹配的呢?这个就由函数的其中一个参数来决定了

如果输入图像的大小为 (W * H) ,而模板图像的大小为 (w * h) ,则输出图像的大小将为(W-w + 1,H-h + 1) ,在我们得到结果后,可以使用cv.minMaxLoc()函数查找最大/最小值在哪,将其作为矩形的左上角,并以 (w,h) 作为矩形的宽度和高度

匹配方式(比较方法)与cv.matchTemplate()的参数有关,我们先来看看都有哪些参数,并且应用不同的参数会有什么样不同的效果。该函数第一个参数是源图像,第二个参数是模板图像,第三个参数是匹配的结果图像,第四个参数是用于指定比较的方法

  • cv::TM_SQDIFF:该方法使用平方差进行匹配,因此最佳的匹配结果在结果为0处,值越大匹配结果越差
  • cv::TM_SQDIFF_NORMED:该方法使用归一化的平方差进行匹配,最佳匹配也在结果为0处
  • cv::TM_CCORR:相关性匹配方法,该方法使用源图像与模板图像的卷积结果进行匹配,因此,最佳匹配位置在值最大处,值越小匹配结果越差
  • cv::TM_CCORR_NORMED:归一化的相关性匹配方法,与相关性匹配方法类似,最佳匹配位置也是在值最大处
  • cv::TM_CCOEFF:相关性系数匹配方法,该方法使用源图像与其均值的差、模板与其均值的差二者之间的相关性进行匹配,最佳匹配结果在值等于1处,最差匹配结果在值等于-1处,值等于0直接表示二者不相关
  • cv::TM_CCOEFF_NORMED:归一化的相关性系数匹配方法,正值表示匹配的结果较好,负值则表示匹配的效果较差,也是值越大,匹配效果也好

资料摘自:【OpenCV3】模板匹配——cv::matchTemplate()详解

2.1 单对象的模板匹配

import cv2 as cv
import numpy as np
from matplotlib import pyplot as pltimg = cv.imread(r'E:\image\test15.png', 0)
img2 = img.copy()
template = cv.imread(r'E:\image\temple.png', 0)
w, h = template.shape[::-1]
# 列表中所有的6种比较方法
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR','cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
for meth in methods:img = img2.copy()method = eval(meth)# 应用模板匹配res = cv.matchTemplate(img, template, method)min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)# 如果方法是TM_SQDIFF或TM_SQDIFF_NORMED,则取最小值if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:top_left = min_locelse:top_left = max_locbottom_right = (top_left[0] + w, top_left[1] + h)cv.rectangle(img, top_left, bottom_right, [255, 0, 0], 2)plt.subplot(121), plt.imshow(res, cmap='gray')plt.title('Matching Result'), plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(img, cmap='gray')plt.title('Detected Point'), plt.xticks([]), plt.yticks([])plt.suptitle(meth)plt.show()

在这里插入图片描述

2.2 多对象的模板匹配

上一节我们匹配了梅大人的面部,但是如果图像中有很多满足匹配条件的模板呢?这个时候cv.minMaxLoc()不会为我们提供所有位置,我们会使用阈值化

import cv2 as cv
import numpy as np
from matplotlib import pyplot as pltimg_rgb = cv.imread(r'E:\image\num.png')
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
template = cv.imread(r'E:\image\temple2.png', 0)
w, h = template.shape[::-1]
res = cv.matchTemplate(img_gray, template, cv.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]):cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
cv.imshow('res.png', img_rgb)
cv.waitKey(0)
cv.destroyWindow()

在这里插入图片描述

代码解析:第8行的shape()函数是numpy.core.fromnumeric中的函数,它的功能是查看矩阵或者数组的维数,第11行的locloc是满足“res >= threshold”的像素点的索引集合,第12行的函数zip()用可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表


(注:文章内容参考OpenCV4.1中文官方文档)
如果文章对您有所帮助,记得一键三连支持一下哦


http://chatgpt.dhexx.cn/article/3AXT4Kww.shtml

相关文章

opencv 多角度模板匹配

总结一下实现多角度模板匹配踩的坑 一 、多角度匹配涉及到要使用mask,首先opencv matchTemplateMask自带的源码如下: static void matchTemplateMask( InputArray _img, InputArray _templ, OutputArray _result, int method, InputArray _mask ) {CV_A…

用OpenCV进行模板匹配

1. 引言 今天我们来研究一种传统图像处理领域中对象检测和跟踪不可或缺的方法——模板匹配,其主要目的是为了在图像上找到我们需要的图案,这听起来十分令人兴奋。 所以,事不宜迟,让我们直接开始吧! 2. 概念 模板匹…

OpenCV之模板匹配

模板匹配的概念与原理 模板匹配是在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术,在OpenCV中,模板匹配由函数MatchTemplate()函数实现。需要注意的是,模板匹配不是基于直方图的,而是通过在输入图…

基于OpenCV的模板匹配

模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术。模板匹配不是基于直方图的, 而是通过在输入图像上滑动图像块(模板)同时比对相似度, 来对模板和输入图像进行匹配的一种方法。 image: 待搜索图像(大图)templ: 搜索模板, 需和原图一样的数据类型且尺寸…

【OpenCV系列】模板匹配

原理 什么是模板匹配? 模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术. 它是怎么实现的? 我们需要2幅图像: 我们的目标是检测最匹配的区域: 原图像 (I): 在这幅图像里,我们希望找到一块和模板匹配的区域模板 (T): 将和原图像比照的图像块 为了…

python opencv 模板匹配

模板匹配是在一个大图里搜索和找模板图像位置的方法。OpenCV有个函数cv2.matchTemplate()来做这个。它吧模板图像在输入图像上滑动,对比模板和在模板图像下的输入图像块。它返回了一个灰度图像,每个像素表示那个像素周围和模板匹配的情况。 如果输入图像…

基于OpenCV的图像匹配----模板匹配(一)

我先介绍一下模板匹配的原理 原图像:我们期望找到与模板图像匹配的图像 模板图像:将于模板图像进行比较的图像 一次移动一个像素(从左到右,从上到下)。在每个位置,计算相似度度量,以便它表示在…

OpenCV图像处理——模板匹配

总目录 图像处理总目录←点击这里 十一、模板匹配 11.1、原理 找一个图片上有的模板,和原图像进行模板匹配模板图像在待匹配图像上滑动,记录下每次滑动后的参数值(如平方差,相关性)。寻找最小值或最大值&#xff0…

OpenCV模板匹配算法详解

本博客在https://www.cnblogs.com/zhaoweiwei/p/OpenVC_matchTemplate.html基础上进行更加详细的注解。当初有几个地方看的比较费劲,但是里面没有注释,现给加上,主要是那些带黄色及红色部分的注释。 在此向weiwei22844致敬。 模板匹配是在一…

OpenCV 模板匹配(Template Match)

文章目录 模板匹配介绍模板匹配定义匹配算法平方差归一化的平方差相关性归一化的相关性相关性系数归一化的相关性系数 相关API代码示例 模板匹配介绍 模板匹配定义 模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域。 所以模板匹配首先需要一个模板图像T&#xff…

OpenCV 模板匹配

模板匹配就是在大图中找小图,也就说在一幅图像中寻找另一幅模板图像的位置。 案例来源于傅老师。 模板匹配的操作方法是将模板图像B在图像A上滑动,遍历所有像素以完成匹配。 工作原理:在带检测图像上,从左到右,从上…

13 -- OpenCV学习—模板匹配

模板匹配 1.模板匹配 模板匹配:在给定的模板中查找最相似的区域 实现流程: 准备两幅图像 (1)原图 (2)模板图滑动模板块和原图像进行比对对于每个像素位置。将计算结果存在矩阵中,输入图像大小…

opencv模板匹配步骤及Code

opencv模板匹配步骤及Code 首先介绍一下模板匹配的适用场景: 1、图像检索 2、目标跟踪 简单的说,模板匹配最主要的功能就是在一幅图像中去寻找和另一幅模板图像中相似度最高的部分,这就是模板匹配。 比如,在下面这图片中: 我们要…

OpenCV 学习笔记(模板匹配)

OpenCV 学习笔记(模板匹配) 模板匹配是在一幅图像中寻找一个特定目标的方法之一。这种方法的原理非常简单,遍历图像中的每一个可能的位置,比较各处与模板是否“相似”,当相似度足够高时,就认为找到了我们的…

OpenCV-模板匹配 单个对象匹配、多个对象匹配

目录 概念步骤单个对象匹配代码实现一代码实现二 多个对象匹配代码实现 概念 模板匹配与剪辑原理很像,模板在原图像上从原点开始浮动,计算模板(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有六…

openCV——模板匹配

单模板匹配 import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline def cvshow(name, ndarray):img cv2.imshow(name, ndarray)cv2.waitKey(0)cv2.destroyAllWindows()模板匹配是指在当前图像 A 内寻找…

Python+Opencv实现模板匹配

目录 一、模板匹配简介二、传统模板匹配算法不足之处三、多尺度模板匹配实现步骤四、多尺度模板匹配实现代码五、多尺度模板匹配效果展示和分析六、思维扩展参考资料注意事项 一、模板匹配简介 所谓的模板匹配,即在给定的图片中查找和模板最相似的区域,该…

OpenCV数字图像处理实战二:模板匹配(C++)

OpenCV数字图像处理实战二:模板匹配(C) 1、模板匹配原理 模板匹配(TemplateMatching)就是在一幅图像中寻找和模板图像(template)最相似的区域,模板匹配不是基于直方图的&#xff0…

opencv 模板匹配形状匹配

文章目录 1. 找圆垫子1.1 得到模板1.2 形状匹配 2. 找瓜子 这是第四次作业要求 所以今天就趁机会讲讲模板匹配,正好之前的项目有一部分重要工作就是和模板匹配紧密相关,对于今天作业来说,之前的项目难度更大,因为涉及到许多要考虑…

Opencv——图像模板匹配

引言 什么是模板匹配呢? 看到这里大家是否会觉得很熟悉的感觉涌上心头!在人脸识别是不是也会看见 等等。 模板匹配可以看作是对象检测的一种非常基本的形式。使用模板匹配,我们可以使用包含要检测对象的“模板”来检测输入图像中的对象。 …