43 #include <visp3/core/vpDisplay.h> 44 #include <visp3/core/vpIoTools.h> 45 #include <visp3/detection/vpDetectorAprilTag.h> 46 #include <visp3/gui/vpDisplayGDI.h> 47 #include <visp3/gui/vpDisplayOpenCV.h> 48 #include <visp3/gui/vpDisplayX.h> 49 #include <visp3/io/vpImageIo.h> 50 #include <visp3/io/vpParseArgv.h> 52 #if defined(VISP_HAVE_APRILTAG) 55 #define GETOPTARGS "cdi:p:C:T:h" 66 void usage(
const char *name,
const char *badparam, std::string ipath)
69 Test AprilTag detection.\n\ 72 %s [-c] [-d] [-i <input image path>] [-p <personal image path>] \ 73 [-C <tag color>] [-T <tag thickness>]\n\ 79 -i <input image path> %s\n\ 80 Set image input path.\n\ 81 From this path read \"AprilTag/AprilTag.pgm image.\n\ 82 Setting the VISP_INPUT_IMAGE_PATH environment\n\ 83 variable produces the same behaviour than using\n\ 86 -p <personal image path> \n\ 87 Path to an image used to test image reading function.\n\ 88 Example: -p /my_path_to/image.png\n\ 91 Disable the mouse click. Useful to automate the \n\ 92 execution of this program without human intervention.\n\ 95 Turn off the display.\n\ 97 -C <color (0, 1, ...)> \n\ 98 Color for tag detection display.\n\ 101 Thickness for tag detection display.\n\ 104 Print the help.\n\n", ipath.c_str());
107 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
123 bool getOptions(
int argc,
const char **argv, std::string &ipath, std::string &ppath,
bool &click_allowed,
bool &display,
124 int &color_id,
unsigned int &thickness)
138 usage(argv[0], NULL, ipath);
142 click_allowed =
false;
148 color_id = atoi(optarg_);
151 thickness = (
unsigned int) atoi(optarg_);
155 usage(argv[0], optarg_, ipath);
161 if ((c == 1) || (c == -1)) {
163 usage(argv[0], NULL, ipath);
164 std::cerr <<
"ERROR: " << std::endl;
165 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
172 struct TagGroundTruth {
174 std::vector<vpImagePoint> corners;
176 TagGroundTruth(
const std::string &msg,
const std::vector<vpImagePoint> &c) : message(msg), corners(c) {}
178 bool operator==(
const TagGroundTruth &b)
const 180 if (message != b.message || corners.size() != b.corners.size())
183 for (
size_t i = 0; i < corners.size(); i++) {
185 if (!
vpMath::equal(corners[i].get_u(), b.corners[i].get_u(), 0.5) ||
186 !
vpMath::equal(corners[i].get_v(), b.corners[i].get_v(), 0.5)) {
194 bool operator!=(
const TagGroundTruth &b)
const {
return !(*
this == b); }
197 std::ostream &operator<<(std::ostream &os, TagGroundTruth &t)
199 os << t.message << std::endl;
200 for (
size_t i = 0; i < t.corners.size(); i++)
201 os << t.corners[i] << std::endl;
207 int main(
int argc,
const char *argv[])
210 std::string env_ipath;
211 std::string opt_ipath =
"";
212 std::string opt_ppath =
"";
213 std::string ipath =
"";
214 std::string filename =
"";
215 bool opt_click_allowed =
true;
216 bool opt_display =
true;
217 int opt_color_id = -1;
218 unsigned int opt_thickness = 2;
225 if (!env_ipath.empty())
229 if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_click_allowed, opt_display,
230 opt_color_id, opt_thickness) ==
false) {
235 if (!opt_ipath.empty())
240 if (!opt_ipath.empty() && !env_ipath.empty()) {
241 if (ipath != env_ipath) {
242 std::cout << std::endl <<
"WARNING: " << std::endl;
243 std::cout <<
" Since -i <visp image path=" << ipath <<
"> " 244 <<
" is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
245 <<
" we skip the environment variable." << std::endl;
254 if (opt_ppath.empty()) {
257 filename = opt_ppath;
261 std::cerr <<
"Filename: " << filename <<
" does not exist." << std::endl;
268 #elif defined(VISP_HAVE_GDI) 270 #elif defined(VISP_HAVE_OPENCV) 278 double tagSize = 0.053;
279 float quad_decimate = 1.0;
281 bool display_tag =
true;
285 dynamic_cast<vpDetectorAprilTag *
>(detector)->setAprilTagPoseEstimationMethod(poseEstimationMethod);
295 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV) 296 d.
init(I, 0, 0,
"AprilTag detection");
301 std::vector<vpHomogeneousMatrix> cMo_vec;
305 std::map<std::string, TagGroundTruth> mapOfTagsGroundTruth;
306 bool use_detection_ground_truth =
false;
309 std::ifstream file_ground_truth(filename_ground_truth.c_str());
310 if (file_ground_truth.is_open() && opt_ppath.empty()) {
311 use_detection_ground_truth =
true;
313 std::string message =
"";
314 double v1 = 0.0, v2 = 0.0, v3 = 0.0, v4 = 0.0;
315 double u1 = 0.0, u2 = 0.0, u3 = 0.0, u4 = 0.0;
316 while (file_ground_truth >> message >> v1 >> u1 >> v2 >> u2 >> v3 >> u3 >> v4 >> u4) {
317 std::vector<vpImagePoint> tagCorners(4);
318 tagCorners[0].set_ij(v1, u1);
319 tagCorners[1].set_ij(v2, u2);
320 tagCorners[2].set_ij(v3, u3);
321 tagCorners[3].set_ij(v4, u4);
322 mapOfTagsGroundTruth.insert(std::make_pair(message, TagGroundTruth(message, tagCorners)));
327 std::map<std::string, vpPoseVector> mapOfPosesGroundTruth;
328 bool use_pose_ground_truth =
false;
331 std::ifstream file_ground_truth(filename_ground_truth.c_str());
332 if (file_ground_truth.is_open() && opt_ppath.empty()) {
333 use_pose_ground_truth =
true;
335 std::string message =
"";
336 double tx = 0.0, ty = 0.0, tz = 0.0;
337 double tux = 0.0, tuy = 0.0, tuz = 0.0;
338 while (file_ground_truth >> message >> tx >> ty >> tz >> tux >> tuy >> tuz) {
339 mapOfPosesGroundTruth.insert(std::make_pair(message,
vpPoseVector(tx, ty, tz, tux, tuy, tuz)));
344 std::cout <<
"use_pose_ground_truth: " << use_pose_ground_truth << std::endl;
347 std::vector<vpImagePoint> p = detector->
getPolygon(i);
349 if (use_detection_ground_truth) {
350 std::string message = detector->
getMessage(i);
351 std::replace(message.begin(), message.end(),
' ',
'_');
352 std::map<std::string, TagGroundTruth>::iterator it = mapOfTagsGroundTruth.find(message);
353 TagGroundTruth current(message, p);
354 if (it == mapOfTagsGroundTruth.end()) {
355 std::cerr <<
"Problem with tag decoding (tag_family or id): " << message << std::endl;
357 }
else if (it->second != current) {
358 std::cerr <<
"Problem, current detection:\n" << current <<
"\nGround truth:\n" << it->second << std::endl;
374 if (opt_click_allowed)
380 for (
size_t i = 0; i < cMo_vec.size(); i++) {
384 if (use_pose_ground_truth) {
387 std::string message = detector->
getMessage(i);
388 std::replace(message.begin(), message.end(),
' ',
'_');
389 std::map<std::string, vpPoseVector>::iterator it = mapOfPosesGroundTruth.find(message);
390 if (it == mapOfPosesGroundTruth.end()) {
391 std::cerr <<
"Problem with tag decoding (tag_family or id): " << message << std::endl;
394 for (
unsigned int cpt = 0; cpt < 6; cpt++) {
396 std::cerr <<
"Problem, current pose: " << pose_vec.t() <<
"\nGround truth pose: " << it->second.t()
408 if (opt_click_allowed)
414 std::cerr <<
"Catch an exception: " << e.
what() << std::endl;
418 std::cout <<
"\ntestAprilTag is ok." << std::endl;
424 std::cout <<
"Need ViSP AprilTag." << std::endl;
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
Display for windows using GDI (available on any windows 32 platform).
Class to define colors available for display functionnalities.
static bool equal(double x, double y, double s=0.001)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
static const vpColor none
error that can be emited by ViSP classes.
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="")
size_t getNbObjects() const
static const vpColor green
static void flush(const vpImage< unsigned char > &I)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
void initPersProjWithoutDistortion(const double px, const double py, const double u0, const double v0)
const char * what() const
static void display(const vpImage< unsigned char > &I)
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Generic class defining intrinsic camera parameters.
static void displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
static void read(vpImage< unsigned char > &I, const std::string &filename)
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color=vpColor::none, unsigned int thickness=1, const vpImagePoint &offset=vpImagePoint(0, 0))
Implementation of a pose vector and operations on poses.
Defines a rectangle in the plane.
static vpColor getColor(const unsigned int &i)
std::vector< std::string > & getMessage()
vpRect getBBox(size_t i) const
std::vector< std::vector< vpImagePoint > > & getPolygon()