Я пытаюсь реализовать проект компьютерного зрения, чтобы определить трансформацию проекции, происходящую в футбольном изображении. Я обнаруживаю точки схода, получаю совпадения по двум точкам и вычисляю проекцию от точек поля модели к точкам изображения на основе перекрестных соотношений. Это действительно хорошо работает почти для всех точек, но для точек (которые лежат за камерой) проекция идет совершенно неверно. Вы знаете, почему и как я могу это исправить?
Он основан на статье Быстрая регистрация двухмерных моделей в изображения с использованием точек схода для анализа спортивных изображений., и я использую эту функцию проекции, приведенную на странице 3. Я попытался вычислить результат, используя разные методы (а именно, на основе пересечений), но результат тот же:
Должна быть нижняя линия поля, но она спроектирована далеко вправо.
Я также попытался использовать десятичную дробь, чтобы увидеть, была ли это ошибка отрицательного переполнения, но для меня это не имело бы особого смысла, поскольку тот же результат был обнаружен в Wolfram Alpha при тестировании.
def Projection(vanpointH, vanpointV, pointmatch2, pointmatch1):
"""
:param vanpointH:
:param vanpointV:
:param pointmatch1:
:param pointmatch2:
:returns function that takes a single modelpoint as input:
"""
X1 = pointmatch1[1]
point1field = pointmatch1[0]
X2 = pointmatch2[1]
point2field = pointmatch2[0]
point1VP = linecalc.calcLineEquation([[point1field[0], point1field[1], vanpointH[0], vanpointH[1], 1]])
point1VP2 = linecalc.calcLineEquation([[point1field[0], point1field[1], vanpointV[0], vanpointV[1], 1]])
point2VP = linecalc.calcLineEquation([[point2field[0], point2field[1], vanpointV[0], vanpointV[1], 1]])
point2VP2 = linecalc.calcLineEquation([[point2field[0], point2field[1], vanpointH[0], vanpointH[1], 1]])
inters = linecalc.calcIntersections([point1VP, point2VP])[0]
inters2 = linecalc.calcIntersections([point1VP2, point2VP2])[0]
def lambdaFcnX(X, inters):
# This fcn provides the solution of where the point to be projected is, according to the matching,
# on the line connecting point1 and vanpointH. Based only on that the cross ratio is the same as in the model field
return (((X[0] - X1[0]) * (inters[1] - point1field[1])) / ((X2[0] - X1[0]) * (inters[1] - vanpointH[1])))
def lambdaFcnX2(X, inters):
# This fcn provides the solution of where the point to be projected is, according to the matching,
# on the line connecting point2 and vanpointH, Based only on that the cross ratio is the same as in the model field
return (((X[0] - X1[0]) * (point2field[1] - inters[1])) / ((X2[0] - X1[0]) * (point2field[1] - vanpointH[1])))
def lambdaFcnY(X, v1, v2):
# return (((X[1] - X1[1]) * (np.subtract(v2,v1))) / ((X2[1] - X1[1]) * (np.subtract(v2, vanpointV))))
return (((X[1] - X1[1]) * (v2[0] - v1[0])) / ((X2[1] - X1[1]) * (v2[0] - vanpointV[0])))
def projection(Point):
lambdaPointx = lambdaFcnX(Point, inters)
lambdaPointx2 = lambdaFcnX2(Point, inters2)
v1 = (np.multiply(-(lambdaPointx / (1 - lambdaPointx)), vanpointH) + np.multiply((1 / (1 - lambdaPointx)),
point1field))
v2 = (np.multiply(-(lambdaPointx2 / (1 - lambdaPointx2)), vanpointH) + np.multiply((1 / (1 - lambdaPointx2)),
inters2))
lambdaPointy = lambdaFcnY(Point, v1, v2)
point = np.multiply(-(lambdaPointy / (1 - lambdaPointy)), vanpointV) + np.multiply((1 / (1 - lambdaPointy)), v1)
return point
return projection
match1 = ((650,390,1),(2478,615,1))
match2 = ((740,795,1),(2114,1284,1))
vanpoint1 = [-2.07526585e+03, -5.07454315e+02, 1.00000000e+00]
vanpoint2 = [ 5.53599881e+03, -2.08240612e+02, 1.00000000e+00]
model = Projection(vanpoint2,vanpoint1,match2,match1)
model((110,1597))
Предположим, что точки схода
vanpoint1 = [-2.07526585e+03, -5.07454315e+02, 1.00000000e+00]
vanpoint2 = [ 5.53599881e+03, -2.08240612e+02, 1.00000000e+00]
и два совпадения:
match1 = ((650,390,1),(2478,615,1))
match2 = ((740,795,1),(2114,1284,1))
Они работают почти для всех точек, как показано на рисунке. Однако левая нижняя точка полностью отключена и получает координаты изображения [ 4.36108177e+04, -1.13418258e+04]
. Это происходит при спуске с (312,1597)
; для (312,1597)
результат будет [-2.34989787e+08, 6.87155603e+07]
, что и должно быть.
Почему он полностью сдвигается до 4000? Возможно, это имело бы смысл, если бы я рассчитал матрицу камеры, а затем точка была за камерой. Но поскольку то, что я делаю, на самом деле похоже на оценку гомографии (2D-отображение), я не могу понять геометрического смысла этого. Однако мои знания об этом определенно ограничены.
Изменить: возможно, это связано с топологией проективной плоскости и что она неориентируема (обтекает)? Мои познания в топологии не такие, какими должны быть ...