31#include <opencv2/calib3d.hpp>
32#include <opencv2/core/eigen.hpp>
33#include <opencv2/highgui.hpp>
36#include <SimoxUtility/algorithm/string.h>
49#include <Calibration/Calibration.h>
50#include <Calibration/StereoCalibration.h>
51#include <Image/IplImageAdaptor.h>
69 p.imageProviderName,
"img.ImageProviderName",
"Name of the image provider to use.");
71 p.referenceFrame,
"img.ReferenceFrameName",
"Name of the ReferenceFrameName");
72 defs->optional(p.agentName,
"img.AgentName",
"Name of the agent");
73 defs->optional(p.cameraIndex,
"img.cameraIndex",
"Camera index. Left = 0, Right = 1, ...");
75 std::string pattern =
"[ k3 [, k4, k5, k6 [, s1, s2, s3, s4 ] ] ]";
77 defs->defineOptionalProperty<std::vector<std::string>>(
78 "cam.ExtraDistortionCoeffs",
80 "Optional extra distortion coefficients (which cannot be retrieved from the image "
82 "\nThe expected parameters are: " +
85 "\nThat is, you must specifiy 1 (k3), 4 (k3-k6), or 8 (k3-k6, s1-s4) elements."
86 "\nNote: k1, k2, p1, p2 are retrieved from the image provider.")
89 defs->defineOptionalProperty<
float>(
90 "ar.MarkerSize", p.markerSize.load(),
"The side length of the marker(s)");
91 defs->optional(p.dictionary,
"ar.Dictionary",
"The ArUco dictionary.")
92 .map(
"4X4_50", cv::aruco::DICT_4X4_50)
93 .map(
"4X4_100", cv::aruco::DICT_4X4_100)
94 .map(
"4X4_250", cv::aruco::DICT_4X4_250)
95 .map(
"4X4_1000", cv::aruco::DICT_4X4_1000)
96 .map(
"5X5_50", cv::aruco::DICT_5X5_50)
97 .map(
"5X5_100", cv::aruco::DICT_5X5_100)
98 .map(
"5X5_250", cv::aruco::DICT_5X5_250)
99 .map(
"5X5_1000", cv::aruco::DICT_5X5_1000)
100 .map(
"6X6_50", cv::aruco::DICT_6X6_50)
101 .map(
"6X6_100", cv::aruco::DICT_6X6_100)
102 .map(
"6X6_250", cv::aruco::DICT_6X6_250)
103 .map(
"6X6_1000", cv::aruco::DICT_6X6_1000)
104 .map(
"7X7_50", cv::aruco::DICT_7X7_50)
105 .map(
"7X7_100", cv::aruco::DICT_7X7_100)
106 .map(
"7X7_250", cv::aruco::DICT_7X7_250)
107 .map(
"7X7_1000", cv::aruco::DICT_7X7_1000)
108 .map(
"ARUCO_ORIGINAL", cv::aruco::DICT_ARUCO_ORIGINAL);
110 defs->defineOptionalProperty<std::string>(
"ar.MarkerGeneration",
111 "https://chev.me/arucogen/",
112 "You can generate ArUco markers here.");
114 defs->defineOptionalProperty<
bool>(
115 "visu.Enabled", p.visuEnabled.load(),
"If true, visualize marker poses.");
134 return "ArMarkerLocalizerOpenCV";
141 *arucoDictionary = cv::aruco::getPredefinedDictionary(p.dictionary);
148 std::string propName =
"cam.ExtraDistortionCoeffs";
149 std::vector<std::string> coeffsStr;
150 getProperty(coeffsStr,
"cam.ExtraDistortionCoeffs");
152 p.extraDistortionCoeffs.clear();
153 for (
const auto& coeffStr : coeffsStr)
157 p.extraDistortionCoeffs.push_back(std::stof(coeffStr));
159 catch (
const std::invalid_argument&)
161 ARMARX_WARNING <<
"Could not parse '" << coeffStr <<
"' as float in property "
163 <<
"\nIgnoring extra parameters.";
164 p.extraDistortionCoeffs.clear();
176 robot = virtualRobotReaderPlugin->get().getRobot(p.agentName);
179 referenceNode = robot->getRobotNode(p.referenceFrame);
185 StereoCalibrationInterfacePrx calibrationProvider =
186 StereoCalibrationInterfacePrx::checkedCast(imageProviderInfo.
proxy);
188 std::unique_ptr<CStereoCalibration> stereoCalibration(
190 CCalibration::CCameraParameters ivtCameraParameters =
191 stereoCalibration->GetLeftCalibration()->GetCameraParameters();
200 std::set<int> allowedSizes = {4, 5, 8, 12};
202 <<
" extra distortion coefficients.";
204 int num = int(4 + p.extraDistortionCoeffs.size());
208 simox::alg::multi_to_string(allowedSizes.begin(), allowedSizes.end()),
" ")
209 <<
"\n num = " << num <<
" = 4 + " << p.extraDistortionCoeffs.size()
210 <<
" = 4 + #extra coeffs";
212 cv::Mat distortionParameters(num, 1, cv::DataType<float>::type);
214 if (!calibrationProvider->getImagesAreUndistorted())
217 for (
int i = 0; i < 4; ++i)
219 distortionParameters.at<
float>(i, 0) = ivtCameraParameters.distortion[i];
222 for (
int i = 0; size_t(i) < p.extraDistortionCoeffs.size(); ++i)
224 distortionParameters.at<
float>(4 + i, 0) =
225 p.extraDistortionCoeffs.at(
size_t(i));
230 for (
int i = 0; i < distortionParameters.rows; ++i)
232 distortionParameters.at<
float>(i, 0) = 0;
236 this->distortionCoeffs = distortionParameters;
239 ARMARX_VERBOSE <<
"Distortion coefficients: \n" << this->distortionCoeffs;
242 cameraImages =
new CByteImage*[2];
256 armarx::MetaInfoSizeBasePtr info;
257 getImages(p.imageProviderName, cameraImages, info);
258 m_timestamp_last_image =
269 ArMarkerLocalizationResultList result = localizeAllMarkersInternal();
271 std::unique_lock lock(resultMutex);
272 lastLocalizationResult = result;
280 const Eigen::Isometry3f global_T_frame{referenceNode->getGlobalPose()};
282 for (
const auto& r : result)
284 const Eigen::Isometry3f frame_T_marker{
285 armarx::FramedPosePtr::dynamicCast(r.pose)->toEigen()};
286 const Eigen::Isometry3f global_T_marker = global_T_frame * frame_T_marker;
292 arviz.commit({layer});
296 ArMarkerLocalizationResultList
297 ArMarkerLocalizerOpenCV::localizeAllMarkersInternal()
303 cameraImages[0]->bytesPerPixel = 3;
304 cameraImages[1]->bytesPerPixel = 3;
306 IplImage* imageIpl = IplImageAdaptor::Adapt(cameraImages[p.cameraIndex]);
307 cv::Mat imageOpenCV = cv::cvarrToMat(imageIpl);
316 std::vector<int> markerIDs;
317 std::vector<std::vector<cv::Point2f>> markerCorners;
318 cv::aruco::detectMarkers(
319 imageOpenCV, arucoDictionary, markerCorners, markerIDs, arucoParameters);
324 ARMARX_VERBOSE <<
"Localized " << markerIDs.size() <<
" markers: "
325 << simox::alg::join(simox::alg::multi_to_string(markerIDs),
" ");
328 cv::Mat outputImage = imageOpenCV.clone();
329 if (not markerIDs.empty())
331 cv::aruco::drawDetectedMarkers(outputImage, markerCorners, markerIDs);
339 std::vector<cv::Vec3d> rvecs, tvecs;
340 cv::aruco::estimatePoseSingleMarkers(
341 markerCorners, p.markerSize, cameraMatrix, distortionCoeffs, rvecs, tvecs);
344 ARMARX_VERBOSE <<
"Estimated " << rvecs.size() <<
" marker poses.";
348 visionx::ArMarkerLocalizationResultList resultList;
350 for (
size_t i = 0; i < markerIDs.size(); ++i)
352 visionx::ArMarkerLocalizationResult& result = resultList.emplace_back();
354 const cv::Vec3d& tvec = tvecs.at(i);
355 Eigen::Vector3f position = Eigen::Vector3d(tvec(0), tvec(1), tvec(2)).cast<
float>();
357 cv::Mat cvOrientation;
360 cv::Rodrigues(rvecs.at(i), cvOrientation);
362 catch (
const std::exception& e)
364 ARMARX_ERROR <<
"Caught exception when running cv::aruco::Rodrigues(): \n"
371 Eigen::Matrix3d orientation;
372 cv::cv2eigen(cvOrientation, orientation);
374 result.pose =
new armarx::FramedPose(
375 orientation.cast<
float>(), position, p.referenceFrame, p.agentName);
376 result.id = markerIDs.at(i);
380 cv::drawFrameAxes(outputImage, cameraMatrix, distortionCoeffs, rvecs[i], tvecs[i], 0.1);
383 CByteImage* output_cimage =
384 new CByteImage(outputImage.size[0], outputImage.size[1], CByteImage::ImageType::eRGB24);
387 CByteImage* result_images[2] = {cameraImages[0], output_cimage};
389 delete output_cimage;
393 visionx::ArMarkerLocalizationResultList
399 return localizeAllMarkersInternal();
408 ArMarkerLocalizationResultList
411 std::unique_lock lock(resultMutex);
412 return lastLocalizationResult;
423 tab.markerSize.setRange(1.0, 1000.0);
424 tab.markerSize.setSteps(1000);
425 tab.markerSize.setDecimals(1);
426 tab.markerSize.setValue(p.markerSize);
428 tab.visuEnabled.setValue(p.visuEnabled);
430 grid.
add(
Label(
"Marker size:"), {row, 0}).add(tab.markerSize, {row, 1});
432 grid.
add(
Label(
"Enable visu:"), {row, 0}).add(tab.visuEnabled, {row, 1});
442 if (tab.markerSize.hasValueChanged())
444 p.markerSize = tab.markerSize.getValue();
446 if (tab.visuEnabled.hasValueChanged())
448 p.visuEnabled = tab.visuEnabled.getValue();
int Label(int n[], int size, int *curLabel, MiscLib::Vector< std::pair< int, size_t > > *labels)
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
armarx::viz::Client arviz
static DateTime Now()
Current time on the virtual clock.
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
static Duration MicroSeconds(std::int64_t microSeconds)
Constructs a duration in microseconds.
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
Represents a point in time.
DerivedT & pose(Eigen::Matrix4f const &pose)
ArMarkerLocalizerOpenCVPropertyDefinitions(std::string prefix)
ArMarkerLocalizerOpenCV uses CTexturedRecognition of IVTRecognition in order to recognize and localiz...
void onConnectImageProcessor() override
Implement this method in the ImageProcessor in order execute parts when the component is fully initia...
ArMarkerLocalizerOpenCV()
void RemoteGui_update() override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void process() override
Process the vision component.
void onInitImageProcessor() override
Setup the vision component.
visionx::ArMarkerLocalizationResultList LocalizeAllMarkersNow(const Ice::Current &) override
visionx::ArMarkerLocalizationResultList GetLatestLocalizationResult(const Ice::Current &) override
static std::string GetDefaultName()
void createRemoteGuiTab()
std::string getDefaultName() const override
ImageProcessorPropertyDefinitions(std::string prefix)
bool waitForImages(int milliseconds=1000)
Wait for new images.
ImageProviderInfo getImageProvider(std::string name, ImageType destinationImageType=eRgb, bool waitForProxy=false)
Select an ImageProvider.
int getImages(CByteImage **ppImages)
Poll images from provider.
void provideResultImages(CByteImage **images, armarx::MetaInfoSizeBasePtr info=nullptr)
sends result images for visualization
ImageProviderInterfacePrx proxy
proxy to image provider
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_POSITIVE(number)
This macro evaluates whether number is positive (> 0) and if it turns out to be false it will throw a...
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
void toIce(dto::ClockType::ClockTypeEnum &dto, const ClockType &bo)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
cv::Mat makeCameraMatrix(const visionx::CameraParameters &cameraParams)
void copyCvMatToIVT(cv::Mat const &input, CByteImage *output)
Copies the contents of an OpenCV matrix to an IVT CByteImage.
void RemoteGui_startRunningTask()
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
GridLayout & add(Widget const &child, Pos pos, Span span=Span{1, 1})
void add(ElementT const &element)