Проекция точки с использованием кросс-соотношений полностью неверна после определенного порога

Я пытаюсь реализовать проект компьютерного зрения, чтобы определить трансформацию проекции, происходящую в футбольном изображении. Я обнаруживаю точки схода, получаю совпадения по двум точкам и вычисляю проекцию от точек поля модели к точкам изображения на основе перекрестных соотношений. Это действительно хорошо работает почти для всех точек, но для точек (которые лежат за камерой) проекция идет совершенно неверно. Вы знаете, почему и как я могу это исправить?

Он основан на статье Быстрая регистрация двухмерных моделей в изображения с использованием точек схода для анализа спортивных изображений., и я использую эту функцию проекции, приведенную на странице 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-отображение), я не могу понять геометрического смысла этого. Однако мои знания об этом определенно ограничены.

Изменить: возможно, это связано с топологией проективной плоскости и что она неориентируема (обтекает)? Мои познания в топологии не такие, какими должны быть ...


person Jacco.Oosterhuis    schedule 28.01.2019    source источник


Ответы (1)


Ладно, разобрался. Это может не иметь большого смысла для других, но для меня это имеет значение (и если у кого-то когда-либо была такая же проблема ...)

Геометрически я понял следующее при использовании эквивалентного подхода, где v1 и v2 вычисляются на основе разных точек схода, а я проецирую на основе пересечения линий, соединяющих точки с точками схода. Здесь в какой-то момент эти линии становятся параллельными, а после этого пересечение фактически полностью проходит на другой стороне. И в этом есть смысл; мне просто потребовалось время, чтобы понять, что это так.

В приведенном выше коде последнее перекрестное отношение, называемое lambdapointy, становится равным 1, а затем - выше. Здесь происходит то же самое, но это легче всего было визуализировать по пересечениям.

Также знаю, как это решить; это на всякий случай, если кто-то еще попробует такой код.

person Jacco.Oosterhuis    schedule 31.01.2019