首页 > 解决方案 > 如何通过分解单应矩阵获得更准确的旋转

问题描述

我正在尝试创建一个程序,该程序可以使用 opencv 从 python 中的两个图像计算平面的旋转。我通过找到表示翻译的单应矩阵,并使用 openCv 中的 decomposeHomographyMat 函数使用固有相机矩阵分解它来做到这一点。

我使用搅拌机测试了精度,方法是创建一个上面有二维码的平面,然后按已知值旋转它,如此处所示,平面在 XYZ Euler 坐标中旋转了 15,30,15,尽管我想要最终程序拍摄现实生活中正在翻译的飞机的照片。

使用这种技术在搅拌机中找到了固有的相机矩阵。并且还发现在搅拌机中使用相机校准,方法是放入一个检查板并从多个角度和平移进行渲染。

但是,当我运行代码时,我得到的 ZYX Euler 输出是 [ 27.9 , -25.4, -26.31] 而不是 [15, -30, -15] ,这是不准确的。下面是代码输出到预期值的一些其他示例,以了解代码的准确性:

预期 - [0 -30 0]

计算 - [0.82 -34.51 -1.91]

预期 - [0 0 15]

计算 - [ 0 0 -15.02]

预期 - [15 0 15]

计算 - [ 16.23 3.76 -13.76]

我想知道是否有任何方法可以提高计算的旋转矩阵的精度,或者这是否是我能得到的最佳精度,如果这是我能得到的最佳精度,我可以做些什么来计算从图像沿 3 轴旋转平面(也可以添加额外的相机)。

任何帮助将非常感激!

我正在使用的代码如下所示:

#Import modules
import cv2
import numpy as np
from matplotlib import pyplot as plt
import glob
import math
########################################################################
#Import pictures
img1 = cv2.imread("top.png", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("150015.png", cv2.IMREAD_GRAYSCALE)

#Feature Extraction
MIN_MATCH_COUNT = 10
sift = cv2.xfeatures2d.SIFT_create()

kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

FLANN_INDEX_KDTREE = 0

index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks = 50)

flann = cv2.FlannBasedMatcher(index_params, search_params)

matches = flann.knnMatch(des1,des2,k=2)

# store all the good matches as per Lowe's ratio test.
good = []
for m,n in matches:
    if m.distance < 0.80*n.distance:
        good.append(m)

if len(good)>MIN_MATCH_COUNT:
    src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
    dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)

    #Finds homography matrix
    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,1)
    matchesMask = mask.ravel().tolist()

    h,w = img1.shape
    pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
    dst = cv2.perspectiveTransform(pts,M)

    img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA)

else:
    print "Not enough matches are found - %d/%d" % (len(good),MIN_MATCH_COUNT)
    matchesMask = None

draw_params = dict(matchColor = (0,255,0), # draw matches in green color
                   singlePointColor = None,
                   matchesMask = matchesMask, # draw only inliers
                   flags = 2)

img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)

plt.imshow(img3, 'gray'),plt.show()


#Camera calibration matrix
K = ((3,3))
K = np.zeros(K)

#Camera calibration matrix from blender python script
#K = np.matrix('1181.2500 0 540; 0 2100 540; 0 0 1')

#Camera calibration matrix from importing checkboard into blender
K = np.matrix('1307.68697 0 600.618354; 0 1309.66779 605.481488; 0 0 1')

#Homography matrix is decomposed
num, Rs, Ts, Ns  = cv2.decomposeHomographyMat(M, K)

# Checks if a matrix is a valid rotation matrix.
def isRotationMatrix(R) :
    Rt = np.transpose(R)
    shouldBeIdentity = np.dot(Rt, R)
    I = np.identity(3, dtype = R.dtype)
    n = np.linalg.norm(I - shouldBeIdentity)
    return n < 1e-6


# Calculates rotation matrix to euler angles
# The result is the same as MATLAB except the order
# of the euler angles ( x and z are swapped ).
def rotationMatrixToEulerAngles(R) :

    assert(isRotationMatrix(R))

    sy = math.sqrt(R[0,0] * R[0,0] +  R[1,0] * R[1,0])

    singular = sy < 1e-6

    if  not singular :
        x = math.atan2(R[2,1] , R[2,2])
        y = math.atan2(-R[2,0], sy)
        z = math.atan2(R[1,0], R[0,0])
    else :
        x = math.atan2(-R[1,2], R[1,1])
        y = math.atan2(-R[2,0], sy)
        z = 0

    return np.array([x, y, z])

#Conver the 4 rotation matrix solutions into XYZ Euler angles
i=0
for i in range(0,4):
    R = Rs[i]
    angles = rotationMatrixToEulerAngles(R)
    x = np.degrees(angles[0])
    y = np.degrees(angles[1])
    z = np.degrees(angles[2])
    anglesDeg = np.array([x,y,z])
    print(anglesDeg)

我从搅拌机生成的图像如下:

top.png (牛, 0y, 0z)

003000.png (0x, 30y, 0z)

150015.png (15x, 0y, 15z)

153000.png (15x, 30y, 0z)

153015.png (15x, 30y, 15z)

这是一个与 153015.png 比较的关键点匹配的图像

标签: pythonopencvimage-processinghomographyrotational-matrices

解决方案


推荐阅读