图像匹配能够应用的场合非常多,如目标跟踪,检测,识别,图像拼接等,而图像匹配最核心的技术就要属角点匹配了,所谓角点匹配是指寻找两幅图像之间的特征像素点的对应关系,从而确定两幅图像的位置关系。
角点配对
OpenCV提供了匹配函数在两个图像之间进行关键点匹配。最常用的匹配函数是Brute-Force。
cv.BFMatcher(normType = cv.NORM_L2,
crossCheck = false)
参数:
- normType
确定用于确定匹配质量的度量标准。默认情况下,normType = cv.NORM_L2
,它用于测量两个描述子之间的距离。但是,对于像ORB创建的二进制描述子一样,汉明度量更合适。汉明度量通过计算二进制描述子之间的不相似位的数量来确定距离。当使用WTA_K = 2
创建ORB描述子时,要选择两个随机像素并在亮度上进行比较。最亮像素的索引返回为0或1。此类输出仅占用1位,因此应使用cv.NORM_HAMMING
度量。另一方面,如果使用WTA_K = 3
创建ORB描述子,则选择三个随机像素并在亮度上进行比较。最亮像素的索引返回0、1或2。这样的输出将占用2位,因此应该使用汉明距离的特殊变体,即cv.NORM_HAMMING2
(2代表2位)。然后,对于所选择的任何度量,当比较训练和查询图像中的关键点时,具有较小度量(它们之间的距离)的对被认为是最佳匹配。 - crossCheck
布尔变量,可以设置为True
或False
。交叉验证对于消除错误匹配非常有用。交叉验证通过执行两次匹配过程来完成。第一次匹配中,将训练图像中的关键点与查询图像中的关键点进行比较;第二次匹配中,将查询图像中的关键点与训练图像中的关键点进行比较(即,反向进行比较)。启用交叉验证时,只有当训练图像中的关键点A是查询图像中关键点B的最佳匹配时,该匹配才被视为有效,反之亦然(即,如果查询图像中的关键点B是训练图像中的关键点A,该匹配则是最佳匹配)。
设置了BFMatcher的参数之后,我们就可以使用.match(descriptors1, descriptors2)
方法,使用它们的ORB描述子找到训练和查询图像之间的匹配关键点。最后,我们将使用cv.drawMatches ()
函数来可视化Brute-Force匹配程序找到的匹配关键点。此函数会水平堆叠训练和查询图像,并将训练图像中关键点的线条绘制到查询图像中对应的最佳匹配关键点。
基本应用
1、尺度不变性
ORB特征点具有尺度不变性。这意味着无论图像大小如何,它能够检测图像中的对象。
# coding = utf-8
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from mahotas.features import surf
# 导入资源
image = cv.imread('123.jpg')
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
img_resize = cv.resize(image, (0, 0), fx=0.5, fy=0.5, interpolation=cv.INTER_NEAREST)
img_resize = cv.cvtColor(img_resize, cv.COLOR_BGR2RGB)
gray_resize = cv.cvtColor(img_resize, cv.COLOR_RGB2GRAY)
# 检测角点
orb = cv.ORB_create(200, 2.0)
keypoints1, desc1 = orb.detectAndCompute(gray, None)
keypoints2, desc2 = orb.detectAndCompute(gray_resize, None)
# 角点配对
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck = True)
matches = bf.match(desc1, desc2)
matches = sorted(matches, key = lambda x : x.distance)
result = cv.drawMatches(gray, keypoints1, gray_resize, keypoints2, matches[:int(len(matches)/2)], gray_resize, flags = 2)
plt.imshow(result)
plt.show()
2、旋转不变性
ORB特征点具有旋转不变性。这意味着无论方向如何,它都能够检测到图像中的对象。
# coding = utf-8
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from mahotas.features import surf
def rotate_bound(image, angle):
'''
图像旋转
INPUT -> 图像数组, 旋转角度(顺时针)
'''
(h, w) = image.shape[:2]
# 旋转中心点
(cX, cY) = (w // 2, h // 2)
# 获得旋转矩阵
M = cv.getRotationMatrix2D((cX, cY), -angle, 1.0)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# 计算图像新外接框
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
M[0, 2] += (nW / 2) - cX
M[1, 2] += (nH / 2) - cY
return cv.warpAffine(image, M, (nW, nH))
# 导入资源
image = cv.imread('123.jpg')
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
img_rotate = rotate_bound(image, 45)
img_rotate = cv.cvtColor(img_rotate, cv.COLOR_BGR2RGB)
gray_rotate = cv.cvtColor(img_rotate, cv.COLOR_RGB2GRAY)
# 检测角点
orb = cv.ORB_create(200, 2.0)
keypoints1, desc1 = orb.detectAndCompute(gray, None)
keypoints2, desc2 = orb.detectAndCompute(gray_rotate, None)
# 角点配对
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck = True)
matches = bf.match(desc1, desc2)
matches = sorted(matches, key = lambda x : x.distance)
result = cv.drawMatches(gray, keypoints1, gray_rotate, keypoints2, matches[:int(len(matches)/2)], gray_rotate, flags = 2)
plt.imshow(result)
plt.show()
3、光照不变性
ORB特征点也具有光照不变性。这意味着无论光照如何,它都能够检测到图像中的物体。
# coding = utf-8
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from mahotas.features import surf
# 导入资源
image = cv.imread('123.jpg')
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
image2 = cv.imread('1232.jpg')
image2 = cv.cvtColor(image2, cv.COLOR_BGR2RGB)
gray2 = cv.cvtColor(image2, cv.COLOR_RGB2GRAY)
# 检测角点
orb = cv.ORB_create(200, 2.0)
keypoints1, desc1 = orb.detectAndCompute(gray, None)
keypoints2, desc2 = orb.detectAndCompute(gray2, None)
# 角点配对
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck = True)
matches = bf.match(desc1, desc2)
matches = sorted(matches, key = lambda x : x.distance)
result = cv.drawMatches(gray, keypoints1, gray2, keypoints2, matches[:int(len(matches)/2)], gray2, flags = 2)
plt.imshow(result)
plt.show()
4、抗噪性
ORB特征点也具有抗噪性。这意味着即使图像具有一定程度的噪声,它也能够检测到图像中的对象。
# coding = utf-8
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from mahotas.features import surf
# 导入资源
image = cv.imread('123.jpg')
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
image2 = cv.imread('1233.jpg')
image2 = cv.cvtColor(image2, cv.COLOR_BGR2RGB)
gray2 = cv.cvtColor(image2, cv.COLOR_RGB2GRAY)
# 检测角点
orb = cv.ORB_create(200, 2.0)
keypoints1, desc1 = orb.detectAndCompute(gray, None)
keypoints2, desc2 = orb.detectAndCompute(gray2, None)
# 角点配对
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck = True)
matches = bf.match(desc1, desc2)
matches = sorted(matches, key = lambda x : x.distance)
result = cv.drawMatches(gray, keypoints1, gray2, keypoints2, matches[:int(len(matches)/2)], gray2, flags = 2)
plt.imshow(result)
plt.show()
高级应用
1、全景图拼接
# coding = utf-8
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from mahotas.features import surf
# 导入资源
image = cv.imread('1.png')
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
image2 = cv.imread('2.png')
image2 = cv.cvtColor(image2, cv.COLOR_BGR2RGB)
gray2 = cv.cvtColor(image2, cv.COLOR_RGB2GRAY)
# 检测角点
orb = cv.ORB_create(200, 2.0)
keypoints1, desc1 = orb.detectAndCompute(gray, None)
keypoints2, desc2 = orb.detectAndCompute(gray2, None)
# 角点配对
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck = True)
matches = bf.match(desc1, desc2)
# 按照相近程度进行排序
matches = sorted(matches, key = lambda x : x.distance)
goodmatches = matches[:int(len(matches)/2)]
# 图像拼接
MIN_MATCH_COUNT = 10
if len(goodmatches) > MIN_MATCH_COUNT:
src_pts = np.float32([keypoints1[m.queryIdx].pt for m in goodmatches]).reshape(-1, 1, 2)
dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in goodmatches]).reshape(-1, 1, 2)
M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0)
warpImg = cv.warpPerspective(image, M, (image.shape[1] + image2.shape[1], image.shape[0]))
warpImg[0:image2.shape[0], 0:image2.shape[1]] = image2
plt.imshow(warpImg)
plt.show()
1.png
2.png
拼接结果