apriltag_demo.c
Go to the documentation of this file.
1 /* Copyright (C) 2013-2016, The Regents of The University of Michigan.
2 All rights reserved.
3 
4 This software was developed in the APRIL Robotics Lab under the
5 direction of Edwin Olson, ebolson@umich.edu. This software may be
6 available under alternative licensing terms; contact the address above.
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 
11 1. Redistributions of source code must retain the above copyright notice, this
12  list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 The views and conclusions contained in the software and documentation are those
29 of the authors and should not be interpreted as representing official policies,
30 either expressed or implied, of the Regents of The University of Michigan.
31 */
32 
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <inttypes.h>
36 #include <ctype.h>
37 #include <math.h>
38 #include <errno.h>
39 
40 #ifdef __linux__
41  #include <unistd.h>
42 #endif
43 
44 #include "apriltag.h"
45 #include "tag36h11.h"
46 #include "tag25h9.h"
47 #include "tag16h5.h"
48 #include "tagCircle21h7.h"
49 #include "tagCircle49h12.h"
50 #include "tagCustom48h12.h"
51 #include "tagStandard41h12.h"
52 #include "tagStandard52h13.h"
53 
54 #include "common/getopt.h"
55 #include "common/image_u8.h"
56 #include "common/pjpeg.h"
57 #include "common/zarray.h"
58 
59 #define HAMM_HIST_MAX 10
60 
61 int main(int argc, char *argv[])
62 {
64 
65  getopt_add_bool(getopt, 'h', "help", 0, "Show this help");
66  getopt_add_bool(getopt, 'd', "debug", 0, "Enable debugging output (slow)");
67  getopt_add_bool(getopt, 'q', "quiet", 0, "Reduce output");
68  getopt_add_string(getopt, 'f', "family", "tag36h11", "Tag family to use");
69  getopt_add_int(getopt, 'i', "iters", "1", "Repeat processing on input set this many times");
70  getopt_add_int(getopt, 't', "threads", "1", "Use this many CPU threads");
71  getopt_add_int(getopt, 'a', "hamming", "1", "Detect tags with up to this many bit errors.");
72  getopt_add_double(getopt, 'x', "decimate", "2.0", "Decimate input image by this factor");
73  getopt_add_double(getopt, 'b', "blur", "0.0", "Apply low-pass blur to input; negative sharpens");
74  getopt_add_bool(getopt, '0', "refine-edges", 1, "Spend more time trying to align edges of tags");
75 
76  if (!getopt_parse(getopt, argc, argv, 1) || getopt_get_bool(getopt, "help")) {
77  printf("Usage: %s [options] <input files>\n", argv[0]);
79  exit(0);
80  }
81 
82  const zarray_t *inputs = getopt_get_extra_args(getopt);
83 
84  apriltag_family_t *tf = NULL;
85  const char *famname = getopt_get_string(getopt, "family");
86  if (!strcmp(famname, "tag36h11")) {
87  tf = tag36h11_create();
88  } else if (!strcmp(famname, "tag25h9")) {
89  tf = tag25h9_create();
90  } else if (!strcmp(famname, "tag16h5")) {
91  tf = tag16h5_create();
92  } else if (!strcmp(famname, "tagCircle21h7")) {
93  tf = tagCircle21h7_create();
94  } else if (!strcmp(famname, "tagCircle49h12")) {
95  tf = tagCircle49h12_create();
96  } else if (!strcmp(famname, "tagStandard41h12")) {
98  } else if (!strcmp(famname, "tagStandard52h13")) {
100  } else if (!strcmp(famname, "tagCustom48h12")) {
101  tf = tagCustom48h12_create();
102  } else {
103  printf("Unrecognized tag family name. Use e.g. \"tag36h11\".\n");
104  exit(-1);
105  }
106 
109 
110  switch(errno){
111  case EINVAL:
112  printf("\"hamming\" parameter is out-of-range.\n");
113  exit(-1);
114  case ENOMEM:
115  printf("Unable to add family to detector due to insufficient memory to allocate the tag-family decoder. Try reducing \"hamming\" from %d or choose an alternative tag family.\n", getopt_get_int(getopt, "hamming"));
116  exit(-1);
117  }
118 
119  td->quad_decimate = getopt_get_double(getopt, "decimate");
120  td->quad_sigma = getopt_get_double(getopt, "blur");
121  td->nthreads = getopt_get_int(getopt, "threads");
122  td->debug = getopt_get_bool(getopt, "debug");
123  td->refine_edges = getopt_get_bool(getopt, "refine-edges");
124 
125  int quiet = getopt_get_bool(getopt, "quiet");
126 
127  int maxiters = getopt_get_int(getopt, "iters");
128 
129  for (int iter = 0; iter < maxiters; iter++) {
130 
131  int total_quads = 0;
132  int total_hamm_hist[HAMM_HIST_MAX];
133  memset(total_hamm_hist, 0, sizeof(int)*HAMM_HIST_MAX);
134  double total_time = 0;
135 
136  if (maxiters > 1)
137  printf("iter %d / %d\n", iter + 1, maxiters);
138 
139  for (int input = 0; input < zarray_size(inputs); input++) {
140 
141  int hamm_hist[HAMM_HIST_MAX];
142  memset(hamm_hist, 0, sizeof(hamm_hist));
143 
144  char *path;
145  zarray_get(inputs, input, &path);
146  if (!quiet)
147  printf("loading %s\n", path);
148  else
149  printf("%20s ", path);
150 
151  image_u8_t *im = NULL;
152  if (str_ends_with(path, "pnm") || str_ends_with(path, "PNM") ||
153  str_ends_with(path, "pgm") || str_ends_with(path, "PGM"))
154  im = image_u8_create_from_pnm(path);
155  else if (str_ends_with(path, "jpg") || str_ends_with(path, "JPG")) {
156  int err = 0;
157  pjpeg_t *pjpeg = pjpeg_create_from_file(path, 0, &err);
158  if (pjpeg == NULL) {
159  printf("pjpeg failed to load: %s, error %d\n", path, err);
160  continue;
161  }
162 
163  if (1) {
165  } else {
166  printf("illumination invariant\n");
167 
169 
170  im = image_u8_create(imc->width, imc->height);
171 
172  for (int y = 0; y < imc->height; y++) {
173  for (int x = 0; x < imc->width; x++) {
174  double r = imc->buf[y*imc->stride + 3*x + 0] / 255.0;
175  double g = imc->buf[y*imc->stride + 3*x + 1] / 255.0;
176  double b = imc->buf[y*imc->stride + 3*x + 2] / 255.0;
177 
178  double alpha = 0.42;
179  double v = 0.5 + log(g) - alpha*log(b) - (1-alpha)*log(r);
180  int iv = v * 255;
181  if (iv < 0)
182  iv = 0;
183  if (iv > 255)
184  iv = 255;
185 
186  im->buf[y*im->stride + x] = iv;
187  }
188  }
189  image_u8x3_destroy(imc);
190  if (td->debug)
191  image_u8_write_pnm(im, "debug_invariant.pnm");
192  }
193 
195  }
196 
197  if (im == NULL) {
198  printf("couldn't load %s\n", path);
199  continue;
200  }
201 
202  printf("image: %s %dx%d\n", path, im->width, im->height);
203 
204  zarray_t *detections = apriltag_detector_detect(td, im);
205 
206  if (errno == EAGAIN) {
207  printf("Unable to create the %d threads requested.\n",td->nthreads);
208  exit(-1);
209  }
210 
211  for (int i = 0; i < zarray_size(detections); i++) {
213  zarray_get(detections, i, &det);
214 
215  if (!quiet)
216  printf("detection %3d: id (%2dx%2d)-%-4d, hamming %d, margin %8.3f\n",
217  i, det->family->nbits, det->family->h, det->id, det->hamming, det->decision_margin);
218 
219  hamm_hist[det->hamming]++;
220  total_hamm_hist[det->hamming]++;
221  }
222 
223  apriltag_detections_destroy(detections);
224 
225  if (!quiet) {
226  timeprofile_display(td->tp);
227  }
228 
229  total_quads += td->nquads;
230 
231  if (!quiet)
232  printf("hamm ");
233 
234  for (int i = 0; i < HAMM_HIST_MAX; i++)
235  printf("%5d ", hamm_hist[i]);
236 
237  double t = timeprofile_total_utime(td->tp) / 1.0E3;
238  total_time += t;
239  printf("%12.3f ", t);
240  printf("%5d", td->nquads);
241 
242  printf("\n");
243 
244  image_u8_destroy(im);
245  }
246 
247 
248  printf("Summary\n");
249 
250  printf("hamm ");
251 
252  for (int i = 0; i < HAMM_HIST_MAX; i++)
253  printf("%5d ", total_hamm_hist[i]);
254  printf("%12.3f ", total_time);
255  printf("%5d", total_quads);
256  printf("\n");
257 
258  }
259 
260  // don't deallocate contents of inputs; those are the argv
262 
263  if (!strcmp(famname, "tag36h11")) {
264  tag36h11_destroy(tf);
265  } else if (!strcmp(famname, "tag25h9")) {
266  tag25h9_destroy(tf);
267  } else if (!strcmp(famname, "tag16h5")) {
268  tag16h5_destroy(tf);
269  } else if (!strcmp(famname, "tagCircle21h7")) {
271  } else if (!strcmp(famname, "tagCircle49h12")) {
273  } else if (!strcmp(famname, "tagStandard41h12")) {
275  } else if (!strcmp(famname, "tagStandard52h13")) {
277  } else if (!strcmp(famname, "tagCustom48h12")) {
279  }
280 
282 
283  return 0;
284 }
apriltag_detector::nthreads
int nthreads
Definition: apriltag.h:133
tagStandard41h12_destroy
void tagStandard41h12_destroy(apriltag_family_t *tf)
Definition: tagStandard41h12.c:2246
apriltag_detector::nquads
uint32_t nquads
Definition: apriltag.h:176
getopt_destroy
void getopt_destroy(getopt_t *gopt)
Definition: getopt.c:94
getopt_parse
int getopt_parse(getopt_t *gopt, int argc, char *argv[], int showErrors)
Definition: getopt.c:147
getopt_get_int
int getopt_get_int(getopt_t *getopt, const char *lname)
Definition: getopt.c:425
image_u8_destroy
void image_u8_destroy(image_u8_t *im)
Definition: image_u8.c:82
apriltag_detection::decision_margin
float decision_margin
Definition: apriltag.h:217
tag36h11_destroy
void tag36h11_destroy(apriltag_family_t *tf)
Definition: tag36h11.c:708
tag16h5_destroy
void tag16h5_destroy(apriltag_family_t *tf)
Definition: tag16h5.c:111
image_u8x3::buf
uint8_t * buf
Definition: image_types.h:53
tagCustom48h12_create
apriltag_family_t * tagCustom48h12_create()
Definition: tagCustom48h12.c:42244
getopt_create
getopt_t * getopt_create()
Definition: getopt.c:67
getopt_add_bool
void getopt_add_bool(getopt_t *gopt, char sopt, const char *lname, int def, const char *help)
Definition: getopt.c:326
getopt.h
image_u8::stride
const int32_t stride
Definition: image_types.h:41
image_u8x3::stride
const int32_t stride
Definition: image_types.h:51
apriltag_detector_detect
zarray_t * apriltag_detector_detect(apriltag_detector_t *td, image_u8_t *im_orig)
Definition: apriltag.c:1029
image_u8x3
Definition: image_types.h:47
getopt
Definition: getopt.c:59
pjpeg_to_u8x3_baseline
image_u8x3_t * pjpeg_to_u8x3_baseline(pjpeg_t *pj)
Definition: pjpeg.c:738
getopt_add_string
void getopt_add_string(getopt_t *gopt, char sopt, const char *lname, const char *def, const char *help)
Definition: getopt.c:376
zarray
Definition: zarray.h:43
getopt_do_usage
void getopt_do_usage(getopt_t *gopt)
Definition: getopt.c:492
pjpeg_to_u8_baseline
image_u8_t * pjpeg_to_u8_baseline(pjpeg_t *pj)
Definition: pjpeg.c:703
zarray_size
static int zarray_size(const zarray_t *za)
Definition: zarray.h:130
apriltag_detector::tp
timeprofile_t * tp
Definition: apriltag.h:172
tag25h9_create
apriltag_family_t * tag25h9_create()
Definition: tag25h9.c:68
getopt_add_double
void getopt_add_double(getopt_t *gopt, char sopt, const char *lname, const char *def, const char *help)
Definition: getopt.c:371
apriltag.h
apriltag_detection::hamming
int hamming
Definition: apriltag.h:208
image_u8_create
image_u8_t * image_u8_create(unsigned int width, unsigned int height)
Definition: image_u8.c:54
tag16h5_create
apriltag_family_t * tag16h5_create()
Definition: tag16h5.c:63
tagCircle49h12_destroy
void tagCircle49h12_destroy(apriltag_family_t *tf)
Definition: tagCircle49h12.c:65682
tagCircle21h7_create
apriltag_family_t * tagCircle21h7_create()
Definition: tagCircle21h7.c:71
image_u8::height
const int32_t height
Definition: image_types.h:40
str_ends_with
bool str_ends_with(const char *haystack, const char *needle)
Definition: string_util.c:559
image_u8::width
const int32_t width
Definition: image_types.h:39
getopt_get_string
const char * getopt_get_string(getopt_t *gopt, const char *lname)
Definition: getopt.c:415
apriltag_detector_create
apriltag_detector_t * apriltag_detector_create()
Definition: apriltag.c:354
tagCircle21h7.h
image_u8
Definition: image_types.h:37
getopt_get_double
double getopt_get_double(getopt_t *getopt, const char *lname)
Definition: getopt.c:455
pjpeg.h
apriltag_detector::debug
bool debug
Definition: apriltag.h:166
apriltag_detections_destroy
void apriltag_detections_destroy(zarray_t *detections)
Definition: apriltag.c:1436
tagCircle21h7_destroy
void tagCircle21h7_destroy(apriltag_family_t *tf)
Definition: tagCircle21h7.c:129
tag16h5.h
apriltag_detector
Definition: apriltag.h:127
apriltag_detection::family
apriltag_family_t * family
Definition: apriltag.h:199
image_u8_write_pnm
int image_u8_write_pnm(const image_u8_t *im, const char *path)
Definition: image_u8.c:200
tagStandard52h13_destroy
void tagStandard52h13_destroy(apriltag_family_t *tf)
Definition: tagStandard52h13.c:48867
apriltag_family
Definition: apriltag.h:61
main
int main(int argc, char *argv[])
Definition: apriltag_demo.c:61
image_u8x3_destroy
void image_u8x3_destroy(image_u8x3_t *im)
Definition: image_u8x3.c:78
tagCustom48h12_destroy
void tagCustom48h12_destroy(apriltag_family_t *tf)
Definition: tagCustom48h12.c:42356
tagStandard52h13.h
apriltag_detector::quad_decimate
float quad_decimate
Definition: apriltag.h:139
image_u8x3::height
const int32_t height
Definition: image_types.h:50
tagCustom48h12.h
tag36h11.h
apriltag_detection::id
int id
Definition: apriltag.h:202
apriltag_family::h
uint32_t h
Definition: apriltag.h:79
tagCircle49h12.h
apriltag_detector_add_family_bits
void apriltag_detector_add_family_bits(apriltag_detector_t *td, apriltag_family_t *fam, int bits_corrected)
Definition: apriltag.c:336
apriltag_detector_destroy
void apriltag_detector_destroy(apriltag_detector_t *td)
Definition: apriltag.c:388
tag25h9_destroy
void tag25h9_destroy(apriltag_family_t *tf)
Definition: tag25h9.c:134
apriltag_family::nbits
uint32_t nbits
Definition: apriltag.h:74
pjpeg_destroy
void pjpeg_destroy(pjpeg_t *pj)
Definition: pjpeg.c:689
tagCircle49h12_create
apriltag_family_t * tagCircle49h12_create()
Definition: tagCircle49h12.c:65568
getopt_get_extra_args
const zarray_t * getopt_get_extra_args(getopt_t *gopt)
Definition: getopt.c:487
zarray_get
static void zarray_get(const zarray_t *za, int idx, void *p)
Definition: zarray.h:195
image_u8.h
apriltag_detection
Definition: apriltag.h:196
image_u8x3::width
const int32_t width
Definition: image_types.h:49
apriltag_detector::refine_edges
bool refine_edges
Definition: apriltag.h:154
zarray.h
timeprofile_display
static void timeprofile_display(timeprofile_t *tp)
Definition: timeprofile.h:87
HAMM_HIST_MAX
#define HAMM_HIST_MAX
Definition: apriltag_demo.c:59
timeprofile_total_utime
static uint64_t timeprofile_total_utime(timeprofile_t *tp)
Definition: timeprofile.h:106
getopt_add_int
void getopt_add_int(getopt_t *gopt, char sopt, const char *lname, const char *def, const char *help)
Definition: getopt.c:365
tagStandard52h13_create
apriltag_family_t * tagStandard52h13_create()
Definition: tagStandard52h13.c:48747
image_u8::buf
uint8_t * buf
Definition: image_types.h:43
image_u8_create_from_pnm
image_u8_t * image_u8_create_from_pnm(const char *path)
Definition: image_u8.c:93
pjpeg
Definition: pjpeg.h:64
tag36h11_create
apriltag_family_t * tag36h11_create()
Definition: tag36h11.c:620
apriltag_detector::quad_sigma
float quad_sigma
Definition: apriltag.h:145
tagStandard41h12_create
apriltag_family_t * tagStandard41h12_create()
Definition: tagStandard41h12.c:2148
tag25h9.h
getopt_get_bool
int getopt_get_bool(getopt_t *getopt, const char *lname)
Definition: getopt.c:447
pjpeg_create_from_file
pjpeg_t * pjpeg_create_from_file(const char *path, uint32_t flags, int *error)
Definition: pjpeg.c:825
tagStandard41h12.h


apriltag
Author(s): Edwin Olson , Max Krogius
autogenerated on Sun Apr 20 2025 02:08:19