Как получить более точные повороты от разложения матрицы гомографии - PullRequest
0 голосов
/ 22 февраля 2019

Я пытаюсь создать программу, которая может вычислять вращение плоскости из двух изображений в 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...