29 #include <rtabmap/core/Version.h> 36 #include <opencv2/imgproc/imgproc.hpp> 41 localTransform_(0,0,1,0, -1,0,0,0, 0,-1,0,0)
47 const std::string & cameraName,
62 UASSERT(
K_.empty() || (
K_.rows == 3 &&
K_.cols == 3 &&
K_.type() == CV_64FC1));
63 UASSERT(
D_.empty() || (
D_.rows == 1 && (
D_.cols == 4 ||
D_.cols == 5 ||
D_.cols == 6 ||
D_.cols == 8) &&
D_.type() == CV_64FC1));
64 UASSERT(
R_.empty() || (
R_.rows == 3 &&
R_.cols == 3 &&
R_.type() == CV_64FC1));
65 UASSERT(
P_.empty() || (
P_.rows == 3 &&
P_.cols == 4 &&
P_.type() == CV_64FC1));
77 K_(
cv::Mat::eye(3, 3, CV_64FC1)),
82 UASSERT_MSG(cx >= 0.0 && imageSize.width>=0,
uFormat(
"cx=%f imageSize.width=%d", cx, imageSize.width).c_str());
83 UASSERT_MSG(cy >= 0.0 && imageSize.height>=0,
uFormat(
"cy=%f imageSize.height=%d", cy, imageSize.height).c_str());
86 if(cx==0.0 && imageSize.width > 0)
88 cx = double(imageSize.width)/2.0-0.5;
90 if(cy==0.0 && imageSize.height > 0)
92 cy = double(imageSize.height)/2.0-0.5;
97 P_ = cv::Mat::eye(3, 4, CV_64FC1),
98 P_.at<
double>(0,0) = fx;
99 P_.at<
double>(1,1) = fy;
100 P_.at<
double>(0,2) = cx;
101 P_.at<
double>(1,2) = cy;
102 P_.at<
double>(0,3) = Tx;
105 K_.at<
double>(0,0) = fx;
106 K_.at<
double>(1,1) = fy;
107 K_.at<
double>(0,2) = cx;
108 K_.at<
double>(1,2) = cy;
112 const std::string &
name,
122 K_(
cv::Mat::eye(3, 3, CV_64FC1)),
127 UASSERT_MSG(cx >= 0.0 && imageSize.width>=0,
uFormat(
"cx=%f imageSize.width=%d", cx, imageSize.width).c_str());
128 UASSERT_MSG(cy >= 0.0 && imageSize.height>=0,
uFormat(
"cy=%f imageSize.height=%d", cy, imageSize.height).c_str());
131 if(cx==0.0 && imageSize.width > 0)
133 cx = double(imageSize.width)/2.0-0.5;
135 if(cy==0.0 && imageSize.height > 0)
137 cy = double(imageSize.height)/2.0-0.5;
142 P_ = cv::Mat::eye(3, 4, CV_64FC1),
143 P_.at<
double>(0,0) = fx;
144 P_.at<
double>(1,1) = fy;
145 P_.at<
double>(0,2) = cx;
146 P_.at<
double>(1,2) = cy;
147 P_.at<
double>(0,3) = Tx;
150 K_.at<
double>(0,0) = fx;
151 K_.at<
double>(1,1) = fy;
152 K_.at<
double>(0,2) = cx;
153 K_.at<
double>(1,2) = cy;
159 UASSERT(
D_.rows == 1 && (
D_.cols == 4 ||
D_.cols == 5 ||
D_.cols == 6 ||
D_.cols == 8));
163 UINFO(
"Initialize rectify map");
166 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10))) 169 cv::Mat
D(1, 4, CV_64FC1);
170 D.at<
double>(0,0) =
D_.at<
double>(0,0);
171 D.at<
double>(0,1) =
D_.at<
double>(0,1);
172 D.at<
double>(0,2) =
D_.at<
double>(0,4);
173 D.at<
double>(0,3) =
D_.at<
double>(0,5);
178 UWARN(
"Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
179 CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
190 UASSERT((size.height > 0 && size.width > 0) || (size.height == 0 && size.width == 0));
204 P_.at<
double>(0,2) = ncx;
205 P_.at<
double>(1,2) = ncy;
209 K_.at<
double>(0,2) = ncx;
210 K_.at<
double>(1,2) = ncy;
229 UINFO(
"Reading calibration file \"%s\"", filePath.c_str());
230 cv::FileStorage fs(filePath, cv::FileStorage::READ);
234 n = fs[
"camera_name"];
235 if(n.type() != cv::FileNode::NONE)
241 UWARN(
"Missing \"camera_name\" field in \"%s\"", filePath.c_str());
244 n = fs[
"image_width"];
245 n2 = fs[
"image_height"];
246 if(n.type() != cv::FileNode::NONE)
253 UWARN(
"Missing \"image_width\" and/or \"image_height\" fields in \"%s\"", filePath.c_str());
257 n = fs[
"camera_matrix"];
258 if(n.type() != cv::FileNode::NONE)
260 int rows = (int)n[
"rows"];
261 int cols = (int)n[
"cols"];
262 std::vector<double> data;
264 UASSERT(rows*cols == (
int)data.size());
265 UASSERT(rows == 3 && cols == 3);
266 K_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
270 UWARN(
"Missing \"camera_matrix\" field in \"%s\"", filePath.c_str());
273 n = fs[
"distortion_coefficients"];
274 if(n.type() != cv::FileNode::NONE)
276 int rows = (int)n[
"rows"];
277 int cols = (int)n[
"cols"];
278 std::vector<double> data;
280 UASSERT(rows*cols == (
int)data.size());
281 UASSERT(rows == 1 && (cols == 4 || cols == 5 || cols == 8));
282 D_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
286 UWARN(
"Missing \"distorsion_coefficients\" field in \"%s\"", filePath.c_str());
289 n = fs[
"distortion_model"];
290 if(n.type() != cv::FileNode::NONE)
292 std::string distortionModel = (std::string)n;
297 cv::Mat
D = cv::Mat::zeros(1,6,CV_64FC1);
298 D.at<
double>(0,0) =
D_.at<
double>(0,0);
299 D.at<
double>(0,1) =
D_.at<
double>(0,1);
300 D.at<
double>(0,4) =
D_.at<
double>(0,2);
301 D.at<
double>(0,5) =
D_.at<
double>(0,3);
307 UWARN(
"Missing \"distortion_model\" field in \"%s\"", filePath.c_str());
310 n = fs[
"rectification_matrix"];
311 if(n.type() != cv::FileNode::NONE)
313 int rows = (int)n[
"rows"];
314 int cols = (int)n[
"cols"];
315 std::vector<double> data;
317 UASSERT(rows*cols == (
int)data.size());
318 UASSERT(rows == 3 && cols == 3);
319 R_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
323 UWARN(
"Missing \"rectification_matrix\" field in \"%s\"", filePath.c_str());
326 n = fs[
"projection_matrix"];
327 if(n.type() != cv::FileNode::NONE)
329 int rows = (int)n[
"rows"];
330 int cols = (int)n[
"cols"];
331 std::vector<double> data;
333 UASSERT(rows*cols == (
int)data.size());
334 UASSERT(rows == 3 && cols == 4);
335 P_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
339 UWARN(
"Missing \"projection_matrix\" field in \"%s\"", filePath.c_str());
351 catch(
const cv::Exception &
e)
353 UERROR(
"Error reading calibration file \"%s\": %s", filePath.c_str(), e.what());
358 UWARN(
"Could not load calibration file \"%s\".", filePath.c_str());
365 return load(directory+
"/"+cameraName+
".yaml");
370 std::string filePath = directory+
"/"+
name_+
".yaml";
371 if(!filePath.empty() && (!
K_.empty() || !
D_.empty() || !
R_.empty() || !
P_.empty()))
373 UINFO(
"Saving calibration to file \"%s\"", filePath.c_str());
374 cv::FileStorage fs(filePath, cv::FileStorage::WRITE);
380 fs <<
"camera_name" <<
name_;
390 fs <<
"camera_matrix" <<
"{";
391 fs <<
"rows" <<
K_.rows;
392 fs <<
"cols" <<
K_.cols;
393 fs <<
"data" << std::vector<double>((
double*)
K_.data, ((
double*)
K_.data)+(
K_.rows*
K_.cols));
402 D = cv::Mat(1,4,CV_64FC1);
403 D.at<
double>(0,0) =
D_.at<
double>(0,0);
404 D.at<
double>(0,1) =
D_.at<
double>(0,1);
405 D.at<
double>(0,2) =
D_.at<
double>(0,4);
406 D.at<
double>(0,3) =
D_.at<
double>(0,5);
408 fs <<
"distortion_coefficients" <<
"{";
409 fs <<
"rows" << D.rows;
410 fs <<
"cols" << D.cols;
411 fs <<
"data" << std::vector<double>((
double*)D.data, ((
double*)D.data)+(D.rows*D.cols));
417 fs <<
"distortion_model" <<
"equidistant";
421 fs <<
"distortion_model" <<
"rational_polynomial";
425 fs <<
"distortion_model" <<
"plumb_bob";
431 fs <<
"rectification_matrix" <<
"{";
432 fs <<
"rows" <<
R_.rows;
433 fs <<
"cols" <<
R_.cols;
434 fs <<
"data" << std::vector<double>((
double*)
R_.data, ((
double*)
R_.data)+(
R_.rows*
R_.cols));
440 fs <<
"projection_matrix" <<
"{";
441 fs <<
"rows" <<
P_.rows;
442 fs <<
"cols" <<
P_.cols;
443 fs <<
"data" << std::vector<double>((
double*)
P_.data, ((
double*)
P_.data)+(
P_.rows*
P_.cols));
453 UERROR(
"Cannot save calibration to \"%s\" because it is empty.", filePath.c_str());
460 const int headerSize = 11;
461 int header[headerSize] = {
462 RTABMAP_VERSION_MAJOR, RTABMAP_VERSION_MINOR, RTABMAP_VERSION_PATCH,
465 (int)
K_.total(), (int)
D_.total(), (int)
R_.total(), (int)
P_.total(),
467 UDEBUG(
"Header: %d %d %d %d %d %d %d %d %d %d %d", header[0],header[1],header[2],header[3],header[4],header[5],header[6],header[7],header[8],header[9],header[10]);
468 std::vector<unsigned char> data(
469 sizeof(
int)*headerSize +
470 sizeof(
double)*(
K_.total()+
D_.total()+
R_.total()+
P_.total()) +
472 memcpy(data.data(), header,
sizeof(int)*headerSize);
473 int index =
sizeof(int)*headerSize;
476 memcpy(data.data()+index,
K_.data,
sizeof(double)*(
K_.total()));
477 index+=
sizeof(double)*(
K_.total());
481 memcpy(data.data()+index,
D_.data,
sizeof(double)*(
D_.total()));
482 index+=
sizeof(double)*(
D_.total());
486 memcpy(data.data()+index,
R_.data,
sizeof(double)*(
R_.total()));
487 index+=
sizeof(double)*(
R_.total());
491 memcpy(data.data()+index,
P_.data,
sizeof(double)*(
P_.total()));
492 index+=
sizeof(double)*(
P_.total());
510 if(dataSize >=
sizeof(
int)*headerSize)
513 const int *
header = (
const int *)data;
514 int type = header[3];
524 UDEBUG(
"Header: %d %d %d %d %d %d %d %d %d %d %d", header[0],header[1],header[2],header[3],header[4],header[5],header[6],header[7],header[8],header[9],header[10]);
525 unsigned int requiredDataSize =
sizeof(int)*headerSize +
526 sizeof(
double)*(header[iK]+header[iD]+header[iR]+header[iP]) +
527 sizeof(
float)*header[iL];
529 uFormat(
"dataSize=%d != required=%d (header: version %d.%d.%d %dx%d type=%d K=%d D=%d R=%d P=%d L=%d)",
532 header[0], header[1], header[2], header[4], header[5], header[3],
533 header[iK], header[iD], header[iR],header[iP], header[iL]).c_str());
534 unsigned int index =
sizeof(int)*headerSize;
538 K_ = cv::Mat(3, 3, CV_64FC1, (
void*)(data+index)).clone();
539 index+=
sizeof(double)*(
K_.total());
543 D_ = cv::Mat(1, header[iD], CV_64FC1, (
void*)(data+index)).clone();
544 index+=
sizeof(double)*(
D_.total());
549 R_ = cv::Mat(3, 3, CV_64FC1, (
void*)(data+index)).clone();
550 index+=
sizeof(double)*(
R_.total());
555 P_ = cv::Mat(3, 4, CV_64FC1, (
void*)(data+index)).clone();
556 index+=
sizeof(double)*(
P_.total());
569 UERROR(
"Serialized calibration is not mono (type=%d), use the appropriate class matching the type to deserialize.", type);
572 UERROR(
"Wrong serialized calibration data format detected (size in bytes=%d)! Cannot deserialize the data.", (
int)dataSize);
587 K.at<
double>(0,0) *= scale;
588 K.at<
double>(1,1) *= scale;
589 K.at<
double>(0,2) *= scale;
590 K.at<
double>(1,2) *= scale;
597 P.at<
double>(0,0) *= scale;
598 P.at<
double>(1,1) *= scale;
599 P.at<
double>(0,2) *= scale;
600 P.at<
double>(1,2) *= scale;
601 P.at<
double>(0,3) *= scale;
602 P.at<
double>(1,3) *= scale;
608 UWARN(
"Trying to scale a camera model not valid! Ignoring scaling...");
623 K.at<
double>(0,2) -= roi.x;
624 K.at<
double>(1,2) -= roi.y;
631 P.at<
double>(0,2) -= roi.x;
632 P.at<
double>(1,2) -= roi.y;
638 UWARN(
"Trying to extract roi from a camera model not valid! Ignoring roi...");
654 return fovX()*180.0/CV_PI;
659 return fovY()*180.0/CV_PI;
668 cv::remap(raw, rectified,
mapX_,
mapY_, interpolation);
673 UERROR(
"Cannot rectify image because the rectify map is not initialized.");
682 UASSERT(raw.type() == CV_16UC1);
685 cv::Mat rectified = cv::Mat::zeros(
mapX_.rows,
mapX_.cols, raw.type());
686 for(
int y=0; y<
mapX_.rows; ++y)
688 for(
int x=0; x<
mapX_.cols; ++x)
690 cv::Point2f pt(
mapX_.at<
float>(y,x),
mapY_.at<
float>(y,x));
691 int xL = (int)
floor(pt.x);
692 int xH = (int)
ceil(pt.x);
693 int yL = (int)
floor(pt.y);
694 int yH = (int)
ceil(pt.y);
695 if(xL >= 0 && yL >= 0 && xH < raw.cols && yH < raw.rows)
697 const unsigned short & pLT = raw.at<
unsigned short>(yL, xL);
698 const unsigned short & pRT = raw.at<
unsigned short>(yL, xH);
699 const unsigned short & pLB = raw.at<
unsigned short>(yH, xL);
700 const unsigned short & pRB = raw.at<
unsigned short>(yH, xH);
701 if(pLT > 0 && pRT > 0 && pLB > 0 && pRB > 0)
703 unsigned short avg = (pLT + pRT + pLB + pRB) / 4;
704 unsigned short thres = 0.01 * avg;
705 if(
abs(pLT - avg) < thres &&
706 abs(pRT - avg) < thres &&
707 abs(pLB - avg) < thres &&
708 abs(pRB - avg) < thres)
711 float a = pt.x - (float)xL;
712 float c = pt.y - (float)yL;
715 rectified.at<
unsigned short>(y,x) =
716 (pLT * (1.
f - a) + pRT * a) * (1.
f - c) +
717 (pLB * (1.f - a) + pRB * a) * c;
727 UERROR(
"Cannot rectify image because the rectify map is not initialized.");
738 x = (u -
cx()) * depth /
fx();
739 y = (v -
cy()) * depth /
fy();
744 x = y = z = std::numeric_limits<float>::quiet_NaN();
752 u = (
fx()*x)*invZ +
cx();
753 v = (
fy()*y)*invZ +
cy();
759 u = (
fx()*x)*invZ +
cx();
760 v = (
fy()*y)*invZ +
cy();
770 os <<
"Name: " << model.
name() << std::endl
772 <<
"K= " << model.
K_raw() << std::endl
773 <<
"D= " << model.
D_raw() << std::endl
774 <<
"R= " << model.
R() << std::endl
775 <<
"P= " << model.
P() << std::endl
void setImageSize(const cv::Size &size)
const cv::Size & imageSize() const
const std::string & name() const
bool uIsInBounds(const T &value, const T &low, const T &high)
bool inFrame(int u, int v) const
Transform localTransform_
std::vector< unsigned char > serialize() const
bool save(const std::string &directory) const
GLM_FUNC_DECL genType e()
double verticalFOV() const
Basic mathematics functions.
bool load(const std::string &filePath)
std_msgs::Header * header(M &m)
Some conversion functions.
bool uStrContains(const std::string &string, const std::string &substring)
#define UASSERT(condition)
double horizontalFOV() const
Wrappers of STL for convenient functions.
void initRectificationMap()
GLM_FUNC_DECL genType floor(genType const &x)
#define UASSERT_MSG(condition, msg_str)
void reproject(float x, float y, float z, float &u, float &v) const
GLM_FUNC_DECL genType atan(genType const &y, genType const &x)
GLM_FUNC_DECL genType abs(genType const &x)
bool isValidForRectification() const
CameraModel roi(const cv::Rect &roi) const
void project(float u, float v, float depth, float &x, float &y, float &z) const
cv::Mat rectifyImage(const cv::Mat &raw, int interpolation=cv::INTER_LINEAR) const
bool isValidForProjection() const
cv::Mat rectifyDepth(const cv::Mat &raw) const
RTABMAP_EXP std::ostream & operator<<(std::ostream &os, const CameraModel &model)
ULogger class and convenient macros.
unsigned int deserialize(const std::vector< unsigned char > &data)
std::string UTILITE_EXP uFormat(const char *fmt,...)
GLM_FUNC_DECL genType ceil(genType const &x)
CameraModel scaled(double scale) const
const Transform & localTransform() const