Фундаментальная матрица для соответствия точек

#python #opencv #computer-vision

Вопрос:

Я оцениваю фундаментальную матрицу, используя

cv2.findFundamentalMat()

метод OpenCV. Я даю ключевые точки, которые получаю от Фланна мэтчера.

 # Initiate ORB detector
orb = cv2.ORB_create()
# find the keypoints with ORB
keyPointsLeft = orb.detect(imgLeft,None)
keyPointsRight= orb.detect(imgRight, None)

# compute the descriptors with ORB
keyPointsLeft, descriptorsLeft = orb.compute(imgLeft, keyPointsLeft)
keyPointsRight, descriptorsRight = orb.compute(imgRight, keyPointsRight)
desLeft = np.float32(descriptorsLeft)
desRight = np.float32(descriptorsRight)
matches = flann.knnMatch(desLeft,desRight,k=2)
# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]

# Apply ratio test
goodMatches = []
ptsLeft = []
ptsRight = []
for i,(m,n) in enumerate(matches):
    if m.distance < 0.7*n.distance:
        x1,y1 = keyPointsLeft[m.queryIdx].pt
        x2,y2 = keyPointsRight[n.trainIdx].pt
        matchesMask[i] = [1,0]
        goodMatches.append([m])
        ptsLeft.append(keyPointsLeft[m.queryIdx].pt)
        ptsRight.append(keyPointsRight[n.trainIdx].pt)

ptsLeft = np.int32(ptsLeft)
ptsRight = np.int32(ptsRight)
F, mask = cv2.findFundamentalMat(ptsLeft,ptsRight,cv2.FM_7POINT)
 

После нахождения фундаментальной матрицы я пытаюсь проверить соответствие точек с помощью уравнения эпиполярного ограничения, которое является :

 (1) p1T * F * p2 = 0
 

Итак, предположим, что у нас есть точка p1 (x1,y1) на левом изображении и точка p1 (x2,y2) на правом изображении. Поэтому, если я применю эпиполярное уравнение (1) к этим точкам, я должен получить 0 или более близкое число к 0.

Итак, это уравнение можно записать следующим образом :

 (2) 0 = x1*x2*F[0][0]   x1*y2*F[0][1]   x1*F[0][2]   y1*x2*F[1][0]   y1*y2*F[1][1]   y1*F[1][2]   x2*F[2][0]   y2*F[2][1]    F[2][2]
 

Используя уравнение (2), я пытаюсь проверить точки, сопоставленные Фланну с этим уравнением. Я напечатал результаты уравнения и точки, которые находятся в одной строке, так как мои входные изображения просто переводятся между ними.

Выход :

 p1(82,340) --> p2(74,340)
p1T * F * p2 =  -0.7662387780488729
p1(355,240) --> p2(354,240)
p1T * F * p2 =  -0.0047911844235635215
p1(354,229) --> p2(349,229)
p1T * F * p2 =  0.11662882831689814
p1(377,175) --> p2(372,175)
p1T * F * p2 =  0.3450325352994703
p1(319,227) --> p2(311,227)
p1T * F * p2 =  0.19119563752361657
p1(276,171) --> p2(273,171)
p1T * F * p2 =  0.251353775637849
p1(371,259) --> p2(366,259)
p1T * F * p2 =  -0.019570666111391688
......
....
...
 

С этим выводом я не могу проверить точки и мою фундаментальную матрицу. Уравнение (1) в моем случае не работает, иногда оно дает значения, близкие к нулю, иногда нет. Есть ли что-нибудь, что я сделал не так ?

Ответ №1:

Я не уверен, что уравнение 1 можно записать как уравнение 2. Я бы определенно рекомендовал использовать уравнение 1 и однородные координаты (значение z равно 1). Вам следует подумать о нормализации координат, потому что X и Y будут намного больше, чем Z. Это можно сделать, вычисляя преобразование подобия, установленное Хартли, Зиссерманом и, например, показанное здесь: стр. 2.

После этого вы можете использовать OpenCV Mat для непосредственного вычисления результатов. Во-первых, я бы рекомендовал вам попробовать использовать различные методы расчета Фундаментальной матрицы. Поскольку у вас много характерных точек, сгенерированных ORB, я бы использовал CV_FM_RANSAC , например, с порогом повторения 3 и уверенностью 0,99. Это уже могло бы сделать свое дело.

Краткий пример кода на C :

 cv::Mat F = cv::findFundamentalMat(kp_left, kp_right, cv::RANSAC, 3.0, 0.999); # here you need to use your feature points cv::Point2f
point_left = cv::Mat(cv::Point3d(82,340,1));
point_right = cv::Mat(cv::Point3d(74,340,1));
cv::Mat distance = point_left.t()*F*point_right;
 

Расстояние обычно никогда не бывает равным 0, но теперь оно должно быть близко к нему.