Я пытаюсь создать программу, которая может вычислять вращение плоскости из двух изображений в python, используя opencv.Я делаю это, находя матрицу гомографии, которая представляет перевод, и декомпозирую ее, используя встроенную матрицу камеры с помощью функции degposeHomographyMat в openCv.
Я проверил точность с помощью blender, создав плоскость с QR-кодом назатем повернуть его на известные значения , как показано здесь, где плоскость была повернута на 15,30,15 в координатах Эйлера XYZ , хотя я хочу, чтобы в окончательной программе были сделаны снимки плоскости, переводимой вреальная жизнь.
Матрица встроенной камеры была найдена в блендере с использованием этой техники .А также обнаружил использование калибровки камеры в Blender'е путем установки контрольной панели и рендеринга с разных углов и трансляций.
Однако, когда я запускаю код, я получаю выходные данные ZYX Euler [27.9, -25.4, -26.31] вместо [15, -30, -15], что не является точным.Ниже приведены некоторые другие примеры вывода в код ожидаемых значений, чтобы дать представление о точности кода:
Ожидаемый - [0 -30 0]
Calcapted - [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 (Ox, 0y, 0z)
003000.png (0x, 30y, 0z)
150015.png (15x, 0y, 15z)
153000.png (15x, 30y, 0z)
153015.png (15x, 30y, 15z)
А вот изображение с совпадением ключевых точек для сравнения 153015.png