29 #include <opencv2/calib3d.hpp>
30 #include <opencv2/core/eigen.hpp>
31 #include <opencv2/highgui.hpp>
34 #include <SimoxUtility/algorithm/string.h>
47 #include <Calibration/Calibration.h>
48 #include <Calibration/StereoCalibration.h>
49 #include <Image/IplImageAdaptor.h>
67 p.imageProviderName,
"img.ImageProviderName",
"Name of the image provider to use.");
69 p.referenceFrame,
"img.ReferenceFrameName",
"Name of the ReferenceFrameName");
70 defs->optional(p.agentName,
"img.AgentName",
"Name of the agent");
71 defs->optional(p.cameraIndex,
"img.cameraIndex",
"Camera index. Left = 0, Right = 1, ...");
73 std::string pattern =
"[ k3 [, k4, k5, k6 [, s1, s2, s3, s4 ] ] ]";
75 defs->defineOptionalProperty<std::vector<std::string>>(
76 "cam.ExtraDistortionCoeffs",
78 "Optional extra distortion coefficients (which cannot be retrieved from the image "
80 "\nThe expected parameters are: " +
83 "\nThat is, you must specifiy 1 (k3), 4 (k3-k6), or 8 (k3-k6, s1-s4) elements."
84 "\nNote: k1, k2, p1, p2 are retrieved from the image provider.")
87 defs->defineOptionalProperty<
float>(
88 "ar.MarkerSize", p.markerSize.load(),
"The side length of the marker(s)");
89 defs->optional(p.dictionary,
"ar.Dictionary",
"The ArUco dictionary.")
90 .map(
"4X4_50", cv::aruco::DICT_4X4_50)
91 .map(
"4X4_100", cv::aruco::DICT_4X4_100)
92 .map(
"4X4_250", cv::aruco::DICT_4X4_250)
93 .map(
"4X4_1000", cv::aruco::DICT_4X4_1000)
94 .map(
"5X5_50", cv::aruco::DICT_5X5_50)
95 .map(
"5X5_100", cv::aruco::DICT_5X5_100)
96 .map(
"5X5_250", cv::aruco::DICT_5X5_250)
97 .map(
"5X5_1000", cv::aruco::DICT_5X5_1000)
98 .map(
"6X6_50", cv::aruco::DICT_6X6_50)
99 .map(
"6X6_100", cv::aruco::DICT_6X6_100)
100 .map(
"6X6_250", cv::aruco::DICT_6X6_250)
101 .map(
"6X6_1000", cv::aruco::DICT_6X6_1000)
102 .map(
"7X7_50", cv::aruco::DICT_7X7_50)
103 .map(
"7X7_100", cv::aruco::DICT_7X7_100)
104 .map(
"7X7_250", cv::aruco::DICT_7X7_250)
105 .map(
"7X7_1000", cv::aruco::DICT_7X7_1000)
106 .map(
"ARUCO_ORIGINAL", cv::aruco::DICT_ARUCO_ORIGINAL);
108 defs->defineOptionalProperty<std::string>(
"ar.MarkerGeneration",
109 "https://chev.me/arucogen/",
110 "You can generate ArUco markers here.");
112 defs->defineOptionalProperty<
bool>(
113 "visu.Enabled", p.visuEnabled.load(),
"If true, visualize marker poses.");
126 return "ArMarkerLocalizerOpenCV";
133 *arucoDictionary = cv::aruco::getPredefinedDictionary(p.dictionary);
134 p.markerSize = getProperty<float>(
"ar.MarkerSize").getValue();
137 p.visuEnabled = getProperty<bool>(
"visu.Enabled").getValue();
140 std::string propName =
"cam.ExtraDistortionCoeffs";
141 std::vector<std::string> coeffsStr;
142 getProperty(coeffsStr,
"cam.ExtraDistortionCoeffs");
144 p.extraDistortionCoeffs.clear();
145 for (
const auto& coeffStr : coeffsStr)
149 p.extraDistortionCoeffs.push_back(std::stof(coeffStr));
151 catch (
const std::invalid_argument&)
153 ARMARX_WARNING <<
"Could not parse '" << coeffStr <<
"' as float in property "
154 << propName <<
"." <<
"\nIgnoring extra parameters.";
155 p.extraDistortionCoeffs.clear();
167 robot = virtualRobotReaderPlugin->get().getRobot(p.agentName);
170 referenceNode = robot->getRobotNode(p.referenceFrame);
176 StereoCalibrationInterfacePrx calibrationProvider =
177 StereoCalibrationInterfacePrx::checkedCast(imageProviderInfo.
proxy);
179 std::unique_ptr<CStereoCalibration> stereoCalibration(
181 CCalibration::CCameraParameters ivtCameraParameters =
182 stereoCalibration->GetLeftCalibration()->GetCameraParameters();
191 std::set<int> allowedSizes = {4, 5, 8, 12};
193 <<
" extra distortion coefficients.";
195 int num = int(4 + p.extraDistortionCoeffs.size());
199 simox::alg::multi_to_string(allowedSizes.begin(), allowedSizes.end()),
" ")
200 <<
"\n num = " << num <<
" = 4 + " << p.extraDistortionCoeffs.size()
201 <<
" = 4 + #extra coeffs";
203 cv::Mat distortionParameters(num, 1, cv::DataType<float>::type);
205 if (!calibrationProvider->getImagesAreUndistorted())
208 for (
int i = 0; i < 4; ++i)
210 distortionParameters.at<
float>(i, 0) = ivtCameraParameters.distortion[i];
213 for (
int i = 0; size_t(i) < p.extraDistortionCoeffs.size(); ++i)
215 distortionParameters.at<
float>(4 + i, 0) =
216 p.extraDistortionCoeffs.at(
size_t(i));
221 for (
int i = 0; i < distortionParameters.rows; ++i)
223 distortionParameters.at<
float>(i, 0) = 0;
227 this->distortionCoeffs = distortionParameters;
230 ARMARX_VERBOSE <<
"Distortion coefficients: \n" << this->distortionCoeffs;
233 cameraImages =
new CByteImage*[2];
247 armarx::MetaInfoSizeBasePtr info;
248 getImages(p.imageProviderName, cameraImages, info);
259 ArMarkerLocalizationResultList result = localizeAllMarkersInternal();
261 std::unique_lock lock(resultMutex);
262 lastLocalizationResult = result;
270 const Eigen::Isometry3f global_T_frame{referenceNode->getGlobalPose()};
272 for (
const auto& r : result)
274 const Eigen::Isometry3f frame_T_marker{
275 armarx::FramedPosePtr::dynamicCast(r.pose)->toEigen()};
276 const Eigen::Isometry3f global_T_marker = global_T_frame * frame_T_marker;
286 ArMarkerLocalizationResultList
287 ArMarkerLocalizerOpenCV::localizeAllMarkersInternal()
293 cameraImages[0]->bytesPerPixel = 3;
294 cameraImages[1]->bytesPerPixel = 3;
296 IplImage* imageIpl = IplImageAdaptor::Adapt(cameraImages[p.cameraIndex]);
297 cv::Mat imageOpenCV = cv::cvarrToMat(imageIpl);
306 std::vector<int> markerIDs;
307 std::vector<std::vector<cv::Point2f>> markerCorners;
308 cv::aruco::detectMarkers(
309 imageOpenCV, arucoDictionary, markerCorners, markerIDs, arucoParameters);
314 ARMARX_VERBOSE <<
"Localized " << markerIDs.size() <<
" markers: "
315 << simox::alg::join(simox::alg::multi_to_string(markerIDs),
" ");
318 cv::Mat outputImage = imageOpenCV.clone();
319 if (not markerIDs.empty())
321 cv::aruco::drawDetectedMarkers(outputImage, markerCorners, markerIDs);
329 std::vector<cv::Vec3d> rvecs, tvecs;
330 cv::aruco::estimatePoseSingleMarkers(
331 markerCorners, p.markerSize, cameraMatrix, distortionCoeffs, rvecs, tvecs);
334 ARMARX_VERBOSE <<
"Estimated " << rvecs.size() <<
" marker poses.";
338 visionx::ArMarkerLocalizationResultList resultList;
340 for (
size_t i = 0; i < markerIDs.size(); ++i)
342 visionx::ArMarkerLocalizationResult& result = resultList.emplace_back();
345 Eigen::Vector3f position = Eigen::Vector3d(tvec(0), tvec(1), tvec(2)).cast<
float>();
347 cv::Mat cvOrientation;
350 cv::Rodrigues(rvecs.at(i), cvOrientation);
352 catch (
const std::exception& e)
354 ARMARX_ERROR <<
"Caught exception when running cv::aruco::Rodrigues(): \n"
361 Eigen::Matrix3d orientation;
365 orientation.cast<
float>(), position, p.referenceFrame, p.agentName);
366 result.id = markerIDs.at(i);
370 cv::drawFrameAxes(outputImage, cameraMatrix, distortionCoeffs, rvecs[i], tvecs[i], 0.1);
373 CByteImage* output_cimage =
374 new CByteImage(outputImage.size[0], outputImage.size[1], CByteImage::ImageType::eRGB24);
377 CByteImage* result_images[2] = {cameraImages[0], output_cimage};
379 delete output_cimage;
383 visionx::ArMarkerLocalizationResultList
386 if (waitForImages(500))
388 getImages(cameraImages);
389 return localizeAllMarkersInternal();
398 ArMarkerLocalizationResultList
401 std::unique_lock lock(resultMutex);
402 return lastLocalizationResult;
413 tab.markerSize.setRange(1.0, 1000.0);
414 tab.markerSize.setSteps(1000);
415 tab.markerSize.setDecimals(1);
416 tab.markerSize.setValue(p.markerSize);
418 tab.visuEnabled.setValue(p.visuEnabled);
420 grid.
add(
Label(
"Marker size:"), {row, 0}).add(tab.markerSize, {row, 1});
422 grid.
add(
Label(
"Enable visu:"), {row, 0}).add(tab.visuEnabled, {row, 1});
432 if (tab.markerSize.hasValueChanged())
434 p.markerSize = tab.markerSize.getValue();
436 if (tab.visuEnabled.hasValueChanged())
438 p.visuEnabled = tab.visuEnabled.getValue();