2016-06-08 3 views
2

У меня есть камера для рыбного глаза в потолке, и я хочу найти некоторые точки на полу. Я поставил источник моей системы ссылок (реальный мир) чуть ниже камеры, и я хочу знать положение каждого объекта в сантиметрах. Эта фотография показывает, что это:Точки изображения (в пикселях) до координат реального мира (метров)

Reference system - Real world

Во-первых, я сделал калибровку камеры и я получил следующий результат с RMS 1,11:

Undistorted image after calibration

В результате калибровки Я получил собственные параметры (матрица камеры), поэтому я использовал cv :: solvePnP для получения векторов вращения и трансляции. Для этого я отметил некоторые моменты неискаженного изображения (в пикселях), и я измерил их в реальном мире в соответствии с моей системой отсчета.

Например, происхождение находится в центре 1024x768 изображения, так что:

  • Точка 0: ImagePoint (512, 384) [пикселей] -> ObjectPoint (0,0) [см]

следующий код показывает это:

std::vector<cv::Point2f> imagePointsPix; 
std::vector<cv::Point3f> objectPointsCm; 
imagePointsPix.push_back(cv::Point2f(512.,384.)); 
imagePointsPix.push_back(cv::Point2f(404.,512.));  
imagePointsPix.push_back(cv::Point2f(666.,211.)); 
imagePointsPix.push_back(cv::Point2f(519.,66.)); 

objectPointsCm.push_back(cv::Point3f(0., 0., 0.)); 
objectPointsCm.push_back(cv::Point3f(-80.,-132.,0.)); 
objectPointsCm.push_back(cv::Point3f(120.,188.,0.)); 
objectPointsCm.push_back(cv::Point3f(-40.,268.,0.)); 

cv::Mat rvec(1,3,cv::DataType<double>::type); 
cv::Mat tvec(1,3,cv::DataType<double>::type); 
cv::Mat rotationMatrix(3,3,cv::DataType<double>::type); 

cv::solvePnP(objectPointsCm, imagePointsPix, cameraMatrix, distCoeffs, rvec, tvec, 0, SOLVEPNP_ITERATIVE); 
cv::Rodrigues(rvec,rotationMatrix); 

Теперь у меня есть матрица камеры, матрицы вращения и вектор traslation, поэтому при использовании this в качестве ссылки Я могу вычислить любую точку, если у меня есть ее позиция в пикселях. Это код:

cv::Mat uvPoint = cv::Mat::ones(3,1,cv::DataType<double>::type); //u,v,1 
uvPoint.at<double>(0,0) = 512.; //img point for which we want its real coordinates 
uvPoint.at<double>(1,0) = 384.; 
cv::Mat tempMat, tempMat2; 
double s; 
tempMat = rotationMatrix.inv() * cameraMatrix.inv() * uvPoint; 
tempMat2 = rotationMatrix.inv() * tvec; 
s = 0 + tempMat2.at<double>(2,0); //before 0 it was 285, which represents the height Zconst 
s /= tempMat.at<double>(2,0); 
std::cout << "P = " << rotationMatrix.inv() * (s * cameraMatrix.inv() * uvPoint - tvec) << std::endl; 

Я получаю это результаты для же точек я использовал для получения своих параметров:

  • точки 0 -> (0,213, 3,391) (оно должно быть (0,0)) ОШИБКА: 3,69 см
  • Точка 1 -> (-68,28, -112.82) (он должен быть (-80, -132)) ОШИБКА: 17.49 см
  • Точка 2 - -> (84,4 8, 137,61) (это должно быть (120, 188)) ОШИБКА: 49,62 см

Остальные точек также показывают ошибку слишком большой ... Я использовал больше очков, но результаты не улучшаются , Я не знаю, где я ошибся, может ли кто-нибудь мне помочь?

Заранее благодарен.

ответ

0

Наконец, я выяснил, что ошибка была вызвана коэффициентами искажения, то есть моей калибровкой. Я установил cameraMatrix в матрицу Identity (eye (3)), а distCoefficients - NULL, так что solvePNP предположил, что у меня идеальная камера. Используя этот подход, я получил ошибку намного ниже. Мне нужно будет сделать более качественную калибровку.

+0

Есть вероятность, что калибровка будет прекрасной, и что вы эффективно искажаете изображение дважды (см. Мой ответ для объяснения). – rob3c

1

Похоже, что вы можете эффективно искажать изображение дважды с точки зрения solvePNP. Это связано с передачей коэффициентов искажения вместе с точечными соответствиями, которые уже получены из неискаженного изображения.

Попробуйте передать фактическую матрицу камеры из вашей калибровки в solvePNP вместо идентификационной матрицы, но все же передайте NULL для коэффициентов искажения, чтобы избежать двойного искажения.

Смежные вопросы