У меня проблема с точным обнаружением маркеров с использованием OpenCV.
Я записал видео, представляющее эту проблему: http://youtu.be/IeSSW4MdyfU
Как вы видите, я - маркеры, которые я обнаруживаю, слегка сдвинуты под некоторые углы камеры. Я читал в Интернете, что это могут быть проблемы с калибровкой камеры, поэтому я расскажу вам, как я откалибрую камеру, и, может быть, вы сможете сказать мне, что я делаю неправильно?
В начале я собираю данные из разных изображений и сохраняю углы калибровки в _imagePoints
, как это показано
std::vector<cv::Point2f> corners;
_imageSize = cvSize(image->size().width, image->size().height);
bool found = cv::findChessboardCorners(*image, _patternSize, corners);
if (found) {
cv::Mat *gray_image = new cv::Mat(image->size().height, image->size().width, CV_8UC1);
cv::cvtColor(*image, *gray_image, CV_RGB2GRAY);
cv::cornerSubPix(*gray_image, corners, cvSize(11, 11), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_EPS+ CV_TERMCRIT_ITER, 30, 0.1));
cv::drawChessboardCorners(*image, _patternSize, corners, found);
}
_imagePoints->push_back(_corners);
Затем, после сбора достаточного количества данных, я вычисляю матрицу камеры и коэффициенты с помощью этого кода:
std::vector< std::vector<cv::Point3f> > *objectPoints = new std::vector< std::vector< cv::Point3f> >();
for (unsigned long i = 0; i < _imagePoints->size(); i++) {
std::vector<cv::Point2f> currentImagePoints = _imagePoints->at(i);
std::vector<cv::Point3f> currentObjectPoints;
for (int j = 0; j < currentImagePoints.size(); j++) {
cv::Point3f newPoint = cv::Point3f(j % _patternSize.width, j / _patternSize.width, 0);
currentObjectPoints.push_back(newPoint);
}
objectPoints->push_back(currentObjectPoints);
}
std::vector<cv::Mat> rvecs, tvecs;
static CGSize size = CGSizeMake(_imageSize.width, _imageSize.height);
cv::Mat cameraMatrix = [_userDefaultsManager cameraMatrixwithCurrentResolution:size]; // previously detected matrix
cv::Mat coeffs = _userDefaultsManager.distCoeffs; // previously detected coeffs
cv::calibrateCamera(*objectPoints, *_imagePoints, _imageSize, cameraMatrix, coeffs, rvecs, tvecs);
Результаты, как вы видели в видео.
Что я делаю неправильно? это проблема в коде? Сколько изображений следует использовать для выполнения калибровки (сейчас я пытаюсь получить 20-30 изображений до окончания калибровки).
Должен ли я использовать изображения, которые содержат неправильно обнаруженные углы шахматной доски, например:
или я должен использовать только правильно обнаруженные шахматные доски, подобные этим:
Я экспериментировал с сеткой кругов вместо шахматных досок, но результаты были намного хуже, чем сейчас.
В случае вопросов, как я обнаруживаю маркер: я использую функцию solvepnp
:
solvePnP(modelPoints, imagePoints, [_arEngine currentCameraMatrix], _userDefaultsManager.distCoeffs, rvec, tvec);
с параметрами модели, указанными следующим образом:
markerPoints3D.push_back(cv::Point3d(-kMarkerRealSize / 2.0f, -kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(kMarkerRealSize / 2.0f, -kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(kMarkerRealSize / 2.0f, kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(-kMarkerRealSize / 2.0f, kMarkerRealSize / 2.0f, 0));
и imagePoints
являются координатами углов маркера в обработке изображения (для этого я использую собственный алгоритм)