20 #include <mrpt/otherlibs/do_opencv_includes.h> 34 unsigned int check_size_y,
double check_squares_length_X_meters,
36 std::vector<double>& distortionParams,
bool normalize_image,
37 double* out_MSE,
bool skipDrawDetectedImgs,
38 bool useScaramuzzaAlternativeDetector)
43 images, check_size_x, check_size_y, check_squares_length_X_meters,
44 check_squares_length_Y_meters, cam, normalize_image, out_MSE,
45 skipDrawDetectedImgs, useScaramuzzaAlternativeDetector);
58 template <
typename _Tp,
int _rows,
int _cols,
int _options,
int _maxRows,
62 Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>&
dst)
64 CV_DbgAssert(
src.rows == _rows &&
src.cols == _cols);
65 if (!(
dst.Flags & Eigen::RowMajorBit))
69 (size_t)(
dst.stride() *
sizeof(_Tp)));
70 if (
src.type() == _dst.type())
72 else if (
src.cols ==
src.rows)
74 src.convertTo(_dst, _dst.type());
78 Mat(
src.t()).convertTo(_dst, _dst.type());
79 CV_DbgAssert(_dst.data == (uchar*)
dst.data());
85 (size_t)(
dst.stride() *
sizeof(_Tp)));
86 src.convertTo(_dst, _dst.type());
87 CV_DbgAssert(_dst.data == (uchar*)
dst.data());
98 unsigned int check_size_y,
double check_squares_length_X_meters,
99 double check_squares_length_Y_meters,
101 double* out_MSE,
bool skipDrawDetectedImgs,
102 bool useScaramuzzaAlternativeDetector)
110 ASSERT_(check_squares_length_X_meters > 0)
111 ASSERT_(check_squares_length_Y_meters > 0)
113 if (images.size() < 1)
115 std::cout <<
"ERROR: No input images." << std::endl;
119 const unsigned CORNERS_COUNT = check_size_x * check_size_y;
120 const CvSize check_size = cvSize(check_size_x, check_size_y);
124 vector<cv::Point3f> pattern_obj_points(CORNERS_COUNT);
127 for (
y = 0, k = 0;
y < check_size_y;
y++)
129 for (
unsigned int x = 0;
x < check_size_x;
x++, k++)
131 pattern_obj_points[k].x = -check_squares_length_X_meters *
135 pattern_obj_points[k].y = check_squares_length_Y_meters *
y;
136 pattern_obj_points[k].z = 0;
144 for (it = images.begin(); it != images.end(); ++it)
157 "Error reading image: %s", it->first.c_str());
166 vector<vector<cv::Point3f>>
168 vector<vector<cv::Point2f>>
171 unsigned int valid_detected_imgs = 0;
172 vector<string> pointsIdx2imageFile;
173 cv::Size imgSize(0, 0);
176 for (i = 0, it = images.begin(); it != images.end(); it++, i++)
187 out_camera_params.
ncols = imgSize.width;
188 out_camera_params.
nrows = imgSize.height;
192 if (imgSize.height != (
int)img_gray.
getHeight() ||
193 imgSize.width != (int)img_gray.
getWidth())
195 std::cout <<
"ERROR: All the images must have the same size" 203 unsigned corners_count;
204 bool corners_found =
false;
206 corners_count = CORNERS_COUNT;
208 vector<cv::Point2f> this_img_pts(
216 vector<TPixelCoordf> detectedCoords;
218 img_gray, detectedCoords, check_size_x, check_size_y,
220 useScaramuzzaAlternativeDetector);
222 corners_count = detectedCoords.size();
225 ASSERT_(detectedCoords.size() <= CORNERS_COUNT);
226 for (
size_t p = 0;
p < detectedCoords.size();
p++)
228 this_img_pts[
p].x = detectedCoords[
p].x;
229 this_img_pts[
p].y = detectedCoords[
p].y;
232 if (corners_found && corners_count != CORNERS_COUNT)
233 corners_found =
false;
238 corners_found ?
"DETECTED" :
"NOT DETECTED");
245 for (
y = 0, k = 0;
y < check_size.height;
y++)
246 for (
x = 0;
x < check_size.width;
x++, k++)
249 this_img_pts[k].x, this_img_pts[k].y));
256 CvPoint prev_pt = cvPoint(0, 0);
257 const int line_max = 8;
258 CvScalar line_colors[8];
260 line_colors[0] = CV_RGB(255, 0, 0);
261 line_colors[1] = CV_RGB(255, 128, 0);
262 line_colors[2] = CV_RGB(255, 128, 0);
263 line_colors[3] = CV_RGB(200, 200, 0);
264 line_colors[4] = CV_RGB(0, 255, 0);
265 line_colors[5] = CV_RGB(0, 200, 200);
266 line_colors[6] = CV_RGB(0, 0, 255);
267 line_colors[7] = CV_RGB(255, 0, 255);
274 for (
y = 0, k = 0;
y < check_size.height;
y++)
276 CvScalar
color = line_colors[
y % line_max];
277 for (
x = 0;
x < check_size.width;
x++, k++)
280 pt.x = cvRound(this_img_pts[k].
x);
281 pt.y = cvRound(this_img_pts[k].
y);
283 if (k != 0) cvLine(rgb_img, prev_pt, pt,
color);
286 rgb_img, cvPoint(pt.x -
r, pt.y -
r),
287 cvPoint(pt.x +
r, pt.y +
r),
color);
289 rgb_img, cvPoint(pt.x -
r, pt.y +
r),
290 cvPoint(pt.x +
r, pt.y -
r),
color);
291 cvCircle(rgb_img, pt,
r + 1,
color);
298 pointsIdx2imageFile.push_back(it->first);
299 imagePoints.push_back(this_img_pts);
300 objectPoints.push_back(pattern_obj_points);
302 valid_detected_imgs++;
307 std::cout << valid_detected_imgs <<
" valid images." << std::endl;
308 if (!valid_detected_imgs)
310 std::cout <<
"ERROR: No valid images. Perhaps the checkerboard " 320 cv::Mat cameraMatrix, distCoeffs(1, 5, CV_64F, cv::Scalar::all(0));
321 vector<cv::Mat> rvecs, tvecs;
323 const double cv_calib_err = cv::calibrateCamera(
324 objectPoints, imagePoints, imgSize, cameraMatrix, distCoeffs, rvecs,
331 out_camera_params.
dist.assign(0);
332 for (
int i = 0; i < 5; i++)
333 out_camera_params.
dist[i] = distCoeffs.ptr<
double>()[i];
336 for (i = 0; i < valid_detected_imgs; i++)
345 cv::Rodrigues(rvecs[i], cv_rot);
349 HM.block<3, 3>(0, 0) = rot;
353 Eigen::Matrix<double, 3, 1> trans;
355 HM.block<3, 1>(0, 3) = trans;
360 images[pointsIdx2imageFile[i]].reconstructed_camera_pose =
p;
364 <<
": " <<
p << std::endl;
376 for (it = images.begin(); it != images.end(); ++it)
389 for (i = 0; i < valid_detected_imgs; i++)
396 vector<TPoint3D> lstPatternPoints(
398 for (
unsigned int p = 0;
p < CORNERS_COUNT;
p++)
400 pattern_obj_points[
p].
x, pattern_obj_points[
p].
y,
401 pattern_obj_points[
p].
z);
403 vector<TPixelCoordf>& projectedPoints =
405 vector<TPixelCoordf>& projectedPoints_distorted =
420 projectedPoints_distorted
423 ASSERT_(projectedPoints.size() == CORNERS_COUNT);
424 ASSERT_(projectedPoints_distorted.size() == CORNERS_COUNT);
426 for (
unsigned int p = 0;
p < CORNERS_COUNT;
p++)
428 const double px = projectedPoints[
p].x;
429 const double py = projectedPoints[
p].y;
431 const double px_d = projectedPoints_distorted[
p].x;
432 const double py_d = projectedPoints_distorted[
p].y;
437 if (px >= 0 && px < imgSize.width && py >= 0 &&
441 cvPoint(px, py), 4, CV_RGB(0, 0, 255));
455 if (valid_detected_imgs)
457 sqrErr /= CORNERS_COUNT * valid_detected_imgs;
458 std::cout <<
"Average err. of reprojection: " << sqrt(sqrErr)
459 <<
" pixels (OpenCV error=" << cv_calib_err <<
")\n";
461 if (out_MSE) *out_MSE = sqrt(sqrErr);
465 catch (std::exception& e)
467 std::cout << e.what() << std::endl;
471 THROW_EXCEPTION(
"Function not available: MRPT was compiled without OpenCV")
A pair (x,y) of pixel coordinates (subpixel resolution).
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
mrpt::utils::CImage img_original
This image will be automatically loaded from the file name passed to checkerBoardCameraCalibration.
A class for storing images as grayscale or RGB bitmaps.
bool findChessboardCorners(const mrpt::utils::CImage &img, std::vector< mrpt::utils::TPixelCoordf > &cornerCoords, unsigned int check_size_x, unsigned int check_size_y, bool normalize_image=true, bool useScaramuzzaMethod=false)
Look for the corners of a chessboard in the image using one of two different methods.
#define THROW_EXCEPTION(msg)
void rectifyImage(CImage &out_img, const mrpt::utils::TCamera &cameraParams) const
Rectify (un-distort) the image according to some camera parameters, and returns an output un-distorte...
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
void projectPoints_with_distortion(const std::vector< mrpt::math::TPoint3D > &in_points_3D, const mrpt::poses::CPose3D &cameraPose, const mrpt::math::CMatrixDouble33 &intrinsicParams, const std::vector< double > &distortionParams, std::vector< mrpt::utils::TPixelCoordf > &projectedPoints, bool accept_points_behind=false)
Project a set of 3D points into a camera at an arbitrary 6D pose using its calibration matrix and dis...
std::vector< mrpt::utils::TPixelCoordf > detected_corners
At output, the detected corners (x,y) in pixel units.
CMatrixFixedNumeric< double, 3, 3 > CMatrixDouble33
bool loadFromFile(const std::string &fileName, int isColor=-1)
Load image from a file, whose format is determined from the extension (internally uses OpenCV)...
const T * getAs() const
Returns a pointer to a const T* containing the image - the idea is to call like "img.getAs<IplImage>()" so we can avoid here including OpenCV's headers.
T square(const T x)
Inline function for the square of a number.
std::vector< mrpt::utils::TPixelCoordf > projectedPoints_undistorted
At output, like projectedPoints_distorted but for the undistorted image.
This class implements a config file-like interface over a memory-stored string list.
void getContent(std::string &str) const
Return the current contents of the virtual "config file".
Data associated to each image in the calibration process mrpt::vision::checkerBoardCameraCalibration ...
This base provides a set of functions for maths stuff.
size_t getWidth() const override
Returns the width of the image in pixels.
mrpt::utils::CImage img_checkboard
At output, this will contain the detected checkerboard overprinted to the image.
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
bool checkerBoardCameraCalibration(TCalibrationImageList &images, unsigned int check_size_x, unsigned int check_size_y, double check_squares_length_X_meters, double check_squares_length_Y_meters, mrpt::utils::TCamera &out_camera_params, bool normalize_image=true, double *out_MSE=nullptr, bool skipDrawDetectedImgs=false, bool useScaramuzzaAlternativeDetector=false)
Performs a camera calibration (computation of projection and distortion parameters) from a sequence o...
std::vector< mrpt::utils::TPixelCoordf > projectedPoints_distorted
At output, only will have an empty vector if the checkerboard was not found in this image...
size_t getHeight() const override
Returns the height of the image in pixels.
uint32_t ncols
Camera resolution.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Classes for computer vision, detectors, features, etc.
void projectPoints_no_distortion(const std::vector< mrpt::math::TPoint3D > &in_points_3D, const mrpt::poses::CPose3D &cameraPose, const mrpt::math::CMatrixDouble33 &intrinsicParams, std::vector< mrpt::utils::TPixelCoordf > &projectedPoints, bool accept_points_behind=false)
Project a set of 3D points into a camera at an arbitrary 6D pose using its calibration matrix (undist...
std::string extractFileExtension(const std::string &filePath, bool ignore_gz=false)
Extract the extension of a filename.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
mrpt::math::CMatrixDouble33 intrinsicParams
Matrix of intrinsic parameters (containing the focal length and principal point coordinates) ...
std::vector< double > getDistortionParamsAsVector() const
Get a vector with the distortion params of the camera.
GLsizei GLboolean transpose
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
GLdouble GLdouble GLdouble r
mrpt::math::CArrayDouble< 5 > dist
[k1 k2 t1 t2 k3] -> k_i: parameters of radial distortion, t_i: parameters of tangential distortion (d...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
void my_cv2eigen(const Mat &src, Eigen::Matrix< _Tp, _rows, _cols, _options, _maxRows, _maxCols > &dst)
mrpt::utils::CImage img_rectified
At output, this will be the rectified image.
void colorImage(CImage &ret) const
Returns a RGB version of the grayscale image, or itself if it is already a RGB image.
bool isExternallyStored() const noexcept
See setExternalStorage().
std::string extractFileName(const std::string &filePath)
Extract just the name (without extension) of a filename from a complete path plus name plus extension...
std::map< std::string, TImageCalibData > TCalibrationImageList
A list of images, used in checkerBoardCameraCalibration.
mrpt::poses::CPose3D reconstructed_camera_pose
At output, the reconstructed pose of the camera.
GLuint GLuint GLsizei GLenum type
Structure to hold the parameters of a pinhole camera model.
void saveToConfigFile(const std::string §ion, mrpt::utils::CConfigFileBase &cfg) const
Save as a config block: