2015-08-26 3 views
65

Я пытаюсь получить 3D-координаты нескольких точек в пространстве, но получаю нечетные результаты как от undistortPoints(), так и от triangulatePoints().OpenCV undistortPoints и triangulatePoint дают нечетные результаты (стерео)

Поскольку обе камеры имеет различное разрешение, я откалиброван их по отдельности, получил RMS ошибки в 0,34 и 0,43, затем использовал stereoCalibrate(), чтобы получить больше матриц, получил RMS из 0,708, а затем использовал stereoRectify(), чтобы получить оставшиеся матрицы. С этим я начал работу над собранными координатами, но получаю странные результаты.

Например, вход: (935, 262), а undistortPoints() выход (1228.709125, 342.79841) для одной точки, а для другого это (934, 176) и (1227.9016, 292.4686) соответственно. Что странно, потому что обе эти точки очень близки к середине кадра, где искажения являются наименьшими. Я не ожидал, что он переместит их на 300 пикселей.

При переходе на traingulatePoints() результаты становятся еще более странными - я измерил расстояние между тремя точками в реальной жизни (с линейкой) и вычислил расстояние между пикселями на каждом снимке. Поскольку на этот раз точки были на довольно плоской плоскости, эти две длины (пиксель и реальность) соответствовали, как в | AB |/| BC | в обоих случаях было около 4/9. Однако triangulatePoints() дает мне результаты с рельсов, с | AB |/| BC | 3/2 или 4/2.

Это мой код:

double pointsBok[2] = { bokList[j].toFloat()+xBok/2, bokList[j+1].toFloat()+yBok/2 }; 
cv::Mat imgPointsBokProper = cv::Mat(1,1, CV_64FC2, pointsBok); 

double pointsTyl[2] = { tylList[j].toFloat()+xTyl/2, tylList[j+1].toFloat()+yTyl/2 }; 
//cv::Mat imgPointsTyl = cv::Mat(2,1, CV_64FC1, pointsTyl); 
cv::Mat imgPointsTylProper = cv::Mat(1,1, CV_64FC2, pointsTyl); 

cv::undistortPoints(imgPointsBokProper, imgPointsBokProper, 
     intrinsicOne, distCoeffsOne, R1, P1); 
cv::undistortPoints(imgPointsTylProper, imgPointsTylProper, 
     intrinsicTwo, distCoeffsTwo, R2, P2); 

cv::triangulatePoints(P1, P2, imgWutBok, imgWutTyl, point4D); 

double wResult = point4D.at<double>(3,0); 
double realX = point4D.at<double>(0,0)/wResult; 
double realY = point4D.at<double>(1,0)/wResult; 
double realZ = point4D.at<double>(2,0)/wResult; 

Углы между точками являются своего рода Сорта хорошо, но, как правило, нет:

`7,16816 168,389 4,44275` vs `5,85232 170,422 3,72561` (degrees) 
`8,44743 166,835 4,71715` vs `12,4064 158,132 9,46158` 
`9,34182 165,388 5,26994` vs `19,0785 150,883 10,0389` 

Я пытался использовать undistort() на весь кадр, но получил результаты так же странно. Расстояние между B и C точек должны быть в значительной степени неизменным во все времена, и все же это то, что я получаю:

7502,42  
4876,46 
3230,13 
2740,67 
2239,95 

кадр за кадром.

Pixel расстояние (внизу) в зависимости от реального расстояния (вверху) - должно быть очень похоже: |BC| distance

Угол обзор:

ABC angle

Кроме того, следует не как undistortPoints() и undistort() дает то же самое результаты (другой набор видео здесь)?
enter image description here

+0

Не могли бы вы включить код, который вы использовали для калибровки, и некоторые образцы изображений для части триангуляции? – AldurDisciple

+0

Это может быть сложно ... там много. Я постараюсь опубликовать только соответствующие части завтра – Petersaber

+0

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

ответ

1

Функция cv :: undistort делает неискаженное и повторное воспроизведение за один раз.Он выполняет следующий перечень операций:

  1. расстегнуть камеры проекции (умножение с обратной матрицы камеры)
  2. применить модель искажения, чтобы отменить искажение
  3. поворачиваются на поставленном матрицу вращения R1/R2
  4. проекта указывает на изображение, используя прилагаемую матрицу проекции P1/P2

Если вы передаете матрицы R1, P1 Респ. R2, P2 из cv :: stereoCalibrate(), точки входа будут неискаженными и исправлены. Выпрямление означает, что изображения преобразуются таким образом, что соответствующие точки имеют одинаковую координату y. Не существует уникального решения для исправления изображения, так как вы можете применить любой перевод или масштабирование к обоим изображениям, не изменяя выравнивание соответствующих точек. Считается, что cv :: stereoCalibrate() может немного смещать центр проекции (например, 300 пикселей). Если вам нужно чистое искажение, вы можете передать матрицу идентичности (вместо R1) и оригинальную матрицу камеры K (вместо P1). Это должно привести к координатам пикселей, подобным исходным.