29 #include <rtabmap/core/Version.h>
36 #include <opencv2/imgproc/imgproc.hpp>
41 localTransform_(opticalRotation())
47 const std::string & cameraName,
48 const cv::Size & imageSize,
55 imageSize_(imageSize),
60 localTransform_(localTransform)
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_.cols == 12 ||
D_.cols == 14) &&
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));
75 const cv::Size & imageSize) :
76 imageSize_(imageSize),
77 K_(
cv::
Mat::eye(3, 3, CV_64FC1)),
78 localTransform_(localTransform)
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,
119 const cv::Size & imageSize) :
121 imageSize_(imageSize),
122 K_(
cv::
Mat::eye(3, 3, CV_64FC1)),
123 localTransform_(localTransform)
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 ||
D_.cols == 12 ||
D_.cols == 14));
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);
184 cv::initUndistortRectifyMap(K_, D_, R_, P_, imageSize_, CV_32FC1, mapX_, mapY_);
186 return isRectificationMapInitialized();
189 void CameraModel::setImageSize(
const cv::Size & size)
195 if(ncx==0.0 && imageSize_.width > 0)
197 ncx = double(imageSize_.width)/2.0-0.5;
199 if(ncy==0.0 && imageSize_.height > 0)
201 ncy = double(imageSize_.height)/2.0-0.5;
205 P_.at<
double>(0,2) = ncx;
206 P_.at<
double>(1,2) = ncy;
210 K_.at<
double>(0,2) = ncx;
211 K_.at<
double>(1,2) = ncy;
215 bool CameraModel::load(
const std::string & filePath)
224 imageSize_ = cv::Size();
230 UINFO(
"Reading calibration file \"%s\"", filePath.c_str());
231 cv::FileStorage fs(filePath, cv::FileStorage::READ);
235 n = fs[
"camera_name"];
236 if(
n.type() != cv::FileNode::NONE)
242 UWARN(
"Missing \"camera_name\" field in \"%s\"", filePath.c_str());
245 n = fs[
"image_width"];
246 n2 = fs[
"image_height"];
247 if(
n.type() != cv::FileNode::NONE)
249 imageSize_.width = (
int)fs[
"image_width"];
250 imageSize_.height = (
int)fs[
"image_height"];
254 UWARN(
"Missing \"image_width\" and/or \"image_height\" fields in \"%s\"", filePath.c_str());
258 n = fs[
"camera_matrix"];
259 if(
n.type() != cv::FileNode::NONE)
263 std::vector<double>
data;
267 K_ = cv::Mat(
rows,
cols, CV_64FC1,
data.data()).clone();
271 UWARN(
"Missing \"camera_matrix\" field in \"%s\"", filePath.c_str());
274 n = fs[
"distortion_coefficients"];
275 if(
n.type() != cv::FileNode::NONE)
279 std::vector<double>
data;
283 D_ = cv::Mat(
rows,
cols, CV_64FC1,
data.data()).clone();
287 UWARN(
"Missing \"distorsion_coefficients\" field in \"%s\"", filePath.c_str());
290 n = fs[
"distortion_model"];
291 if(
n.type() != cv::FileNode::NONE)
293 std::string distortionModel = (std::string)
n;
298 cv::Mat
D = cv::Mat::zeros(1,6,CV_64FC1);
299 D.at<
double>(0,0) = D_.at<
double>(0,0);
300 D.at<
double>(0,1) = D_.at<
double>(0,1);
301 D.at<
double>(0,4) = D_.at<
double>(0,2);
302 D.at<
double>(0,5) = D_.at<
double>(0,3);
308 UWARN(
"Missing \"distortion_model\" field in \"%s\"", filePath.c_str());
311 n = fs[
"rectification_matrix"];
312 if(
n.type() != cv::FileNode::NONE)
316 std::vector<double>
data;
320 R_ = cv::Mat(
rows,
cols, CV_64FC1,
data.data()).clone();
324 UWARN(
"Missing \"rectification_matrix\" field in \"%s\"", filePath.c_str());
327 n = fs[
"projection_matrix"];
328 if(
n.type() != cv::FileNode::NONE)
332 std::vector<double>
data;
336 P_ = cv::Mat(
rows,
cols, CV_64FC1,
data.data()).clone();
340 UWARN(
"Missing \"projection_matrix\" field in \"%s\"", filePath.c_str());
343 n = fs[
"local_transform"];
344 if(
n.type() != cv::FileNode::NONE)
348 std::vector<float>
data;
359 UWARN(
"Missing \"local_transform\" field in \"%s\"", filePath.c_str());
364 if(isValidForRectification())
366 initRectificationMap();
371 catch(
const cv::Exception &
e)
373 UERROR(
"Error reading calibration file \"%s\": %s (Make sure the first line of the yaml file is \"%YAML:1.0\")", filePath.c_str(),
e.what());
378 UWARN(
"Could not load calibration file \"%s\".", filePath.c_str());
383 bool CameraModel::load(
const std::string & directory,
const std::string & cameraName)
385 return load(directory+
"/"+cameraName+
".yaml");
388 bool CameraModel::save(
const std::string & directory)
const
392 UWARN(
"Camera name is empty, will use general \"camera\" as name.");
394 std::string filePath = directory+
"/"+(
name_.empty()?
"camera":
name_)+
".yaml";
395 if(!filePath.empty() && (!K_.empty() || !D_.empty() || !R_.empty() || !P_.empty()))
397 UINFO(
"Saving calibration to file \"%s\"", filePath.c_str());
398 cv::FileStorage fs(filePath, cv::FileStorage::WRITE);
404 fs <<
"camera_name" <<
name_;
406 if(imageSize_.width>0 && imageSize_.height>0)
408 fs <<
"image_width" << imageSize_.width;
409 fs <<
"image_height" << imageSize_.height;
414 fs <<
"camera_matrix" <<
"{";
415 fs <<
"rows" << K_.rows;
416 fs <<
"cols" << K_.cols;
417 fs <<
"data" << std::vector<double>((
double*)K_.data, ((
double*)K_.data)+(K_.rows*K_.cols));
426 D = cv::Mat(1,4,CV_64FC1);
427 D.at<
double>(0,0) = D_.at<
double>(0,0);
428 D.at<
double>(0,1) = D_.at<
double>(0,1);
429 D.at<
double>(0,2) = D_.at<
double>(0,4);
430 D.at<
double>(0,3) = D_.at<
double>(0,5);
432 fs <<
"distortion_coefficients" <<
"{";
433 fs <<
"rows" <<
D.rows;
434 fs <<
"cols" <<
D.cols;
435 fs <<
"data" << std::vector<double>((
double*)
D.data, ((
double*)
D.data)+(
D.rows*
D.cols));
441 fs <<
"distortion_model" <<
"equidistant";
445 fs <<
"distortion_model" <<
"rational_polynomial";
449 fs <<
"distortion_model" <<
"plumb_bob";
455 fs <<
"rectification_matrix" <<
"{";
456 fs <<
"rows" << R_.rows;
457 fs <<
"cols" << R_.cols;
458 fs <<
"data" << std::vector<double>((
double*)R_.data, ((
double*)R_.data)+(R_.rows*R_.cols));
464 fs <<
"projection_matrix" <<
"{";
465 fs <<
"rows" << P_.rows;
466 fs <<
"cols" << P_.cols;
467 fs <<
"data" << std::vector<double>((
double*)P_.data, ((
double*)P_.data)+(P_.rows*P_.cols));
471 if(!localTransform_.isNull())
473 fs <<
"local_transform" <<
"{";
476 fs <<
"data" << std::vector<float>((
float*)localTransform_.data(), ((
float*)localTransform_.data())+12);
486 UERROR(
"Cannot save calibration to \"%s\" because it is empty.", filePath.c_str());
493 const int headerSize = 11;
494 int header[headerSize] = {
495 RTABMAP_VERSION_MAJOR, RTABMAP_VERSION_MINOR, RTABMAP_VERSION_PATCH,
497 imageSize_.width, imageSize_.height,
498 (
int)K_.total(), (
int)D_.total(), (
int)R_.total(), (
int)P_.total(),
499 localTransform_.isNull()?0:localTransform_.size()};
500 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]);
501 std::vector<unsigned char>
data(
502 sizeof(
int)*headerSize +
503 sizeof(
double)*(K_.total()+D_.total()+R_.total()+P_.total()) +
504 (localTransform_.isNull()?0:
sizeof(
float)*localTransform_.size()));
505 memcpy(
data.data(),
header,
sizeof(
int)*headerSize);
506 int index =
sizeof(
int)*headerSize;
509 memcpy(
data.data()+index, K_.data,
sizeof(
double)*(K_.total()));
510 index+=
sizeof(double)*(K_.total());
514 memcpy(
data.data()+index, D_.data,
sizeof(
double)*(D_.total()));
515 index+=
sizeof(double)*(D_.total());
519 memcpy(
data.data()+index, R_.data,
sizeof(
double)*(R_.total()));
520 index+=
sizeof(double)*(R_.total());
524 memcpy(
data.data()+index, P_.data,
sizeof(
double)*(P_.total()));
525 index+=
sizeof(double)*(P_.total());
527 if(!localTransform_.isNull())
529 memcpy(
data.data()+index, localTransform_.data(),
sizeof(
float)*(localTransform_.size()));
530 index+=
sizeof(
float)*(localTransform_.size());
543 if(dataSize >=
sizeof(
int)*headerSize)
550 imageSize_.width =
header[4];
551 imageSize_.height =
header[5];
557 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]);
558 unsigned int requiredDataSize =
sizeof(
int)*headerSize +
562 uFormat(
"dataSize=%d != required=%d (header: version %d.%d.%d %dx%d type=%d K=%d D=%d R=%d P=%d L=%d)",
567 unsigned int index =
sizeof(
int)*headerSize;
571 K_ = cv::Mat(3, 3, CV_64FC1, (
void*)(
data+index)).clone();
572 index+=
sizeof(double)*(K_.total());
576 D_ = cv::Mat(1,
header[iD], CV_64FC1, (
void*)(
data+index)).clone();
577 index+=
sizeof(double)*(D_.total());
582 R_ = cv::Mat(3, 3, CV_64FC1, (
void*)(
data+index)).clone();
583 index+=
sizeof(double)*(R_.total());
588 P_ = cv::Mat(3, 4, CV_64FC1, (
void*)(
data+index)).clone();
589 index+=
sizeof(double)*(P_.total());
594 memcpy(localTransform_.data(),
data+index,
sizeof(
float)*localTransform_.size());
595 index+=
sizeof(
float)*localTransform_.size();
602 UERROR(
"Serialized calibration is not mono (type=%d), use the appropriate class matching the type to deserialize.",
type);
605 UERROR(
"Wrong serialized calibration data format detected (size in bytes=%d)! Cannot deserialize the data.", (
int)dataSize);
613 if(this->isValidForProjection())
620 K.at<
double>(0,0) *=
scale;
621 K.at<
double>(1,1) *=
scale;
622 K.at<
double>(0,2) *=
scale;
623 K.at<
double>(1,2) *=
scale;
630 P.at<
double>(0,0) *=
scale;
631 P.at<
double>(1,1) *=
scale;
632 P.at<
double>(0,2) *=
scale;
633 P.at<
double>(1,2) *=
scale;
634 P.at<
double>(0,3) *=
scale;
635 P.at<
double>(1,3) *=
scale;
637 scaledModel =
CameraModel(
name_, cv::Size(
double(imageSize_.width)*
scale,
double(imageSize_.height)*
scale),
K, D_, R_,
P, localTransform_);
641 UWARN(
"Trying to scale a camera model not valid! Ignoring scaling...");
649 if(this->isValidForProjection())
656 K.at<
double>(0,2) -= roi.x;
657 K.at<
double>(1,2) -= roi.y;
664 P.at<
double>(0,2) -= roi.x;
665 P.at<
double>(1,2) -= roi.y;
671 UWARN(
"Trying to extract roi from a camera model not valid! Ignoring roi...");
676 double CameraModel::fovX()
const
678 return imageSize_.width>0 &&
fx()>0?2.0*
atan(imageSize_.width/(
fx()*2.0)):0.0;
680 double CameraModel::fovY()
const
682 return imageSize_.height>0 &&
fy()>0?2.0*
atan(imageSize_.height/(
fy()*2.0)):0.0;
685 double CameraModel::horizontalFOV()
const
687 return fovX()*180.0/CV_PI;
690 double CameraModel::verticalFOV()
const
692 return fovY()*180.0/CV_PI;
695 cv::Mat CameraModel::rectifyImage(
const cv::Mat & raw,
int interpolation)
const
698 if(!mapX_.empty() && !mapY_.empty())
701 cv::remap(raw, rectified, mapX_, mapY_, interpolation);
706 UERROR(
"Cannot rectify image because the rectify map is not initialized.");
712 cv::Mat CameraModel::rectifyDepth(
const cv::Mat & raw)
const
715 UASSERT(raw.type() == CV_16UC1);
716 if(!mapX_.empty() && !mapY_.empty())
718 cv::Mat rectified = cv::Mat::zeros(mapX_.rows, mapX_.cols, raw.type());
719 for(
int y=0;
y<mapX_.rows; ++
y)
721 for(
int x=0;
x<mapX_.cols; ++
x)
723 cv::Point2f pt(mapX_.at<
float>(
y,
x), mapY_.at<
float>(
y,
x));
728 if(xL >= 0 && yL >= 0 && xH < raw.cols && yH < raw.rows)
730 const unsigned short & pLT = raw.at<
unsigned short>(yL, xL);
731 const unsigned short & pRT = raw.at<
unsigned short>(yL, xH);
732 const unsigned short & pLB = raw.at<
unsigned short>(yH, xL);
733 const unsigned short & pRB = raw.at<
unsigned short>(yH, xH);
734 if(pLT > 0 && pRT > 0 && pLB > 0 && pRB > 0)
736 unsigned short avg = (pLT + pRT + pLB + pRB) / 4;
737 unsigned short thres = 0.01 * avg;
738 if(
abs(pLT - avg) < thres &&
739 abs(pRT - avg) < thres &&
740 abs(pLB - avg) < thres &&
741 abs(pRB - avg) < thres)
744 float a = pt.x - (
float)xL;
745 float c = pt.y - (
float)yL;
748 rectified.at<
unsigned short>(
y,
x) =
749 (pLT * (1.
f -
a) + pRT *
a) * (1.
f -
c) +
750 (pLB * (1.f -
a) + pRB *
a) *
c;
760 UERROR(
"Cannot rectify image because the rectify map is not initialized.");
771 x = (u -
cx()) * depth /
fx();
772 y = (
v -
cy()) * depth /
fy();
777 x =
y =
z = std::numeric_limits<float>::quiet_NaN();
781 void CameraModel::reproject(
float x,
float y,
float z,
float & u,
float & v)
const
785 u = (
fx()*
x)*invZ +
cx();
788 void CameraModel::reproject(
float x,
float y,
float z,
int & u,
int & v)
const
792 u = (
fx()*
x)*invZ +
cx();
796 bool CameraModel::inFrame(
int u,
int v)
const
803 os <<
"Name: " <<
model.name().c_str() << std::endl
804 <<
"Size: " <<
model.imageWidth() <<
"x" <<
model.imageHeight() << std::endl
805 <<
"K= " <<
model.K_raw() << std::endl
806 <<
"D= " <<
model.D_raw() << std::endl
807 <<
"R= " <<
model.R() << std::endl
808 <<
"P= " <<
model.P() << std::endl
809 <<
"LocalTransform= " <<
model.localTransform();