OpenCV::solvePNP() - утверждение не выполнено
Я пытаюсь получить позу камеры с помощью solvePNP() от OpenCV.
После запуска моей программы я получаю следующие ошибки:
OpenCV Error: Assertion failed (npoints >= 0 && npoints == std::max(ipoints.checkVector(2, CV_32F), ipoints.checkVector(2, CV_64F))) in solvePnP, file /opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_tarballs_ports_graphics_opencv/opencv/work/OpenCV-2.4.2/modules/calib3d/src/solvepnp.cpp, line 55
libc++abi.dylib: terminate called throwing an exception
Я пытался найти, как решить эти ошибки, но, к сожалению, я не смог ее решить!
Вот мой код, все комментарии / помощь очень ценятся:
enum Pattern { NOT_EXISTING, CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
void calcBoardCornerPositions(Size boardSize, float squareSize, vector<Point3f>& corners,
Pattern patternType)
{
corners.clear();
switch(patternType)
{
case CHESSBOARD:
case CIRCLES_GRID:
for( int i = 0; i < boardSize.height; ++i )
for( int j = 0; j < boardSize.width; ++j )
corners.push_back(Point3f(float( j*squareSize ), float( i*squareSize ), 0));
break;
case ASYMMETRIC_CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float((2*j + i % 2)*squareSize), float(i*squareSize), 0));
break;
}
}
int main(int argc, char* argv[])
{
float squareSize = 50.f;
Pattern calibrationPattern = CHESSBOARD;
//vector<Point2f> boardCorners;
vector<vector<Point2f> > imagePoints(1);
vector<vector<Point3f> > boardPoints(1);
Size boardSize;
boardSize.width = 9;
boardSize.height = 6;
vector<Mat> intrinsics, distortion;
string filename = "out_camera_xml.xml";
FileStorage fs(filename, FileStorage::READ);
fs["camera_matrix"] >> intrinsics;
fs["distortion_coefficients"] >> distortion;
fs.release();
vector<Mat> rvec, tvec;
Mat img = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); // at kell adnom egy kepet
bool found = findChessboardCorners(img, boardSize, imagePoints[0], CV_CALIB_CB_ADAPTIVE_THRESH);
calcBoardCornerPositions(boardSize, squareSize, boardPoints[0], calibrationPattern);
boardPoints.resize(imagePoints.size(),boardPoints[0]);
//***Debug start***
cout << imagePoints.size() << endl << boardPoints.size() << endl << intrinsics.size() << endl << distortion.size() << endl;
//***Debug end***
solvePnP(Mat(boardPoints), Mat(imagePoints), intrinsics, distortion, rvec, tvec);
for(int i=0; i<rvec.size(); i++) {
cout << rvec[i] << endl;
}
return 0;
}
РЕДАКТИРОВАТЬ (некоторая отладочная информация):
Я отлаживал это построчно. Я вошел во все функции. Я получаю утверждение не удалось в SolvePNP(...). Ниже вы можете увидеть то, что я вижу, когда вступаю в функцию solvePNP. Сначала он перепрыгивает через первый оператор if / if (vec.empty ()) / и переходит во второй оператор if / if (! CopyData) /, там, когда он выполняет последнюю строку /*datalimit = dataend = datastart + lines*step[0]*/ переходит обратно к первому оператору if и возвращает =>, после чего я получаю ошибку Assertion fail.
template<typename _Tp> inline Mat::Mat(const vector<_Tp>& vec, bool copyData)
: flags(MAGIC_VAL | DataType<_Tp>::type | CV_MAT_CONT_FLAG),
dims(2), rows((int)vec.size()), cols(1), data(0), refcount(0),
datastart(0), dataend(0), allocator(0), size(&rows)
{
if(vec.empty())
return;
if( !copyData )
{
step[0] = step[1] = sizeof(_Tp);
data = datastart = (uchar*)&vec[0];
datalimit = dataend = datastart + rows*step[0];
}
else
Mat((int)vec.size(), 1, DataType<_Tp>::type, (uchar*)&vec[0]).copyTo(*this);
}
4 ответа
Войдите в функцию в отладчике и посмотрите, какое утверждение не выполняется. (Возможно, для этого требуются значения в двойном (CV_64F), а не с плавающей точкой.)
Новая оболочка "inputarray" OpenCV выдана для того, чтобы вы могли вызывать функции с любой формой мата, вектором точек и т. Д., И она будет разбираться с этим. Но многие функции принимают определенный формат inut или имеют устаревшие утверждения, обеспечивающие соблюдение определенного формата.
Системы стерео / калибровки являются наихудшими для того, чтобы требовать определенной компоновки, и часто для последовательных операций требуется другая компоновка.
Я запускаю точно такую же проблему с solvePnP и opencv3. Я попытался выделить проблему в одном тестовом случае. Передача std:: vector в cv:: InputArray выполняется не так, как ожидается. Следующий небольшой тест работает с opencv 2.4.9, но не с 3.2.
И это как раз та проблема, когда передается std:: vector точек в solvePnP, и это приводит к сбою утверждения в строке 63 в solvepnp.cpp!
Генерация cv:: mat из списка векторов перед передачей на решение solvePnP работает.
//create list with 3 points
std::vector<cv::Point3f> vectorList;
vectorList.push_back(cv::Point3f(1.0, 1.0, 1.0));
vectorList.push_back(cv::Point3f(1.0, 1.0, 1.0));
vectorList.push_back(cv::Point3f(1.0, 1.0, 1.0));
//to input array
cv::InputArray inputArray(vectorList);
cv::Mat mat = inputArray.getMat();
cv::Mat matDirect = cv::Mat(vectorList);
LOG_INFO("Size vector: %d mat: %d matDirect: %d", vectorList.size(), mat.checkVector(3, CV_32F), matDirect.checkVector(3, CV_32F));
QVERIFY(vectorList.size() == mat.checkVector(3, CV_32F));
Результат opencv 2.4.9 macos:
TestObject: OpenCV
Size vector: 3 mat: 3 matDirect: 3
Результат opencv 3.2 win64:
TestObject: OpenCV
Size vector: 3 mat: 9740 matDirect: 3
Типы не кажутся правильными, по крайней мере, в коде, который работал для меня, я использовал разные типы (как упомянуто в документации).
objectPoints - Массив точек объекта в координатном пространстве объекта, 3xN/Nx3 1-канальный или 1xN/Nx1 3-канальный, где N - количество точек. вектор также может быть передан здесь.
imagePoints - Массив соответствующих точек изображения, 2xN/Nx2 1-канальный или 1xN/Nx1 2-канальный, где N - количество точек. вектор также может быть передан здесь.
cameraMatrix - Введите матрицу камеры A = \ vecthreethree {fx} {0} {cx} {0} {fy} {cy} {0} {0} {1}.
distCoeffs - входной вектор коэффициентов искажения (k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]]) из 4, 5 или 8 элементов. Если вектор НЕДЕЙСТВИТЕЛЕН / пуст, предполагаются нулевые коэффициенты искажения.
rvec - Выходной вектор вращения (см. Rodrigues()), который вместе с tvec переносит точки из системы координат модели в систему координат камеры.
tvec - выходной вектор перевода.
useExtrinsicGuess - если true (1), функция использует предоставленные значения rvec и tvec в качестве начальных приближений векторов вращения и перемещения соответственно и дополнительно оптимизирует их.
vector<Mat> rvec, tvec
должно быть Mat rvec, tvec
вместо.
vector<vector<Point2f> > imagePoints(1)
должно быть vector<Point2f> imagePoints(1)
вместо.
vector<vector<Point3f> > boardPoints(1)
должно бытьvector<Point3f> boardPoints(1)
вместо.
Примечание: я столкнулся с точно такой же проблемой, и это сработало для меня (это немного сбивает с толку, так как калибровка камеры использует векторы). Хотя я не пробовал его для imagePoints или boardPoints (но, как указано в ссылке выше, вектор,вектор должны работать, я подумал, что лучше упомянуть об этом), но для rvec,trec, я попробовал это сам.
Я столкнулся с той же проблемой. В моем случае (в python) тип входного массива был преобразован как float.
После этого работало нормально.