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 > 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION >= 7)
43 detectorParams_.reset(
new cv::aruco::DetectorParameters());
44 #elif CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=2)
45 detectorParams_ = cv::aruco::DetectorParameters::create();
47 detectorParams_.reset(
new cv::aruco::DetectorParameters());
49 #if CV_MAJOR_VERSION > 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION >= 7)
50 detectorParams_->cornerRefinementMethod = (cv::aruco::CornerRefineMethod) Parameters::defaultMarkerCornerRefinementMethod();
51 #elif CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=3)
52 detectorParams_->cornerRefinementMethod = Parameters::defaultMarkerCornerRefinementMethod();
54 detectorParams_->doCornerRefinement = Parameters::defaultMarkerCornerRefinementMethod()!=0;
66 #ifdef HAVE_OPENCV_ARUCO
67 detectorParams_->adaptiveThreshWinSizeMin = 3;
68 detectorParams_->adaptiveThreshWinSizeMax = 23;
69 detectorParams_->adaptiveThreshWinSizeStep = 10;
70 detectorParams_->adaptiveThreshConstant = 7;
71 detectorParams_->minMarkerPerimeterRate = 0.03;
72 detectorParams_->maxMarkerPerimeterRate = 4.0;
73 detectorParams_->polygonalApproxAccuracyRate = 0.03;
74 detectorParams_->minCornerDistanceRate = 0.05;
75 detectorParams_->minDistanceToBorder = 3;
76 detectorParams_->minMarkerDistanceRate = 0.05;
77 #if CV_MAJOR_VERSION > 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION >= 7)
78 int cornerRefinementMethod;
79 Parameters::parse(parameters, Parameters::kMarkerCornerRefinementMethod(), cornerRefinementMethod);
80 detectorParams_->cornerRefinementMethod = (cv::aruco::CornerRefineMethod)cornerRefinementMethod;
81 #elif CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=3)
82 Parameters::parse(parameters, Parameters::kMarkerCornerRefinementMethod(), detectorParams_->cornerRefinementMethod);
84 int doCornerRefinement = detectorParams_->doCornerRefinement?1:0;
85 Parameters::parse(parameters, Parameters::kMarkerCornerRefinementMethod(), doCornerRefinement);
86 detectorParams_->doCornerRefinement = doCornerRefinement!=0;
88 detectorParams_->cornerRefinementWinSize = 5;
89 detectorParams_->cornerRefinementMaxIterations = 30;
90 detectorParams_->cornerRefinementMinAccuracy = 0.1;
91 detectorParams_->markerBorderBits = 1;
92 detectorParams_->perspectiveRemovePixelPerCell = 4;
93 detectorParams_->perspectiveRemoveIgnoredMarginPerCell = 0.13;
94 detectorParams_->maxErroneousBitsInBorderRate = 0.35;
95 detectorParams_->minOtsuStdDev = 5.0;
96 detectorParams_->errorCorrectionRate = 0.6;
99 Parameters::parse(parameters, Parameters::kMarkerMaxDepthError(), maxDepthError_);
103 #if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION <4 || (CV_MINOR_VERSION ==4 && CV_SUBMINOR_VERSION<2)))
104 if(dictionaryId_ >= 17)
106 UERROR(
"Cannot set AprilTag dictionary. OpenCV version should be at least 3.4.2, "
107 "current version is %s. Setting %s to default (%d)",
109 Parameters::kMarkerDictionary().
c_str(),
110 Parameters::defaultMarkerDictionary());
111 dictionaryId_ = Parameters::defaultMarkerDictionary();
114 #if CV_MAJOR_VERSION > 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION >= 7)
115 dictionary_.reset(
new cv::aruco::Dictionary());
116 *dictionary_ = cv::aruco::getPredefinedDictionary(cv::aruco::PredefinedDictionaryType(dictionaryId_));
117 #elif CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=2)
118 dictionary_ = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId_));
120 dictionary_.reset(
new cv::aruco::Dictionary());
121 *dictionary_ = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId_));
128 std::map<int, Transform> detections;
129 std::map<int, MarkerInfo> infos =
detect(image,
model, depth, std::map<int, float>(), imageWithDetections);
131 for(std::map<int, MarkerInfo>::iterator
iter=infos.begin();
iter!=infos.end(); ++
iter)
133 detections.insert(std::make_pair(
iter->first,
iter->second.pose()));
137 *markerLengthOut =
iter->second.length();
145 const std::vector<CameraModel> & models,
146 const cv::Mat & depth,
147 const std::map<int, float> & markerLengths,
148 cv::Mat * imageWithDetections)
150 UASSERT(!models.empty() && !image.empty());
151 UASSERT(
int((image.cols/models.size())*models.size()) == image.cols);
152 UASSERT(
int((depth.cols/models.size())*models.size()) == depth.cols);
153 int subRGBWidth = image.cols/models.size();
154 int subDepthWidth = depth.cols/models.size();
156 std::map<int, MarkerInfo> allInfo;
157 for(
size_t i=0;
i<models.size(); ++
i)
159 cv::Mat subImage(image, cv::Rect(subRGBWidth*
i, 0, subRGBWidth, image.rows));
162 subDepth = cv::Mat(depth, cv::Rect(subDepthWidth*
i, 0, subDepthWidth, depth.rows));
164 cv::Mat subImageWithDetections;
165 std::map<int, MarkerInfo> subInfo =
detect(subImage,
model, subDepth, markerLengths, imageWithDetections?&subImageWithDetections:0);
168 for(std::map<int, MarkerInfo>::iterator
iter=subInfo.begin();
iter!=subInfo.end(); ++
iter)
170 std::pair<std::map<int, MarkerInfo>::iterator,
bool> inserted = allInfo.insert(*
iter);
173 UWARN(
"Marker %d already added by another camera, ignoring detection from camera %d",
iter->first,
i);
179 allInfo.insert(subInfo.begin(), subInfo.end());
181 if(imageWithDetections)
185 *imageWithDetections = cv::Mat(image.size(), subImageWithDetections.type());
187 if(!subImageWithDetections.empty())
189 subImageWithDetections.copyTo(cv::Mat(*imageWithDetections, cv::Rect(subRGBWidth*
i, 0, subRGBWidth, image.rows)));
198 const cv::Mat & depth,
199 const std::map<int, float> & markerLengths,
200 cv::Mat * imageWithDetections)
202 if(!image.empty() && image.cols !=
model.imageWidth())
204 UERROR(
"This method cannot handle multi-camera marker detection, use the other function version supporting it.");
205 return std::map<int, MarkerInfo>();
208 std::map<int, MarkerInfo> detections;
210 #ifdef HAVE_OPENCV_ARUCO
212 std::vector< int > ids;
213 std::vector< std::vector< cv::Point2f > >
corners, rejected;
214 std::vector< cv::Vec3d > rvecs, tvecs;
217 #if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=2)
218 cv::aruco::detectMarkers(image, dictionary_,
corners, ids, detectorParams_, rejected);
220 cv::aruco::detectMarkers(image, *dictionary_,
corners, ids, *detectorParams_, rejected);
222 UDEBUG(
"Markers detected=%d rejected=%d", (
int)ids.size(), (
int)rejected.size());
225 float rgbToDepthFactorX = 1.0f;
226 float rgbToDepthFactorY = 1.0f;
229 rgbToDepthFactorX = 1.0f/(
model.imageWidth()>0?
model.imageWidth()/depth.cols:1);
230 rgbToDepthFactorY = 1.0f/(
model.imageHeight()>0?
model.imageHeight()/depth.rows:1);
232 else if(markerLength_ == 0)
236 UERROR(
"Depth image is empty, please set %s parameter to non-null.", Parameters::kMarkerLength().
c_str());
241 cv::aruco::estimatePoseSingleMarkers(
corners, markerLength_<=0.0?1.0
f:markerLength_,
model.K(),
model.D(), rvecs, tvecs);
242 std::vector<float> scales;
243 for(
size_t i=0;
i<ids.size(); ++
i)
246 std::map<int, float>::const_iterator findIter = markerLengths.find(ids[
i]);
247 if(!depth.empty() && (markerLength_ == 0 || (markerLength_<0 && findIter==markerLengths.end())))
257 if(
d>0 &&
d1>0 &&
d2>0 && d3>0 && d4>0)
259 float scale =
d/tvecs[
i].val[2];
261 if(
fabs(
d-
d1) < maxDepthError_ &&
263 fabs(
d-d3) < maxDepthError_ &&
264 fabs(
d-d4) < maxDepthError_)
268 tvecs[
i] *= scales.back();
269 UWARN(
"Automatic marker length estimation: id=%d depth=%fm length=%fm", ids[
i],
d, scales.back());
273 UWARN(
"The four marker's corners should be "
274 "perpendicular to camera to estimate correctly "
275 "the marker's length. Errors: %f, %f, %f > %fm (%s). Four corners: %f %f %f %f (middle=%f). "
276 "Parameter %s can be set to non-null to skip automatic "
277 "marker length estimation. Detections are ignored.",
280 Parameters::kMarkerLength().
c_str());
286 UWARN(
"Some depth values (%f,%f,%f,%f, middle=%f) cannot be detected on the "
287 "marker's corners, cannot initialize marker length. "
288 "Parameter %s can be set to non-null to skip automatic "
289 "marker length estimation. Detections are ignored.",
291 Parameters::kMarkerLength().
c_str());
295 else if(markerLength_ < 0)
297 if(findIter!=markerLengths.end())
299 length = findIter->second;
304 UWARN(
"Cannot find marker length for marker %d, ignoring this marker (count=%d)", ids[
i], (
int)markerLengths.size());
308 else if(markerLength_ > 0)
319 if((maxRange_ <= 0 || tvecs[
i].val[2] < maxRange_) &&
320 (minRange_ <= 0 || tvecs[
i].val[2] > minRange_))
323 cv::Rodrigues(rvecs[
i],
R);
324 Transform t(
R.at<
double>(0,0),
R.at<
double>(0,1),
R.at<
double>(0,2), tvecs[
i].val[0],
325 R.at<
double>(1,0),
R.at<
double>(1,1),
R.at<
double>(1,2), tvecs[
i].val[1],
326 R.at<
double>(2,0),
R.at<
double>(2,1),
R.at<
double>(2,2), tvecs[
i].val[2]);
329 UDEBUG(
"Marker %d detected in base_link: %s, optical_link=%s, local transform=%s", ids[
i], pose.
prettyPrint().c_str(),
t.prettyPrint().c_str(),
model.localTransform().prettyPrint().c_str());
332 if(markerLength_ == 0 && !scales.empty())
335 float maxError = 0.0f;
336 for(
size_t i=0;
i<scales.size(); ++
i)
343 UWARN(
"The marker's length detected between 2 of the "
344 "markers doesn't match (%fm vs %fm)."
345 "Parameter %s can be set to non-null to skip automatic "
346 "marker length estimation. Detections are ignored.",
347 scales[
i], scales[0],
348 Parameters::kMarkerLength().
c_str());
359 markerLength_ = sum/
float(scales.size());
360 UWARN(
"Final marker length estimated = %fm, max error=%fm (used for subsequent detections)", markerLength_, maxError);
364 if(imageWithDetections)
366 if(image.channels()==1)
368 cv::cvtColor(image, *imageWithDetections, cv::COLOR_GRAY2BGR);
372 image.copyTo(*imageWithDetections);
376 cv::aruco::drawDetectedMarkers(*imageWithDetections,
corners, ids);
378 for(
unsigned int i = 0;
i < ids.size();
i++)
380 std::map<int, MarkerInfo>::iterator
iter = detections.find(ids[
i]);
381 if(
iter!=detections.end())
383 #if CV_MAJOR_VERSION > 4 || (CV_MAJOR_VERSION == 4 && (CV_MINOR_VERSION >1 || (CV_MINOR_VERSION==1 && CV_PATCH_VERSION>=1)))
384 cv::drawFrameAxes(*imageWithDetections,
model.K(),
model.D(), rvecs[
i], tvecs[
i],
iter->second.length() * 0.5f);
386 cv::aruco::drawAxis(*imageWithDetections,
model.K(),
model.D(), rvecs[
i], tvecs[
i],
iter->second.length() * 0.5f);
394 UERROR(
"RTAB-Map is not built with \"aruco\" module from OpenCV.");