00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rtabmap/core/Camera.h"
00029 #include "rtabmap/core/DBDriver.h"
00030
00031 #include <rtabmap/utilite/UEventsManager.h>
00032 #include <rtabmap/utilite/UConversion.h>
00033 #include <rtabmap/utilite/UStl.h>
00034 #include <rtabmap/utilite/UConversion.h>
00035 #include <rtabmap/utilite/UFile.h>
00036 #include <rtabmap/utilite/UDirectory.h>
00037 #include <rtabmap/utilite/UTimer.h>
00038
00039 #include <opencv2/imgproc/imgproc.hpp>
00040
00041 #include <iostream>
00042 #include <cmath>
00043
00044 namespace rtabmap
00045 {
00046
00047 Camera::Camera(float imageRate,
00048 unsigned int imageWidth,
00049 unsigned int imageHeight) :
00050 _imageRate(imageRate),
00051 _imageWidth(imageWidth),
00052 _imageHeight(imageHeight),
00053 _mirroring(false),
00054 _frameRateTimer(new UTimer())
00055 {
00056 }
00057
00058 Camera::~Camera()
00059 {
00060 if(_frameRateTimer)
00061 {
00062 delete _frameRateTimer;
00063 }
00064 }
00065
00066 void Camera::setImageSize(unsigned int width, unsigned int height)
00067 {
00068 _imageWidth = width;
00069 _imageHeight = height;
00070 }
00071
00072 void Camera::getImageSize(unsigned int & width, unsigned int & height)
00073 {
00074 width = _imageWidth;
00075 height = _imageHeight;
00076 }
00077
00078 void Camera::setCalibration(const std::string & fileName)
00079 {
00080 if(UFile::getExtension(fileName).compare("yaml") == 0)
00081 {
00082 cv::FileStorage fs;
00083 fs.open(fileName, cv::FileStorage::READ);
00084
00085 if (!fs.isOpened())
00086 {
00087 UERROR("Failed to open file \"%s\"", fileName.c_str());
00088 return;
00089 }
00090
00091 cv::Mat k,d;
00092
00093 cv::FileNode n = fs["camera_matrix"];
00094 int rows = n["rows"];
00095 int cols = n["cols"];
00096 std::vector<double> data;
00097 n["data"] >> data;
00098 if(rows > 0 && cols > 0 && (int)data.size() == rows*cols)
00099 {
00100 k = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
00101 }
00102
00103 cv::FileNode nd = fs["distortion_coefficients"];
00104 rows = nd["rows"];
00105 cols = nd["cols"];
00106 data.clear();
00107 nd["data"] >> data;
00108 if(rows > 0 && cols > 0 && (int)data.size() == rows*cols)
00109 {
00110 d = cv::Mat(rows, cols, CV_64FC1, data.data()).clone();
00111 }
00112
00113 if(k.empty())
00114 {
00115 UERROR("Failed to load \"camera_matrix\" matrix.");
00116 }
00117 if(d.empty())
00118 {
00119 UERROR("Failed to load \"distortion_coefficients\" matrix.");
00120 }
00121 if(!k.empty() && !d.empty())
00122 {
00123 this->setCalibration(k, d);
00124 }
00125 }
00126 else
00127 {
00128 UERROR("Calibration file must be in \"*.yaml\" format");
00129 }
00130 }
00131
00132 void Camera::setCalibration(const cv::Mat & cameraMatrix, const cv::Mat & distorsionCoefficients)
00133 {
00134 UASSERT(cameraMatrix.type() == CV_64FC1 &&
00135 cameraMatrix.rows == 3 &&
00136 cameraMatrix.cols == 3);
00137 UASSERT(distorsionCoefficients.type() == CV_64FC1 &&
00138 distorsionCoefficients.rows ==1 &&
00139 (distorsionCoefficients.cols == 4 || distorsionCoefficients.cols == 5 || distorsionCoefficients.cols == 8));
00140
00141 _k = cameraMatrix;
00142 _d = distorsionCoefficients;
00143 }
00144
00145 void Camera::resetCalibration()
00146 {
00147 _k = cv::Mat();
00148 _d = cv::Mat();
00149 }
00150
00151 cv::Mat Camera::takeImage()
00152 {
00153 cv::Mat img;
00154 float imageRate = _imageRate==0.0f?33.0f:_imageRate;
00155 if(imageRate>0)
00156 {
00157 int sleepTime = (1000.0f/imageRate - 1000.0f*_frameRateTimer->getElapsedTime());
00158 if(sleepTime > 2)
00159 {
00160 uSleep(sleepTime-2);
00161 }
00162
00163
00164 while(_frameRateTimer->getElapsedTime() < 1.0/double(imageRate)-0.000001)
00165 {
00166
00167 }
00168
00169 double slept = _frameRateTimer->getElapsedTime();
00170 _frameRateTimer->start();
00171 UDEBUG("slept=%fs vs target=%fs", slept, 1.0/double(imageRate));
00172 }
00173
00174 UTimer timer;
00175 img = this->captureImage();
00176 if(!img.empty() && !_k.empty() && !_d.empty())
00177 {
00178 cv::Mat temp = img.clone();
00179 cv::undistort(temp, img, _k, _d);
00180 }
00181 if(!img.empty() && _mirroring)
00182 {
00183 cv::flip(img,img,1);
00184 }
00185 UDEBUG("Time capturing image = %fs", timer.ticks());
00186 return img;
00187 }
00188
00190
00192 CameraImages::CameraImages(const std::string & path,
00193 int startAt,
00194 bool refreshDir,
00195 float imageRate,
00196 unsigned int imageWidth,
00197 unsigned int imageHeight) :
00198 Camera(imageRate, imageWidth, imageHeight),
00199 _path(path),
00200 _startAt(startAt),
00201 _refreshDir(refreshDir),
00202 _count(0),
00203 _dir(0)
00204 {
00205
00206 }
00207
00208 CameraImages::~CameraImages(void)
00209 {
00210 if(_dir)
00211 {
00212 delete _dir;
00213 }
00214 }
00215
00216 bool CameraImages::init()
00217 {
00218 UDEBUG("");
00219 if(_dir)
00220 {
00221 _dir->setPath(_path, "jpg ppm png bmp pnm tiff");
00222 }
00223 else
00224 {
00225 _dir = new UDirectory(_path, "jpg ppm png bmp pnm tiff");
00226 }
00227 _count = 0;
00228 if(_path[_path.size()-1] != '\\' && _path[_path.size()-1] != '/')
00229 {
00230 _path.append("/");
00231 }
00232 if(!_dir->isValid())
00233 {
00234 ULOGGER_ERROR("Directory path is not valid \"%s\"", _path.c_str());
00235 }
00236 else if(_dir->getFileNames().size() == 0)
00237 {
00238 UWARN("Directory is empty \"%s\"", _path.c_str());
00239 }
00240 return _dir->isValid();
00241 }
00242
00243 cv::Mat CameraImages::captureImage()
00244 {
00245 cv::Mat img;
00246 UDEBUG("");
00247 if(_dir->isValid())
00248 {
00249 if(_refreshDir)
00250 {
00251 _dir->update();
00252 }
00253 if(_startAt == 0)
00254 {
00255 const std::list<std::string> & fileNames = _dir->getFileNames();
00256 if(fileNames.size())
00257 {
00258 if(_lastFileName.empty() || uStrNumCmp(_lastFileName,*fileNames.rbegin()) < 0)
00259 {
00260 _lastFileName = *fileNames.rbegin();
00261 std::string fullPath = _path + _lastFileName;
00262 img = cv::imread(fullPath.c_str());
00263 }
00264 }
00265 }
00266 else
00267 {
00268 std::string fileName;
00269 std::string fullPath;
00270 fileName = _dir->getNextFileName();
00271 if(fileName.size())
00272 {
00273 fullPath = _path + fileName;
00274 while(++_count < _startAt && (fileName = _dir->getNextFileName()).size())
00275 {
00276 fullPath = _path + fileName;
00277 }
00278 if(fileName.size())
00279 {
00280 ULOGGER_DEBUG("Loading image : %s", fullPath.c_str());
00281
00282 #if CV_MAJOR_VERSION >2 || (CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4)
00283 img = cv::imread(fullPath.c_str(), cv::IMREAD_UNCHANGED);
00284 #else
00285 img = cv::imread(fullPath.c_str(), -1);
00286 #endif
00287 UDEBUG("width=%d, height=%d, channels=%d, elementSize=%d, total=%d",
00288 img.cols, img.rows, img.channels(), img.elemSize(), img.total());
00289
00290
00291 if(img.depth() != CV_8U)
00292 {
00293
00294 UWARN("Cannot read the image correctly, falling back to old OpenCV C interface...");
00295 IplImage * i = cvLoadImage(fullPath.c_str());
00296 img = cv::Mat(i, true);
00297 cvReleaseImage(&i);
00298 }
00299
00300 if(img.channels()>3)
00301 {
00302 UWARN("Conversion from 4 channels to 3 channels (file=%s)", fullPath.c_str());
00303 cv::Mat out;
00304 cv::cvtColor(img, out, CV_BGRA2BGR);
00305 img = out;
00306 }
00307 }
00308 }
00309 }
00310 }
00311 else
00312 {
00313 UWARN("Directory is not set, camera must be initialized.");
00314 }
00315
00316 unsigned int w;
00317 unsigned int h;
00318 this->getImageSize(w, h);
00319
00320 if(!img.empty() &&
00321 w &&
00322 h &&
00323 w != (unsigned int)img.cols &&
00324 h != (unsigned int)img.rows)
00325 {
00326 cv::Mat resampled;
00327 cv::resize(img, resampled, cv::Size(w, h));
00328 img = resampled;
00329 }
00330 return img;
00331 }
00332
00333
00334
00336
00338 CameraVideo::CameraVideo(int usbDevice,
00339 float imageRate,
00340 unsigned int imageWidth,
00341 unsigned int imageHeight) :
00342 Camera(imageRate, imageWidth, imageHeight),
00343 _src(kUsbDevice),
00344 _usbDevice(usbDevice)
00345 {
00346
00347 }
00348
00349 CameraVideo::CameraVideo(const std::string & filePath,
00350 float imageRate,
00351 unsigned int imageWidth,
00352 unsigned int imageHeight) :
00353 Camera(imageRate, imageWidth, imageHeight),
00354 _filePath(filePath),
00355 _src(kVideoFile),
00356 _usbDevice(0)
00357 {
00358 }
00359
00360 CameraVideo::~CameraVideo()
00361 {
00362 _capture.release();
00363 }
00364
00365 bool CameraVideo::init()
00366 {
00367 if(_capture.isOpened())
00368 {
00369 _capture.release();
00370 }
00371
00372 if(_src == kUsbDevice)
00373 {
00374 unsigned int w;
00375 unsigned int h;
00376 this->getImageSize(w, h);
00377
00378 ULOGGER_DEBUG("CameraVideo::init() Usb device initialization on device %d with imgSize=[%d,%d]", _usbDevice, w, h);
00379 _capture.open(_usbDevice);
00380
00381 if(w && h)
00382 {
00383 _capture.set(CV_CAP_PROP_FRAME_WIDTH, double(w));
00384 _capture.set(CV_CAP_PROP_FRAME_HEIGHT, double(h));
00385 }
00386 }
00387 else if(_src == kVideoFile)
00388 {
00389 ULOGGER_DEBUG("Camera: filename=\"%s\"", _filePath.c_str());
00390 _capture.open(_filePath.c_str());
00391 }
00392 else
00393 {
00394 ULOGGER_ERROR("Camera: Unknown source...");
00395 }
00396 if(!_capture.isOpened())
00397 {
00398 ULOGGER_ERROR("Camera: Failed to create a capture object!");
00399 _capture.release();
00400 return false;
00401 }
00402 return true;
00403 }
00404
00405 cv::Mat CameraVideo::captureImage()
00406 {
00407 cv::Mat img;
00408 if(_capture.isOpened())
00409 {
00410 if(_capture.read(img))
00411 {
00412 unsigned int w;
00413 unsigned int h;
00414 this->getImageSize(w, h);
00415
00416 if(!img.empty() &&
00417 w &&
00418 h &&
00419 w != (unsigned int)img.cols &&
00420 h != (unsigned int)img.rows)
00421 {
00422 cv::Mat resampled;
00423 cv::resize(img, resampled, cv::Size(w, h));
00424 img = resampled;
00425 }
00426 else
00427 {
00428
00429 img = img.clone();
00430 }
00431 }
00432 else if(_usbDevice)
00433 {
00434 UERROR("Camera has been disconnected!");
00435 }
00436 }
00437 else
00438 {
00439 ULOGGER_WARN("The camera must be initialized before requesting an image.");
00440 }
00441 return img;
00442 }
00443
00444 }