36 #ifdef HAVE_OPENCV_ARUCO 37 markerLength_ = Parameters::defaultMarkerLength();
38 maxDepthError_ = Parameters::defaultMarkerMaxDepthError();
39 maxRange_ = Parameters::defaultMarkerMaxRange();
40 minRange_ = Parameters::defaultMarkerMinRange();
41 dictionaryId_ = Parameters::defaultMarkerDictionary();
42 #if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=2) 43 detectorParams_ = cv::aruco::DetectorParameters::create();
45 detectorParams_.reset(
new cv::aruco::DetectorParameters());
47 #if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=3) 48 detectorParams_->cornerRefinementMethod = Parameters::defaultMarkerCornerRefinementMethod();
50 detectorParams_->doCornerRefinement = Parameters::defaultMarkerCornerRefinementMethod()!=0;
62 #ifdef HAVE_OPENCV_ARUCO 63 detectorParams_->adaptiveThreshWinSizeMin = 3;
64 detectorParams_->adaptiveThreshWinSizeMax = 23;
65 detectorParams_->adaptiveThreshWinSizeStep = 10;
66 detectorParams_->adaptiveThreshConstant = 7;
67 detectorParams_->minMarkerPerimeterRate = 0.03;
68 detectorParams_->maxMarkerPerimeterRate = 4.0;
69 detectorParams_->polygonalApproxAccuracyRate = 0.03;
70 detectorParams_->minCornerDistanceRate = 0.05;
71 detectorParams_->minDistanceToBorder = 3;
72 detectorParams_->minMarkerDistanceRate = 0.05;
73 #if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=3) 74 Parameters::parse(parameters, Parameters::kMarkerCornerRefinementMethod(), detectorParams_->cornerRefinementMethod);
76 int doCornerRefinement = detectorParams_->doCornerRefinement?1:0;
77 Parameters::parse(parameters, Parameters::kMarkerCornerRefinementMethod(), doCornerRefinement);
78 detectorParams_->doCornerRefinement = doCornerRefinement!=0;
80 detectorParams_->cornerRefinementWinSize = 5;
81 detectorParams_->cornerRefinementMaxIterations = 30;
82 detectorParams_->cornerRefinementMinAccuracy = 0.1;
83 detectorParams_->markerBorderBits = 1;
84 detectorParams_->perspectiveRemovePixelPerCell = 4;
85 detectorParams_->perspectiveRemoveIgnoredMarginPerCell = 0.13;
86 detectorParams_->maxErroneousBitsInBorderRate = 0.35;
87 detectorParams_->minOtsuStdDev = 5.0;
88 detectorParams_->errorCorrectionRate = 0.6;
91 Parameters::parse(parameters, Parameters::kMarkerMaxDepthError(), maxDepthError_);
95 #if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION <4 || (CV_MINOR_VERSION ==4 && CV_SUBMINOR_VERSION<2))) 96 if(dictionaryId_ >= 17)
98 UERROR(
"Cannot set AprilTag dictionary. OpenCV version should be at least 3.4.2, " 99 "current version is %s. Setting %s to default (%d)",
101 Parameters::kMarkerDictionary().c_str(),
102 Parameters::defaultMarkerDictionary());
103 dictionaryId_ = Parameters::defaultMarkerDictionary();
106 #if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=2) 107 dictionary_ = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId_));
109 dictionary_.reset(
new cv::aruco::Dictionary());
110 *dictionary_ = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId_));
115 std::map<int, Transform>
MarkerDetector::detect(
const cv::Mat & image,
const CameraModel & model,
const cv::Mat & depth,
float * markerLengthOut, cv::Mat * imageWithDetections)
117 std::map<int, Transform> detections;
119 #ifdef HAVE_OPENCV_ARUCO 121 std::vector< int > ids;
122 std::vector< std::vector< cv::Point2f > > corners, rejected;
123 std::vector< cv::Vec3d > rvecs, tvecs;
126 #if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=2) 127 cv::aruco::detectMarkers(image, dictionary_, corners, ids, detectorParams_, rejected);
129 cv::aruco::detectMarkers(image, *dictionary_, corners, ids, *detectorParams_, rejected);
131 UDEBUG(
"Markers detected=%d rejected=%d", (
int)ids.size(), (int)rejected.size());
134 float rgbToDepthFactorX = 1.0f;
135 float rgbToDepthFactorY = 1.0f;
136 if(markerLength_ == 0)
140 UERROR(
"Depth image is empty, please set %s parameter to non-null.", Parameters::kMarkerLength().c_str());
147 cv::aruco::estimatePoseSingleMarkers(corners, markerLength_==0?1.0
f:markerLength_, model.
K(), model.
D(), rvecs, tvecs);
148 std::vector<float> scales;
149 for(
size_t i=0; i<ids.size(); ++i)
151 if(markerLength_ == 0)
153 float d1 =
util2d::getDepth(depth, corners[i][0].x*rgbToDepthFactorX, corners[i][0].y*rgbToDepthFactorY,
true, 0.02
f,
true);
154 float d2 =
util2d::getDepth(depth, corners[i][1].x*rgbToDepthFactorX, corners[i][1].y*rgbToDepthFactorY,
true, 0.02
f,
true);
155 float d3 =
util2d::getDepth(depth, corners[i][2].x*rgbToDepthFactorX, corners[i][2].y*rgbToDepthFactorY,
true, 0.02
f,
true);
156 float d4 =
util2d::getDepth(depth, corners[i][3].x*rgbToDepthFactorX, corners[i][3].y*rgbToDepthFactorY,
true, 0.02
f,
true);
160 if(d1>0 && d2>0 && d3>0 && d4>0)
162 if( fabs(d1-d2) < maxDepthError_ &&
163 fabs(d1-d3) < maxDepthError_ &&
164 fabs(d1-d4) < maxDepthError_)
166 float depth = (d1+d2+d3+d4)/4.0
f;
167 scales.push_back(depth/tvecs[i].val[2]);
168 tvecs[i] *= scales.back();
169 UWARN(
"Automatic marker length estimation: id=%d depth=%fm length=%fm", ids[i], depth, scales.back());
173 UWARN(
"The four marker's corners should be " 174 "perpendicular to camera to estimate correctly " 175 "the marker's length. Errors: %f, %f, %f > %fm (%s). Four corners: %f %f %f %f. " 176 "Parameter %s can be set to non-null to skip automatic " 177 "marker length estimation. Detections are ignored.",
178 fabs(d1-d2), fabs(d1-d3), fabs(d1-d4), maxDepthError_, Parameters::kMarkerMaxDepthError().c_str(),
180 Parameters::kMarkerLength().c_str());
187 UWARN(
"Some depth values (%f,%f,%f,%f) cannot be detected on the " 188 "marker's corners, cannot initialize marker length. " 189 "Parameter %s can be set to non-null to skip automatic " 190 "marker length estimation. Detections are ignored.",
192 Parameters::kMarkerLength().c_str());
200 if((maxRange_ <= 0 || tvecs[i].val[2] < maxRange_) &&
201 (minRange_ <= 0 || tvecs[i].val[2] > minRange_))
204 cv::Rodrigues(rvecs[i], R);
205 Transform t(R.at<
double>(0,0), R.at<
double>(0,1), R.at<
double>(0,2), tvecs[i].val[0],
206 R.at<
double>(1,0), R.at<
double>(1,1), R.at<
double>(1,2), tvecs[i].val[1],
207 R.at<
double>(2,0), R.at<
double>(2,1), R.at<
double>(2,2), tvecs[i].val[2]);
209 detections.insert(std::make_pair(ids[i], pose));
213 if(markerLength_ == 0)
216 float maxError = 0.0f;
217 for(
size_t i=0; i<scales.size(); ++i)
221 float error = fabs(scales[i]-scales[0]);
224 UWARN(
"The marker's length detected between 2 of the " 225 "markers doesn't match (%d->%fm vs %d->%fm)." 226 "Parameter %s can be set to non-null to skip automatic " 227 "marker length estimation. Detections are ignored.",
228 ids[i], scales[i], ids[0], scales[0],
229 Parameters::kMarkerLength().c_str());
240 markerLength_ = sum/float(scales.size());
241 UWARN(
"Final marker length estimated = %fm, max error=%fm (used for subsequent detections)", markerLength_, maxError);
247 *markerLengthOut = markerLength_;
250 if(imageWithDetections)
252 image.copyTo(*imageWithDetections);
255 cv::aruco::drawDetectedMarkers(*imageWithDetections, corners, ids);
257 for(
unsigned int i = 0; i < ids.size(); i++)
259 cv::aruco::drawAxis(*imageWithDetections, model.
K(), model.
D(), rvecs[i], tvecs[i], markerLength_ * 0.5f);
265 UERROR(
"RTAB-Map is not built with \"aruco\" module from OpenCV.");
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
std::map< std::string, std::string > ParametersMap
MarkerDetector(const ParametersMap ¶meters=ParametersMap())
virtual ~MarkerDetector()
ULogger class and convenient macros.
void parseParameters(const ParametersMap ¶meters)
std::map< int, Transform > detect(const cv::Mat &image, const CameraModel &model, const cv::Mat &depth=cv::Mat(), float *estimatedMarkerLength=0, cv::Mat *imageWithDetections=0)
float RTABMAP_EXP getDepth(const cv::Mat &depthImage, float x, float y, bool smoothing, float depthErrorRatio=0.02f, bool estWithNeighborsIfNull=false)
const Transform & localTransform() const