Я преследовал эту ошибку всю ночь, так что, пожалуйста, прости меня за любую непоследовательность.
Я пытаюсь использовать OpenCV calibrateCamera()
извлекать внутренние и внешние параметры из набора пятнадцати изображений, чьи точки объекта и точки мира даны. Из того, что я могу сказать из отладки, я беру действительные точки из входных файлов и помещаю их в vector<Point3f>
, который сам помещен в другой vector
,
Я передаю весь Шебанг calibrateCamera()
,
double rms = calibrateCamera(worldPoints, pixelPoints, src.size(), intrinsic, distCoeffs, rvecs, tvecs);
который бросает Assertion failed (ni >= 0) in unknown function, file ...\calibration.cpp, line 3173
Подтягивание этого файла дает нам
static void collectCalibrationData( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints1,
InputArrayOfArrays imagePoints2,
Mat& objPtMat, Mat& imgPtMat1, Mat* imgPtMat2,
Mat& npoints )
{
int nimages = (int)objectPoints.total();
int i, j = 0, ni = 0, total = 0;
CV_Assert(nimages > 0 && nimages == (int)imagePoints1.total() &&
(!imgPtMat2 || nimages == (int)imagePoints2.total()));
for( i = 0; i < nimages; i++ )
{
ni = objectPoints.getMat(i).checkVector(3, CV_32F);
CV_Assert( ni >= 0 );
total += ni;
}
...
Насколько я знаю, Point3f
имеет CV_32F
глубины, и я вижу хорошие данные в двойном векторе перед вызовом calibrateCamera.
Есть идеи, что здесь может происходить? calibrateCamera()
требует vector<vector<Point3f>>
как сказано http://aishack.in/tutorials/calibrating-undistorting-with-opencv-in-c-oh-yeah/ и документация; надеюсь, getMat (i) не выходит из строя из-за этого.
Возможно, это было вызвано на vector<vector<Point2f>>
пикселей после него? Я преодолел так много ошибок, что готов поверить во что угодно.
Редактировать:
Как следствие, checkVector()
документация была не очень полезна
int cv::Mat::checkVector (int elemChannels, int depth = -1, bool RequireContinuous = true) const
returns N if the matrix is 1-channel (N x ptdim) or ptdim-channel (1 x N) or (N x 1); negative number otherwise
Возможно, проблема в одном из ваших аргументов InputArrayOfArrays (точно в worldPoints, если утверждение выбрасывается из строки, вставленной в ваш вопрос). Mat: s должен работать очень хорошо здесь.
Я решил ту же ошибку утверждения в своем коде, сделав все 3 вектора InputArrayOfArrays (или vector> и vector> в одной строке) одинаковыми по длине с полностью заполненными записями. Так что моя проблема была в моей архитектуре: мой вектор objectPoints содержал пустые записи (даже если существующие данные были действительны), а calibrate.cpp требует, чтобы ни в одном из 3 InputArrayOfArrays не было пустых записей. Кстати, я использую изображения в градациях серого для калибровки, поэтому данные одного канала.
В источнике calib3d наиболее вероятной причиной возникновения ошибки является нулевое значение, если вы проверили соответствие типов данных. Вы можете попробовать дважды проверить ваши действительные входные данные:
1) подсчитать количество действительных калибровочных изображений из выбранной вами структуры
validCalibImages = (int)goodCalibrationImages.size()
2) определить worldPoints как vector<vector<Point3f> > worldPoints
3) ВАЖНО: изменить размер для размещения данных для каждой записи калибровки
worldPoints.resize(validCalibImages)
4) заполнить данными, например,
for(int k = 0; k < (int)goodCalibImages.size(); k++){
for(int i = 0; i < chessboardSize.height; i++){
for(int j = 0; j < chessboardSize.width; j++){
objectPoints[k].push_back(Point3f(i*squareSize, j*squareSize, 0));
}
}
}
‘
Надеюсь, поможет!
Я согласен с FSaccilotto — вызовите checkVector и убедитесь, что вы передаете вектор размером n из Mat 1x1:{3 channel}
а не вектор Mat 1 x n:{3 channel}
или хуже Mat 1 x n:{2 channel}
это то, что выплевывает MatOfPoint. Обычно это устраняет 90% проблем, связанных с ошибками. Явно объявить коврик самостоятельно.
Паттерн объекта несколько странный в том смысле, что координаты x y z находятся в каналах, а не в размерах Mat.