2015-06-26 18:21:32 -04:00
|
|
|
/*
|
2016-07-17 21:57:10 -04:00
|
|
|
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
|
2015-06-26 18:21:32 -04:00
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
|
notice, this list of conditions and the following disclaimer in the
|
|
|
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
|
* Neither the name of the Universite de Sherbrooke nor the
|
|
|
|
|
names of its contributors may be used to endorse or promote products
|
|
|
|
|
derived from this software without specific prior written permission.
|
|
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
|
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "rtabmap/core/CameraStereo.h"
|
|
|
|
|
#include "rtabmap/core/util2d.h"
|
|
|
|
|
#include "rtabmap/core/CameraRGB.h"
|
2016-03-01 14:25:00 -05:00
|
|
|
#include "rtabmap/core/Version.h"
|
2015-06-26 18:21:32 -04:00
|
|
|
|
|
|
|
|
#include <rtabmap/utilite/UEventsManager.h>
|
|
|
|
|
#include <rtabmap/utilite/UConversion.h>
|
|
|
|
|
#include <rtabmap/utilite/UStl.h>
|
|
|
|
|
#include <rtabmap/utilite/UConversion.h>
|
|
|
|
|
#include <rtabmap/utilite/UFile.h>
|
|
|
|
|
#include <rtabmap/utilite/UDirectory.h>
|
|
|
|
|
#include <rtabmap/utilite/UTimer.h>
|
|
|
|
|
#include <rtabmap/utilite/UMath.h>
|
|
|
|
|
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2015-06-26 18:21:32 -04:00
|
|
|
#include <dc1394/dc1394.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
#include <triclops.h>
|
|
|
|
|
#include <fc2triclops.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-05-31 19:09:49 -04:00
|
|
|
#ifdef RTABMAP_ZED
|
2017-04-18 15:03:10 +09:00
|
|
|
#include <sl/Camera.hpp>
|
2016-05-31 19:09:49 -04:00
|
|
|
#endif
|
|
|
|
|
|
2015-06-26 18:21:32 -04:00
|
|
|
namespace rtabmap
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// CameraStereoDC1394
|
|
|
|
|
// Inspired from ROS camera1394stereo package
|
|
|
|
|
//
|
|
|
|
|
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2015-06-26 18:21:32 -04:00
|
|
|
class DC1394Device
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
DC1394Device() :
|
|
|
|
|
camera_(0),
|
|
|
|
|
context_(0)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
~DC1394Device()
|
|
|
|
|
{
|
|
|
|
|
if (camera_)
|
|
|
|
|
{
|
|
|
|
|
if (DC1394_SUCCESS != dc1394_video_set_transmission(camera_, DC1394_OFF) ||
|
|
|
|
|
DC1394_SUCCESS != dc1394_capture_stop(camera_))
|
|
|
|
|
{
|
|
|
|
|
UWARN("unable to stop camera");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Free resources
|
|
|
|
|
dc1394_capture_stop(camera_);
|
|
|
|
|
dc1394_camera_free(camera_);
|
|
|
|
|
camera_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
if(context_)
|
|
|
|
|
{
|
|
|
|
|
dc1394_free(context_);
|
|
|
|
|
context_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string & guid() const {return guid_;}
|
|
|
|
|
|
|
|
|
|
bool init()
|
|
|
|
|
{
|
|
|
|
|
if(camera_)
|
|
|
|
|
{
|
|
|
|
|
// Free resources
|
|
|
|
|
dc1394_capture_stop(camera_);
|
|
|
|
|
dc1394_camera_free(camera_);
|
|
|
|
|
camera_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// look for a camera
|
|
|
|
|
int err;
|
|
|
|
|
if(context_ == NULL)
|
|
|
|
|
{
|
|
|
|
|
context_ = dc1394_new ();
|
|
|
|
|
if (context_ == NULL)
|
|
|
|
|
{
|
|
|
|
|
UERROR( "Could not initialize dc1394_context.\n"
|
|
|
|
|
"Make sure /dev/raw1394 exists, you have access permission,\n"
|
|
|
|
|
"and libraw1394 development package is installed.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dc1394camera_list_t *list;
|
|
|
|
|
err = dc1394_camera_enumerate(context_, &list);
|
|
|
|
|
if (err != DC1394_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
UERROR("Could not get camera list");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list->num == 0)
|
|
|
|
|
{
|
|
|
|
|
UERROR("No cameras found");
|
|
|
|
|
dc1394_camera_free_list (list);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
uint64_t guid = list->ids[0].guid;
|
|
|
|
|
dc1394_camera_free_list (list);
|
|
|
|
|
|
|
|
|
|
// Create a camera
|
|
|
|
|
camera_ = dc1394_camera_new (context_, guid);
|
|
|
|
|
if (!camera_)
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to initialize camera with GUID [%016lx]", guid);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t value[3];
|
|
|
|
|
value[0]= camera_->guid & 0xffffffff;
|
|
|
|
|
value[1]= (camera_->guid >>32) & 0x000000ff;
|
|
|
|
|
value[2]= (camera_->guid >>40) & 0xfffff;
|
|
|
|
|
guid_ = uFormat("%06x%02x%08x", value[2], value[1], value[0]);
|
|
|
|
|
|
|
|
|
|
UINFO("camera model: %s %s", camera_->vendor, camera_->model);
|
|
|
|
|
|
|
|
|
|
// initialize camera
|
|
|
|
|
// Enable IEEE1394b mode if the camera and bus support it
|
|
|
|
|
bool bmode = camera_->bmode_capable;
|
|
|
|
|
if (bmode
|
|
|
|
|
&& (DC1394_SUCCESS !=
|
|
|
|
|
dc1394_video_set_operation_mode(camera_,
|
|
|
|
|
DC1394_OPERATION_MODE_1394B)))
|
|
|
|
|
{
|
|
|
|
|
bmode = false;
|
|
|
|
|
UWARN("failed to set IEEE1394b mode");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// start with highest speed supported
|
|
|
|
|
dc1394speed_t request = DC1394_ISO_SPEED_3200;
|
|
|
|
|
int rate = 3200;
|
|
|
|
|
if (!bmode)
|
|
|
|
|
{
|
|
|
|
|
// not IEEE1394b capable: so 400Mb/s is the limit
|
|
|
|
|
request = DC1394_ISO_SPEED_400;
|
|
|
|
|
rate = 400;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// round requested speed down to next-lower defined value
|
|
|
|
|
while (rate > 400)
|
|
|
|
|
{
|
|
|
|
|
if (request <= DC1394_ISO_SPEED_MIN)
|
|
|
|
|
{
|
|
|
|
|
// get current ISO speed of the device
|
|
|
|
|
dc1394speed_t curSpeed;
|
|
|
|
|
if (DC1394_SUCCESS == dc1394_video_get_iso_speed(camera_, &curSpeed) && curSpeed <= DC1394_ISO_SPEED_MAX)
|
|
|
|
|
{
|
|
|
|
|
// Translate curSpeed back to an int for the parameter
|
|
|
|
|
// update, works as long as any new higher speeds keep
|
|
|
|
|
// doubling.
|
|
|
|
|
request = curSpeed;
|
|
|
|
|
rate = 100 << (curSpeed - DC1394_ISO_SPEED_MIN);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UWARN("Unable to get ISO speed; assuming 400Mb/s");
|
|
|
|
|
rate = 400;
|
|
|
|
|
request = DC1394_ISO_SPEED_400;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// continue with next-lower possible value
|
|
|
|
|
request = (dc1394speed_t) ((int) request - 1);
|
|
|
|
|
rate = rate / 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set the requested speed
|
|
|
|
|
if (DC1394_SUCCESS != dc1394_video_set_iso_speed(camera_, request))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to set iso speed");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set video mode
|
|
|
|
|
dc1394video_modes_t vmodes;
|
|
|
|
|
err = dc1394_video_get_supported_modes(camera_, &vmodes);
|
|
|
|
|
if (err != DC1394_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
UERROR("unable to get supported video modes");
|
|
|
|
|
return (dc1394video_mode_t) 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// see if requested mode is available
|
|
|
|
|
bool found = false;
|
|
|
|
|
dc1394video_mode_t videoMode = DC1394_VIDEO_MODE_FORMAT7_3; // bumblebee
|
|
|
|
|
for (uint32_t i = 0; i < vmodes.num; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (vmodes.modes[i] == videoMode)
|
|
|
|
|
{
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!found)
|
|
|
|
|
{
|
|
|
|
|
UERROR("unable to get video mode %d", videoMode);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DC1394_SUCCESS != dc1394_video_set_mode(camera_, videoMode))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to set video mode %d", videoMode);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// special handling for Format7 modes
|
|
|
|
|
if (dc1394_is_video_mode_scalable(videoMode) == DC1394_TRUE)
|
|
|
|
|
{
|
|
|
|
|
if (DC1394_SUCCESS != dc1394_format7_set_color_coding(camera_, videoMode, DC1394_COLOR_CODING_RAW16))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Could not set color coding");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
uint32_t packetSize;
|
|
|
|
|
if (DC1394_SUCCESS != dc1394_format7_get_recommended_packet_size(camera_, videoMode, &packetSize))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Could not get default packet size");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DC1394_SUCCESS != dc1394_format7_set_packet_size(camera_, videoMode, packetSize))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Could not set packet size");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UERROR("Video is not in mode scalable");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// start the device streaming data
|
|
|
|
|
// Set camera to use DMA, improves performance.
|
|
|
|
|
if (DC1394_SUCCESS != dc1394_capture_setup(camera_, 4, DC1394_CAPTURE_FLAGS_DEFAULT))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to open device!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start transmitting camera data
|
|
|
|
|
if (DC1394_SUCCESS != dc1394_video_set_transmission(camera_, DC1394_ON))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to start device!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool getImages(cv::Mat & left, cv::Mat & right)
|
|
|
|
|
{
|
|
|
|
|
if(camera_)
|
|
|
|
|
{
|
|
|
|
|
dc1394video_frame_t * frame = NULL;
|
|
|
|
|
UDEBUG("[%016lx] waiting camera", camera_->guid);
|
|
|
|
|
dc1394_capture_dequeue (camera_, DC1394_CAPTURE_POLICY_WAIT, &frame);
|
|
|
|
|
if (!frame)
|
|
|
|
|
{
|
|
|
|
|
UERROR("Unable to capture frame");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
dc1394video_frame_t frame1 = *frame;
|
|
|
|
|
// deinterlace frame into two imagesCount one on top the other
|
|
|
|
|
size_t frame1_size = frame->total_bytes;
|
|
|
|
|
frame1.image = (unsigned char *) malloc(frame1_size);
|
|
|
|
|
frame1.allocated_image_bytes = frame1_size;
|
|
|
|
|
frame1.color_coding = DC1394_COLOR_CODING_RAW8;
|
|
|
|
|
int err = dc1394_deinterlace_stereo_frames(frame, &frame1, DC1394_STEREO_METHOD_INTERLACED);
|
|
|
|
|
if (err != DC1394_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
free(frame1.image);
|
|
|
|
|
dc1394_capture_enqueue(camera_, frame);
|
|
|
|
|
UERROR("Could not extract stereo frames");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t* capture_buffer = reinterpret_cast<uint8_t *>(frame1.image);
|
|
|
|
|
UASSERT(capture_buffer);
|
|
|
|
|
|
|
|
|
|
cv::Mat image(frame->size[1], frame->size[0], CV_8UC3);
|
|
|
|
|
cv::Mat image2 = image.clone();
|
|
|
|
|
|
|
|
|
|
//DC1394_COLOR_CODING_RAW16:
|
|
|
|
|
//DC1394_COLOR_FILTER_BGGR
|
|
|
|
|
cv::cvtColor(cv::Mat(frame->size[1], frame->size[0], CV_8UC1, capture_buffer), left, CV_BayerRG2BGR);
|
|
|
|
|
cv::cvtColor(cv::Mat(frame->size[1], frame->size[0], CV_8UC1, capture_buffer+image.total()), right, CV_BayerRG2GRAY);
|
|
|
|
|
|
|
|
|
|
dc1394_capture_enqueue(camera_, frame);
|
|
|
|
|
|
|
|
|
|
free(frame1.image);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
dc1394camera_t *camera_;
|
|
|
|
|
dc1394_t *context_;
|
|
|
|
|
std::string guid_;
|
|
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool CameraStereoDC1394::available()
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2015-06-26 18:21:32 -04:00
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoDC1394::CameraStereoDC1394(float imageRate, const Transform & localTransform) :
|
2016-12-02 12:29:38 -05:00
|
|
|
Camera(imageRate, localTransform)
|
|
|
|
|
#ifdef RTABMAP_DC1394
|
|
|
|
|
,
|
2015-06-26 18:21:32 -04:00
|
|
|
device_(0)
|
2016-12-02 12:29:38 -05:00
|
|
|
#endif
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2015-06-26 18:21:32 -04:00
|
|
|
device_ = new DC1394Device();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoDC1394::~CameraStereoDC1394()
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2015-06-26 18:21:32 -04:00
|
|
|
if(device_)
|
|
|
|
|
{
|
|
|
|
|
delete device_;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoDC1394::init(const std::string & calibrationFolder, const std::string & cameraName)
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2015-06-26 18:21:32 -04:00
|
|
|
if(device_)
|
|
|
|
|
{
|
|
|
|
|
bool ok = device_->init();
|
|
|
|
|
if(ok)
|
|
|
|
|
{
|
|
|
|
|
// look for calibration files
|
|
|
|
|
if(!calibrationFolder.empty())
|
|
|
|
|
{
|
|
|
|
|
if(!stereoModel_.load(calibrationFolder, cameraName.empty()?device_->guid():cameraName))
|
|
|
|
|
{
|
|
|
|
|
UWARN("Missing calibration files for camera \"%s\" in \"%s\" folder, you should calibrate the camera!",
|
|
|
|
|
cameraName.empty()?device_->guid().c_str():cameraName.c_str(), calibrationFolder.c_str());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UINFO("Stereo parameters: fx=%f cx=%f cy=%f baseline=%f",
|
|
|
|
|
stereoModel_.left().fx(),
|
|
|
|
|
stereoModel_.left().cx(),
|
|
|
|
|
stereoModel_.left().cy(),
|
|
|
|
|
stereoModel_.baseline());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
UERROR("CameraDC1394: RTAB-Map is not built with dc1394 support!");
|
|
|
|
|
#endif
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoDC1394::isCalibrated() const
|
|
|
|
|
{
|
2016-12-02 12:29:38 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2016-01-19 21:01:56 -05:00
|
|
|
return stereoModel_.isValidForProjection();
|
2016-12-02 12:29:38 -05:00
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CameraStereoDC1394::getSerial() const
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2015-06-26 18:21:32 -04:00
|
|
|
if(device_)
|
|
|
|
|
{
|
|
|
|
|
return device_->guid();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-21 11:22:24 -04:00
|
|
|
SensorData CameraStereoDC1394::captureImage(CameraInfo * info)
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
|
|
|
|
SensorData data;
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_DC1394
|
2015-06-26 18:21:32 -04:00
|
|
|
if(device_)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat left, right;
|
|
|
|
|
device_->getImages(left, right);
|
|
|
|
|
|
|
|
|
|
if(!left.empty() && !right.empty())
|
|
|
|
|
{
|
|
|
|
|
// Rectification
|
2016-01-19 17:43:33 -05:00
|
|
|
if(stereoModel_.left().isValidForRectification())
|
|
|
|
|
{
|
|
|
|
|
left = stereoModel_.left().rectifyImage(left);
|
|
|
|
|
}
|
|
|
|
|
if(stereoModel_.right().isValidForRectification())
|
|
|
|
|
{
|
|
|
|
|
right = stereoModel_.right().rectifyImage(right);
|
|
|
|
|
}
|
2015-07-08 15:44:49 -04:00
|
|
|
StereoCameraModel model;
|
2016-01-19 21:01:56 -05:00
|
|
|
if(stereoModel_.isValidForProjection())
|
2015-07-08 15:44:49 -04:00
|
|
|
{
|
|
|
|
|
model = StereoCameraModel(
|
|
|
|
|
stereoModel_.left().fx(), //fx
|
|
|
|
|
stereoModel_.left().fy(), //fy
|
|
|
|
|
stereoModel_.left().cx(), //cx
|
|
|
|
|
stereoModel_.left().cy(), //cy
|
|
|
|
|
stereoModel_.baseline(),
|
2016-03-10 09:07:44 -05:00
|
|
|
this->getLocalTransform(),
|
|
|
|
|
left.size());
|
2015-07-08 15:44:49 -04:00
|
|
|
}
|
2015-06-26 18:21:32 -04:00
|
|
|
data = SensorData(left, right, model, this->getNextSeqID(), UTimer::now());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
UERROR("CameraDC1394: RTAB-Map is not built with dc1394 support!");
|
|
|
|
|
#endif
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// CameraTriclops
|
|
|
|
|
//
|
|
|
|
|
CameraStereoFlyCapture2::CameraStereoFlyCapture2(float imageRate, const Transform & localTransform) :
|
2016-12-02 12:29:38 -05:00
|
|
|
Camera(imageRate, localTransform)
|
|
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
|
|
|
|
,
|
2015-06-26 18:21:32 -04:00
|
|
|
camera_(0),
|
|
|
|
|
triclopsCtx_(0)
|
2016-12-02 12:29:38 -05:00
|
|
|
#endif
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
camera_ = new FlyCapture2::Camera();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoFlyCapture2::~CameraStereoFlyCapture2()
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
// Close the camera
|
|
|
|
|
camera_->StopCapture();
|
|
|
|
|
camera_->Disconnect();
|
|
|
|
|
|
|
|
|
|
// Destroy the Triclops context
|
|
|
|
|
triclopsDestroyContext( triclopsCtx_ ) ;
|
|
|
|
|
|
|
|
|
|
delete camera_;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoFlyCapture2::available()
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoFlyCapture2::init(const std::string & calibrationFolder, const std::string & cameraName)
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
if(camera_)
|
|
|
|
|
{
|
|
|
|
|
// Close the camera
|
|
|
|
|
camera_->StopCapture();
|
|
|
|
|
camera_->Disconnect();
|
|
|
|
|
}
|
|
|
|
|
if(triclopsCtx_)
|
|
|
|
|
{
|
|
|
|
|
triclopsDestroyContext(triclopsCtx_);
|
|
|
|
|
triclopsCtx_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// connect camera
|
|
|
|
|
FlyCapture2::Error fc2Error = camera_->Connect();
|
|
|
|
|
if(fc2Error != FlyCapture2::PGRERROR_OK)
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to connect the camera.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// configure camera
|
|
|
|
|
Fc2Triclops::StereoCameraMode mode = Fc2Triclops::TWO_CAMERA_NARROW;
|
|
|
|
|
if(Fc2Triclops::setStereoMode(*camera_, mode ))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to set stereo mode.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// generate the Triclops context
|
|
|
|
|
FlyCapture2::CameraInfo camInfo;
|
|
|
|
|
if(camera_->GetCameraInfo(&camInfo) != FlyCapture2::PGRERROR_OK)
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to get camera info.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float dummy;
|
|
|
|
|
unsigned packetSz;
|
|
|
|
|
FlyCapture2::Format7ImageSettings imageSettings;
|
|
|
|
|
int maxWidth = 640;
|
|
|
|
|
int maxHeight = 480;
|
|
|
|
|
if(camera_->GetFormat7Configuration(&imageSettings, &packetSz, &dummy) == FlyCapture2::PGRERROR_OK)
|
|
|
|
|
{
|
|
|
|
|
maxHeight = imageSettings.height;
|
|
|
|
|
maxWidth = imageSettings.width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get calibration from th camera
|
|
|
|
|
if(Fc2Triclops::getContextFromCamera(camInfo.serialNumber, &triclopsCtx_))
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to get calibration from the camera.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float fx, cx, cy, baseline;
|
|
|
|
|
triclopsGetFocalLength(triclopsCtx_, &fx);
|
|
|
|
|
triclopsGetImageCenter(triclopsCtx_, &cy, &cx);
|
|
|
|
|
triclopsGetBaseline(triclopsCtx_, &baseline);
|
|
|
|
|
UINFO("Stereo parameters: fx=%f cx=%f cy=%f baseline=%f", fx, cx, cy, baseline);
|
|
|
|
|
|
|
|
|
|
triclopsSetCameraConfiguration(triclopsCtx_, TriCfg_2CAM_HORIZONTAL_NARROW );
|
|
|
|
|
UASSERT(triclopsSetResolutionAndPrepare(triclopsCtx_, maxHeight, maxWidth, maxHeight, maxWidth) == Fc2Triclops::ERRORTYPE_OK);
|
|
|
|
|
|
|
|
|
|
if(camera_->StartCapture() != FlyCapture2::PGRERROR_OK)
|
|
|
|
|
{
|
|
|
|
|
UERROR("Failed to start capture.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
UERROR("CameraStereoFlyCapture2: RTAB-Map is not built with Triclops support!");
|
|
|
|
|
#endif
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoFlyCapture2::isCalibrated() const
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
if(triclopsCtx_)
|
|
|
|
|
{
|
|
|
|
|
float fx, cx, cy, baseline;
|
|
|
|
|
triclopsGetFocalLength(triclopsCtx_, &fx);
|
|
|
|
|
triclopsGetImageCenter(triclopsCtx_, &cy, &cx);
|
|
|
|
|
triclopsGetBaseline(triclopsCtx_, &baseline);
|
|
|
|
|
return fx > 0.0f && cx > 0.0f && cy > 0.0f && baseline > 0.0f;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CameraStereoFlyCapture2::getSerial() const
|
|
|
|
|
{
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
if(camera_ && camera_->IsConnected())
|
|
|
|
|
{
|
|
|
|
|
FlyCapture2::CameraInfo camInfo;
|
|
|
|
|
if(camera_->GetCameraInfo(&camInfo) == FlyCapture2::PGRERROR_OK)
|
|
|
|
|
{
|
|
|
|
|
return uNumber2Str(camInfo.serialNumber);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// struct containing image needed for processing
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
struct ImageContainer
|
|
|
|
|
{
|
|
|
|
|
FlyCapture2::Image tmp[2];
|
|
|
|
|
FlyCapture2::Image unprocessed[2];
|
|
|
|
|
} ;
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-06-21 11:22:24 -04:00
|
|
|
SensorData CameraStereoFlyCapture2::captureImage(CameraInfo * info)
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
|
|
|
|
SensorData data;
|
2016-03-01 14:25:00 -05:00
|
|
|
#ifdef RTABMAP_FLYCAPTURE2
|
2015-06-26 18:21:32 -04:00
|
|
|
if(camera_ && triclopsCtx_ && camera_->IsConnected())
|
|
|
|
|
{
|
|
|
|
|
// grab image from camera.
|
|
|
|
|
// this image contains both right and left imagesCount
|
|
|
|
|
FlyCapture2::Image grabbedImage;
|
|
|
|
|
if(camera_->RetrieveBuffer(&grabbedImage) == FlyCapture2::PGRERROR_OK)
|
|
|
|
|
{
|
|
|
|
|
// right and left image extracted from grabbed image
|
|
|
|
|
ImageContainer imageCont;
|
|
|
|
|
|
|
|
|
|
// generate triclops input from grabbed image
|
|
|
|
|
FlyCapture2::Image imageRawRight;
|
|
|
|
|
FlyCapture2::Image imageRawLeft;
|
|
|
|
|
FlyCapture2::Image * unprocessedImage = imageCont.unprocessed;
|
|
|
|
|
|
|
|
|
|
// Convert the pixel interleaved raw data to de-interleaved and color processed data
|
|
|
|
|
if(Fc2Triclops::unpackUnprocessedRawOrMono16Image(
|
|
|
|
|
grabbedImage,
|
|
|
|
|
true /*assume little endian*/,
|
|
|
|
|
imageRawLeft /* right */,
|
|
|
|
|
imageRawRight /* left */) == Fc2Triclops::ERRORTYPE_OK)
|
|
|
|
|
{
|
|
|
|
|
// convert to color
|
|
|
|
|
FlyCapture2::Image srcImgRightRef(imageRawRight);
|
|
|
|
|
FlyCapture2::Image srcImgLeftRef(imageRawLeft);
|
|
|
|
|
|
|
|
|
|
bool ok = true;;
|
|
|
|
|
if ( srcImgRightRef.SetColorProcessing(FlyCapture2::HQ_LINEAR) != FlyCapture2::PGRERROR_OK ||
|
|
|
|
|
srcImgLeftRef.SetColorProcessing(FlyCapture2::HQ_LINEAR) != FlyCapture2::PGRERROR_OK)
|
|
|
|
|
{
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ok)
|
|
|
|
|
{
|
|
|
|
|
FlyCapture2::Image imageColorRight;
|
|
|
|
|
FlyCapture2::Image imageColorLeft;
|
|
|
|
|
if ( srcImgRightRef.Convert(FlyCapture2::PIXEL_FORMAT_MONO8, &imageColorRight) != FlyCapture2::PGRERROR_OK ||
|
|
|
|
|
srcImgLeftRef.Convert(FlyCapture2::PIXEL_FORMAT_BGRU, &imageColorLeft) != FlyCapture2::PGRERROR_OK)
|
|
|
|
|
{
|
|
|
|
|
ok = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ok)
|
|
|
|
|
{
|
|
|
|
|
//RECTIFY RIGHT
|
|
|
|
|
TriclopsInput triclopsColorInputs;
|
|
|
|
|
triclopsBuildRGBTriclopsInput(
|
|
|
|
|
grabbedImage.GetCols(),
|
|
|
|
|
grabbedImage.GetRows(),
|
|
|
|
|
imageColorRight.GetStride(),
|
|
|
|
|
(unsigned long)grabbedImage.GetTimeStamp().seconds,
|
|
|
|
|
(unsigned long)grabbedImage.GetTimeStamp().microSeconds,
|
|
|
|
|
imageColorRight.GetData(),
|
|
|
|
|
imageColorRight.GetData(),
|
|
|
|
|
imageColorRight.GetData(),
|
|
|
|
|
&triclopsColorInputs);
|
|
|
|
|
|
|
|
|
|
triclopsRectify(triclopsCtx_, const_cast<TriclopsInput *>(&triclopsColorInputs) );
|
|
|
|
|
// Retrieve the rectified image from the triclops context
|
|
|
|
|
TriclopsImage rectifiedImage;
|
|
|
|
|
triclopsGetImage( triclopsCtx_,
|
|
|
|
|
TriImg_RECTIFIED,
|
|
|
|
|
TriCam_REFERENCE,
|
|
|
|
|
&rectifiedImage );
|
|
|
|
|
|
|
|
|
|
cv::Mat left,right;
|
|
|
|
|
right = cv::Mat(rectifiedImage.nrows, rectifiedImage.ncols, CV_8UC1, rectifiedImage.data).clone();
|
|
|
|
|
|
|
|
|
|
//RECTIFY LEFT COLOR
|
|
|
|
|
triclopsBuildPackedTriclopsInput(
|
|
|
|
|
grabbedImage.GetCols(),
|
|
|
|
|
grabbedImage.GetRows(),
|
|
|
|
|
imageColorLeft.GetStride(),
|
|
|
|
|
(unsigned long)grabbedImage.GetTimeStamp().seconds,
|
|
|
|
|
(unsigned long)grabbedImage.GetTimeStamp().microSeconds,
|
|
|
|
|
imageColorLeft.GetData(),
|
|
|
|
|
&triclopsColorInputs );
|
|
|
|
|
|
|
|
|
|
cv::Mat pixelsLeftBuffer( grabbedImage.GetRows(), grabbedImage.GetCols(), CV_8UC4);
|
|
|
|
|
TriclopsPackedColorImage colorImage;
|
|
|
|
|
triclopsSetPackedColorImageBuffer(
|
|
|
|
|
triclopsCtx_,
|
|
|
|
|
TriCam_LEFT,
|
|
|
|
|
(TriclopsPackedColorPixel*)pixelsLeftBuffer.data );
|
|
|
|
|
|
|
|
|
|
triclopsRectifyPackedColorImage(
|
|
|
|
|
triclopsCtx_,
|
|
|
|
|
TriCam_LEFT,
|
|
|
|
|
&triclopsColorInputs,
|
|
|
|
|
&colorImage );
|
|
|
|
|
|
|
|
|
|
cv::cvtColor(pixelsLeftBuffer, left, CV_RGBA2RGB);
|
|
|
|
|
|
|
|
|
|
// Set calibration stuff
|
|
|
|
|
float fx, cy, cx, baseline;
|
|
|
|
|
triclopsGetFocalLength(triclopsCtx_, &fx);
|
|
|
|
|
triclopsGetImageCenter(triclopsCtx_, &cy, &cx);
|
|
|
|
|
triclopsGetBaseline(triclopsCtx_, &baseline);
|
|
|
|
|
|
|
|
|
|
StereoCameraModel model(
|
|
|
|
|
fx,
|
2015-07-06 17:25:38 -04:00
|
|
|
fx,
|
|
|
|
|
cx,
|
|
|
|
|
cy,
|
2015-06-26 18:21:32 -04:00
|
|
|
baseline,
|
2016-03-10 09:07:44 -05:00
|
|
|
this->getLocalTransform(),
|
|
|
|
|
left.size());
|
2015-06-26 18:21:32 -04:00
|
|
|
data = SensorData(left, right, model, this->getNextSeqID(), UTimer::now());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
UERROR("CameraStereoFlyCapture2: RTAB-Map is not built with Triclops support!");
|
|
|
|
|
#endif
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-31 19:09:49 -04:00
|
|
|
//
|
|
|
|
|
// CameraStereoZED
|
|
|
|
|
//
|
|
|
|
|
bool CameraStereoZed::available()
|
|
|
|
|
{
|
|
|
|
|
#ifdef RTABMAP_ZED
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-02 17:27:12 -04:00
|
|
|
CameraStereoZed::CameraStereoZed(
|
|
|
|
|
int deviceId,
|
|
|
|
|
int resolution,
|
|
|
|
|
int quality,
|
|
|
|
|
int sensingMode,
|
|
|
|
|
int confidenceThr,
|
2016-06-24 18:49:34 -04:00
|
|
|
bool computeOdometry,
|
2016-06-02 17:27:12 -04:00
|
|
|
float imageRate,
|
2016-10-25 16:06:55 -04:00
|
|
|
const Transform & localTransform,
|
|
|
|
|
bool selfCalibration) :
|
2016-12-02 12:29:38 -05:00
|
|
|
Camera(imageRate, localTransform)
|
|
|
|
|
#ifdef RTABMAP_ZED
|
|
|
|
|
,
|
2016-06-02 17:27:12 -04:00
|
|
|
zed_(0),
|
|
|
|
|
src_(CameraVideo::kUsbDevice),
|
|
|
|
|
usbDevice_(deviceId),
|
|
|
|
|
svoFilePath_(""),
|
|
|
|
|
resolution_(resolution),
|
|
|
|
|
quality_(quality),
|
2016-10-25 16:06:55 -04:00
|
|
|
selfCalibration_(selfCalibration),
|
2016-06-02 17:27:12 -04:00
|
|
|
sensingMode_(sensingMode),
|
2016-06-24 18:49:34 -04:00
|
|
|
confidenceThr_(confidenceThr),
|
|
|
|
|
computeOdometry_(computeOdometry),
|
|
|
|
|
lost_(true)
|
2016-12-02 12:29:38 -05:00
|
|
|
#endif
|
2016-05-31 19:09:49 -04:00
|
|
|
{
|
2016-10-25 16:06:55 -04:00
|
|
|
UDEBUG("");
|
2016-06-02 17:27:12 -04:00
|
|
|
#ifdef RTABMAP_ZED
|
2017-04-18 15:03:10 +09:00
|
|
|
UASSERT(resolution_ >= sl::RESOLUTION_HD2K && resolution_ <sl::RESOLUTION_LAST);
|
|
|
|
|
UASSERT(quality_ >= sl::DEPTH_MODE_NONE && quality_ <sl::DEPTH_MODE_LAST);
|
2017-04-18 20:16:04 -04:00
|
|
|
UASSERT(sensingMode_ >= sl::SENSING_MODE_STANDARD && sensingMode_ <sl::SENSING_MODE_LAST);
|
2016-06-02 17:27:12 -04:00
|
|
|
UASSERT(confidenceThr_ >= 0 && confidenceThr_ <=100);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoZed::CameraStereoZed(
|
|
|
|
|
const std::string & filePath,
|
|
|
|
|
int quality,
|
|
|
|
|
int sensingMode,
|
|
|
|
|
int confidenceThr,
|
2016-06-24 18:49:34 -04:00
|
|
|
bool computeOdometry,
|
2016-06-02 17:27:12 -04:00
|
|
|
float imageRate,
|
2016-10-25 16:06:55 -04:00
|
|
|
const Transform & localTransform,
|
|
|
|
|
bool selfCalibration) :
|
2016-12-02 12:29:38 -05:00
|
|
|
Camera(imageRate, localTransform)
|
|
|
|
|
#ifdef RTABMAP_ZED
|
|
|
|
|
,
|
2016-06-02 17:27:12 -04:00
|
|
|
zed_(0),
|
|
|
|
|
src_(CameraVideo::kVideoFile),
|
|
|
|
|
usbDevice_(0),
|
|
|
|
|
svoFilePath_(filePath),
|
|
|
|
|
resolution_(2),
|
|
|
|
|
quality_(quality),
|
2016-10-25 16:06:55 -04:00
|
|
|
selfCalibration_(selfCalibration),
|
2016-06-02 17:27:12 -04:00
|
|
|
sensingMode_(sensingMode),
|
2016-06-24 18:49:34 -04:00
|
|
|
confidenceThr_(confidenceThr),
|
|
|
|
|
computeOdometry_(computeOdometry),
|
|
|
|
|
lost_(true)
|
2016-12-02 12:29:38 -05:00
|
|
|
#endif
|
2016-06-02 17:27:12 -04:00
|
|
|
{
|
2016-10-25 16:06:55 -04:00
|
|
|
UDEBUG("");
|
2016-06-02 17:27:12 -04:00
|
|
|
#ifdef RTABMAP_ZED
|
2017-04-18 15:03:10 +09:00
|
|
|
UASSERT(resolution_ >= sl::RESOLUTION_HD2K && resolution_ <sl::RESOLUTION_LAST);
|
|
|
|
|
UASSERT(quality_ >= sl::DEPTH_MODE_NONE && quality_ <sl::DEPTH_MODE_LAST);
|
2017-05-09 09:02:02 -04:00
|
|
|
UASSERT(sensingMode_ >= sl::SENSING_MODE_STANDARD && sensingMode_ <sl::SENSING_MODE_LAST);
|
2016-06-02 17:27:12 -04:00
|
|
|
UASSERT(confidenceThr_ >= 0 && confidenceThr_ <=100);
|
|
|
|
|
#endif
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoZed::~CameraStereoZed()
|
|
|
|
|
{
|
|
|
|
|
#ifdef RTABMAP_ZED
|
|
|
|
|
if(zed_)
|
|
|
|
|
{
|
|
|
|
|
delete zed_;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoZed::init(const std::string & calibrationFolder, const std::string & cameraName)
|
|
|
|
|
{
|
2016-10-25 16:06:55 -04:00
|
|
|
UDEBUG("");
|
2016-05-31 19:09:49 -04:00
|
|
|
#ifdef RTABMAP_ZED
|
|
|
|
|
if(zed_)
|
|
|
|
|
{
|
|
|
|
|
delete zed_;
|
|
|
|
|
zed_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-24 18:49:34 -04:00
|
|
|
lost_ = true;
|
2017-05-09 15:46:47 -04:00
|
|
|
|
|
|
|
|
sl::InitParameters param;
|
|
|
|
|
param.camera_resolution=static_cast<sl::RESOLUTION>(resolution_);
|
|
|
|
|
param.camera_fps=getImageRate();
|
|
|
|
|
param.camera_linux_id=usbDevice_;
|
|
|
|
|
param.depth_mode=(sl::DEPTH_MODE)quality_;
|
|
|
|
|
param.coordinate_units=sl::UNIT_METER;
|
|
|
|
|
param.coordinate_system=(sl::COORDINATE_SYSTEM)sl::COORDINATE_SYSTEM_IMAGE ;
|
|
|
|
|
param.sdk_verbose=false;
|
|
|
|
|
param.sdk_gpu_id=-1;
|
|
|
|
|
param.depth_minimum_distance=-1;
|
|
|
|
|
param.camera_disable_self_calib=!selfCalibration_;
|
|
|
|
|
|
2017-07-31 14:11:32 -04:00
|
|
|
sl::ERROR_CODE r = sl::ERROR_CODE::SUCCESS;
|
2016-06-02 17:27:12 -04:00
|
|
|
if(src_ == CameraVideo::kVideoFile)
|
2016-05-31 19:09:49 -04:00
|
|
|
{
|
2016-10-25 16:06:55 -04:00
|
|
|
UINFO("svo file = %s", svoFilePath_.c_str());
|
2017-04-18 15:03:10 +09:00
|
|
|
zed_ = new sl::Camera(); // Use in SVO playback mode
|
|
|
|
|
param.svo_input_filename=svoFilePath_.c_str();
|
2017-07-31 14:11:32 -04:00
|
|
|
r = zed_->open(param);
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-10-25 16:06:55 -04:00
|
|
|
UINFO("Resolution=%d imagerate=%f device=%d", resolution_, getImageRate(), usbDevice_);
|
2017-04-18 15:03:10 +09:00
|
|
|
zed_ = new sl::Camera(); // Use in Live Mode
|
2017-07-31 14:11:32 -04:00
|
|
|
r = zed_->open(param);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(r!=sl::ERROR_CODE::SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
UERROR("Camera initialization failed: \"%s\"", errorCode2str(r).c_str());
|
|
|
|
|
delete zed_;
|
|
|
|
|
zed_ = 0;
|
|
|
|
|
return false;
|
2016-06-02 17:27:12 -04:00
|
|
|
}
|
|
|
|
|
|
2016-10-25 16:06:55 -04:00
|
|
|
|
|
|
|
|
UINFO("Init ZED: Mode=%d Unit=%d CoordinateSystem=%d Verbose=false device=-1 minDist=-1 self-calibration=%s vflip=false",
|
2017-04-18 15:03:10 +09:00
|
|
|
quality_, sl::UNIT_METER, sl::COORDINATE_SYSTEM_IMAGE , selfCalibration_?"true":"false");
|
2016-10-25 16:06:55 -04:00
|
|
|
UDEBUG("");
|
2016-06-02 17:27:12 -04:00
|
|
|
|
|
|
|
|
zed_->setConfidenceThreshold(confidenceThr_);
|
|
|
|
|
|
2016-06-24 18:49:34 -04:00
|
|
|
if (computeOdometry_)
|
|
|
|
|
{
|
2017-04-18 15:03:10 +09:00
|
|
|
sl::TrackingParameters tparam;
|
|
|
|
|
tparam.enable_spatial_memory=false;
|
|
|
|
|
zed_->enableTracking(tparam);
|
2016-06-24 18:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
2017-04-18 15:03:10 +09:00
|
|
|
sl::CameraInformation infos = zed_->getCameraInformation();
|
|
|
|
|
sl::CalibrationParameters *stereoParams = &(infos.calibration_parameters );
|
|
|
|
|
sl::Resolution res = stereoParams->left_cam.image_size;
|
2016-05-31 19:09:49 -04:00
|
|
|
|
|
|
|
|
stereoModel_ = StereoCameraModel(
|
2017-04-18 15:03:10 +09:00
|
|
|
stereoParams->left_cam.fx,
|
|
|
|
|
stereoParams->left_cam.fy,
|
|
|
|
|
stereoParams->left_cam.cx,
|
|
|
|
|
stereoParams->left_cam.cy,
|
|
|
|
|
stereoParams->T[0],//baseline
|
2016-05-31 19:09:49 -04:00
|
|
|
this->getLocalTransform(),
|
|
|
|
|
cv::Size(res.width, res.height));
|
|
|
|
|
|
2017-04-18 20:16:04 -04:00
|
|
|
UINFO("Calibration: fx=%f, fy=%f, cx=%f, cy=%f, baseline=%f, width=%d, height=%d, transform=%s",
|
|
|
|
|
stereoParams->left_cam.fx,
|
|
|
|
|
stereoParams->left_cam.fy,
|
|
|
|
|
stereoParams->left_cam.cx,
|
|
|
|
|
stereoParams->left_cam.cy,
|
|
|
|
|
stereoParams->T[0],//baseline
|
|
|
|
|
(int)res.width,
|
|
|
|
|
(int)res.height,
|
|
|
|
|
this->getLocalTransform().prettyPrint().c_str());
|
|
|
|
|
|
2016-05-31 19:09:49 -04:00
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
UERROR("CameraStereoZED: RTAB-Map is not built with ZED sdk support!");
|
|
|
|
|
#endif
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoZed::isCalibrated() const
|
|
|
|
|
{
|
2016-12-02 12:29:38 -05:00
|
|
|
#ifdef RTABMAP_ZED
|
2016-05-31 19:09:49 -04:00
|
|
|
return stereoModel_.isValidForProjection();
|
2016-12-02 12:29:38 -05:00
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CameraStereoZed::getSerial() const
|
|
|
|
|
{
|
|
|
|
|
#ifdef RTABMAP_ZED
|
|
|
|
|
if(zed_)
|
|
|
|
|
{
|
2017-04-18 15:03:10 +09:00
|
|
|
return uFormat("%x", zed_->getCameraInformation ().serial_number);
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return "";
|
2016-12-02 12:29:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoZed::odomProvided() const
|
|
|
|
|
{
|
|
|
|
|
#ifdef RTABMAP_ZED
|
|
|
|
|
return computeOdometry_;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
2017-04-18 15:03:10 +09:00
|
|
|
#ifdef RTABMAP_ZED
|
|
|
|
|
static cv::Mat slMat2cvMat(sl::Mat& input) {
|
|
|
|
|
//convert MAT_TYPE to CV_TYPE
|
|
|
|
|
int cv_type = -1;
|
|
|
|
|
switch (input.getDataType()) {
|
|
|
|
|
case sl::MAT_TYPE_32F_C1: cv_type = CV_32FC1; break;
|
|
|
|
|
case sl::MAT_TYPE_32F_C2: cv_type = CV_32FC2; break;
|
|
|
|
|
case sl::MAT_TYPE_32F_C3: cv_type = CV_32FC3; break;
|
|
|
|
|
case sl::MAT_TYPE_32F_C4: cv_type = CV_32FC4; break;
|
|
|
|
|
case sl::MAT_TYPE_8U_C1: cv_type = CV_8UC1; break;
|
|
|
|
|
case sl::MAT_TYPE_8U_C2: cv_type = CV_8UC2; break;
|
|
|
|
|
case sl::MAT_TYPE_8U_C3: cv_type = CV_8UC3; break;
|
|
|
|
|
case sl::MAT_TYPE_8U_C4: cv_type = CV_8UC4; break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
// cv::Mat data requires a uchar* pointer. Therefore, we get the uchar1 pointer from sl::Mat (getPtr<T>())
|
|
|
|
|
//cv::Mat and sl::Mat will share the same memory pointer
|
|
|
|
|
return cv::Mat(input.getHeight(), input.getWidth(), cv_type, input.getPtr<sl::uchar1>(sl::MEM_CPU));
|
|
|
|
|
}
|
2016-05-31 19:09:49 -04:00
|
|
|
|
2017-04-18 20:16:04 -04:00
|
|
|
Transform zedPoseToTransform(const sl::Pose & pose)
|
|
|
|
|
{
|
|
|
|
|
return Transform(
|
|
|
|
|
pose.pose_data.m[0], pose.pose_data.m[1], pose.pose_data.m[2], pose.pose_data.m[3],
|
|
|
|
|
pose.pose_data.m[4], pose.pose_data.m[5], pose.pose_data.m[6], pose.pose_data.m[7],
|
|
|
|
|
pose.pose_data.m[8], pose.pose_data.m[9], pose.pose_data.m[10], pose.pose_data.m[11]);
|
|
|
|
|
}
|
2017-04-18 20:22:05 -04:00
|
|
|
#endif
|
2017-04-18 20:16:04 -04:00
|
|
|
|
2016-06-21 11:22:24 -04:00
|
|
|
SensorData CameraStereoZed::captureImage(CameraInfo * info)
|
2016-05-31 19:09:49 -04:00
|
|
|
{
|
|
|
|
|
SensorData data;
|
|
|
|
|
#ifdef RTABMAP_ZED
|
2017-04-18 15:03:10 +09:00
|
|
|
sl::RuntimeParameters rparam;
|
|
|
|
|
rparam.sensing_mode=(sl::SENSING_MODE)sensingMode_;
|
|
|
|
|
rparam.enable_depth=quality_ > 0;
|
|
|
|
|
rparam.enable_point_cloud=quality_ > 0;
|
|
|
|
|
rparam.move_point_cloud_to_world_frame=false;
|
2016-05-31 19:09:49 -04:00
|
|
|
if(zed_)
|
|
|
|
|
{
|
2016-06-04 15:17:13 -04:00
|
|
|
UTimer timer;
|
2017-04-18 15:03:10 +09:00
|
|
|
bool res = zed_->grab(rparam);
|
2016-06-04 15:17:13 -04:00
|
|
|
while (src_ == CameraVideo::kUsbDevice && res && timer.elapsed() < 2.0)
|
|
|
|
|
{
|
|
|
|
|
// maybe there is a latency with the USB, try again in 10 ms (for the next 2 seconds)
|
|
|
|
|
uSleep(10);
|
2017-04-18 15:03:10 +09:00
|
|
|
res = zed_->grab(rparam);
|
2016-06-04 15:17:13 -04:00
|
|
|
}
|
2016-05-31 19:09:49 -04:00
|
|
|
if(!res)
|
|
|
|
|
{
|
|
|
|
|
// get left image
|
2017-04-18 15:03:10 +09:00
|
|
|
sl::Mat tmp;zed_->retrieveImage(tmp,sl::VIEW_LEFT);
|
|
|
|
|
cv::Mat rgbaLeft = slMat2cvMat(tmp);
|
2016-08-31 11:37:27 -04:00
|
|
|
|
2016-05-31 19:09:49 -04:00
|
|
|
cv::Mat left;
|
|
|
|
|
cv::cvtColor(rgbaLeft, left, cv::COLOR_BGRA2BGR);
|
|
|
|
|
|
2016-06-02 17:27:12 -04:00
|
|
|
if(quality_ > 0)
|
2016-05-31 19:09:49 -04:00
|
|
|
{
|
|
|
|
|
// get depth image
|
|
|
|
|
cv::Mat depth;
|
2017-04-18 15:03:10 +09:00
|
|
|
sl::Mat tmp;
|
|
|
|
|
zed_->retrieveMeasure(tmp,sl::MEASURE_DEPTH);
|
|
|
|
|
slMat2cvMat(tmp).copyTo(depth);
|
2016-05-31 19:09:49 -04:00
|
|
|
|
|
|
|
|
data = SensorData(left, depth, stereoModel_.left(), this->getNextSeqID(), UTimer::now());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// get right image
|
2017-04-18 15:03:10 +09:00
|
|
|
sl::Mat tmp;zed_->retrieveImage(tmp,sl::VIEW_RIGHT );
|
|
|
|
|
cv::Mat rgbaRight = slMat2cvMat(tmp);
|
2016-05-31 19:09:49 -04:00
|
|
|
cv::Mat right;
|
|
|
|
|
cv::cvtColor(rgbaRight, right, cv::COLOR_BGRA2GRAY);
|
|
|
|
|
|
|
|
|
|
data = SensorData(left, right, stereoModel_, this->getNextSeqID(), UTimer::now());
|
|
|
|
|
}
|
2016-06-24 18:49:34 -04:00
|
|
|
|
|
|
|
|
if (computeOdometry_ && info)
|
|
|
|
|
{
|
2017-04-18 15:03:10 +09:00
|
|
|
sl::Pose pose;
|
|
|
|
|
zed_->getPosition(pose);
|
|
|
|
|
int trackingConfidence = pose.pose_confidence;
|
2017-05-18 17:32:00 -04:00
|
|
|
// FIXME What does pose_confidence == -1 mean?
|
|
|
|
|
if (trackingConfidence>0)
|
2016-06-24 18:49:34 -04:00
|
|
|
{
|
2017-04-18 20:16:04 -04:00
|
|
|
info->odomPose = zedPoseToTransform(pose);
|
2016-06-24 18:49:34 -04:00
|
|
|
if (!info->odomPose.isNull())
|
|
|
|
|
{
|
|
|
|
|
//transform x->forward, y->left, z->up
|
|
|
|
|
Transform opticalTransform(0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0);
|
|
|
|
|
info->odomPose = opticalTransform * info->odomPose * opticalTransform.inverse();
|
2017-05-18 17:32:00 -04:00
|
|
|
|
|
|
|
|
if (lost_)
|
|
|
|
|
{
|
|
|
|
|
info->odomCovariance = cv::Mat::eye(6, 6, CV_64FC1) * 9999.0f; // don't know transform with previous pose
|
|
|
|
|
lost_ = false;
|
|
|
|
|
UDEBUG("Init %s (var=%f)", info->odomPose.prettyPrint().c_str(), 9999.0f);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
info->odomCovariance = cv::Mat::eye(6, 6, CV_64FC1) * 1.0f / float(trackingConfidence);
|
|
|
|
|
UDEBUG("Run %s (var=%f)", info->odomPose.prettyPrint().c_str(), 1.0f / float(trackingConfidence));
|
|
|
|
|
}
|
2016-06-24 18:49:34 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-05-18 17:32:00 -04:00
|
|
|
info->odomCovariance = cv::Mat::eye(6, 6, CV_64FC1) * 9999.0f; // lost
|
|
|
|
|
lost_ = true;
|
|
|
|
|
UWARN("ZED lost! (trackingConfidence=%d)", trackingConfidence);
|
2016-06-24 18:49:34 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
info->odomCovariance = cv::Mat::eye(6, 6, CV_64FC1) * 9999.0f; // lost
|
|
|
|
|
lost_ = true;
|
2017-05-18 17:32:00 -04:00
|
|
|
UWARN("ZED lost! (trackingConfidence=%d)", trackingConfidence);
|
2016-06-24 18:49:34 -04:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
2016-06-02 17:27:12 -04:00
|
|
|
else if(src_ == CameraVideo::kUsbDevice)
|
2016-05-31 19:09:49 -04:00
|
|
|
{
|
2016-06-04 15:17:13 -04:00
|
|
|
UERROR("CameraStereoZed: Failed to grab images after 2 seconds!");
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
2016-06-02 17:27:12 -04:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UWARN("CameraStereoZed: end of stream is reached!");
|
|
|
|
|
}
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
UERROR("CameraStereoZED: RTAB-Map is not built with ZED sdk support!");
|
|
|
|
|
#endif
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-06-26 18:21:32 -04:00
|
|
|
//
|
|
|
|
|
// CameraStereoImages
|
|
|
|
|
//
|
|
|
|
|
bool CameraStereoImages::available()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoImages::CameraStereoImages(
|
2015-07-30 14:17:29 -04:00
|
|
|
const std::string & pathLeftImages,
|
|
|
|
|
const std::string & pathRightImages,
|
2015-07-16 14:44:25 -04:00
|
|
|
bool rectifyImages,
|
2015-06-26 18:21:32 -04:00
|
|
|
float imageRate,
|
|
|
|
|
const Transform & localTransform) :
|
2015-12-17 14:13:19 -05:00
|
|
|
CameraImages(pathLeftImages, imageRate, localTransform),
|
|
|
|
|
camera2_(new CameraImages(pathRightImages))
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
2015-12-17 14:13:19 -05:00
|
|
|
this->setImagesRectified(rectifyImages);
|
2015-07-30 14:17:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoImages::CameraStereoImages(
|
|
|
|
|
const std::string & pathLeftRightImages,
|
|
|
|
|
bool rectifyImages,
|
|
|
|
|
float imageRate,
|
|
|
|
|
const Transform & localTransform) :
|
2015-12-17 14:13:19 -05:00
|
|
|
CameraImages("", imageRate, localTransform),
|
|
|
|
|
camera2_(0)
|
2015-07-30 14:17:29 -04:00
|
|
|
{
|
|
|
|
|
std::vector<std::string> paths = uListToVector(uSplit(pathLeftRightImages, uStrContains(pathLeftRightImages, ":")?':':';'));
|
2015-06-26 18:21:32 -04:00
|
|
|
if(paths.size() >= 1)
|
|
|
|
|
{
|
2015-12-17 14:13:19 -05:00
|
|
|
this->setPath(paths[0]);
|
|
|
|
|
this->setImagesRectified(rectifyImages);
|
2015-06-26 18:21:32 -04:00
|
|
|
|
|
|
|
|
if(paths.size() >= 2)
|
|
|
|
|
{
|
|
|
|
|
camera2_ = new CameraImages(paths[1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UERROR("The path is empty!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoImages::~CameraStereoImages()
|
|
|
|
|
{
|
2015-12-17 14:13:19 -05:00
|
|
|
UDEBUG("");
|
2015-06-26 18:21:32 -04:00
|
|
|
if(camera2_)
|
|
|
|
|
{
|
|
|
|
|
delete camera2_;
|
|
|
|
|
}
|
2015-12-17 14:13:19 -05:00
|
|
|
UDEBUG("");
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoImages::init(const std::string & calibrationFolder, const std::string & cameraName)
|
|
|
|
|
{
|
|
|
|
|
// look for calibration files
|
|
|
|
|
if(!calibrationFolder.empty() && !cameraName.empty())
|
|
|
|
|
{
|
|
|
|
|
if(!stereoModel_.load(calibrationFolder, cameraName))
|
|
|
|
|
{
|
|
|
|
|
UWARN("Missing calibration files for camera \"%s\" in \"%s\" folder, you should calibrate the camera!",
|
|
|
|
|
cameraName.c_str(), calibrationFolder.c_str());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UINFO("Stereo parameters: fx=%f cx=%f cy=%f baseline=%f",
|
|
|
|
|
stereoModel_.left().fx(),
|
|
|
|
|
stereoModel_.left().cx(),
|
|
|
|
|
stereoModel_.left().cy(),
|
|
|
|
|
stereoModel_.baseline());
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-22 18:08:32 -05:00
|
|
|
|
2015-07-16 14:44:25 -04:00
|
|
|
stereoModel_.setLocalTransform(this->getLocalTransform());
|
2015-12-17 14:13:19 -05:00
|
|
|
stereoModel_.setName(cameraName);
|
2016-01-19 17:43:33 -05:00
|
|
|
if(this->isImagesRectified() && !stereoModel_.isValidForRectification())
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
|
|
|
|
UERROR("Parameter \"rectifyImages\" is set, but no stereo model is loaded or valid.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-17 14:13:19 -05:00
|
|
|
//desactivate before init as we will do it in this class instead for convenience
|
2016-01-04 12:45:20 -05:00
|
|
|
bool rectify = this->isImagesRectified();
|
2015-12-17 14:13:19 -05:00
|
|
|
this->setImagesRectified(false);
|
|
|
|
|
|
2015-06-26 18:21:32 -04:00
|
|
|
bool success = false;
|
2015-12-17 14:13:19 -05:00
|
|
|
if(CameraImages::init())
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
|
|
|
|
if(camera2_)
|
|
|
|
|
{
|
2016-01-19 17:43:33 -05:00
|
|
|
camera2_->setBayerMode(this->getBayerMode());
|
2015-06-26 18:21:32 -04:00
|
|
|
if(camera2_->init())
|
|
|
|
|
{
|
2015-12-17 14:13:19 -05:00
|
|
|
if(this->imagesCount() == camera2_->imagesCount())
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
|
|
|
|
success = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UERROR("Cameras don't have the same number of images (%d vs %d)",
|
2015-12-17 14:13:19 -05:00
|
|
|
this->imagesCount(), camera2_->imagesCount());
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UERROR("Cannot initialize the second camera.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
success = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-04 12:45:20 -05:00
|
|
|
this->setImagesRectified(rectify); // reset the flag
|
2015-06-26 18:21:32 -04:00
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoImages::isCalibrated() const
|
|
|
|
|
{
|
2016-01-19 21:01:56 -05:00
|
|
|
return stereoModel_.isValidForProjection();
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CameraStereoImages::getSerial() const
|
|
|
|
|
{
|
2015-12-17 14:13:19 -05:00
|
|
|
return stereoModel_.name();
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
|
|
|
|
|
2016-06-21 11:22:24 -04:00
|
|
|
SensorData CameraStereoImages::captureImage(CameraInfo * info)
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
|
|
|
|
SensorData data;
|
2015-12-17 14:13:19 -05:00
|
|
|
|
|
|
|
|
SensorData left, right;
|
2016-06-21 11:22:24 -04:00
|
|
|
left = CameraImages::captureImage(info);
|
2015-12-17 14:13:19 -05:00
|
|
|
if(!left.imageRaw().empty())
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
2015-12-17 14:13:19 -05:00
|
|
|
if(camera2_)
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
2016-06-21 11:22:24 -04:00
|
|
|
right = camera2_->takeImage(info);
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-06-21 11:22:24 -04:00
|
|
|
right = this->takeImage(info);
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
|
|
|
|
|
2015-12-17 14:13:19 -05:00
|
|
|
if(!right.imageRaw().empty())
|
|
|
|
|
{
|
|
|
|
|
// Rectification
|
|
|
|
|
cv::Mat leftImage = left.imageRaw();
|
|
|
|
|
cv::Mat rightImage = right.imageRaw();
|
|
|
|
|
if(rightImage.type() != CV_8UC1)
|
2015-06-26 18:21:32 -04:00
|
|
|
{
|
2015-12-17 14:13:19 -05:00
|
|
|
cv::Mat tmp;
|
|
|
|
|
cv::cvtColor(rightImage, tmp, CV_BGR2GRAY);
|
|
|
|
|
rightImage = tmp;
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
2016-01-19 17:43:33 -05:00
|
|
|
if(this->isImagesRectified() && stereoModel_.isValidForRectification())
|
2015-12-17 14:13:19 -05:00
|
|
|
{
|
|
|
|
|
leftImage = stereoModel_.left().rectifyImage(leftImage);
|
|
|
|
|
rightImage = stereoModel_.right().rectifyImage(rightImage);
|
|
|
|
|
}
|
2016-01-19 17:43:33 -05:00
|
|
|
|
2016-03-10 09:07:44 -05:00
|
|
|
if(stereoModel_.left().imageHeight() == 0 || stereoModel_.left().imageWidth() == 0)
|
|
|
|
|
{
|
|
|
|
|
stereoModel_.setImageSize(leftImage.size());
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-21 19:33:01 -04:00
|
|
|
data = SensorData(left.laserScanRaw(), left.laserScanInfo(), leftImage, rightImage, stereoModel_, left.id()/(camera2_?1:2), left.stamp());
|
2015-12-17 14:13:19 -05:00
|
|
|
data.setGroundTruth(left.groundTruth());
|
2015-06-26 18:21:32 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-16 14:44:25 -04:00
|
|
|
//
|
|
|
|
|
// CameraStereoVideo
|
|
|
|
|
//
|
|
|
|
|
bool CameraStereoVideo::available()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoVideo::CameraStereoVideo(
|
|
|
|
|
const std::string & path,
|
|
|
|
|
bool rectifyImages,
|
|
|
|
|
float imageRate,
|
|
|
|
|
const Transform & localTransform) :
|
|
|
|
|
Camera(imageRate, localTransform),
|
|
|
|
|
path_(path),
|
2016-05-31 19:09:49 -04:00
|
|
|
rectifyImages_(rectifyImages),
|
|
|
|
|
src_(CameraVideo::kVideoFile),
|
|
|
|
|
usbDevice_(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-11 12:45:12 -04:00
|
|
|
CameraStereoVideo::CameraStereoVideo(
|
|
|
|
|
const std::string & pathLeft,
|
|
|
|
|
const std::string & pathRight,
|
|
|
|
|
bool rectifyImages,
|
|
|
|
|
float imageRate,
|
|
|
|
|
const Transform & localTransform) :
|
|
|
|
|
Camera(imageRate, localTransform),
|
|
|
|
|
path_(pathLeft),
|
|
|
|
|
path2_(pathRight),
|
|
|
|
|
rectifyImages_(rectifyImages),
|
|
|
|
|
src_(CameraVideo::kVideoFile),
|
|
|
|
|
usbDevice_(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-31 19:09:49 -04:00
|
|
|
CameraStereoVideo::CameraStereoVideo(
|
|
|
|
|
int device,
|
2016-06-15 11:30:05 -04:00
|
|
|
bool rectifyImages,
|
2016-05-31 19:09:49 -04:00
|
|
|
float imageRate,
|
|
|
|
|
const Transform & localTransform) :
|
|
|
|
|
Camera(imageRate, localTransform),
|
2016-06-15 11:30:05 -04:00
|
|
|
rectifyImages_(rectifyImages),
|
2016-05-31 19:09:49 -04:00
|
|
|
src_(CameraVideo::kUsbDevice),
|
|
|
|
|
usbDevice_(device)
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CameraStereoVideo::~CameraStereoVideo()
|
|
|
|
|
{
|
|
|
|
|
capture_.release();
|
2016-09-11 12:45:12 -04:00
|
|
|
capture2_.release();
|
2015-07-16 14:44:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoVideo::init(const std::string & calibrationFolder, const std::string & cameraName)
|
|
|
|
|
{
|
2016-05-31 19:09:49 -04:00
|
|
|
cameraName_ = cameraName;
|
2015-07-16 14:44:25 -04:00
|
|
|
if(capture_.isOpened())
|
|
|
|
|
{
|
|
|
|
|
capture_.release();
|
|
|
|
|
}
|
2016-09-11 12:45:12 -04:00
|
|
|
if(capture2_.isOpened())
|
|
|
|
|
{
|
|
|
|
|
capture2_.release();
|
|
|
|
|
}
|
2016-05-31 19:09:49 -04:00
|
|
|
|
|
|
|
|
if (src_ == CameraVideo::kUsbDevice)
|
|
|
|
|
{
|
|
|
|
|
ULOGGER_DEBUG("CameraStereoVideo: Usb device initialization on device %d", usbDevice_);
|
|
|
|
|
capture_.open(usbDevice_);
|
|
|
|
|
}
|
|
|
|
|
else if (src_ == CameraVideo::kVideoFile)
|
|
|
|
|
{
|
2016-09-11 12:45:12 -04:00
|
|
|
if(path2_.empty())
|
|
|
|
|
{
|
|
|
|
|
ULOGGER_DEBUG("CameraStereoVideo: filename=\"%s\"", path_.c_str());
|
|
|
|
|
capture_.open(path_.c_str());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ULOGGER_DEBUG("CameraStereoVideo: filenames=\"%s\" and \"%s\"", path_.c_str(), path2_.c_str());
|
|
|
|
|
capture_.open(path_.c_str());
|
|
|
|
|
capture2_.open(path2_.c_str());
|
|
|
|
|
}
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ULOGGER_ERROR("CameraStereoVideo: Unknown source...");
|
|
|
|
|
}
|
2015-07-16 14:44:25 -04:00
|
|
|
|
2016-09-11 12:45:12 -04:00
|
|
|
if(!capture_.isOpened() || (!path2_.empty() && !capture2_.isOpened()))
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
2016-05-31 19:09:49 -04:00
|
|
|
ULOGGER_ERROR("CameraStereoVideo: Failed to create a capture object!");
|
2015-07-16 14:44:25 -04:00
|
|
|
capture_.release();
|
2016-09-11 12:45:12 -04:00
|
|
|
capture2_.release();
|
2015-07-16 14:44:25 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
2016-09-11 12:45:12 -04:00
|
|
|
|
|
|
|
|
if (cameraName_.empty())
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
2016-09-11 12:45:12 -04:00
|
|
|
unsigned int guid = (unsigned int)capture_.get(CV_CAP_PROP_GUID);
|
|
|
|
|
if (guid != 0 && guid != 0xffffffff)
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
2016-09-11 12:45:12 -04:00
|
|
|
cameraName_ = uFormat("%08x", guid);
|
2016-05-31 19:09:49 -04:00
|
|
|
}
|
2016-09-11 12:45:12 -04:00
|
|
|
}
|
2016-05-31 19:09:49 -04:00
|
|
|
|
2016-09-11 12:45:12 -04:00
|
|
|
// look for calibration files
|
|
|
|
|
if(!calibrationFolder.empty() && !cameraName_.empty())
|
|
|
|
|
{
|
|
|
|
|
if(!stereoModel_.load(calibrationFolder, cameraName_))
|
2016-05-31 19:09:49 -04:00
|
|
|
{
|
2016-09-11 12:45:12 -04:00
|
|
|
UWARN("Missing calibration files for camera \"%s\" in \"%s\" folder, you should calibrate the camera!",
|
|
|
|
|
cameraName_.c_str(), calibrationFolder.c_str());
|
2015-07-16 14:44:25 -04:00
|
|
|
}
|
2016-09-11 12:45:12 -04:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UINFO("Stereo parameters: fx=%f cx=%f cy=%f baseline=%f",
|
|
|
|
|
stereoModel_.left().fx(),
|
|
|
|
|
stereoModel_.left().cx(),
|
|
|
|
|
stereoModel_.left().cy(),
|
|
|
|
|
stereoModel_.baseline());
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-22 18:08:32 -05:00
|
|
|
|
2016-09-11 12:45:12 -04:00
|
|
|
stereoModel_.setLocalTransform(this->getLocalTransform());
|
|
|
|
|
if(rectifyImages_ && !stereoModel_.isValidForRectification())
|
|
|
|
|
{
|
|
|
|
|
UERROR("Parameter \"rectifyImages\" is set, but no stereo model is loaded or valid.");
|
|
|
|
|
return false;
|
2015-07-16 14:44:25 -04:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CameraStereoVideo::isCalibrated() const
|
|
|
|
|
{
|
2016-01-19 21:01:56 -05:00
|
|
|
return stereoModel_.isValidForProjection();
|
2015-07-16 14:44:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CameraStereoVideo::getSerial() const
|
|
|
|
|
{
|
|
|
|
|
return cameraName_;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-21 11:22:24 -04:00
|
|
|
SensorData CameraStereoVideo::captureImage(CameraInfo * info)
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
|
|
|
|
SensorData data;
|
|
|
|
|
|
|
|
|
|
cv::Mat img;
|
2016-09-11 12:45:12 -04:00
|
|
|
if(capture_.isOpened() && (path2_.empty() || capture2_.isOpened()))
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
2016-09-11 12:45:12 -04:00
|
|
|
cv::Mat leftImage;
|
|
|
|
|
cv::Mat rightImage;
|
|
|
|
|
if(path2_.empty())
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
2016-09-11 12:45:12 -04:00
|
|
|
if(!capture_.read(img))
|
2015-07-16 14:44:25 -04:00
|
|
|
{
|
2016-09-11 12:45:12 -04:00
|
|
|
return data;
|
2015-07-16 14:44:25 -04:00
|
|
|
}
|
2016-09-11 12:45:12 -04:00
|
|
|
// Side by side stream
|
|
|
|
|
leftImage = cv::Mat(img, cv::Rect( 0, 0, img.size().width/2, img.size().height ));
|
|
|
|
|
rightImage = cv::Mat(img, cv::Rect( img.size().width/2, 0, img.size().width/2, img.size().height ));
|
2015-07-16 14:44:25 -04:00
|
|
|
}
|
2016-09-11 12:45:12 -04:00
|
|
|
else if(!capture_.read(leftImage) || !capture2_.read(rightImage))
|
|
|
|
|
{
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
else if(leftImage.cols != rightImage.cols || leftImage.rows != rightImage.rows)
|
|
|
|
|
{
|
|
|
|
|
UERROR("Left and right streams don't have image of the same size: left=%dx%d right=%dx%d",
|
|
|
|
|
leftImage.cols, leftImage.rows, rightImage.cols, rightImage.rows);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rectification
|
|
|
|
|
bool rightCvt = false;
|
|
|
|
|
if(rightImage.type() != CV_8UC1)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat tmp;
|
|
|
|
|
cv::cvtColor(rightImage, tmp, CV_BGR2GRAY);
|
|
|
|
|
rightImage = tmp;
|
|
|
|
|
rightCvt = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(rectifyImages_ && stereoModel_.left().isValidForRectification() && stereoModel_.right().isValidForRectification())
|
|
|
|
|
{
|
|
|
|
|
leftImage = stereoModel_.left().rectifyImage(leftImage);
|
|
|
|
|
rightImage = stereoModel_.right().rectifyImage(rightImage);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
leftImage = leftImage.clone();
|
|
|
|
|
if(!rightCvt)
|
|
|
|
|
{
|
|
|
|
|
rightImage = rightImage.clone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(stereoModel_.left().imageHeight() == 0 || stereoModel_.left().imageWidth() == 0)
|
|
|
|
|
{
|
|
|
|
|
stereoModel_.setImageSize(leftImage.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data = SensorData(leftImage, rightImage, stereoModel_, this->getNextSeqID(), UTimer::now());
|
2015-07-16 14:44:25 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ULOGGER_WARN("The camera must be initialized before requesting an image.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-06-26 18:21:32 -04:00
|
|
|
} // namespace rtabmap
|