Charuco calibration + depthai calibration support (#1302)

* In progress: adding charuco option

* DepthAI: added raw image publishing mode (added support rtabmap's calibration file). Calibration: working charuco board calibration (on opencv 4.5).

* fixed build with Qt<5.14

* Updated calibration options

* Removed depthai flashing delays

* depthai: fixed camera not detected as calibrated in Mono-depth mode. Calibration: added option to scale sampling factor.
This commit is contained in:
matlabbe
2024-06-30 17:11:37 -07:00
committed by GitHub
parent 2fbe31f7cb
commit f5a477f0f4
10 changed files with 1457 additions and 405 deletions
@@ -60,7 +60,7 @@ public:
void setExtendedDisparity(bool extendedDisparity); void setExtendedDisparity(bool extendedDisparity);
void setSubpixelMode(bool enabled, int fractionalBits = 3); void setSubpixelMode(bool enabled, int fractionalBits = 3);
void setCompanding(bool enabled, int width=96); void setCompanding(bool enabled, int width=96);
void setRectification(bool useSpecTranslation, float alphaScaling = 0.0f); void setRectification(bool useSpecTranslation, float alphaScaling = 0.0f, bool enabled=true);
void setIMU(bool imuPublished, bool publishInterIMU); void setIMU(bool imuPublished, bool publishInterIMU);
void setIrIntensity(float dotIntensity = 0.0f, float floodIntensity = 0.0f); void setIrIntensity(float dotIntensity = 0.0f, float floodIntensity = 0.0f);
void setDetectFeatures(int detectFeatures = 0); void setDetectFeatures(int detectFeatures = 0);
@@ -90,6 +90,7 @@ private:
int compandingWidth_; int compandingWidth_;
bool useSpecTranslation_; bool useSpecTranslation_;
float alphaScaling_; float alphaScaling_;
bool imagesRectified_;
bool imuPublished_; bool imuPublished_;
bool publishInterIMU_; bool publishInterIMU_;
float dotIntensity_; float dotIntensity_;
+9 -2
View File
@@ -182,7 +182,7 @@ std::map<int, MarkerInfo> MarkerDetector::detect(const cv::Mat & image,
{ {
if(i==0) if(i==0)
{ {
*imageWithDetections = image.clone(); *imageWithDetections = cv::Mat(image.size(), subImageWithDetections.type());
} }
if(!subImageWithDetections.empty()) if(!subImageWithDetections.empty())
{ {
@@ -363,7 +363,14 @@ std::map<int, MarkerInfo> MarkerDetector::detect(const cv::Mat & image,
if(imageWithDetections) if(imageWithDetections)
{ {
image.copyTo(*imageWithDetections); if(image.channels()==1)
{
cv::cvtColor(image, *imageWithDetections, cv::COLOR_GRAY2BGR);
}
else
{
image.copyTo(*imageWithDetections);
}
if(!ids.empty()) if(!ids.empty())
{ {
cv::aruco::drawDetectedMarkers(*imageWithDetections, corners, ids); cv::aruco::drawDetectedMarkers(*imageWithDetections, corners, ids);
+179 -54
View File
@@ -162,11 +162,12 @@ void CameraDepthAI::setCompanding(bool enabled, int width)
#endif #endif
} }
void CameraDepthAI::setRectification(bool useSpecTranslation, float alphaScaling) void CameraDepthAI::setRectification(bool useSpecTranslation, float alphaScaling, bool enabled)
{ {
#ifdef RTABMAP_DEPTHAI #ifdef RTABMAP_DEPTHAI
useSpecTranslation_ = useSpecTranslation; useSpecTranslation_ = useSpecTranslation;
alphaScaling_ = alphaScaling; alphaScaling_ = alphaScaling;
imagesRectified_ = enabled;
#else #else
UERROR("CameraDepthAI: RTAB-Map is not built with depthai-core support!"); UERROR("CameraDepthAI: RTAB-Map is not built with depthai-core support!");
#endif #endif
@@ -274,11 +275,15 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
dai::Pipeline p; dai::Pipeline p;
auto monoLeft = p.create<dai::node::MonoCamera>(); auto monoLeft = p.create<dai::node::MonoCamera>();
auto monoRight = p.create<dai::node::MonoCamera>(); auto monoRight = p.create<dai::node::MonoCamera>();
auto stereo = p.create<dai::node::StereoDepth>(); std::shared_ptr<dai::node::StereoDepth> stereo;
if(imagesRectified_)
stereo = p.create<dai::node::StereoDepth>();
std::shared_ptr<dai::node::Camera> colorCam; std::shared_ptr<dai::node::Camera> colorCam;
if(outputMode_==2) if(outputMode_==2)
{ {
colorCam = p.create<dai::node::Camera>(); colorCam = p.create<dai::node::Camera>();
if(!imagesRectified_)
colorCam->setMeshSource(dai::CameraProperties::WarpMeshSource::NONE);
if(detectFeatures_) if(detectFeatures_)
{ {
UWARN("On-device feature detectors cannot be enabled on color camera input!"); UWARN("On-device feature detectors cannot be enabled on color camera input!");
@@ -340,31 +345,34 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
} }
// StereoDepth // StereoDepth
if(outputMode_ == 2) if(stereo.get())
stereo->setDepthAlign(dai::CameraBoardSocket::CAM_A); {
else if(outputMode_ == 2)
stereo->setDepthAlign(dai::StereoDepthProperties::DepthAlign::RECTIFIED_LEFT); stereo->setDepthAlign(dai::CameraBoardSocket::CAM_A);
stereo->setExtendedDisparity(extendedDisparity_); else
stereo->setRectifyEdgeFillColor(0); // black, to better see the cutout stereo->setDepthAlign(dai::StereoDepthProperties::DepthAlign::RECTIFIED_LEFT);
stereo->enableDistortionCorrection(true); stereo->setExtendedDisparity(extendedDisparity_);
stereo->setDisparityToDepthUseSpecTranslation(useSpecTranslation_); stereo->setRectifyEdgeFillColor(0); // black, to better see the cutout
stereo->setDepthAlignmentUseSpecTranslation(useSpecTranslation_); stereo->enableDistortionCorrection(true);
if(alphaScaling_ > -1.0f) stereo->setDisparityToDepthUseSpecTranslation(useSpecTranslation_);
stereo->setAlphaScaling(alphaScaling_); stereo->setDepthAlignmentUseSpecTranslation(useSpecTranslation_);
stereo->initialConfig.setConfidenceThreshold(confThreshold_); if(alphaScaling_ > -1.0f)
stereo->initialConfig.setLeftRightCheck(lrcThreshold_>=0); stereo->setAlphaScaling(alphaScaling_);
if(lrcThreshold_>=0) stereo->initialConfig.setConfidenceThreshold(confThreshold_);
stereo->initialConfig.setLeftRightCheckThreshold(lrcThreshold_); stereo->initialConfig.setLeftRightCheck(lrcThreshold_>=0);
stereo->initialConfig.setMedianFilter(dai::MedianFilter::KERNEL_7x7); if(lrcThreshold_>=0)
auto config = stereo->initialConfig.get(); stereo->initialConfig.setLeftRightCheckThreshold(lrcThreshold_);
config.censusTransform.kernelSize = dai::StereoDepthConfig::CensusTransform::KernelSize::KERNEL_7x9; stereo->initialConfig.setMedianFilter(dai::MedianFilter::KERNEL_7x7);
config.censusTransform.kernelMask = 0X2AA00AA805540155; auto config = stereo->initialConfig.get();
config.postProcessing.brightnessFilter.maxBrightness = 255; config.censusTransform.kernelSize = dai::StereoDepthConfig::CensusTransform::KernelSize::KERNEL_7x9;
stereo->initialConfig.set(config); config.censusTransform.kernelMask = 0X2AA00AA805540155;
config.postProcessing.brightnessFilter.maxBrightness = 255;
stereo->initialConfig.set(config);
// Link plugins CAM -> STEREO -> XLINK // Link plugins CAM -> STEREO -> XLINK
monoLeft->out.link(stereo->left); monoLeft->out.link(stereo->left);
monoRight->out.link(stereo->right); monoRight->out.link(stereo->right);
}
if(outputMode_ == 2) if(outputMode_ == 2)
{ {
@@ -386,7 +394,12 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
depthOrRightEnc->setDefaultProfilePreset(monoRight->getFps(), dai::VideoEncoderProperties::Profile::MJPEG); depthOrRightEnc->setDefaultProfilePreset(monoRight->getFps(), dai::VideoEncoderProperties::Profile::MJPEG);
if(outputMode_ < 2) if(outputMode_ < 2)
{ {
stereo->rectifiedLeft.link(leftOrColorEnc->input); if(imagesRectified_) {
stereo->rectifiedLeft.link(leftOrColorEnc->input);
}
else {
monoLeft->out.link(leftOrColorEnc->input);
}
leftOrColorEnc->bitstream.link(sync->inputs["left"]); leftOrColorEnc->bitstream.link(sync->inputs["left"]);
} }
else else
@@ -394,7 +407,7 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
colorCam->video.link(leftOrColorEnc->input); colorCam->video.link(leftOrColorEnc->input);
leftOrColorEnc->bitstream.link(sync->inputs["color"]); leftOrColorEnc->bitstream.link(sync->inputs["color"]);
} }
if(outputMode_) if(imagesRectified_ && outputMode_)
{ {
depthOrRightEnc->setQuality(100); depthOrRightEnc->setQuality(100);
stereo->disparity.link(depthOrRightEnc->input); stereo->disparity.link(depthOrRightEnc->input);
@@ -402,23 +415,33 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
} }
else else
{ {
stereo->rectifiedRight.link(depthOrRightEnc->input); if(imagesRectified_) {
stereo->rectifiedRight.link(depthOrRightEnc->input);
}
else {
monoRight->out.link(depthOrRightEnc->input);
}
depthOrRightEnc->bitstream.link(sync->inputs["right"]); depthOrRightEnc->bitstream.link(sync->inputs["right"]);
} }
} }
else else
{ {
stereo->setSubpixel(subpixelFractionalBits_>=3 && subpixelFractionalBits_<=5); if(stereo.get()) {
if(subpixelFractionalBits_>=3 && subpixelFractionalBits_<=5) stereo->setSubpixel(subpixelFractionalBits_>=3 && subpixelFractionalBits_<=5);
stereo->setSubpixelFractionalBits(subpixelFractionalBits_); if(subpixelFractionalBits_>=3 && subpixelFractionalBits_<=5)
config = stereo->initialConfig.get(); stereo->setSubpixelFractionalBits(subpixelFractionalBits_);
config.costMatching.enableCompanding = compandingWidth_>0; auto config = stereo->initialConfig.get();
if(compandingWidth_>0) config.costMatching.enableCompanding = compandingWidth_>0;
config.costMatching.disparityWidth = compandingWidth_==64?dai::StereoDepthConfig::CostMatching::DisparityWidth::DISPARITY_64:dai::StereoDepthConfig::CostMatching::DisparityWidth::DISPARITY_96; if(compandingWidth_>0)
stereo->initialConfig.set(config); config.costMatching.disparityWidth = compandingWidth_==64?dai::StereoDepthConfig::CostMatching::DisparityWidth::DISPARITY_64:dai::StereoDepthConfig::CostMatching::DisparityWidth::DISPARITY_96;
stereo->initialConfig.set(config);
}
if(outputMode_ < 2) if(outputMode_ < 2)
{ {
stereo->rectifiedLeft.link(sync->inputs["left"]); if(imagesRectified_)
stereo->rectifiedLeft.link(sync->inputs["left"]);
else
monoLeft->out.link(sync->inputs["left"]);
} }
else else
{ {
@@ -426,10 +449,15 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
monoRight->setResolution(dai::MonoCameraProperties::SensorResolution::THE_400_P); monoRight->setResolution(dai::MonoCameraProperties::SensorResolution::THE_400_P);
colorCam->video.link(sync->inputs["color"]); colorCam->video.link(sync->inputs["color"]);
} }
if(outputMode_) if(imagesRectified_) {
stereo->depth.link(sync->inputs["depth"]); if(outputMode_)
else stereo->depth.link(sync->inputs["depth"]);
stereo->rectifiedRight.link(sync->inputs["right"]); else
stereo->rectifiedRight.link(sync->inputs["right"]);
}
else {
monoRight->out.link(sync->inputs["right"]);
}
} }
sync->setSyncThreshold(std::chrono::milliseconds(int(500 / monoLeft->getFps()))); sync->setSyncThreshold(std::chrono::milliseconds(int(500 / monoLeft->getFps())));
@@ -460,7 +488,10 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
auto cfg = gfttDetector->initialConfig.get(); auto cfg = gfttDetector->initialConfig.get();
cfg.featureMaintainer.minimumDistanceBetweenFeatures = minDistance_ * minDistance_; cfg.featureMaintainer.minimumDistanceBetweenFeatures = minDistance_ * minDistance_;
gfttDetector->initialConfig.set(cfg); gfttDetector->initialConfig.set(cfg);
stereo->rectifiedLeft.link(gfttDetector->inputImage); if(stereo.get())
stereo->rectifiedLeft.link(gfttDetector->inputImage);
else
monoLeft->out.link(gfttDetector->inputImage);
gfttDetector->outputFeatures.link(sync->inputs["feat"]); gfttDetector->outputFeatures.link(sync->inputs["feat"]);
} }
else if(detectFeatures_ >= 2) else if(detectFeatures_ >= 2)
@@ -472,13 +503,17 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
neuralNetwork->setNumInferenceThreads(2); neuralNetwork->setNumInferenceThreads(2);
neuralNetwork->setNumNCEPerInferenceThread(1); neuralNetwork->setNumNCEPerInferenceThread(1);
neuralNetwork->input.setBlocking(false); neuralNetwork->input.setBlocking(false);
stereo->rectifiedLeft.link(manip->inputImage); if(stereo.get())
stereo->rectifiedLeft.link(manip->inputImage);
else
monoLeft->out.link(manip->inputImage);
manip->out.link(neuralNetwork->input); manip->out.link(neuralNetwork->input);
neuralNetwork->out.link(sync->inputs["feat"]); neuralNetwork->out.link(sync->inputs["feat"]);
} }
device_.reset(new dai::Device(p, deviceToUse)); device_.reset(new dai::Device(p, deviceToUse));
UINFO("Device serial: %s", device_->getMxId().c_str());
UINFO("Available camera sensors: "); UINFO("Available camera sensors: ");
for(auto& sensor : device_->getCameraSensorNames()) { for(auto& sensor : device_->getCameraSensorNames()) {
UINFO("Socket: CAM_%c - %s", 'A'+(unsigned char)sensor.first, sensor.second.c_str()); UINFO("Socket: CAM_%c - %s", 'A'+(unsigned char)sensor.first, sensor.second.c_str());
@@ -487,6 +522,93 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
UINFO("Loading eeprom calibration data"); UINFO("Loading eeprom calibration data");
dai::CalibrationHandler calibHandler = device_->readCalibration(); dai::CalibrationHandler calibHandler = device_->readCalibration();
if(!calibrationFolder.empty() && !cameraName.empty() && imagesRectified_)
{
UINFO("Flashing camera...");
if(outputMode_ == 2)
{
stereoModel_.setName(cameraName, "rgb", "depth");
}
if(stereoModel_.load(calibrationFolder, cameraName, false))
{
std::vector<std::vector<float> > intrinsicsLeft(3);
std::vector<std::vector<float> > intrinsicsRight(3);
for(int row = 0; row<3; ++row)
{
intrinsicsLeft[row].resize(3);
intrinsicsRight[row].resize(3);
for(int col = 0; col<3; ++col)
{
intrinsicsLeft[row][col] = stereoModel_.left().K_raw().at<double>(row,col);
intrinsicsRight[row][col] = stereoModel_.right().K_raw().at<double>(row,col);
}
}
std::vector<float> distortionsLeft = stereoModel_.left().D_raw();
std::vector<float> distortionsRight = stereoModel_.right().D_raw();
std::vector<std::vector<float> > rotationMatrix(3);
for(int row = 0; row<3; ++row)
{
rotationMatrix[row].resize(3);
for(int col = 0; col<3; ++col)
{
rotationMatrix[row][col] = stereoModel_.stereoTransform()(row,col);
}
}
std::vector<float> translation(3);
translation[0] = stereoModel_.stereoTransform().x()*100.0f;
translation[1] = stereoModel_.stereoTransform().y()*100.0f;
translation[2] = stereoModel_.stereoTransform().z()*100.0f;
if(outputMode_ == 2)
{
// Only set RGB intrinsics
calibHandler.setCameraIntrinsics(dai::CameraBoardSocket::CAM_A, intrinsicsLeft, stereoModel_.left().imageWidth(), stereoModel_.left().imageHeight());
calibHandler.setDistortionCoefficients(dai::CameraBoardSocket::CAM_A, distortionsLeft);
std::vector<float> specTranslation = calibHandler.getCameraTranslationVector(dai::CameraBoardSocket::CAM_A, dai::CameraBoardSocket::CAM_C, true);
calibHandler.setCameraExtrinsics(dai::CameraBoardSocket::CAM_A, dai::CameraBoardSocket::CAM_C, rotationMatrix, translation, specTranslation);
}
else
{
calibHandler.setCameraIntrinsics(dai::CameraBoardSocket::CAM_B, intrinsicsLeft, stereoModel_.left().imageWidth(), stereoModel_.left().imageHeight());
calibHandler.setDistortionCoefficients(dai::CameraBoardSocket::CAM_B, distortionsLeft);
calibHandler.setCameraIntrinsics(dai::CameraBoardSocket::CAM_C, intrinsicsRight, stereoModel_.right().imageWidth(), stereoModel_.right().imageHeight());
calibHandler.setDistortionCoefficients(dai::CameraBoardSocket::CAM_C, distortionsRight);
std::vector<float> specTranslation = calibHandler.getCameraTranslationVector(dai::CameraBoardSocket::CAM_B, dai::CameraBoardSocket::CAM_C, true);
calibHandler.setCameraExtrinsics(dai::CameraBoardSocket::CAM_B, dai::CameraBoardSocket::CAM_C, rotationMatrix, translation, specTranslation);
}
try {
UINFO("Flashing camera with calibration from %s with camera name %s", calibrationFolder.c_str(), cameraName.c_str());
if(ULogger::level() <= ULogger::kInfo)
{
std::cout << "K left: " << stereoModel_.left().K_raw() << std::endl;
std::cout << "K right: " << stereoModel_.right().K_raw() << std::endl;
std::cout << "D left: " << stereoModel_.left().D_raw() << std::endl;
std::cout << "D right: " << stereoModel_.right().D_raw() << std::endl;
std::cout << "Extrinsics: " << stereoModel_.stereoTransform() << std::endl;
std::cout << "Expected K with rectification_alpha=0: " << stereoModel_.left().K()*(double(targetSize_.width)/double(stereoModel_.left().imageWidth())) << std::endl;
}
device_->flashCalibration2(calibHandler);
UINFO("Closing device...");
device_->close();
UINFO("Restarting pipeline...");
device_.reset(new dai::Device(p, deviceToUse));
}
catch(const std::runtime_error & e) {
UERROR("Failed flashing calibration: %s", e.what());
}
}
else
{
UERROR("Failed loading calibration from %s with camera name %s", calibrationFolder.c_str(), cameraName.c_str());
}
//Reload calibration
calibHandler = device_->readCalibration();
}
auto eeprom = calibHandler.getEepromData(); auto eeprom = calibHandler.getEepromData();
UINFO("Product name: %s, board name: %s", eeprom.productName.c_str(), eeprom.boardName.c_str()); UINFO("Product name: %s, board name: %s", eeprom.productName.c_str(), eeprom.boardName.c_str());
@@ -512,12 +634,15 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
double fy = newCameraMatrix.at<double>(1, 1); double fy = newCameraMatrix.at<double>(1, 1);
double cx = newCameraMatrix.at<double>(0, 2); double cx = newCameraMatrix.at<double>(0, 2);
double cy = newCameraMatrix.at<double>(1, 2); double cy = newCameraMatrix.at<double>(1, 2);
double baseline = calibHandler.getBaselineDistance(dai::CameraBoardSocket::CAM_C, dai::CameraBoardSocket::CAM_B, useSpecTranslation_)/100.0; UINFO("fx=%f fy=%f cx=%f cy=%f (target size = %dx%d)", fx, fy, cx, cy, targetSize_.width, targetSize_.height);
UINFO("fx=%f fy=%f cx=%f cy=%f baseline=%f", fx, fy, cx, cy, baseline); if(outputMode_ == 2) {
if(outputMode_ == 2) stereoModel_ = StereoCameraModel(device_->getDeviceName(), fx, fy, cx, cy, 0, this->getLocalTransform(), targetSize_);
stereoModel_ = StereoCameraModel(device_->getDeviceName(), fx, fy, cx, cy, baseline, this->getLocalTransform(), targetSize_); }
else else {
stereoModel_ = StereoCameraModel(device_->getDeviceName(), fx, fy, cx, cy, baseline, this->getLocalTransform()*Transform(-calibHandler.getBaselineDistance(dai::CameraBoardSocket::CAM_A)/100.0, 0, 0), targetSize_); double baseline = calibHandler.getBaselineDistance(dai::CameraBoardSocket::CAM_C, dai::CameraBoardSocket::CAM_B, false)/100.0;
UINFO("baseline=%f", baseline);
stereoModel_ = StereoCameraModel(device_->getDeviceName(), fx, fy, cx, cy, outputMode_==0?baseline:0, this->getLocalTransform()*Transform(-calibHandler.getBaselineDistance(dai::CameraBoardSocket::CAM_A)/100.0, 0, 0), targetSize_);
}
if(imuPublished_) if(imuPublished_)
{ {
@@ -624,7 +749,7 @@ bool CameraDepthAI::init(const std::string & calibrationFolder, const std::strin
bool CameraDepthAI::isCalibrated() const bool CameraDepthAI::isCalibrated() const
{ {
#ifdef RTABMAP_DEPTHAI #ifdef RTABMAP_DEPTHAI
return stereoModel_.isValidForProjection(); return outputMode_ == 0?stereoModel_.isValidForProjection():stereoModel_.left().isValidForProjection();
#else #else
return false; return false;
#endif #endif
@@ -645,14 +770,14 @@ SensorData CameraDepthAI::captureImage(SensorCaptureInfo * info)
auto messageGroup = cameraQueue_->get<dai::MessageGroup>(); auto messageGroup = cameraQueue_->get<dai::MessageGroup>();
auto rectifLeftOrColor = messageGroup->get<dai::ImgFrame>(outputMode_<2?"left":"color"); auto rectifLeftOrColor = messageGroup->get<dai::ImgFrame>(outputMode_<2?"left":"color");
auto rectifRightOrDepth = messageGroup->get<dai::ImgFrame>(outputMode_?"depth":"right"); auto rectifRightOrDepth = messageGroup->get<dai::ImgFrame>(imagesRectified_ && outputMode_?"depth":"right");
cv::Mat leftOrColor, depthOrRight; cv::Mat leftOrColor, depthOrRight;
if(device_->getDeviceInfo().protocol == X_LINK_TCP_IP || mxidOrName_.find(".") != std::string::npos) if(device_->getDeviceInfo().protocol == X_LINK_TCP_IP || mxidOrName_.find(".") != std::string::npos)
{ {
leftOrColor = cv::imdecode(rectifLeftOrColor->getData(), cv::IMREAD_ANYCOLOR); leftOrColor = cv::imdecode(rectifLeftOrColor->getData(), cv::IMREAD_ANYCOLOR);
depthOrRight = cv::imdecode(rectifRightOrDepth->getData(), cv::IMREAD_GRAYSCALE); depthOrRight = cv::imdecode(rectifRightOrDepth->getData(), cv::IMREAD_GRAYSCALE);
if(outputMode_) if(imagesRectified_ && outputMode_)
{ {
cv::Mat disp; cv::Mat disp;
depthOrRight.convertTo(disp, CV_16UC1); depthOrRight.convertTo(disp, CV_16UC1);
@@ -666,7 +791,7 @@ SensorData CameraDepthAI::captureImage(SensorCaptureInfo * info)
} }
double stamp = std::chrono::duration<double>(rectifLeftOrColor->getTimestampDevice(dai::CameraExposureOffset::MIDDLE).time_since_epoch()).count(); double stamp = std::chrono::duration<double>(rectifLeftOrColor->getTimestampDevice(dai::CameraExposureOffset::MIDDLE).time_since_epoch()).count();
if(outputMode_) if(imagesRectified_ && outputMode_)
data = SensorData(leftOrColor, depthOrRight, stereoModel_.left(), this->getNextSeqID(), stamp); data = SensorData(leftOrColor, depthOrRight, stereoModel_.left(), this->getNextSeqID(), stamp);
else else
data = SensorData(leftOrColor, depthOrRight, stereoModel_, this->getNextSeqID(), stamp); data = SensorData(leftOrColor, depthOrRight, stereoModel_, this->getNextSeqID(), stamp);
+22 -1
View File
@@ -39,7 +39,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UEventsHandler.h> #include <rtabmap/utilite/UEventsHandler.h>
#include <opencv2/aruco/charuco.hpp>
class Ui_calibrationDialog; class Ui_calibrationDialog;
class QTextStream;
namespace rtabmap { namespace rtabmap {
@@ -60,6 +63,7 @@ public:
int boardWidth() const; int boardWidth() const;
int boardHeight() const; int boardHeight() const;
double squareSize() const; double squareSize() const;
double markerLength() const;
void saveSettings(QSettings & settings, const QString & group = "") const; void saveSettings(QSettings & settings, const QString & group = "") const;
void loadSettings(QSettings & settings, const QString & group = ""); void loadSettings(QSettings & settings, const QString & group = "");
@@ -74,17 +78,24 @@ public:
void setStereoMode(bool stereo, const QString & leftSuffix = "left", const QString & rightSuffix = "right"); void setStereoMode(bool stereo, const QString & leftSuffix = "left", const QString & rightSuffix = "right");
void setSavingDirectory(const QString & savingDirectory) {savingDirectory_ = savingDirectory;} void setSavingDirectory(const QString & savingDirectory) {savingDirectory_ = savingDirectory;}
StereoCameraModel stereoCalibration(const CameraModel & left, const CameraModel & right, bool ignoreStereoRectification) const; StereoCameraModel stereoCalibration(const CameraModel & left, const CameraModel & right, bool ignoreStereoRectification, QTextStream * logStream = 0) const;
public Q_SLOTS: public Q_SLOTS:
void setBoardType(int type);
void setBoardWidth(int width); void setBoardWidth(int width);
void setBoardHeight(int height); void setBoardHeight(int height);
void setSquareSize(double size); void setSquareSize(double size);
void setMarkerDictionary(int dictionary);
void setMarkerLength(double length);
void setSubpixelRefinement(bool enabled);
void setSubpixelMaxError(double value);
void setCalibrationDataSaved(bool enabled); void setCalibrationDataSaved(bool enabled);
void setExpectedStereoBaseline(double length); void setExpectedStereoBaseline(double length);
void setMaxScale(int scale); void setMaxScale(int scale);
void processImages(const cv::Mat & imageLeft, const cv::Mat & imageRight, const QString & cameraName); void processImages(const cv::Mat & imageLeft, const cv::Mat & imageRight, const QString & cameraName);
void generateBoard();
void calibrate(); void calibrate();
void restart(); void restart();
bool save(); bool save();
@@ -98,6 +109,7 @@ protected:
private: private:
float getArea(const std::vector<cv::Point2f> & corners, const cv::Size & boardSize); float getArea(const std::vector<cv::Point2f> & corners, const cv::Size & boardSize);
float getSkew(const std::vector<cv::Point2f> & fourCorners);
float getSkew(const std::vector<cv::Point2f> & corners, const cv::Size & boardSize); float getSkew(const std::vector<cv::Point2f> & corners, const cv::Size & boardSize);
// x -> [0, 1] (left, right) // x -> [0, 1] (left, right)
@@ -120,10 +132,19 @@ private:
int currentId_; int currentId_;
QString timestamp_; QString timestamp_;
std::vector<cv::Point3f> chessboardPoints_;
std::vector<int> chessboardPointIds_;
cv::Ptr<cv::aruco::Dictionary> markerDictionary_;
cv::Ptr<cv::aruco::DetectorParameters> arucoDetectorParams_;
cv::Ptr<cv::aruco::CharucoBoard> charucoBoard_;
std::vector<std::vector<std::vector<cv::Point2f> > > imagePoints_; std::vector<std::vector<std::vector<cv::Point2f> > > imagePoints_;
std::vector<std::vector<std::vector<cv::Point3f> > > objectPoints_;
std::vector<std::vector<std::vector<float> > > imageParams_; std::vector<std::vector<std::vector<float> > > imageParams_;
std::vector<std::vector<int > > imageIds_; std::vector<std::vector<int > > imageIds_;
std::vector<std::vector<std::vector<cv::Point2f> > > stereoImagePoints_; std::vector<std::vector<std::vector<cv::Point2f> > > stereoImagePoints_;
std::vector<std::vector<cv::Point3f> > stereoObjectPoints_;
std::vector<int> stereoImageIds_; std::vector<int> stereoImageIds_;
std::vector<cv::Size > imageSize_; std::vector<cv::Size > imageSize_;
std::vector<rtabmap::CameraModel> models_; std::vector<rtabmap::CameraModel> models_;
@@ -44,6 +44,7 @@ namespace rtabmap {
class ImageView; class ImageView;
class CloudViewer; class CloudViewer;
class MarkerDetector;
class RTABMAP_GUI_EXPORT CameraViewer : public QDialog, public UEventsHandler class RTABMAP_GUI_EXPORT CameraViewer : public QDialog, public UEventsHandler
{ {
@@ -70,6 +71,8 @@ private:
QLabel * imageSizeLabel_; QLabel * imageSizeLabel_;
QCheckBox * showCloudCheckbox_; QCheckBox * showCloudCheckbox_;
QCheckBox * showScanCheckbox_; QCheckBox * showScanCheckbox_;
QCheckBox * markerCheckbox_;
MarkerDetector * markerDetector_;
}; };
} /* namespace rtabmap */ } /* namespace rtabmap */
@@ -76,7 +76,8 @@ public:
kPanelCloudRendering = 2, kPanelCloudRendering = 2,
kPanelLogging = 4, kPanelLogging = 4,
kPanelSource = 8, kPanelSource = 8,
kPanelAll = 15 kPanelCalibration = 16,
kPanelAll = 31
}; };
// TODO, tried to change the name of PANEL_FLAGS to PanelFlags... but signals/slots errors appeared... // TODO, tried to change the name of PANEL_FLAGS to PanelFlags... but signals/slots errors appeared...
Q_DECLARE_FLAGS(PANEL_FLAGS, PanelFlag); Q_DECLARE_FLAGS(PANEL_FLAGS, PanelFlag);
@@ -347,6 +348,7 @@ private Q_SLOTS:
void makeObsoleteCloudRenderingPanel(); void makeObsoleteCloudRenderingPanel();
void makeObsoleteLoggingPanel(); void makeObsoleteLoggingPanel();
void makeObsoleteSourcePanel(); void makeObsoleteSourcePanel();
void makeObsoleteCalibrationPanel();
void clicked(const QModelIndex & current, const QModelIndex & previous); void clicked(const QModelIndex & current, const QModelIndex & previous);
void addParameter(int value); void addParameter(int value);
void addParameter(bool value); void addParameter(bool value);
File diff suppressed because it is too large Load Diff
+61 -2
View File
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/util3d.h> #include <rtabmap/core/util3d.h>
#include <rtabmap/core/util2d.h> #include <rtabmap/core/util2d.h>
#include <rtabmap/core/util3d_filtering.h> #include <rtabmap/core/util3d_filtering.h>
#include <rtabmap/core/MarkerDetector.h>
#include <rtabmap/gui/ImageView.h> #include <rtabmap/gui/ImageView.h>
#include <rtabmap/gui/CloudViewer.h> #include <rtabmap/gui/CloudViewer.h>
#include <rtabmap/utilite/UCv2Qt.h> #include <rtabmap/utilite/UCv2Qt.h>
@@ -52,7 +53,8 @@ CameraViewer::CameraViewer(QWidget * parent, const ParametersMap & parameters) :
imageView_(new ImageView(this)), imageView_(new ImageView(this)),
cloudView_(new CloudViewer(this)), cloudView_(new CloudViewer(this)),
processingImages_(false), processingImages_(false),
parameters_(parameters) parameters_(parameters),
markerDetector_(0)
{ {
qRegisterMetaType<rtabmap::SensorData>("rtabmap::SensorData"); qRegisterMetaType<rtabmap::SensorData>("rtabmap::SensorData");
@@ -79,6 +81,16 @@ CameraViewer::CameraViewer(QWidget * parent, const ParametersMap & parameters) :
showScanCheckbox_->setEnabled(false); showScanCheckbox_->setEnabled(false);
showScanCheckbox_->setChecked(true); showScanCheckbox_->setChecked(true);
markerCheckbox_ = new QCheckBox("Detect markers", this);
#ifdef HAVE_OPENCV_ARUCO
markerCheckbox_->setEnabled(true);
markerDetector_ = new MarkerDetector(parameters);
#else
markerCheckbox_->setEnabled(false);
markerCheckbox_->setToolTip("Disabled: RTAB-Map is not built with OpenCV's aruco module.");
#endif
markerCheckbox_->setChecked(false);
imageSizeLabel_ = new QLabel(this); imageSizeLabel_ = new QLabel(this);
QDialogButtonBox * buttonBox = new QDialogButtonBox(this); QDialogButtonBox * buttonBox = new QDialogButtonBox(this);
@@ -91,6 +103,7 @@ CameraViewer::CameraViewer(QWidget * parent, const ParametersMap & parameters) :
layout2->addWidget(decimationSpin_); layout2->addWidget(decimationSpin_);
layout2->addWidget(showCloudCheckbox_); layout2->addWidget(showCloudCheckbox_);
layout2->addWidget(showScanCheckbox_); layout2->addWidget(showScanCheckbox_);
layout2->addWidget(markerCheckbox_);
layout2->addWidget(imageSizeLabel_); layout2->addWidget(imageSizeLabel_);
layout2->addStretch(1); layout2->addStretch(1);
layout2->addWidget(buttonBox); layout2->addWidget(buttonBox);
@@ -107,6 +120,7 @@ CameraViewer::CameraViewer(QWidget * parent, const ParametersMap & parameters) :
CameraViewer::~CameraViewer() CameraViewer::~CameraViewer()
{ {
this->unregisterFromEventsManager(); this->unregisterFromEventsManager();
delete markerDetector_;
} }
void CameraViewer::setDecimation(int value) void CameraViewer::setDecimation(int value)
@@ -119,9 +133,32 @@ void CameraViewer::showImage(const rtabmap::SensorData & data)
processingImages_ = true; processingImages_ = true;
QString sizes; QString sizes;
imageView_->setVisible(!data.imageRaw().empty() || !data.imageRaw().empty()); imageView_->setVisible(!data.imageRaw().empty() || !data.imageRaw().empty());
std::map<int, MarkerInfo> detections;
if(!data.imageRaw().empty()) if(!data.imageRaw().empty())
{ {
imageView_->setImage(uCvMat2QImage(data.imageRaw())); std::vector<CameraModel> models;
if(markerCheckbox_->isEnabled() && markerCheckbox_->isChecked())
{
models = data.cameraModels();
if(models.empty())
{
for(size_t i=0; i<data.stereoCameraModels().size(); ++i)
{
models.push_back(data.stereoCameraModels()[i].left());
}
}
}
if(!models.empty() && models[0].isValidForProjection())
{
cv::Mat imageWithDetections;
detections = markerDetector_->detect(data.imageRaw(), models, data.depthRaw(), std::map<int, float>(), &imageWithDetections);
imageView_->setImage(uCvMat2QImage(imageWithDetections));
}
else
{
imageView_->setImage(uCvMat2QImage(data.imageRaw()));
}
sizes.append(QString("Color=%1x%2").arg(data.imageRaw().cols).arg(data.imageRaw().rows)); sizes.append(QString("Color=%1x%2").arg(data.imageRaw().cols).arg(data.imageRaw().rows));
} }
if(!data.depthOrRightRaw().empty()) if(!data.depthOrRightRaw().empty())
@@ -146,6 +183,28 @@ void CameraViewer::showImage(const rtabmap::SensorData & data)
showCloudCheckbox_->setEnabled(true); showCloudCheckbox_->setEnabled(true);
cloudView_->addCloud("cloud", util3d::cloudFromSensorData(data, decimationSpin_->value()!=0?fabs(decimationSpin_->value()):1, 0, 0, 0, parameters_)); cloudView_->addCloud("cloud", util3d::cloudFromSensorData(data, decimationSpin_->value()!=0?fabs(decimationSpin_->value()):1, 0, 0, 0, parameters_));
} }
// Add landmarks to 3D Map view
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
cloudView_->removeAllCoordinates("landmark_");
#endif
cloudView_->removeAllTexts();
if(!detections.empty())
{
for(std::map<int, MarkerInfo>::const_iterator iter=detections.begin(); iter!=detections.end(); ++iter)
{
#if PCL_VERSION_COMPARE(>=, 1, 7, 2)
cloudView_->addOrUpdateCoordinate(uFormat("landmark_%d", iter->first), iter->second.pose(), iter->second.length(), false);
#endif
std::string num = uNumber2Str(iter->first);
cloudView_->addOrUpdateText(
std::string("landmark_str_") + num,
num,
iter->second.pose(),
0.05,
Qt::yellow);
}
}
} }
} }
+13 -2
View File
@@ -5193,9 +5193,16 @@ void PreferencesDialog::makeObsoleteLoggingPanel()
void PreferencesDialog::makeObsoleteSourcePanel() void PreferencesDialog::makeObsoleteSourcePanel()
{ {
ULOGGER_DEBUG("");
_obsoletePanels = _obsoletePanels | kPanelSource; _obsoletePanels = _obsoletePanels | kPanelSource;
} }
void PreferencesDialog::makeObsoleteCalibrationPanel()
{
ULOGGER_DEBUG("");
_obsoletePanels = _obsoletePanels | kPanelCalibration;
}
QList<QGroupBox*> PreferencesDialog::getGroupBoxes() QList<QGroupBox*> PreferencesDialog::getGroupBoxes()
{ {
QList<QGroupBox*> boxes; QList<QGroupBox*> boxes;
@@ -6796,7 +6803,7 @@ Camera * PreferencesDialog::createCamera(
((CameraDepthAI*)camera)->setExtendedDisparity(_ui->checkBox_depthai_extended_disparity->isChecked()); ((CameraDepthAI*)camera)->setExtendedDisparity(_ui->checkBox_depthai_extended_disparity->isChecked());
((CameraDepthAI*)camera)->setSubpixelMode(_ui->comboBox_depthai_subpixel_fractional_bits->currentIndex()!=0, _ui->comboBox_depthai_subpixel_fractional_bits->currentIndex()==2?4:_ui->comboBox_depthai_subpixel_fractional_bits->currentIndex()==3?5:3); ((CameraDepthAI*)camera)->setSubpixelMode(_ui->comboBox_depthai_subpixel_fractional_bits->currentIndex()!=0, _ui->comboBox_depthai_subpixel_fractional_bits->currentIndex()==2?4:_ui->comboBox_depthai_subpixel_fractional_bits->currentIndex()==3?5:3);
((CameraDepthAI*)camera)->setCompanding(_ui->comboBox_depthai_disparity_companding->currentIndex()!=0, _ui->comboBox_depthai_disparity_companding->currentIndex()==1?64:96); ((CameraDepthAI*)camera)->setCompanding(_ui->comboBox_depthai_disparity_companding->currentIndex()!=0, _ui->comboBox_depthai_disparity_companding->currentIndex()==1?64:96);
((CameraDepthAI*)camera)->setRectification(_ui->checkBox_depthai_use_spec_translation->isChecked(), _ui->doubleSpinBox_depthai_alpha_scaling->value()); ((CameraDepthAI*)camera)->setRectification(_ui->checkBox_depthai_use_spec_translation->isChecked(), _ui->doubleSpinBox_depthai_alpha_scaling->value(), !useRawImages);
((CameraDepthAI*)camera)->setIMU(_ui->checkBox_depthai_imu_published->isChecked(), _ui->checkbox_publishInterIMU->isChecked()); ((CameraDepthAI*)camera)->setIMU(_ui->checkBox_depthai_imu_published->isChecked(), _ui->checkbox_publishInterIMU->isChecked());
((CameraDepthAI*)camera)->setIrIntensity(_ui->doubleSpinBox_depthai_dot_intensity->value(), _ui->doubleSpinBox_depthai_flood_intensity->value()); ((CameraDepthAI*)camera)->setIrIntensity(_ui->doubleSpinBox_depthai_dot_intensity->value(), _ui->doubleSpinBox_depthai_flood_intensity->value());
((CameraDepthAI*)camera)->setDetectFeatures(_ui->comboBox_depthai_detect_features->currentIndex()); ((CameraDepthAI*)camera)->setDetectFeatures(_ui->comboBox_depthai_detect_features->currentIndex());
@@ -7562,11 +7569,14 @@ void PreferencesDialog::calibrate()
} }
bool freenect2 = driver == kSrcFreenect2; bool freenect2 = driver == kSrcFreenect2;
_calibrationDialog->setStereoMode(this->getSourceType() != kSrcRGB && driver != kSrcRealSense, freenect2?"rgb":"left", freenect2?"depth":"right"); // RGB+Depth or left+right bool rgbDepth = freenect2 || (driver==kSrcStereoDepthAI && _ui->comboBox_depthai_output_mode->currentIndex() == 2);
_calibrationDialog->setStereoMode(this->getSourceType() != kSrcRGB && driver != kSrcRealSense, rgbDepth?"rgb":"left", rgbDepth?"depth":"right"); // RGB+Depth or left+right
_calibrationDialog->setCameraName(""); _calibrationDialog->setCameraName("");
_calibrationDialog->setSwitchedImages(freenect2); _calibrationDialog->setSwitchedImages(freenect2);
if(driver == kSrcStereoRealSense2) if(driver == kSrcStereoRealSense2)
_calibrationDialog->setFisheyeModel(); _calibrationDialog->setFisheyeModel();
if(driver == kSrcStereoDepthAI)
_calibrationDialog->setRationalModel();
_calibrationDialog->setSavingDirectory(this->getCameraInfoDir()); _calibrationDialog->setSavingDirectory(this->getCameraInfoDir());
_calibrationDialog->registerToEventsManager(); _calibrationDialog->registerToEventsManager();
@@ -7580,6 +7590,7 @@ void PreferencesDialog::calibrate()
cameraThread.join(true); cameraThread.join(true);
} }
makeObsoleteCalibrationPanel();
} }
void PreferencesDialog::calibrateSimple() void PreferencesDialog::calibrateSimple()
+427 -153
View File
@@ -6,34 +6,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1189</width> <width>1100</width>
<height>692</height> <height>828</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Dialog</string> <string>Dialog</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,0"> <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,0">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing"> <property name="spacing">
@@ -155,9 +137,6 @@
<property name="horizontalScrollBarPolicy"> <property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum> <enum>Qt::ScrollBarAlwaysOff</enum>
</property> </property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="widgetResizable"> <property name="widgetResizable">
<bool>false</bool> <bool>false</bool>
</property> </property>
@@ -166,8 +145,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>387</width> <width>428</width>
<height>928</height> <height>1070</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
@@ -186,20 +165,274 @@
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
<string>Chessboard</string> <string>Configuration</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<item row="8" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_stereoBaseline_2"> <widget class="QLabel" name="label_13">
<property name="toolTip"> <property name="toolTip">
<string>If &gt; 1, image is scaled down to help board detection on high definition images</string> <string>Number of inner squares on the board</string>
</property> </property>
<property name="text"> <property name="text">
<string>Calibration Model</string> <string>Board Type</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="2" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QComboBox" name="comboBox_board_type">
<item>
<property name="text">
<string>Chessboard</string>
</property>
</item>
<item>
<property name="text">
<string>ChArUco Board</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton_generateBoard">
<property name="toolTip">
<string>Generate image of the board</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="autoRaise">
<bool>false</bool>
</property>
<property name="arrowType">
<enum>Qt::RightArrow</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_markerDictionary">
<property name="toolTip">
<string>Number of inner squares on the board</string>
</property>
<property name="text">
<string>Marker Dictionary</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="3">
<widget class="QComboBox" name="comboBox_marker_dictionary">
<property name="currentIndex">
<number>3</number>
</property>
<item>
<property name="text">
<string>4X4_50</string>
</property>
</item>
<item>
<property name="text">
<string>4X4_100</string>
</property>
</item>
<item>
<property name="text">
<string>4X4_250</string>
</property>
</item>
<item>
<property name="text">
<string>4X4_1000</string>
</property>
</item>
<item>
<property name="text">
<string>5X5_50</string>
</property>
</item>
<item>
<property name="text">
<string>5X5_100</string>
</property>
</item>
<item>
<property name="text">
<string>5X5_250</string>
</property>
</item>
<item>
<property name="text">
<string>5X5_1000</string>
</property>
</item>
<item>
<property name="text">
<string>6X6_50</string>
</property>
</item>
<item>
<property name="text">
<string>6X6_100</string>
</property>
</item>
<item>
<property name="text">
<string>6X6_250</string>
</property>
</item>
<item>
<property name="text">
<string>6X6_1000</string>
</property>
</item>
<item>
<property name="text">
<string>7X7_50</string>
</property>
</item>
<item>
<property name="text">
<string>7X7_100</string>
</property>
</item>
<item>
<property name="text">
<string>7X7_250</string>
</property>
</item>
<item>
<property name="text">
<string>7X7_1000</string>
</property>
</item>
<item>
<property name="text">
<string>ARUCO_ORIGINAL</string>
</property>
</item>
<item>
<property name="text">
<string>APRILTAG_16h5</string>
</property>
</item>
<item>
<property name="text">
<string>APRILTAG_25h9</string>
</property>
</item>
<item>
<property name="text">
<string>APRILTAG_36h10</string>
</property>
</item>
<item>
<property name="text">
<string>APRILTAG_36h11</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_15">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Square Size</string>
</property>
</widget>
</item>
<item row="2" column="2" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSpinBox" name="spinBox_boardWidth">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="minimum">
<number>2</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_boardHeight">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="minimum">
<number>2</number>
</property>
<property name="value">
<number>6</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_12">
<property name="toolTip">
<string>Number of inner squares on the board</string>
</property>
<property name="text">
<string>Board Size</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="3">
<widget class="QDoubleSpinBox" name="doubleSpinBox_squareSize">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.033000000000000</double>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_markerLength">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Marker Length</string>
</property>
</widget>
</item>
<item row="4" column="2" colspan="3">
<widget class="QDoubleSpinBox" name="doubleSpinBox_markerLength">
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.024750000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_22"> <widget class="QLabel" name="label_22">
<property name="toolTip"> <property name="toolTip">
<string>If &gt; 1, image is scaled down to help board detection on high definition images</string> <string>If &gt; 1, image is scaled down to help board detection on high definition images</string>
@@ -209,7 +442,78 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="5" column="2" colspan="2">
<widget class="QSpinBox" name="spinBox_maxScale">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>3</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_stereoBaseline_4">
<property name="toolTip">
<string>If &gt; 1, image is scaled down to help board detection on high definition images</string>
</property>
<property name="text">
<string>Sub Pixel Refinement</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QCheckBox" name="checkBox_subpixel_refinement">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="4">
<widget class="QDoubleSpinBox" name="doubleSpinBox_subpixel_error">
<property name="toolTip">
<string>0 means infinity (accept all)</string>
</property>
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="suffix">
<string> pix</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>9.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_stereoBaseline">
<property name="toolTip">
<string>If &gt; 1, image is scaled down to help board detection on high definition images</string>
</property>
<property name="text">
<string>Stereo Expected Baseline</string>
</property>
</widget>
</item>
<item row="7" column="2" colspan="3">
<widget class="QDoubleSpinBox" name="doubleSpinBox_stereoBaseline"> <widget class="QDoubleSpinBox" name="doubleSpinBox_stereoBaseline">
<property name="toolTip"> <property name="toolTip">
<string>If you know the exact baseline of the stereo cameras, you can set it here in case the square size is not super accurate.</string> <string>If you know the exact baseline of the stereo cameras, you can set it here in case the square size is not super accurate.</string>
@@ -228,40 +532,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="8" column="0">
<widget class="QLabel" name="label_20"> <widget class="QLabel" name="label_stereoBaseline_2">
<property name="toolTip">
<string>Number of inner squares on the board</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/introlab/rtabmap/raw/master/data/check-108.pdf&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Sample8x6&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_stereoBaseline">
<property name="toolTip"> <property name="toolTip">
<string>If &gt; 1, image is scaled down to help board detection on high definition images</string> <string>If &gt; 1, image is scaled down to help board detection on high definition images</string>
</property> </property>
<property name="text"> <property name="text">
<string>Stereo Expected Baseline</string> <string>Calibration Model</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="8" column="2" colspan="3">
<widget class="QLabel" name="label_15">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Square Size</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="comboBox_calib_model"> <widget class="QComboBox" name="comboBox_calib_model">
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>1</number>
@@ -283,16 +564,6 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="0" column="0">
<widget class="QLabel" name="label_21">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Download</string>
</property>
</widget>
</item>
<item row="9" column="0"> <item row="9" column="0">
<widget class="QLabel" name="label_stereoBaseline_3"> <widget class="QLabel" name="label_stereoBaseline_3">
<property name="toolTip"> <property name="toolTip">
@@ -303,76 +574,23 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="9" column="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_squareSize">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.033000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="toolTip">
<string>Number of inner squares on the board</string>
</property>
<property name="text">
<string>Board Size</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSpinBox" name="spinBox_boardWidth">
<property name="minimum">
<number>2</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_boardHeight">
<property name="minimum">
<number>2</number>
</property>
<property name="value">
<number>6</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBox_maxScale">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>3</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QCheckBox" name="checkBox_saveCalibrationData"> <widget class="QCheckBox" name="checkBox_saveCalibrationData">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="3">
<widget class="QLabel" name="label_stereoBaseline_5">
<property name="toolTip">
<string>If &gt; 1, image is scaled down to help board detection on high definition images</string>
</property>
<property name="text">
<string>Max Error</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@@ -390,22 +608,15 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_6"> <layout class="QVBoxLayout" name="verticalLayout_6">
<item> <item>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0"> <layout class="QHBoxLayout" name="horizontalLayout_6">
<item row="5" column="0"> <item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Skew</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_19"> <widget class="QLabel" name="label_19">
<property name="text"> <property name="text">
<string>Serial</string> <string>Serial</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item>
<widget class="QLabel" name="label_serial"> <widget class="QLabel" name="label_serial">
<property name="text"> <property name="text">
<string>0</string> <string>0</string>
@@ -415,6 +626,49 @@
</property> </property>
</widget> </widget>
</item> </item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QCheckBox" name="checkBox_keep_all">
<property name="text">
<string>Keep all</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox_sample_factor">
<property name="toolTip">
<string>Sample factor to adjust how often a new sample is added. The larger the factor is, less samples are generated.</string>
</property>
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="suffix">
<string>x</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>9.900000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2"> <item row="0" column="2">
<widget class="QCheckBox" name="checkBox_switchImages"> <widget class="QCheckBox" name="checkBox_switchImages">
<property name="text"> <property name="text">
@@ -533,6 +787,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Skew</string>
</property>
</widget>
</item>
<item row="5" column="1"> <item row="5" column="1">
<widget class="QProgressBar" name="progressBar_skew"> <widget class="QProgressBar" name="progressBar_skew">
<property name="value"> <property name="value">
@@ -703,8 +964,11 @@
</item> </item>
<item row="7" column="0"> <item row="7" column="0">
<widget class="QLabel" name="label_baseline_name"> <widget class="QLabel" name="label_baseline_name">
<property name="toolTip">
<string>Stereo</string>
</property>
<property name="text"> <property name="text">
<string>baseline</string> <string>Baseline/Err</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -776,16 +1040,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="2">
<widget class="QLabel" name="label_baseline">
<property name="text">
<string>0</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="2"> <item row="11" column="2">
<widget class="QLineEdit" name="lineEdit_P_2"> <widget class="QLineEdit" name="lineEdit_P_2">
<property name="readOnly"> <property name="readOnly">
@@ -900,6 +1154,26 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1">
<widget class="QLabel" name="label_baseline">
<property name="text">
<string>0</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLabel" name="label_stereoError">
<property name="text">
<string>0</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>