39#include <visp3/core/vpConfig.h>
41#if defined(VISP_HAVE_CATCH2) && defined(VISP_HAVE_APRILTAG) && (VISP_HAVE_DATASET_VERSION >= 0x030300)
43#include <catch_amalgamated.hpp>
46#include <visp3/core/vpDisplay.h>
47#include <visp3/core/vpIoTools.h>
48#include <visp3/core/vpPixelMeterConversion.h>
49#include <visp3/core/vpPoint.h>
50#include <visp3/detection/vpDetectorAprilTag.h>
51#include <visp3/io/vpImageIo.h>
52#include <visp3/vision/vpPose.h>
54#ifdef ENABLE_VISP_NAMESPACE
61 std::string m_message;
62 std::vector<vpImagePoint> m_corners;
64 TagGroundTruth(
const std::string &msg,
const std::vector<vpImagePoint> &c) : m_message(msg), m_corners(c) { }
66 bool operator==(
const TagGroundTruth &b)
const
68 if (m_message != b.m_message || m_corners.size() != b.m_corners.size()) {
72 for (
size_t i = 0;
i < m_corners.size();
i++) {
74 if (!
vpMath::equal(m_corners[i].get_u(), b.m_corners[i].get_u(), 0.5) ||
75 !
vpMath::equal(m_corners[i].get_v(), b.m_corners[i].get_v(), 0.5)) {
83 bool operator!=(
const TagGroundTruth &b)
const {
return !(*
this == b); }
85 double rmse(
const std::vector<vpImagePoint> &c)
89 if (m_corners.size() == c.size()) {
90 for (
size_t i = 0;
i < m_corners.size();
i++) {
91 const vpImagePoint &a = m_corners[
i];
92 const vpImagePoint &b = c[
i];
100 return sqrt(error / (2 * m_corners.size()));
104#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_EIGEN3)
105std::ostream &operator<<(std::ostream &os, TagGroundTruth &t)
107 os <<
t.m_message << std::endl;
108 for (
size_t i = 0;
i <
t.m_corners.size();
i++) {
109 os <<
t.m_corners[
i] << std::endl;
124 : m_family(family), m_method(method), m_tagId(tagId)
127 bool operator==(
const FailedTestCase &b)
const
129 return m_family == b.m_family && m_method == b.m_method && m_tagId == b.m_tagId;
132 bool operator!=(
const FailedTestCase &b)
const {
return !(*
this == b); }
136TEST_CASE(
"Apriltag pose estimation test",
"[apriltag_pose_estimation_test]")
138 std::map<vpDetectorAprilTag::vpAprilTagFamily, std::string> apriltagMap = {
143#if defined(VISP_HAVE_APRILTAG_BIG_FAMILY)
152 std::map<vpDetectorAprilTag::vpAprilTagFamily, double> tagSizeScales = {
157#if defined(VISP_HAVE_APRILTAG_BIG_FAMILY)
166 std::vector<vpDetectorAprilTag::vpPoseEstimationMethod> poseMethods = {
169#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_EIGEN3)
176 std::map<vpDetectorAprilTag::vpPoseEstimationMethod, std::string> methodNames = {
180#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_EIGEN3)
187 const size_t nbTags = 5;
188 const double tagSize_ = 0.25;
189 std::map<int, double> tagsSize = {
190 {0, tagSize_}, {1, tagSize_}, {2, tagSize_}, {3, tagSize_ / 2}, {4, tagSize_ / 2},
193 std::map<int, double> errorTranslationThresh = {
194 {0, 0.025}, {1, 0.09}, {2, 0.05}, {3, 0.13}, {4, 0.09},
196 std::map<int, double> errorRotationThresh = {
197 {0, 0.04}, {1, 0.075}, {2, 0.07}, {3, 0.18}, {4, 0.13},
199 std::vector<FailedTestCase> ignoreTests = {
205 cam.initPersProjWithoutDistortion(700.0, 700.0, 320.0, 240.0);
207 std::map<int, vpHomogeneousMatrix> groundTruthPoses;
208 for (
size_t i = 0;
i < nbTags;
i++) {
211 std::to_string(i) + std::string(
".txt"));
212 std::ifstream file(filename);
213 groundTruthPoses[
static_cast<int>(
i)].load(file);
216 for (
const auto &kv : apriltagMap) {
217 auto family = kv.first;
218 std::cout <<
"\nApriltag family: " << family << std::endl;
221 std::string(
"AprilTag/benchmark/640x480/") + kv.second + std::string(
"_640x480.png"));
222 const double tagSize = tagSize_ * tagSizeScales[family];
227 REQUIRE(I.getSize() == 640 * 480);
231 for (
auto method : poseMethods) {
232 std::cout <<
"\tPose estimation method: " << method << std::endl;
233 apriltag_detector.setAprilTagPoseEstimationMethod(method);
237 std::vector<vpHomogeneousMatrix> cMo_vec;
238 apriltag_detector.detect(I, tagSize, cam, cMo_vec);
239 CHECK(cMo_vec.size() == nbTags);
241 std::vector<std::vector<vpImagePoint> > tagsCorners = apriltag_detector.getPolygon();
242 CHECK(tagsCorners.size() == nbTags);
244 std::vector<std::string> messages = apriltag_detector.getMessage();
245 CHECK(messages.size() == nbTags);
247 std::vector<int> tagsId = apriltag_detector.getTagsId();
248 CHECK(tagsId.size() == nbTags);
249 std::map<int, int> idsCount;
250 for (
size_t i = 0;
i < tagsId.size();
i++) {
251 idsCount[tagsId[
i]]++;
252 CHECK((tagsId[i] >= 0 && tagsId[i] < 5));
254 CHECK(idsCount.size() == nbTags);
256 for (
size_t i = 0;
i < cMo_vec.size();
i++) {
263 std::cout <<
"\t\tSame size, Tag: " <<
i << std::endl;
267 vpColVector error_translation =
vpColVector(pose.getTranslationVector() - pose_truth.getTranslationVector());
269 double error_trans = sqrt(error_translation.
sumSquare() / 3);
270 double error_orientation = sqrt(error_thetau.
sumSquare() / 3);
271 std::cout <<
"\t\t\tTranslation error: " << error_trans <<
" / Rotation error: " << error_orientation
273 CHECK((error_trans < errorTranslationThresh[
id] && error_orientation < errorRotationThresh[
id]));
279 apriltag_detector.detect(I);
281 std::vector<std::vector<vpImagePoint> > tagsCorners = apriltag_detector.getPolygon();
282 CHECK(tagsCorners.size() == nbTags);
284 std::vector<std::string> messages = apriltag_detector.getMessage();
285 CHECK(messages.size() == nbTags);
287 std::vector<int> tagsId = apriltag_detector.getTagsId();
288 CHECK(tagsId.size() == nbTags);
289 std::map<int, int> idsCount;
290 for (
size_t i = 0;
i < tagsId.size();
i++) {
291 idsCount[tagsId[
i]]++;
292 CHECK((tagsId[i] >= 0 && tagsId[i] < 5));
294 CHECK(idsCount.size() == nbTags);
296 for (
size_t idx = 0;
idx < tagsId.size();
idx++) {
297 std::cout <<
"\t\tCustom size, Tag: " <<
idx << std::endl;
298 const int id = tagsId[
idx];
300 apriltag_detector.getPose(idx, tagsSize[
id] * tagSizeScales[family], cam, cMo);
306 vpColVector error_translation =
vpColVector(pose.getTranslationVector() - pose_truth.getTranslationVector());
308 double error_trans = sqrt(error_translation.
sumSquare() / 3);
309 double error_orientation = sqrt(error_thetau.
sumSquare() / 3);
310 std::cout <<
"\t\t\tTranslation error: " << error_trans <<
" / Rotation error: " << error_orientation
312 if (std::find(ignoreTests.begin(), ignoreTests.end(),
313 FailedTestCase(family, method,
static_cast<int>(idx))) == ignoreTests.end()) {
314 CHECK((error_trans < errorTranslationThresh[
id] && error_orientation < errorRotationThresh[
id]));
321 apriltag_detector.detect(I);
323 std::vector<std::vector<vpImagePoint> > tagsCorners = apriltag_detector.getPolygon();
324 CHECK(tagsCorners.size() == nbTags);
326 std::vector<std::string> messages = apriltag_detector.getMessage();
327 CHECK(messages.size() == nbTags);
329 std::vector<int> tagsId = apriltag_detector.getTagsId();
330 CHECK(tagsId.size() == nbTags);
331 std::map<int, int> idsCount;
332 for (
size_t i = 0;
i < tagsId.size();
i++) {
333 idsCount[tagsId[
i]]++;
334 CHECK((tagsId[i] >= 0 && tagsId[i] < 5));
336 CHECK(idsCount.size() == nbTags);
338 for (
size_t idx = 0;
idx < tagsId.size();
idx++) {
339 std::cout <<
"\t\tCustom size + aligned Z-axis, Tag: " <<
idx << std::endl;
340 const int id = tagsId[
idx];
342 apriltag_detector.setZAlignedWithCameraAxis(
true);
343 apriltag_detector.getPose(idx, tagsSize[
id] * tagSizeScales[family], cam, cMo);
344 apriltag_detector.setZAlignedWithCameraAxis(
false);
351 vpColVector error_translation =
vpColVector(pose.getTranslationVector() - pose_truth.getTranslationVector());
353 double error_trans = sqrt(error_translation.
sumSquare() / 3);
354 double error_orientation = sqrt(error_thetau.
sumSquare() / 3);
355 std::cout <<
"\t\t\tTranslation error: " << error_trans <<
" / Rotation error: " << error_orientation
357 if (std::find(ignoreTests.begin(), ignoreTests.end(),
358 FailedTestCase(family, method,
static_cast<int>(idx))) == ignoreTests.end()) {
359 CHECK((error_trans < errorTranslationThresh[
id] && error_orientation < errorRotationThresh[
id]));
367TEST_CASE(
"Apriltag corners accuracy test",
"[apriltag_corners_accuracy_test]")
369 std::map<vpDetectorAprilTag::vpAprilTagFamily, std::string> apriltagMap = {
374#if defined(VISP_HAVE_APRILTAG_BIG_FAMILY)
383 const size_t nbTags = 5;
384 std::map<vpDetectorAprilTag::vpAprilTagFamily, std::map<int, std::vector<vpImagePoint> > > groundTruthCorners;
385 for (
const auto &kv : apriltagMap) {
388 std::string(
"AprilTag/benchmark/640x480/corners_") + kv.second + std::string(
".txt"));
389 std::ifstream file(filename);
390 REQUIRE(file.is_open());
393 double p0x = 0, p0y = 0;
394 double p1x = 0, p1y = 0;
395 double p2x = 0, p2y = 0;
396 double p3x = 0, p3y = 0;
397 while (file >>
id >> p0x >> p0y >> p1x >> p1y >> p2x >> p2y >> p3x >> p3y) {
398 groundTruthCorners[kv.first][id].push_back(
vpImagePoint(p0y, p0x));
399 groundTruthCorners[kv.first][id].push_back(
vpImagePoint(p1y, p1x));
400 groundTruthCorners[kv.first][id].push_back(
vpImagePoint(p2y, p2x));
401 groundTruthCorners[kv.first][id].push_back(
vpImagePoint(p3y, p3x));
402 REQUIRE(groundTruthCorners[kv.first][
id].size() == 4);
406 for (
const auto &kv : apriltagMap) {
407 auto family = kv.first;
408 std::cout <<
"\nApriltag family: " << family << std::endl;
411 std::string(
"AprilTag/benchmark/640x480/") + kv.second + std::string(
"_640x480.png"));
416 REQUIRE(I.getSize() == 640 * 480);
419 apriltag_detector.detect(I);
420 std::vector<int> tagsId = apriltag_detector.getTagsId();
421 std::vector<std::vector<vpImagePoint> > tagsCorners = apriltag_detector.getTagsCorners();
423 REQUIRE(tagsCorners.size() == nbTags);
424 REQUIRE(tagsId.size() == nbTags);
425 for (
size_t i = 0;
i < tagsCorners.size();
i++) {
426 const int tagId = tagsId[
i];
427 REQUIRE(tagsCorners[i].size() == 4);
429 TagGroundTruth corners_ref(
"", groundTruthCorners[family][tagId]);
430 TagGroundTruth corners_cur(
"", tagsCorners[i]);
431 CHECK((corners_ref == corners_cur));
433 std::cout <<
"\tid: " << tagId <<
" - RMSE: " << corners_ref.rmse(corners_cur.m_corners) << std::endl;
438#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_EIGEN3)
439TEST_CASE(
"Apriltag regression test",
"[apriltag_regression_test]")
441#if (VISP_HAVE_DATASET_VERSION >= 0x030600)
450 REQUIRE(I.getSize() == 640 * 480);
454 const double tagSize = 0.053;
455 const float quad_decimate = 1.0;
458 dynamic_cast<vpDetectorAprilTag *
>(detector)->setAprilTagPoseEstimationMethod(poseEstimationMethod);
461 cam.initPersProjWithoutDistortion(615.1674805, 615.1675415, 312.1889954, 243.4373779);
463 std::vector<vpHomogeneousMatrix> cMo_vec;
467 std::map<std::string, TagGroundTruth> mapOfTagsGroundTruth;
469 std::string filename_ground_truth =
471 std::ifstream file_ground_truth(filename_ground_truth.c_str());
472 REQUIRE(file_ground_truth.is_open());
473 std::string message =
"";
474 double v1 = 0.0, v2 = 0.0, v3 = 0.0, v4 = 0.0;
475 double u1 = 0.0, u2 = 0.0, u3 = 0.0, u4 = 0.0;
476 while (file_ground_truth >> message >> v1 >> u1 >> v2 >> u2 >> v3 >> u3 >> v4 >> u4) {
477 std::vector<vpImagePoint> tagCorners(4);
478 tagCorners[0].set_ij(v1, u1);
479 tagCorners[1].set_ij(v2, u2);
480 tagCorners[2].set_ij(v3, u3);
481 tagCorners[3].set_ij(v4, u4);
482 mapOfTagsGroundTruth.insert(std::make_pair(message, TagGroundTruth(message, tagCorners)));
486 std::map<std::string, vpPoseVector> mapOfPosesGroundTruth;
488 std::string filename_ground_truth =
490 std::ifstream file_ground_truth(filename_ground_truth.c_str());
491 REQUIRE(file_ground_truth.is_open());
492 std::string message =
"";
493 double tx = 0.0, ty = 0.0, tz = 0.0;
494 double tux = 0.0, tuy = 0.0, tuz = 0.0;
495 while (file_ground_truth >> message >> tx >> ty >> tz >> tux >> tuy >> tuz) {
496 mapOfPosesGroundTruth.insert(std::make_pair(message,
vpPoseVector(tx, ty, tz, tux, tuy, tuz)));
501 std::vector<vpImagePoint>
p = detector->
getPolygon(i);
503 std::string message = detector->
getMessage(i);
504 std::replace(message.begin(), message.end(),
' ',
'_');
505 std::map<std::string, TagGroundTruth>::iterator it = mapOfTagsGroundTruth.find(message);
506 TagGroundTruth current(message, p);
507 if (it == mapOfTagsGroundTruth.end()) {
508 std::cerr <<
"Problem with tag decoding (tag_family or id): " << message << std::endl;
510 else if (it->second != current) {
511 std::cerr <<
"Problem, current detection:\n" << current <<
"\nReference:\n" << it->second << std::endl;
513 REQUIRE(it != mapOfTagsGroundTruth.end());
514 CHECK(it->second == current);
517 for (
size_t i = 0;
i < cMo_vec.size();
i++) {
520 std::string message = detector->
getMessage(i);
521 std::replace(message.begin(), message.end(),
' ',
'_');
522 std::map<std::string, vpPoseVector>::iterator it = mapOfPosesGroundTruth.find(message);
523 if (it == mapOfPosesGroundTruth.end()) {
524 std::cerr <<
"Problem with tag decoding (tag_family or id): " << message << std::endl;
526 REQUIRE(it != mapOfPosesGroundTruth.end());
527 std::cout <<
"Tag: " << message << std::endl;
528 std::cout <<
"\tEstimated pose: " << pose_vec.t() << std::endl;
529 std::cout <<
"\tReference pose: " << it->second.t() << std::endl;
530 for (
unsigned int cpt = 0; cpt < 3; cpt++) {
532 !
vpMath::equal(it->second[cpt + 3], pose_vec[cpt + 3], 0.005)) {
533 std::cerr <<
"Problem, current pose: " << pose_vec.t() <<
"\nReference pose: " << it->second.t() << std::endl;
535 CHECK((
vpMath::equal(it->second[cpt], pose_vec[cpt], 0.005) &&
536 vpMath::equal(it->second[cpt + 3], pose_vec[cpt + 3], 0.005)));
543TEST_CASE(
"Apriltag copy constructor test",
"[apriltag_copy_constructor_test]")
551 REQUIRE(I.getSize() == 640 * 480);
555 const double tagSize = 0.25 * 5 / 9;
556 const float quad_decimate = 1.0;
561 cam.initPersProjWithoutDistortion(700, 700, 320, 240);
563 std::vector<vpHomogeneousMatrix> cMo_vec;
564 detector->
detect(I, tagSize, cam, cMo_vec);
565 std::vector<std::vector<vpImagePoint> > tagsCorners = detector->
getTagsCorners();
566 std::vector<int> tagsId = detector->
getTagsId();
573 std::vector<std::vector<vpImagePoint> > tagsCorners_copy = detector_copy.
getTagsCorners();
574 std::vector<int> tagsId_copy = detector_copy.getTagsId();
575 REQUIRE(tagsCorners_copy.size() == tagsCorners.size());
576 REQUIRE(tagsId_copy.size() == tagsId.size());
577 REQUIRE(tagsCorners_copy.size() == tagsId_copy.size());
579 for (
size_t i = 0;
i < tagsCorners.size();
i++) {
580 const std::vector<vpImagePoint> &corners_ref = tagsCorners[
i];
581 const std::vector<vpImagePoint> &corners_copy = tagsCorners_copy[
i];
582 REQUIRE(corners_ref.size() == corners_copy.size());
584 for (
size_t j = 0;
j < corners_ref.size();
j++) {
587 CHECK(corner_ref == corner_copy);
590 int id_ref = tagsId[
i];
591 int id_copy = tagsId_copy[
i];
592 CHECK(id_ref == id_copy);
595 std::vector<vpHomogeneousMatrix> cMo_vec_copy;
596 detector_copy.detect(I, tagSize, cam, cMo_vec_copy);
597 REQUIRE(cMo_vec.size() == cMo_vec_copy.size());
598 for (
size_t idx = 0;
idx < cMo_vec_copy.size();
idx++) {
601 for (
unsigned int i = 0;
i < 3;
i++) {
602 for (
unsigned int j = 0;
j < 4;
j++) {
603 CHECK(
vpMath::equal(cMo[i][j], cMo_copy[i][j], std::numeric_limits<double>::epsilon()));
609TEST_CASE(
"Apriltag assignment operator test",
"[apriltag_assignment_operator_test]")
617 REQUIRE(I.getSize() == 640 * 480);
621 const double tagSize = 0.25 * 5 / 9;
622 const float quad_decimate = 1.0;
627 cam.initPersProjWithoutDistortion(700, 700, 320, 240);
629 std::vector<vpHomogeneousMatrix> cMo_vec;
630 detector->
detect(I, tagSize, cam, cMo_vec);
631 std::vector<std::vector<vpImagePoint> > tagsCorners = detector->
getTagsCorners();
632 std::vector<int> tagsId = detector->
getTagsId();
639 std::vector<std::vector<vpImagePoint> > tagsCorners_copy = detector_copy.
getTagsCorners();
640 std::vector<int> tagsId_copy = detector_copy.
getTagsId();
641 REQUIRE(tagsCorners_copy.size() == tagsCorners.size());
642 REQUIRE(tagsId_copy.size() == tagsId.size());
643 REQUIRE(tagsCorners_copy.size() == tagsId_copy.size());
645 for (
size_t i = 0;
i < tagsCorners.size();
i++) {
646 const std::vector<vpImagePoint> &corners_ref = tagsCorners[
i];
647 const std::vector<vpImagePoint> &corners_copy = tagsCorners_copy[
i];
648 REQUIRE(corners_ref.size() == corners_copy.size());
650 for (
size_t j = 0;
j < corners_ref.size();
j++) {
653 CHECK(corner_ref == corner_copy);
656 int id_ref = tagsId[
i];
657 int id_copy = tagsId_copy[
i];
658 CHECK(id_ref == id_copy);
661 std::vector<vpHomogeneousMatrix> cMo_vec_copy;
662 detector_copy.
detect(I, tagSize, cam, cMo_vec_copy);
663 REQUIRE(cMo_vec.size() == cMo_vec_copy.size());
664 for (
size_t idx = 0;
idx < cMo_vec_copy.size();
idx++) {
667 for (
unsigned int i = 0;
i < 3;
i++) {
668 for (
unsigned int j = 0;
j < 4;
j++) {
669 CHECK(
vpMath::equal(cMo[i][j], cMo_copy[i][j], std::numeric_limits<double>::epsilon()));
675TEST_CASE(
"Apriltag getTagsPoints3D test",
"[apriltag_get_tags_points3D_test]")
683 REQUIRE(I.getSize() == 640 * 480);
687 const double familyScale = 5.0 / 9;
688 const double tagSize = 0.25;
689 std::map<int, double> tagsSize = {
690 {-1, tagSize * familyScale}, {3, tagSize / 2 * familyScale}, {4, tagSize / 2 * familyScale} };
695 cam.initPersProjWithoutDistortion(700, 700, 320, 240);
697 std::vector<vpHomogeneousMatrix> cMo_vec;
698 REQUIRE(detector.
detect(I));
701 std::vector<int> tagsId = detector.
getTagsId();
702 for (
size_t i = 0;
i < tagsId.size();
i++) {
704 double size = tagsSize[-1];
705 if (tagsSize.find(
id) != tagsSize.end()) {
710 detector.
getPose(i, size, cam, cMo);
711 cMo_vec.push_back(cMo);
715 std::vector<std::vector<vpPoint> > tagsPoints = detector.
getTagsPoints3D(tagsId, tagsSize);
716 std::vector<std::vector<vpImagePoint> > tagsCorners = detector.
getTagsCorners();
717 REQUIRE(tagsPoints.size() == tagsCorners.size());
719 for (
size_t i = 0;
i < tagsPoints.size();
i++) {
720 REQUIRE(tagsPoints[i].size() == tagsCorners[i].size());
722 for (
size_t j = 0;
j < tagsPoints[
i].size();
j++) {
731 vpPose pose(tagsPoints[i]);
741 double epsilon = 1
e-12;
743 for (
unsigned int row = 0; row <
cMo.getRows(); row++) {
744 for (
unsigned int col = 0; col <
cMo.getCols(); col++) {
745 CHECK(
vpMath::equal(cMo[row][col], cMo_manual[row][col], epsilon));
752int main(
int argc,
const char *argv[])
754 Catch::Session session;
756 session.applyCommandLine(argc, argv);
757 int numFailed = session.run();
763int main() {
return EXIT_SUCCESS; }
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
@ BEST_RESIDUAL_VIRTUAL_VS
@ HOMOGRAPHY_ORTHOGONAL_ITERATION
std::vector< std::vector< vpImagePoint > > getTagsCorners() const
void setAprilTagQuadDecimate(float quadDecimate)
std::vector< std::vector< vpPoint > > getTagsPoints3D(const std::vector< int > &tagsId, const std::map< int, double > &tagsSize) const
bool detect(const vpImage< unsigned char > &I) VP_OVERRIDE
@ TAG_CIRCLE21h7
AprilTag Circle21h7 pattern.
@ TAG_25h9
AprilTag 25h9 pattern.
@ TAG_CUSTOM48h12
AprilTag Custom48h12 pattern.
@ TAG_36h11
AprilTag 36h11 pattern (recommended).
@ TAG_STANDARD52h13
AprilTag Standard52h13 pattern.
@ TAG_16h5
AprilTag 16h5 pattern.
@ TAG_STANDARD41h12
AprilTag Standard41h12 pattern.
@ TAG_CIRCLE49h12
AprilTag Circle49h12 pattern.
std::vector< int > getTagsId() const
bool getPose(size_t tagIndex, double tagSize, const vpCameraParameters &cam, vpHomogeneousMatrix &cMo, vpHomogeneousMatrix *cMo2=nullptr, double *projError=nullptr, double *projError2=nullptr)
std::vector< std::vector< vpImagePoint > > & getPolygon()
std::vector< std::string > & getMessage()
size_t getNbObjects() const
Implementation of an homogeneous matrix and operations on such kind of matrices.
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition of the vpImage class member functions.
static bool equal(double x, double y, double threshold=0.001)
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
void set_x(double x)
Set the point x coordinate in the image plane.
void set_y(double y)
Set the point y coordinate in the image plane.
Implementation of a pose vector and operations on poses.
Class used for pose computation from N points (pose from point only). Some of the algorithms implemen...
@ DEMENTHON_LAGRANGE_VIRTUAL_VS
Implementation of a rotation vector as axis-angle minimal representation.
Class that consider the case of a translation vector.