Нужна помощь в понимании ошибки для cv2.undistortPoints()

Я пытаюсь триангулировать точки с проектора и камеры, используя Structured Light в OpenCV Python. В этом процессе у меня есть список кортежей, которые соответствуют один к одному между камерой и проектором. Я передаю это в cv2.undistortedPoints(), как показано ниже:

camera_normalizedPoints = cv2.undistortPoints(camera_points, camera_K, camera_d)

Однако python выдает следующую ошибку, и я не могу понять, что означает эта ошибка.

camera_normalizedPoints = cv2.undistortPoints(camera_points, camera_K, camera_d) cv2.error: /home/base/opencv_build/opencv/modules/imgproc/src/undistort.cpp:312: error: (-215) CV_IS_MAT(_src) && CV_IS_MAT(_dst) && (_src->rows == 1 || _src->cols == 1) && (_dst->rows == 1 || _dst->cols == 1) && _src->cols + _src->rows - 1 == _dst->rows + _dst->cols - 1 && (CV_MAT_TYPE(_src->type) == CV_32FC2 || CV_MAT_TYPE(_src->type) == CV_64FC2) && (CV_MAT_TYPE(_dst->type) == CV_32FC2 || CV_MAT_TYPE(_dst->type) == CV_64FC2) in function cvUndistortPoints

Любая помощь приветствуется.

Спасибо.


person Shubs    schedule 20.11.2017    source источник
comment
Вы должны были точно указать, как выглядят точки, которые вы передаете. OpenCV в Python обычно требует точки в массиве двухканальный, и я полагаю, что вы передаете их как одноканальный множество. Вместо точек в виде списка списков типа [[x1, y1], [x2, y2], ...] они должны быть на один уровень глубже, например [[[x1, y1]], [[x2, y2]], ...]. Также убедитесь, что точки являются 32-битными или 64-битными числами с плавающей запятой, поэтому в целом массивы точек должны выглядеть как np.array([[[x1, y1]], [[x2, y2]], ...], dtype=np.float32). Если это решит, я напишу это как ответ.   -  person alkasm    schedule 21.11.2017
comment
@AlexanderReynolds - Да, я передаю баллы как [[x1, y1], [x2, y2], ...]. Как вы и предложили, сейчас пытаюсь добавить еще одно измерение командой camera_points = np.array([camera_points], dtype=np.float32), но вместо [[[x1, y1]], [[x2, y2]], ...] получаю [[[x1, y1], [x2, y2], ...]]. Не могли бы вы подсказать мне, как это сделать правильно, чтобы я мог проверить?   -  person Shubs    schedule 21.11.2017
comment
Вы должны просто иметь возможность перемещать эти точки, переворачивая оси. points = points.transpose(1,0,2) должно помочь (это переворачивает оси 0 и 1).   -  person alkasm    schedule 21.11.2017
comment
@AlexanderReynolds - Да, это сработало. Благодарю вас!   -  person Shubs    schedule 21.11.2017
comment
Отлично, я добавил это как ответ.   -  person alkasm    schedule 21.11.2017


Ответы (2)


К сожалению, документация не всегда четко описывает форму ввода в Python, а undistortPoints() еще даже не имеет документации по Python.

Входные точки должны быть массивом формы (n_points, 1, n_dimensions). Итак, если у вас есть 2D-координаты, они должны быть в форме (n_points, 1, 2). Или для 3D-координат они должны быть в форме (n_points, 1, 3). Это верно для большинства функций OpenCV. Насколько мне известно, этот формат будет работать для всех функций OpenCV, в то время как некоторые функции OpenCV также будут принимать точки в форме (n_points, n_dimensions). Я считаю, что лучше просто сохранять все последовательно и в формате (n_points, 1, n_dimensions).

Чтобы было ясно, это означает, что массив из четырех 32-битных 2D-точек с плавающей запятой будет выглядеть так:

points = np.array([[[x1, y1]], [[x2, y2]], [[x3, y3]], [[x4, y4]]], dtype=np.float32)

Если у вас есть массив формы (n_points, n_dimensions), вы можете расширить его с помощью np.newaxis:

>>> points = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
>>> points.shape
(4, 2)
>>> points = points[:, np.newaxis, :]
>>> points.shape
(4, 1, 2)

или с np.expand_dims():

>>> points = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
>>> points.shape
(4, 2)
>>> points = np.expand_dims(points, 1)
>>> points.shape
(4, 1, 2)

или с различным порядком np.transpose() в зависимости от порядка ваших измерений. Например, если ваша фигура (1, n_points, n_dimensions), то вы хотите поменять местами ось 0 с осью 1, чтобы получить (n_points, 1, n_dimensions), поэтому points = np.transpose(points, (1, 0, 2)) изменит оси, поставив сначала ось 1, затем ось 0, затем ось 2, чтобы новая форма была правильной.


Если вы думаете, что это странный формат для точек, это если вы рассматриваете только список точек, но разумно, если вы думаете о точках как о координатах изображения. Если у вас есть изображение, то координаты каждой точки изображения определяются парой (x, y), например:

(0, 0)    (1, 0)    (2, 0)    ...
(0, 1)    (1, 1)    (2, 1)    ...
(0, 2)    (1, 2)    (2, 2)    ...
...

Здесь имеет смысл поместить каждую координату в отдельный канал двухканального массива, чтобы получить один 2D-массив x-координат и один 2D-массив y-координат, например:

Канал 0 (х-координаты):

0    1    2    ...
0    1    2    ...
0    1    2    ...
...

Канал 1 (координаты Y):

0    0    0    ...
1    1    1    ...
2    2    2    ...
...

Вот почему каждая координата находится на отдельном канале.


Некоторые другие функции OpenCV, для которых требуется этот формат, включают cv2.transform() и cv2.perspectiveTransform(), о которых я уже отвечал на идентичные вопросы ранее, здесь и здесь соответственно.

person alkasm    schedule 21.11.2017

Я также достигаю этих проблем, и мне требуется некоторое время, чтобы исследовать, наконец, понять.

В открытой системе операция искажения предшествует матрице камеры, поэтому порядок процесса следующий: image_distorted -> camera_matrix -> функция устранения искажения-> camera_matrix-> обратно в image_undistorted.

Так что вам снова нужно небольшое исправление и camera_K.

camera_normalizedPoints = cv2.undistortPoints (camera_points, camera_K, camera_d, cv2.Mat.sye (3,3), camera_K)

Форум: https://i.stack.imgur.com/nmR5P.jpg

person B.Blue    schedule 07.01.2019