У меня есть матрицы 3x3
intrinsics
и 4x3
extrinsics
для моей камеры, полученные через cv2.calibrateCamera()
Теперь я хочу использовать эти параметры для вычисления преобразования BEV (Bird Eye View)
для любых заданных координат в кадре, полученном с камеры.
Какую функцию openCv
можно использовать для вычисления преобразования перспективы BEV
для заданных координат точки и камеры extrinsics
и/или intrinsics
3x3 matrices
?
Я нашел кое-что очень похожее в следующем посте: https://deepnote.com/article/social-distancing-detector/ на основе https://www.pyimagesearch.com/2014/08/25/4 -point-opencv-getperspective-transform-example/,
они используют cv2.getPerspectiveTransform()
, чтобы получить 3X3 matrix
, но я не знаю, представляет ли эта матрица intrinsics
, extrinsecs
или что-то еще. Затем они преобразуют список точек с помощью такой матрицы следующим образом:
#Assuming list_downoids is the list of points to be transformed and matrix is the one obtained above
list_points_to_detect = np.float32(list_downoids).reshape(-1, 1, 2)
transformed_points = cv2.perspectiveTransform(list_points_to_detect, matrix)
Мне действительно нужно знать, могу ли я использовать эту функцию cv2.perspectiveTransform
для вычисления преобразования или есть ли другой лучший способ сделать это, используя extrinsics
, intrinsics
или оба, без необходимости повторного использования кадра, поскольку у меня уже есть обнаруженные/выбранные координаты сохраняется в массиве.
Ответ таков: невозможно вычислить BEV сцены, если у вас нет информации о расстоянии о пикселях вашего изображения.
Подумайте об этом: представьте, что у вас есть изображение вертикального экрана: тогда вид с высоты птичьего полета будет линией. Теперь скажем, что на этом экране отображается изображение пейзажа и что изображение на этом экране неотличимо от изображения самого пейзажа. BEV по-прежнему будет линией (хотя и красочной).
Теперь представьте, что у вас есть точно такая же картинка, но на этот раз это не изображение экрана, а пейзаж. Тогда вид с высоты птичьего полета не является линией и ближе к тому, что мы обычно представляем себе как BEV.
Наконец, позвольте мне заявить, что OpenCV не может узнать, описывает ли ваше изображение плоскость чего-то другого (даже с заданными параметрами камеры), поэтому он не может вычислить BEV вашей сцены. Функция cv2.perspectiveTransform
требует, чтобы вы передали ей матрицу гомографии (вы можете получить ее, используя cv2.findHomography()
, но вам также понадобится информация о расстоянии от вашего изображения).
Извините за отрицательный ответ, но решить вашу проблему невозможно, учитывая только внутреннюю и внешнюю калибровочные матрицы камеры.
Если у вас есть 3D-координаты хотя бы из 3-х точек (думаю, вам нужно только три, но чем больше, тем лучше), то вы сможете сделать это с помощью cv2.findHomography
. Там мало технических деталей, поэтому я бы посоветовал вам поискать учебные пособия. Помнится, я нашла там несколько очень интересных :)
Например, если ваше изображение представляет собой наклонную плоскость (я считаю, что дороги достаточно похожи на плоскости для этого), я думаю, что этот урок поможет вам: Learnopencv.com/tag/findhomography
Большое спасибо за ваше время. У меня есть x
, y
, width
и height
для каждой точки. Я думаю, это может сработать.
Пожалуйста ! Удачи ! (Кстати, я был бы очень признателен, если бы вы могли принять мой ответ, спасибо!) :)
Хорошо. Звучит отлично. Не могли бы вы отметить один из моих комментариев на верхней стрелке?
для преобразования перспективы требуется четыре пары точек (по четыре точки в каждом из обоих представлений). Я бы ответил ДА, потому что, если вы понимаете, что "вид с высоты птичьего полета" является преобразованием плоскости в плоскость, getPerspectiveTransform и warpPerspective будут работать. все ломается, только если вы пытаетесь деформировать изображение 3D-сцены, которая не является плоской плоскостью. разумно предположить, что «BEV» означало отображение плоскости.
@ChristophRackwitz, что вы подразумеваете под «изображением трехмерной сцены, которая не является плоской плоскостью»?
скажем, вы летите на самолете и фотографируете землю. вы летите над фермами в Канзасе. плоский как блин. затем вы пролетите над Манхэттеном. небоскребы. если сфотографировать их под углом, то вы увидите не только крыши, но и бока небоскребов. нет способа деформировать изображение, чтобы получить настоящий вид сверху вниз (только крыши).
После тщательного расследования я нашел хорошее решение:
projection matrix
— это произведение матриц extrinsic
и intrinsic
камеры.
extrinsic
— это матрица 4x3
, а intrinsec
— это матрица 3x3
, но нам нужно, чтобы projection matrix
была матрицей 3x3
, то перед выполнением умножения нам нужно преобразовать extrinsic
в 3x3
.cv2.getPerspectiveTransform()
дает нам Projection Matrix
, когда у нас нет параметров камеры:
cv2.warpPerspective()
трансформирует само изображение.
Для приведенной выше задачи нам не нужны эти две функции, поскольку у нас уже есть extrinsics
, intrinsecs
и координаты точек на изображении.
Учитывая вышеизложенное, я написал функцию для преобразования в BEV
список точек list_x_y
с учетом intrinsics
и extrinsics
:
def compute_point_perspective_transformation(intrinsics, extrinsics, point_x_y):
"""Auxiliary function to project a specific point to BEV
Parameters
----------
intrinsics (array) : The camera intrinsics matrix
extrinsics (array) : The camera extrinsics matrix
point_x_y (tuple[x,y]) : The coordinates of the point to be projected to BEV
Returns
----------
tuple[x,y] : the projection of the point
"""
# Using the camera calibration for Bird Eye View
intrinsics_matrix = np.array(intrinsics, dtype='float32')
#In the intrinsics we have parameters such as focal length and the principal point
extrinsics_matrix = np.array(extrinsics, dtype='float32')
#The extrinsic matrix stores the position of the camera in global space
#The 1st 3 columns represents the rotation matrix and the last is a translation vector
extrinsics = extrinsics[:, [0, 1, 3]]
#We removed the 3rd column of the extrinsics because it represents the z coordinate (0)
projection_matrix = np.matmul(intrinsics_matrix, extrinsics_matrix)
# Compute the new coordinates of our points - cv2.perspectiveTransform expects shape 3
list_points_to_detect = np.array([[point_x_y]], dtype=np.float32)
transformed_points = cv2.perspectiveTransform(list_points_to_detect, projection_matrix)
return transformed_points[0][0][0], transformed_points[0][0][1]
Не могли бы вы объяснить, почему это ответ на ваш вопрос? (часть после «рассмотрения представленного выше») Я вижу, что вы возвращаете части матрицы перспективного преобразования, но как это отвечает на «вычислить перспективное преобразование BEV для данной точки координаты" вопрос?
Поскольку у вас есть модель камеры, готовым (но не полным) решением будет использование функции getTopViewOfImage
из библиотеки преобразования камеры
Спасибо за ответ Иосиф. Что, если я дополнительно укажу кадр и координаты точек в упомянутом кадре, которые я хочу спроецировать?