CameraModel.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
29 #include <rtabmap/core/Version.h>
32 #include <rtabmap/utilite/UFile.h>
34 #include <rtabmap/utilite/UMath.h>
35 #include <rtabmap/utilite/UStl.h>
36 #include <opencv2/imgproc/imgproc.hpp>
37 
38 namespace rtabmap {
39 
41  localTransform_(opticalRotation())
42 {
43 
44 }
45 
47  const std::string & cameraName,
48  const cv::Size & imageSize,
49  const cv::Mat & K,
50  const cv::Mat & D,
51  const cv::Mat & R,
52  const cv::Mat & P,
53  const Transform & localTransform) :
54  name_(cameraName),
55  imageSize_(imageSize),
56  K_(K),
57  D_(D),
58  R_(R),
59  P_(P),
60  localTransform_(localTransform)
61 {
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));
66 }
67 
69  double fx,
70  double fy,
71  double cx,
72  double cy,
73  const Transform & localTransform,
74  double Tx,
75  const cv::Size & imageSize) :
76  imageSize_(imageSize),
77  K_(cv::Mat::eye(3, 3, CV_64FC1)),
78  localTransform_(localTransform)
79 {
80  UASSERT_MSG(fx > 0.0, uFormat("fx=%f", fx).c_str());
81  UASSERT_MSG(fy > 0.0, uFormat("fy=%f", fy).c_str());
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());
84  UASSERT(!localTransform.isNull());
85 
86  if(cx==0.0 && imageSize.width > 0)
87  {
88  cx = double(imageSize.width)/2.0-0.5;
89  }
90  if(cy==0.0 && imageSize.height > 0)
91  {
92  cy = double(imageSize.height)/2.0-0.5;
93  }
94 
95  if(Tx != 0.0)
96  {
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;
103  }
104 
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;
109 }
110 
112  const std::string & name,
113  double fx,
114  double fy,
115  double cx,
116  double cy,
117  const Transform & localTransform,
118  double Tx,
119  const cv::Size & imageSize) :
120  name_(name),
121  imageSize_(imageSize),
122  K_(cv::Mat::eye(3, 3, CV_64FC1)),
123  localTransform_(localTransform)
124 {
125  UASSERT_MSG(fx > 0.0, uFormat("fx=%f", fx).c_str());
126  UASSERT_MSG(fy > 0.0, uFormat("fy=%f", fy).c_str());
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());
129  UASSERT(!localTransform.isNull());
130 
131  if(cx==0.0 && imageSize.width > 0)
132  {
133  cx = double(imageSize.width)/2.0-0.5;
134  }
135  if(cy==0.0 && imageSize.height > 0)
136  {
137  cy = double(imageSize.height)/2.0-0.5;
138  }
139 
140  if(Tx != 0.0)
141  {
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;
148  }
149 
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;
154 }
155 
157 {
158  UASSERT(imageSize_.height > 0 && imageSize_.width > 0);
159  UASSERT(D_.rows == 1 && (D_.cols == 4 || D_.cols == 5 || D_.cols == 6 || D_.cols == 8));
160  UASSERT(R_.rows == 3 && R_.cols == 3);
161  UASSERT(P_.rows == 3 && P_.cols == 4);
162  // init rectification map
163  UINFO("Initialize rectify map");
164  if(D_.cols == 6)
165  {
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)))
167  // Equidistant / FishEye
168  // get only k parameters (k1,k2,p1,p2,k3,k4)
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);
174  cv::fisheye::initUndistortRectifyMap(K_, D, R_, P_, imageSize_, CV_32FC1, mapX_, mapY_);
175  }
176  else
177 #else
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);
180  }
181 #endif
182  {
183  // RadialTangential
184  cv::initUndistortRectifyMap(K_, D_, R_, P_, imageSize_, CV_32FC1, mapX_, mapY_);
185  }
187 }
188 
189 void CameraModel::setImageSize(const cv::Size & size)
190 {
191  UASSERT((size.height > 0 && size.width > 0) || (size.height == 0 && size.width == 0));
192  imageSize_ = size;
193  double ncx = cx();
194  double ncy = cy();
195  if(ncx==0.0 && imageSize_.width > 0)
196  {
197  ncx = double(imageSize_.width)/2.0-0.5;
198  }
199  if(ncy==0.0 && imageSize_.height > 0)
200  {
201  ncy = double(imageSize_.height)/2.0-0.5;
202  }
203  if(!P_.empty())
204  {
205  P_.at<double>(0,2) = ncx;
206  P_.at<double>(1,2) = ncy;
207  }
208  if(!K_.empty())
209  {
210  K_.at<double>(0,2) = ncx;
211  K_.at<double>(1,2) = ncy;
212  }
213 }
214 
215 bool CameraModel::load(const std::string & filePath)
216 {
217  K_ = cv::Mat();
218  D_ = cv::Mat();
219  R_ = cv::Mat();
220  P_ = cv::Mat();
221  mapX_ = cv::Mat();
222  mapY_ = cv::Mat();
223  name_.clear();
224  imageSize_ = cv::Size();
225 
226  if(UFile::exists(filePath))
227  {
228  try
229  {
230  UINFO("Reading calibration file \"%s\"", filePath.c_str());
231  cv::FileStorage fs(filePath, cv::FileStorage::READ);
232 
233  cv::FileNode n,n2;
234 
235  n = fs["camera_name"];
236  if(n.type() != cv::FileNode::NONE)
237  {
238  name_ = (std::string)n;
239  }
240  else
241  {
242  UWARN("Missing \"camera_name\" field in \"%s\"", filePath.c_str());
243  }
244 
245  n = fs["image_width"];
246  n2 = fs["image_height"];
247  if(n.type() != cv::FileNode::NONE)
248  {
249  imageSize_.width = (int)fs["image_width"];
250  imageSize_.height = (int)fs["image_height"];
251  }
252  else
253  {
254  UWARN("Missing \"image_width\" and/or \"image_height\" fields in \"%s\"", filePath.c_str());
255  }
256 
257  // import from ROS calibration format
258  n = fs["camera_matrix"];
259  if(n.type() != cv::FileNode::NONE)
260  {
261  int rows = (int)n["rows"];
262  int cols = (int)n["cols"];
263  std::vector<double> data;
264  n["data"] >> data;
265  UASSERT(rows*cols == (int)data.size());
266  UASSERT(rows == 3 && cols == 3);
267  K_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
268  }
269  else
270  {
271  UWARN("Missing \"camera_matrix\" field in \"%s\"", filePath.c_str());
272  }
273 
274  n = fs["distortion_coefficients"];
275  if(n.type() != cv::FileNode::NONE)
276  {
277  int rows = (int)n["rows"];
278  int cols = (int)n["cols"];
279  std::vector<double> data;
280  n["data"] >> data;
281  UASSERT(rows*cols == (int)data.size());
282  UASSERT(rows == 1 && (cols == 4 || cols == 5 || cols == 8));
283  D_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
284  }
285  else
286  {
287  UWARN("Missing \"distorsion_coefficients\" field in \"%s\"", filePath.c_str());
288  }
289 
290  n = fs["distortion_model"];
291  if(n.type() != cv::FileNode::NONE)
292  {
293  std::string distortionModel = (std::string)n;
294  if(D_.cols>=4 &&
295  (uStrContains(distortionModel, "fisheye") ||
296  uStrContains(distortionModel, "equidistant")))
297  {
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);
303  D_ = D;
304  }
305  }
306  else
307  {
308  UWARN("Missing \"distortion_model\" field in \"%s\"", filePath.c_str());
309  }
310 
311  n = fs["rectification_matrix"];
312  if(n.type() != cv::FileNode::NONE)
313  {
314  int rows = (int)n["rows"];
315  int cols = (int)n["cols"];
316  std::vector<double> data;
317  n["data"] >> data;
318  UASSERT(rows*cols == (int)data.size());
319  UASSERT(rows == 3 && cols == 3);
320  R_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
321  }
322  else
323  {
324  UWARN("Missing \"rectification_matrix\" field in \"%s\"", filePath.c_str());
325  }
326 
327  n = fs["projection_matrix"];
328  if(n.type() != cv::FileNode::NONE)
329  {
330  int rows = (int)n["rows"];
331  int cols = (int)n["cols"];
332  std::vector<double> data;
333  n["data"] >> data;
334  UASSERT(rows*cols == (int)data.size());
335  UASSERT(rows == 3 && cols == 4);
336  P_ = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
337  }
338  else
339  {
340  UWARN("Missing \"projection_matrix\" field in \"%s\"", filePath.c_str());
341  }
342 
343  n = fs["local_transform"];
344  if(n.type() != cv::FileNode::NONE)
345  {
346  int rows = (int)n["rows"];
347  int cols = (int)n["cols"];
348  std::vector<float> data;
349  n["data"] >> data;
350  UASSERT(rows*cols == (int)data.size());
351  UASSERT(rows == 3 && cols == 4);
353  data[0], data[1], data[2], data[3],
354  data[4], data[5], data[6], data[7],
355  data[8], data[9], data[10], data[11]);
356  }
357  else
358  {
359  UWARN("Missing \"local_transform\" field in \"%s\"", filePath.c_str());
360  }
361 
362  fs.release();
363 
365  {
367  }
368 
369  return true;
370  }
371  catch(const cv::Exception & e)
372  {
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());
374  }
375  }
376  else
377  {
378  UWARN("Could not load calibration file \"%s\".", filePath.c_str());
379  }
380  return false;
381 }
382 
383 bool CameraModel::load(const std::string & directory, const std::string & cameraName)
384 {
385  return load(directory+"/"+cameraName+".yaml");
386 }
387 
388 bool CameraModel::save(const std::string & directory) const
389 {
390  if(name_.empty())
391  {
392  UWARN("Camera name is empty, will use general \"camera\" as name.");
393  }
394  std::string filePath = directory+"/"+(name_.empty()?"camera":name_)+".yaml";
395  if(!filePath.empty() && (!K_.empty() || !D_.empty() || !R_.empty() || !P_.empty()))
396  {
397  UINFO("Saving calibration to file \"%s\"", filePath.c_str());
398  cv::FileStorage fs(filePath, cv::FileStorage::WRITE);
399 
400  // export in ROS calibration format
401 
402  if(!name_.empty())
403  {
404  fs << "camera_name" << name_;
405  }
406  if(imageSize_.width>0 && imageSize_.height>0)
407  {
408  fs << "image_width" << imageSize_.width;
409  fs << "image_height" << imageSize_.height;
410  }
411 
412  if(!K_.empty())
413  {
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));
418  fs << "}";
419  }
420 
421  if(!D_.empty())
422  {
423  cv::Mat D = D_;
424  if(D_.cols == 6)
425  {
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);
431  }
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));
436  fs << "}";
437 
438  // compaibility with ROS
439  if(D_.cols == 6)
440  {
441  fs << "distortion_model" << "equidistant"; // equidistant, fisheye
442  }
443  else if(D.cols > 5)
444  {
445  fs << "distortion_model" << "rational_polynomial"; // rad tan
446  }
447  else
448  {
449  fs << "distortion_model" << "plumb_bob"; // rad tan
450  }
451  }
452 
453  if(!R_.empty())
454  {
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));
459  fs << "}";
460  }
461 
462  if(!P_.empty())
463  {
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));
468  fs << "}";
469  }
470 
471  if(!localTransform_.isNull())
472  {
473  fs << "local_transform" << "{";
474  fs << "rows" << 3;
475  fs << "cols" << 4;
476  fs << "data" << std::vector<float>((float*)localTransform_.data(), ((float*)localTransform_.data())+12);
477  fs << "}";
478  }
479 
480  fs.release();
481 
482  return true;
483  }
484  else
485  {
486  UERROR("Cannot save calibration to \"%s\" because it is empty.", filePath.c_str());
487  }
488  return false;
489 }
490 
491 std::vector<unsigned char> CameraModel::serialize() const
492 {
493  const int headerSize = 11;
494  int header[headerSize] = {
495  RTABMAP_VERSION_MAJOR, RTABMAP_VERSION_MINOR, RTABMAP_VERSION_PATCH, // 0,1,2
496  0, //mono // 3,
497  imageSize_.width, imageSize_.height, // 4,5
498  (int)K_.total(), (int)D_.total(), (int)R_.total(), (int)P_.total(), // 6,7,8,9
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;
507  if(!K_.empty())
508  {
509  memcpy(data.data()+index, K_.data, sizeof(double)*(K_.total()));
510  index+=sizeof(double)*(K_.total());
511  }
512  if(!D_.empty())
513  {
514  memcpy(data.data()+index, D_.data, sizeof(double)*(D_.total()));
515  index+=sizeof(double)*(D_.total());
516  }
517  if(!R_.empty())
518  {
519  memcpy(data.data()+index, R_.data, sizeof(double)*(R_.total()));
520  index+=sizeof(double)*(R_.total());
521  }
522  if(!P_.empty())
523  {
524  memcpy(data.data()+index, P_.data, sizeof(double)*(P_.total()));
525  index+=sizeof(double)*(P_.total());
526  }
527  if(!localTransform_.isNull())
528  {
529  memcpy(data.data()+index, localTransform_.data(), sizeof(float)*(localTransform_.size()));
530  index+=sizeof(float)*(localTransform_.size());
531  }
532  return data;
533 }
534 
535 unsigned int CameraModel::deserialize(const std::vector<unsigned char>& data)
536 {
537  return deserialize(data.data(), data.size());
538 }
539 unsigned int CameraModel::deserialize(const unsigned char * data, unsigned int dataSize)
540 {
541  *this = CameraModel();
542  int headerSize = 11;
543  if(dataSize >= sizeof(int)*headerSize)
544  {
545  UASSERT(data != 0);
546  const int * header = (const int *)data;
547  int type = header[3];
548  if(type == 0)
549  {
550  imageSize_.width = header[4];
551  imageSize_.height = header[5];
552  int iK = 6;
553  int iD = 7;
554  int iR = 8;
555  int iP = 9;
556  int iL = 10;
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 +
559  sizeof(double)*(header[iK]+header[iD]+header[iR]+header[iP]) +
560  sizeof(float)*header[iL];
561  UASSERT_MSG(dataSize >= requiredDataSize,
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)",
563  dataSize,
564  requiredDataSize,
565  header[0], header[1], header[2], header[4], header[5], header[3],
566  header[iK], header[iD], header[iR],header[iP], header[iL]).c_str());
567  unsigned int index = sizeof(int)*headerSize;
568  if(header[iK] != 0)
569  {
570  UASSERT(header[iK] == 9);
571  K_ = cv::Mat(3, 3, CV_64FC1, (void*)(data+index)).clone();
572  index+=sizeof(double)*(K_.total());
573  }
574  if(header[iD] != 0)
575  {
576  D_ = cv::Mat(1, header[iD], CV_64FC1, (void*)(data+index)).clone();
577  index+=sizeof(double)*(D_.total());
578  }
579  if(header[iR] != 0)
580  {
581  UASSERT(header[iR] == 9);
582  R_ = cv::Mat(3, 3, CV_64FC1, (void*)(data+index)).clone();
583  index+=sizeof(double)*(R_.total());
584  }
585  if(header[iP] != 0)
586  {
587  UASSERT(header[iP] == 12);
588  P_ = cv::Mat(3, 4, CV_64FC1, (void*)(data+index)).clone();
589  index+=sizeof(double)*(P_.total());
590  }
591  if(header[iL] != 0)
592  {
593  UASSERT(header[iL] == 12);
594  memcpy(localTransform_.data(), data+index, sizeof(float)*localTransform_.size());
595  index+=sizeof(float)*localTransform_.size();
596  }
597  UASSERT(index <= dataSize);
598  return index;
599  }
600  else
601  {
602  UERROR("Serialized calibration is not mono (type=%d), use the appropriate class matching the type to deserialize.", type);
603  }
604  }
605  UERROR("Wrong serialized calibration data format detected (size in bytes=%d)! Cannot deserialize the data.", (int)dataSize);
606  return 0;
607 }
608 
610 {
611  CameraModel scaledModel = *this;
612  UASSERT(scale > 0.0);
613  if(this->isValidForProjection())
614  {
615  // has only effect on K and P
616  cv::Mat K;
617  if(!K_.empty())
618  {
619  K = K_.clone();
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;
624  }
625 
626  cv::Mat P;
627  if(!P_.empty())
628  {
629  P = P_.clone();
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;
636  }
637  scaledModel = CameraModel(name_, cv::Size(double(imageSize_.width)*scale, double(imageSize_.height)*scale), K, D_, R_, P, localTransform_);
638  }
639  else
640  {
641  UWARN("Trying to scale a camera model not valid! Ignoring scaling...");
642  }
643  return scaledModel;
644 }
645 
646 CameraModel CameraModel::roi(const cv::Rect & roi) const
647 {
648  CameraModel roiModel = *this;
649  if(this->isValidForProjection())
650  {
651  // has only effect on cx and cy
652  cv::Mat K;
653  if(!K_.empty())
654  {
655  K = K_.clone();
656  K.at<double>(0,2) -= roi.x;
657  K.at<double>(1,2) -= roi.y;
658  }
659 
660  cv::Mat P;
661  if(!P_.empty())
662  {
663  P = P_.clone();
664  P.at<double>(0,2) -= roi.x;
665  P.at<double>(1,2) -= roi.y;
666  }
667  roiModel = CameraModel(name_, roi.size(), K, D_, R_, P, localTransform_);
668  }
669  else
670  {
671  UWARN("Trying to extract roi from a camera model not valid! Ignoring roi...");
672  }
673  return roiModel;
674 }
675 
676 double CameraModel::fovX() const
677 {
678  return imageSize_.width>0 && fx()>0?2.0*atan(imageSize_.width/(fx()*2.0)):0.0;
679 }
680 double CameraModel::fovY() const
681 {
682  return imageSize_.height>0 && fy()>0?2.0*atan(imageSize_.height/(fy()*2.0)):0.0;
683 }
684 
686 {
687  return fovX()*180.0/CV_PI;
688 }
689 
691 {
692  return fovY()*180.0/CV_PI;
693 }
694 
695 cv::Mat CameraModel::rectifyImage(const cv::Mat & raw, int interpolation) const
696 {
697  UDEBUG("");
698  if(!mapX_.empty() && !mapY_.empty())
699  {
700  cv::Mat rectified;
701  cv::remap(raw, rectified, mapX_, mapY_, interpolation);
702  return rectified;
703  }
704  else
705  {
706  UERROR("Cannot rectify image because the rectify map is not initialized.");
707  return raw.clone();
708  }
709 }
710 
711 //inspired from https://github.com/code-iai/iai_kinect2/blob/master/depth_registration/src/depth_registration_cpu.cpp
712 cv::Mat CameraModel::rectifyDepth(const cv::Mat & raw) const
713 {
714  UDEBUG("");
715  UASSERT(raw.type() == CV_16UC1);
716  if(!mapX_.empty() && !mapY_.empty())
717  {
718  cv::Mat rectified = cv::Mat::zeros(mapX_.rows, mapX_.cols, raw.type());
719  for(int y=0; y<mapX_.rows; ++y)
720  {
721  for(int x=0; x<mapX_.cols; ++x)
722  {
723  cv::Point2f pt(mapX_.at<float>(y,x), mapY_.at<float>(y,x));
724  int xL = (int)floor(pt.x);
725  int xH = (int)ceil(pt.x);
726  int yL = (int)floor(pt.y);
727  int yH = (int)ceil(pt.y);
728  if(xL >= 0 && yL >= 0 && xH < raw.cols && yH < raw.rows)
729  {
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)
735  {
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)
742  {
743  //bilinear interpolation
744  float a = pt.x - (float)xL;
745  float c = pt.y - (float)yL;
746 
747  //http://stackoverflow.com/questions/13299409/how-to-get-the-image-pixel-at-real-locations-in-opencv
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;
751  }
752  }
753  }
754  }
755  }
756  return rectified;
757  }
758  else
759  {
760  UERROR("Cannot rectify image because the rectify map is not initialized.");
761  return raw.clone();
762  }
763 }
764 
765 // resulting 3D point is in /camera_link frame
766 void CameraModel::project(float u, float v, float depth, float & x, float & y, float & z) const
767 {
768  if(depth > 0.0f)
769  {
770  // Fill in XYZ
771  x = (u - cx()) * depth / fx();
772  y = (v - cy()) * depth / fy();
773  z = depth;
774  }
775  else
776  {
777  x = y = z = std::numeric_limits<float>::quiet_NaN();
778  }
779 }
780 // 3D point is in /camera_link frame
781 void CameraModel::reproject(float x, float y, float z, float & u, float & v) const
782 {
783  UASSERT(z!=0.0f);
784  float invZ = 1.0f/z;
785  u = (fx()*x)*invZ + cx();
786  v = (fy()*y)*invZ + cy();
787 }
788 void CameraModel::reproject(float x, float y, float z, int & u, int & v) const
789 {
790  UASSERT(z!=0.0f);
791  float invZ = 1.0f/z;
792  u = (fx()*x)*invZ + cx();
793  v = (fy()*y)*invZ + cy();
794 }
795 
796 bool CameraModel::inFrame(int u, int v) const
797 {
798  return uIsInBounds(u, 0, imageWidth()) && uIsInBounds(v, 0, imageHeight());
799 }
800 
801 std::ostream& operator<<(std::ostream& os, const CameraModel& model)
802 {
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();
810  return os;
811 }
812 
813 } /* namespace rtabmap */
cv::Mat R() const
Definition: CameraModel.h:112
const cv::Size & imageSize() const
Definition: CameraModel.h:119
std::vector< unsigned char > serialize() const
void setImageSize(const cv::Size &size)
double horizontalFOV() const
int imageHeight() const
Definition: CameraModel.h:121
CameraModel scaled(double scale) const
bool isRectificationMapInitialized() const
Definition: CameraModel.h:85
bool save(const std::string &directory) const
double fovX() const
f
bool uIsInBounds(const T &value, const T &low, const T &high)
Definition: UMath.h:934
x
double verticalFOV() const
Transform localTransform_
Definition: CameraModel.h:159
data
GLM_FUNC_DECL genType e()
GLM_FUNC_DECL detail::tmat4x4< T, P > scale(detail::tmat4x4< T, P > const &m, detail::tvec3< T, P > const &v)
double fx() const
Definition: CameraModel.h:102
Basic mathematics functions.
bool load(const std::string &filePath)
std_msgs::Header * header(M &m)
const float * data() const
Definition: Transform.h:88
Some conversion functions.
Definition: Features2d.h:41
void reproject(float x, float y, float z, float &u, float &v) const
bool uStrContains(const std::string &string, const std::string &substring)
Definition: UStl.h:787
#define UASSERT(condition)
Wrappers of STL for convenient functions.
GLM_FUNC_DECL genType floor(genType const &x)
bool isValidForRectification() const
Definition: CameraModel.h:89
#define UASSERT_MSG(condition, msg_str)
Definition: ULogger.h:67
cv::Mat D_raw() const
Definition: CameraModel.h:109
cv::Mat K() const
Definition: CameraModel.h:110
GLM_FUNC_DECL genType atan(genType const &y, genType const &x)
cv::Mat K_raw() const
Definition: CameraModel.h:108
GLM_FUNC_DECL genType abs(genType const &x)
CameraModel roi(const cv::Rect &roi) const
const Transform & localTransform() const
Definition: CameraModel.h:116
bool isNull() const
Definition: Transform.cpp:107
double cx() const
Definition: CameraModel.h:104
cv::Mat rectifyDepth(const cv::Mat &raw) const
double cy() const
Definition: CameraModel.h:105
#define UDEBUG(...)
bool exists()
Definition: UFile.h:104
cv::Mat rectifyImage(const cv::Mat &raw, int interpolation=cv::INTER_LINEAR) const
#define UERROR(...)
RTABMAP_EXP std::ostream & operator<<(std::ostream &os, const CameraModel &model)
ULogger class and convenient macros.
#define UWARN(...)
const std::string & name() const
Definition: CameraModel.h:100
cv::Mat P() const
Definition: CameraModel.h:113
unsigned int deserialize(const std::vector< unsigned char > &data)
double fy() const
Definition: CameraModel.h:103
model
Definition: trace.py:4
int size() const
Definition: Transform.h:90
int imageWidth() const
Definition: CameraModel.h:120
bool inFrame(int u, int v) const
double fovY() const
double Tx() const
Definition: CameraModel.h:106
std::string UTILITE_EXP uFormat(const char *fmt,...)
cv::Mat D() const
Definition: CameraModel.h:111
GLM_FUNC_DECL genType ceil(genType const &x)
bool isValidForProjection() const
Definition: CameraModel.h:87
void project(float u, float v, float depth, float &x, float &y, float &z) const
#define UINFO(...)


rtabmap
Author(s): Mathieu Labbe
autogenerated on Mon Jan 23 2023 03:37:28