Camera.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2010-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       notice, this list of conditions and the following disclaimer in the
00011       documentation and/or other materials provided with the distribution.
00012     * Neither the name of the Universite de Sherbrooke nor the
00013       names of its contributors may be used to endorse or promote products
00014       derived from this software without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
00020 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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; // limit to 33Hz if infinity
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                 // Add precision at the cost of a small overhead
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 // CameraImages
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                                         // FIXME : it seems that some png are incorrectly loaded with opencv c++ interface, where c interface works...
00291                                         if(img.depth() != CV_8U)
00292                                         {
00293                                                 // The depth should be 8U
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 // CameraVideo
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                                 // clone required
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 } // namespace rtabmap


rtabmap
Author(s): Mathieu Labbe
autogenerated on Fri Aug 28 2015 12:51:31