1.图像金字塔
图像金字塔是一种多尺度表示的方法,用于在不同分辨率下对图像进行分析和处理。如下图所示:
图像金字塔可以将原始图像分解为一系列层级的图像,每个层级都代表了不同尺度的细节信息。比如说我们要做一些图像特征提取,在进行特征提取的时候,我们不仅仅对一张原始输入进行特征提取,而是在图像金字塔每一层当中都进行特征提取,而每一层特征提取出来的结果是不一样的,我们再把特征提取出来的结果融合在一起。
图像金字塔主要有两种类型:高斯金字塔和拉普拉斯金字塔。
1.1 高斯金字塔
1.1.1 向下采样法(缩小)
向下采样法是越采样越小,不断降低图像的分辨率,使得图片越变越小,因此它的方向是朝着金字塔顶端。
构建过程如下:
- 首先,将原始图像作为第一层(底层)的图像。
- 然后,通过应用高斯滤波器对当前层级的图像进行平滑处理。
- 接着,将平滑后的图像进行下采样,将图像的尺寸缩小一半。
- 重复上述步骤直到达到金字塔的顶层(分辨率最低的层级)。
1.1.2 向上采样法(放大)
向下采样法是越采样越大,不断增加图像的分辨率,使得图片越变越大,因此它的方向是朝着金字塔底端。具体做法如下:
- 使图像在每个方向扩大为原来的两倍,新增的行和列以0填充
- 使用高斯核与放大后的图形进行卷积操作,得到近似值
在OpenCV中,我们分别调用cv2.pyrUP()
和cv2.pyrDown()
来实现上采样和下采样,下面我们来看具体代码
scss
import cv2
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 查看原始图片
img=cv2.imread("yangqi.jpg")
cv_show(img,'img')
print (img.shape)
scss
(238, 218, 3)
下面我们来分别看下采样和上采样后的结果
上采样
bash
# 上采样
up=cv2.pyrUp(img)
cv_show(up,'up')
print (up.shape) #查看上采样后的结果维度
scss
(476, 436, 3)
可以看到,图片变得更大了,并且图像的行和宽都是原来的两倍
下采样:
bash
# 下采样
down=cv2.pyrDown(img)
cv_show(down,'down')
print (down.shape) #查看下采样后的结果维度
scss
(119, 109, 3)
可以看到,图片变得更小了,并且图像的行和宽都是原来的一半。
小结:
高斯金字塔的每一层级都包含了原始图像的低频信息,并且每个层级的分辨率比前一层级低。高斯金字塔可用于图像的缩放、降噪以及图像融合等应用。
1.2拉普拉斯金字塔
拉普拉斯金字塔是通过高斯金字塔构建的,可以用于重建原始图像,也可以用于实现图像的增强和压缩等操作。构建过程如下:
对图像项进行下采样,得到G1,然后经过上采样得到E1,然后用原始图像减去E1即可,我们可以进行多次重复操作得到不同层的结果,下面以生成L1为例,使用opencv代码如下:
ini
down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
l_1=img-down_up
cv_show(l_1,'l_1')
2.模板匹配
模板匹配是指在图像中寻找与给定模板最相似的部分,它的基本思想和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,以此来找到最佳匹配位置。这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB
大小,而模板是axb
大小,则输出结果的矩阵是(A-a+1)x(B-b+1)
TM_SQDIFF
:计算平方不同,计算出来的值越小,越相关TM_CCORR
:计算相关性,计算出来的值越大,越相关TM_CCOEFF
:计算相关系数,计算出来的值越大,越相关TM_SQDIFF_NORMED
:计算归一化平方不同,计算出来的值越接近0,越相关TM_CCORR_NORMED
:计算归一化相关性,计算出来的值越接近1,越相关TM_CCOEFF_NORMED
:计算归一化相关系数,计算出来的值越接近1,越相关
我们先来看两张图
ini
# 模板匹配
import cv2
img = cv2.imread('lena.jpg', 0) #目标图片
template = cv2.imread('face.jpg', 0) #要匹配的模板
h, w = template.shape[:2] #模板的大小
img.shape,template.shape
scss
((263, 263), (110, 85))
scss
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 显示原始图片
cv_show(img,'img')
arduino
cv_show(template,'template')
我们想要做的就是将模板匹配到目标图形的位置
2.1 获取匹配结果
在Opencv
中,我们调用cv2.matchTemplate()
函数来进行模板匹配,具体语法如下
arduino
cv2.matchTemplate(img, template, method)
其中img是传入的图片,template是要匹配的模板,method就是我们刚刚介绍到的几种方法,下面来看具体例子
ini
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
res.shape
scss
(154, 179)
可以看到这里的维度是(154,179),验证了我们之前所介绍的内容,等于(263-110+1,263-85+1)。
2.2 获取匹配位置信息
匹配后,我们可以通过 cv2.minMaxLoc()
函数获取匹配结果的最大值和最小值,以及对应的位置信息。
ini
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
min_val,max_val,min_loc,max_loc
scss
(39168.0, 74403584.0, (107, 89), (159, 62))
这里给出了最大最小值和对应的坐标,我们就能根据这些信息绘制出模板匹配的位置。
2.3 绘制匹配边框
根据最佳匹配位置,可以在原始图像上绘制一个矩形框来标记匹配位置。使用 cv2.rectangle()
函数可以实现这一步骤。我们接下来分别看使用六种不同方法得到的结果
ini
import matplotlib.pyplot as plt
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
for i in methods:
img2 = img.copy()
# 匹配方法的真值
method = eval(i)
print (method)
res = cv2.matchTemplate(img, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# 绘制匹配边框
cv2.rectangle(img2, top_left, bottom_right, 255, 2)
plt.subplot(121), plt.imshow(res, cmap='gray')
plt.xticks([]), plt.yticks([]) #
plt.subplot(122), plt.imshow(img2, cmap='gray')
plt.xticks([]), plt.yticks([])
plt.suptitle(i)
plt.show()
从结果上来看,使用了归一化的几种方法效果都不错。
需要注意的是,另外,模板匹配是一种局部匹配方法,对光照变化、旋转变换等情况比较敏感。在某些情况下,可能需要结合其他技术,如特征提取和机器学习等方法,来提高匹配的准确性和鲁棒性。