计算图像间的旋转角度可以通过提取特征点、匹配特征点,然后用 OpenCV 的 estimateAffinePartial2D 函数来计算仿射变换矩阵。最后从该矩阵中提取旋转角度。
步骤
-
提取特征点和描述符:使用 SIFT 或 ORB 算法提取图像的特征点和描述符。
-
匹配特征点:使用 BFMatcher 或其他匹配算法匹配两幅图像的特征点。
-
计算仿射变换矩阵:使用
estimateAffinePartial2D函数,从匹配的特征点对中计算部分仿射变换矩阵(允许旋转、平移和缩放)。 -
提取旋转角度:从仿射变换矩阵中提取旋转角度。
以下是完整的代码示例,分别使用 SIFT 和 ORB 特征:
使用 SIFT 特征
import cv2
import numpy as np
# 读取图像
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
# 初始化 SIFT 特征检测器
sift = cv2.SIFT_create()
# 检测关键点并计算描述符
keypoints1, descriptors1 = sift.detectAndCompute(image1, None)
keypoints2, descriptors2 = sift.detectAndCompute(image2, None)
# 使用 BFMatcher 进行特征匹配
bf = cv2.BFMatcher()
matches = bf.knnMatch(descriptors1, descriptors2, k=2)
# 应用比率测试筛选匹配点
good_matches = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
good_matches.append(m)
# 提取匹配点的坐标
src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 2)
dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 2)
# 计算部分仿射变换矩阵
affine_matrix, inliers = cv2.estimateAffinePartial2D(src_pts, dst_pts)
result_dict = {}
if affine_matrix is not None:
# 提取旋转角度
theta = np.arctan2(affine_matrix[1, 0], affine_matrix[0, 0]) * 180 / np.pi
print("旋转角度为:{:.2f} 度".format(theta))
# 计算缩放比例的大小
if affine_matrix[0, 0] != 0:
scale_x = np.sqrt(affine_matrix[0, 0] ** 2 + affine_matrix[0, 1] ** 2)
scale_y = np.sqrt(affine_matrix[1, 0] ** 2 + affine_matrix[1, 1] ** 2)
print("X 缩放比例为:{:.2f}".format(scale_x))
print("Y 缩放比例为:{:.2f}".format(scale_y))
else:
print("无法计算缩放比例")
else:
print("无法计算变换矩阵")
使用 ORB 特征
import cv2
import numpy as np
# 读取图像
image1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
# 初始化 ORB 特征检测器
orb = cv2.ORB_create()
# 检测关键点并计算描述符
keypoints1, descriptors1 = orb.detectAndCompute(image1, None)
keypoints2, descriptors2 = orb.detectAndCompute(image2, None)
# 使用 BFMatcher 进行特征匹配
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(descriptors1, descriptors2)
# 按距离排序匹配结果并选择前 N 个最佳匹配
matches = sorted(matches, key=lambda x: x.distance)
good_matches = matches[:30] # 选择前 30 个最佳匹配
# 提取匹配点的坐标
src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 2)
dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 2)
# 计算部分仿射变换矩阵
affine_matrix, inliers = cv2.estimateAffinePartial2D(src_pts, dst_pts)
result_dict = {}
if affine_matrix is not None:
# 提取旋转角度
theta = np.arctan2(affine_matrix[1, 0], affine_matrix[0, 0]) * 180 / np.pi
print("旋转角度为:{:.2f} 度".format(theta))
# 计算缩放比例的大小
if affine_matrix[0, 0] != 0:
scale_x = np.sqrt(affine_matrix[0, 0] ** 2 + affine_matrix[0, 1] ** 2)
scale_y = np.sqrt(affine_matrix[1, 0] ** 2 + affine_matrix[1, 1] ** 2)
print("X 缩放比例为:{:.2f}".format(scale_x))
print("Y 缩放比例为:{:.2f}".format(scale_y))
else:
print("无法计算缩放比例")
else:
print("无法计算变换矩阵")
注意事项
-
特征匹配质量:特征匹配的质量会直接影响变换矩阵的准确性。确保图像中有足够的特征点可供匹配。
-
旋转范围:
estimateAffinePartial2D计算出的旋转角度会在 [-90, 90] 度范围内,如果实际旋转角度超过这个范围,可能需要进一步调整计算结果。 -
性能考虑:SIFT 特征计算较为耗时,但对于复杂图像效果较好;ORB 特征计算速度快,适合实时应用。
4224

被折叠的 条评论
为什么被折叠?



