59 # define M_PI 3.141592653589793238462643383279502884196 108 return gm->
C[0]*x + gm->
C[1]*y + gm->
C[2];
137 for (int32_t r = d-1; r >=0; r--) {
138 for (int32_t c = 0; c < d; c++) {
143 if ((w & (((uint64_t) 1) << b))!=0)
163 struct quad *q = calloc(1,
sizeof(
struct quad));
164 memcpy(q, quad,
sizeof(
struct quad));
174 uint32_t bucket = code % qd->
nentries;
177 bucket = (bucket + 1) % qd->
nentries;
198 assert(family->
impl == NULL);
199 assert(family->
ncodes < 65535);
202 int capacity = family->
ncodes;
204 int nbits = family->
d * family->
d;
207 capacity += family->
ncodes * nbits;
210 capacity += family->
ncodes * nbits * (nbits-1);
213 capacity += family->
ncodes * nbits * (nbits-1) * (nbits-2);
222 printf(
"apriltag.c: failed to allocate hamming decode table. Reduce max hamming size.\n");
226 for (
int i = 0; i < qd->
nentries; i++)
229 for (
int i = 0; i < family->
ncodes; i++) {
230 uint64_t code = family->
codes[i];
235 if (maxhamming >= 1) {
237 for (
int j = 0; j < nbits; j++)
241 if (maxhamming >= 2) {
243 for (
int j = 0; j < nbits; j++)
244 for (
int k = 0; k < j; k++)
248 if (maxhamming >= 3) {
250 for (
int j = 0; j < nbits; j++)
251 for (
int k = 0; k < j; k++)
252 for (
int m = 0; m < k; m++)
256 if (maxhamming > 3) {
257 printf(
"apriltag.c: maxhamming beyond 3 not supported\n");
271 for (
int i = 0; i < qd->
nentries; i++) {
280 longest_run =
imax(longest_run, run);
284 printf(
"quick decode: longest run: %d, average run %.3f\n", longest_run, 1.0 * run_sum / run_count);
294 for (
int ridx = 0; ridx < 4; ridx++) {
296 for (
int bucket = rcode % qd->
nentries;
298 bucket = (bucket + 1) % qd->
nentries) {
321 return a->
id - b->
id;
366 pthread_mutex_init(&td->
mutex, NULL);
420 for (
int i = 0; i < 4; i++) {
428 corr[0] = (i==0 || i==3) ? -1 : 1;
429 corr[1] = (i==0 || i==1) ? -1 : 1;
431 corr[2] = quad->
p[i][0];
432 corr[3] = quad->
p[i][1];
447 if (quad->
H && quad->
Hinv)
464 float white_border = 1;
467 double bit_size = 2.0 / (2*family->
black_border + family->
d);
470 int32_t xmin = INT32_MAX, xmax = 0, ymin = INT32_MAX, ymax = 0;
472 for (
int i = 0; i < 4; i++) {
473 double tx = (i == 0 || i == 3) ? -1 - bit_size : 1 + bit_size;
474 double ty = (i == 0 || i == 1) ? -1 - bit_size : 1 + bit_size;
478 xmin =
imin(xmin, x);
479 xmax =
imax(xmax, x);
480 ymin =
imin(ymin, y);
481 ymax =
imax(ymax, y);
485 xmin =
imax(0, xmin);
487 ymin =
imax(0, ymin);
492 int64_t
W1 = 0, B1 = 0, Wn = 0, Bn = 0;
494 float wsz = bit_size*white_border;
501 for (
int y = ymin; y <= ymax; y++) {
507 double Hx =
MATD_EL(Hinv, 0, 0) * (.5 + (int) xmin) +
509 double Hy =
MATD_EL(Hinv, 1, 0) * (.5 + (int) xmin) +
511 double Hh =
MATD_EL(Hinv, 2, 0) * (.5 + (int) xmin) +
514 for (
int x = xmin; x <= xmax; x++) {
528 float txa = fabsf((
float) tx), tya = fabsf((
float) ty);
529 float xymax = fmaxf(txa, tya);
532 if (xymax >= 1 + wsz)
547 if (xymax >= 1 - bsz) {
560 double margin = 1.0 * W1 / Wn - 1.0 * B1 / Bn;
575 float white_border = 1.0;
585 0 - white_border / 2.0, 0.5,
605 0.5, -white_border / 2.0,
615 0.5, 2*family->
black_border + family->
d + white_border / 2.0,
631 for (
int pattern_idx = 0; pattern_idx <
sizeof(patterns)/(5*
sizeof(
float)); pattern_idx ++) {
632 float *pattern = &patterns[pattern_idx * 5];
634 int is_white = pattern[4];
636 for (
int i = 0; i < 2*family->
black_border + family->
d; i++) {
637 double tagx01 = (pattern[0] + i*pattern[2]) / (2*family->
black_border + family->
d);
638 double tagy01 = (pattern[1] + i*pattern[3]) / (2*family->
black_border + family->
d);
640 double tagx = 2*(tagx01-0.5);
641 double tagy = 2*(tagy01-0.5);
649 if (ix < 0 || iy < 0 || ix >= im->
width || iy >= im->
height)
655 im_samples->
buf[iy*im_samples->
stride + ix] = (1-is_white)*255;
678 float black_score = 0, white_score = 0;
679 float black_score_count = 1, white_score_count = 1;
681 for (
int bitidx = 0; bitidx < family->
d * family->
d; bitidx++) {
682 int bitx = bitidx % family->
d;
683 int bity = bitidx / family->
d;
689 double tagx = 2*(tagx01-0.5);
690 double tagy = 2*(tagy01-0.5);
695 rcode = (rcode << 1);
701 if (ix < 0 || iy < 0 || ix >= im->
width || iy >= im->
height)
708 white_score += (v - thresh);
709 white_score_count ++;
712 black_score += (thresh - v);
713 black_score_count ++;
717 im_samples->
buf[iy*im_samples->
stride + ix] = (1 - (rcode & 1)) * 255;
722 return fmin(white_score / white_score_count, black_score / black_score_count);
734 float decision_margin =
quad_decode(family, im, quad, &entry, NULL);
737 return decision_margin - entry.
hamming*1000;
742 float *stepsizes,
int nstepsizes,
746 struct quad *best_quad =
quad_copy(quad0);
747 double best_score = score(family, im, best_quad, user);
749 for (
int stepsize_idx = 0; stepsize_idx < nstepsizes; stepsize_idx++) {
760 for (
int repeat = 0; repeat <= max_repeat && improved; repeat++) {
765 for (
int i = 0; i < 4; i++) {
767 float stepsize = stepsizes[stepsize_idx];
772 struct quad *this_best_quad = NULL;
773 double this_best_score = best_score;
775 for (
int sx = -nsteps; sx <= nsteps; sx++) {
776 for (
int sy = -nsteps; sy <= nsteps; sy++) {
780 struct quad *this_quad =
quad_copy(best_quad);
781 this_quad->
p[i][0] = best_quad->
p[i][0] + sx*stepsize;
782 this_quad->
p[i][1] = best_quad->
p[i][1] + sy*stepsize;
786 double this_score = score(family, im, this_quad, user);
788 if (this_score > this_best_score) {
791 this_best_quad = this_quad;
792 this_best_score = this_score;
799 if (this_best_score > best_score) {
801 best_quad = this_best_quad;
802 best_score = this_best_score;
811 memcpy(quad0, best_quad,
sizeof(
struct quad));
820 for (
int edge = 0; edge < 4; edge++) {
821 int a = edge, b = (edge + 1) & 3;
824 double nx = quad->
p[b][1] - quad->
p[a][1];
825 double ny = -quad->
p[b][0] + quad->
p[a][0];
826 double mag = sqrt(nx*nx + ny*ny);
833 int nsamples =
imax(16, mag / 8);
836 double Mx = 0, My = 0, Mxx = 0, Mxy = 0, Myy = 0, N = 0;
838 for (
int s = 0; s < nsamples; s++) {
842 double alpha = (1.0 + s) / (nsamples + 1);
843 double x0 = alpha*quad->
p[a][0] + (1-alpha)*quad->
p[b][0];
844 double y0 = alpha*quad->
p[a][1] + (1-alpha)*quad->
p[b][1];
863 for (
double n = -range; n <= range; n += 0.25) {
873 int x1 = x0 + (n + grange)*nx;
874 int y1 = y0 + (n + grange)*ny;
875 if (x1 < 0 || x1 >= im_orig->
width || y1 < 0 || y1 >= im_orig->
height)
878 int x2 = x0 + (n - grange)*nx;
879 int y2 = y0 + (n - grange)*ny;
880 if (x2 < 0 || x2 >= im_orig->
width || y2 < 0 || y2 >= im_orig->
height)
883 int g1 = im_orig->
buf[y1*im_orig->
stride + x1];
884 int g2 = im_orig->
buf[y2*im_orig->
stride + x2];
889 double weight = (g2 - g1)*(g2 - g1);
900 double n0 = Mn / Mcount;
903 double bestx = x0 + n0*nx;
904 double besty = y0 + n0*ny;
916 double Ex = Mx / N, Ey = My / N;
917 double Cxx = Mxx / N - Ex*Ex;
918 double Cxy = Mxy / N - Ex*Ey;
919 double Cyy = Myy / N - Ey*Ey;
921 double normal_theta = .5 * atan2f(-2*Cxy, (Cyy - Cxx));
922 nx = cosf(normal_theta);
923 ny = sinf(normal_theta);
931 for (
int i = 0; i < 4; i++) {
934 double A00 = lines[i][3], A01 = -lines[(i+1)&3][3];
935 double A10 = -lines[i][2], A11 = lines[(i+1)&3][2];
936 double B0 = -lines[i][0] + lines[(i+1)&3][0];
937 double B1 = -lines[i][1] + lines[(i+1)&3][1];
939 double det = A00 * A11 - A10 * A01;
942 if (fabs(det) > 0.001) {
944 double W00 = A11 / det, W01 = -A01 / det;
946 double L0 = W00*B0 + W01*B1;
949 quad->
p[i][0] = lines[i][0] + L0*A00;
950 quad->
p[i][1] = lines[i][1] + L0*A10;
964 for (
int quadidx = task->
i0; quadidx < task->
i1; quadidx++) {
965 struct quad *quad_original;
999 float stepsizes[] = { 1, .4, .16, .064 };
1000 int nstepsizes =
sizeof(stepsizes)/
sizeof(
float);
1009 float stepsizes[] = { .4 };
1010 int nstepsizes =
sizeof(stepsizes)/
sizeof(
float);
1019 if (entry.
hamming < 255 && decision_margin >= 0) {
1029 double c = cos(theta), s = sin(theta);
1049 for (
int i = 0; i < 4; i++) {
1050 int tcx = (i == 1 || i == 2) ? 1 : -1;
1051 int tcy = (i < 2) ? 1 : -1;
1057 det->
p[i][0] = p[0];
1058 det->
p[i][1] = p[1];
1061 pthread_mutex_lock(&td->
mutex);
1063 pthread_mutex_unlock(&td->
mutex);
1098 printf(
"apriltag.c: No tag families enabled.");
1132 int ksz = 4 * sigma;
1146 for (
int y = 0; y < orig->
height; y++) {
1147 for (
int x = 0; x < orig->
width; x++) {
1148 int vorig = orig->
buf[y*orig->
stride + x];
1149 int vblur = quad_im->
buf[y*quad_im->
stride + x];
1151 int v = 2*vorig - vblur;
1157 quad_im->
buf[y*quad_im->
stride + x] = (uint8_t) v;
1180 for (
int i = 0; i < 4; i++) {
1187 if (quad_im != im_orig)
1207 const int bias = 100;
1208 int color = bias + (random() % (255-bias));
1230 for (
int i = 0; i <
zarray_size(quads); i+= chunksize) {
1231 tasks[ntasks].
i0 = i;
1234 tasks[ntasks].
td =
td;
1235 tasks[ntasks].
im = im_orig;
1246 if (im_samples != NULL) {
1263 const int bias = 100;
1264 int color = bias + (random() % (255-bias));
1286 for (
int i0 = 0; i0 <
zarray_size(detections); i0++) {
1291 for (
int k = 0; k < 4; k++)
1294 for (
int i1 = i0+1; i1 <
zarray_size(detections); i1++) {
1302 for (
int k = 0; k < 4; k++)
1315 for (
int i = 0; i < 4; i++) {
1323 printf(
"uh oh, no preference for overlappingdetection\n");
1362 FILE *f = fopen(
"debug_output.ps",
"w");
1363 fprintf(f,
"%%!PS\n\n");
1364 double scale = fmin(612.0/darker->
width, 792.0/darker->
height);
1365 fprintf(f,
"%f %f scale\n", scale, scale);
1366 fprintf(f,
"0 %d translate\n", darker->
height);
1367 fprintf(f,
"1 -1 scale\n");
1372 for (
int i = 0; i <
zarray_size(detections); i++) {
1379 for (
int i = 0; i < 3; i++)
1380 rgb[i] = bias + (random() % (255-bias));
1382 fprintf(f,
"%f %f %f setrgbcolor\n", rgb[0]/255.0f, rgb[1]/255.0f, rgb[2]/255.0f);
1383 fprintf(f,
"%f %f moveto %f %f lineto %f %f lineto %f %f lineto %f %f lineto stroke\n",
1384 det->
p[0][0], det->
p[0][1],
1385 det->
p[1][0], det->
p[1][1],
1386 det->
p[2][0], det->
p[2][1],
1387 det->
p[3][0], det->
p[3][1],
1388 det->
p[0][0], det->
p[0][1]);
1391 fprintf(f,
"showpage\n");
1401 for (
int y = 0; y < im_orig->
height; y++) {
1402 for (
int x = 0; x < im_orig->
width; x++) {
1409 for (
int i = 0; i <
zarray_size(detections); i++) {
1416 for (
int i = 0; i < 3; i++)
1417 rgb[i] = bias + (random() % (255-bias));
1419 for (
int j = 0; j < 4; j++) {
1420 int k = (j + 1) & 3;
1422 det->
p[j][0], det->
p[j][1], det->
p[k][0], det->
p[k][1],
1423 (uint8_t[]) { rgb[0], rgb[1], rgb[2] },
1434 FILE *f = fopen(
"debug_quads.ps",
"w");
1435 fprintf(f,
"%%!PS\n\n");
1442 double scale = fmin(612.0/darker->
width, 792.0/darker->
height);
1443 fprintf(f,
"%f %f scale\n", scale, scale);
1444 fprintf(f,
"0 %d translate\n", darker->
height);
1445 fprintf(f,
"1 -1 scale\n");
1458 for (
int i = 0; i < 3; i++)
1459 rgb[i] = bias + (random() % (255-bias));
1461 fprintf(f,
"%f %f %f setrgbcolor\n", rgb[0]/255.0f, rgb[1]/255.0f, rgb[2]/255.0f);
1462 fprintf(f,
"%f %f moveto %f %f lineto %f %f lineto %f %f lineto %f %f lineto stroke\n",
1463 q->
p[0][0], q->
p[0][1],
1464 q->
p[1][0], q->
p[1][1],
1465 q->
p[2][0], q->
p[2][1],
1466 q->
p[3][0], q->
p[3][1],
1467 q->
p[0][0], q->
p[0][1]);
1470 fprintf(f,
"showpage\n");
1495 for (
int i = 0; i <
zarray_size(detections); i++) {
1507 assert(fam != NULL);
1508 assert(idx >= 0 && idx < fam->ncodes);
1510 uint64_t code = fam->
codes[idx];
1512 int dim = fam->
d + 2*border;
1516 for (
int i = 0; i < dim; i += 1) {
1523 for (
int y = 0; y < fam->
d; y += 1) {
1524 for (
int x = 0; x < fam->
d; x += 1) {
1525 int pos = (fam->
d-1 - y) * fam->
d + (fam->
d-1 - x);
1526 if ((code >> pos) & 0x1) {
1527 int i = (y+border)*im->
stride + x+border;
void graymodel_add(struct graymodel *gm, double x, double y, double gray)
void image_u8_gaussian_blur(image_u8_t *im, double sigma, int k)
image_u8_t * image_u8_decimate(image_u8_t *im, float factor)
#define APRILTAG_TASKS_PER_THREAD_TARGET
static void zarray_get_volatile(const zarray_t *za, int idx, void *p)
static void zarray_sort(zarray_t *za, int(*compar)(const void *, const void *))
static int zarray_remove_value(zarray_t *za, const void *p, int shuffle)
void matd_destroy(matd_t *m)
static void timeprofile_stamp(timeprofile_t *tp, const char *name)
int quad_update_homographies(struct quad *quad)
int workerpool_get_nthreads(workerpool_t *wp)
matd_t * matd_inverse(const matd_t *a)
matd_t * matd_op(const char *expr,...)
void quick_decode_add(struct quick_decode *qd, uint64_t code, int id, int hamming)
double score_goodness(apriltag_family_t *family, image_u8_t *im, struct quad *quad, void *user)
static void quad_decode_task(void *_u)
static void mat33_sym_solve(const double *A, const double *B, double *R)
static int zarray_size(const zarray_t *za)
static void homography_project(const matd_t *H, double x, double y, double *ox, double *oy)
int prefer_smaller(int pref, double q0, double q1)
static void zarray_destroy(zarray_t *za)
static void zarray_set(zarray_t *za, int idx, const void *p, void *outp)
apriltag_detector_t * apriltag_detector_create()
int image_u8_write_pnm(const image_u8_t *im, const char *path)
image_u8_t * image_u8_create(unsigned int width, unsigned int height)
static void zarray_remove_index(zarray_t *za, int idx, int shuffle)
static int imax(int a, int b)
static int detection_compare_function(const void *_a, const void *_b)
#define MATD_EL(m, row, col)
void apriltag_detections_destroy(zarray_t *detections)
void quad_destroy(struct quad *quad)
matd_t * matd_create(int rows, int cols)
static zarray_t * zarray_create(size_t el_sz)
struct apriltag_quad_thresh_params qtp
void graymodel_init(struct graymodel *gm)
void workerpool_add_task(workerpool_t *wp, void(*f)(void *p), void *p)
image_u8_t * image_u8_copy(const image_u8_t *in)
void graymodel_solve(struct graymodel *gm)
void apriltag_detector_remove_family(apriltag_detector_t *td, apriltag_family_t *fam)
matd_t * matd_copy(const matd_t *m)
void apriltag_detection_destroy(apriltag_detection_t *det)
void quick_decode_uninit(apriltag_family_t *fam)
static timeprofile_t * timeprofile_create()
static int imin(int a, int b)
static uint64_t rotate90(uint64_t w, uint32_t d)
zarray_t * apriltag_quad_thresh(apriltag_detector_t *td, image_u8_t *im)
double graymodel_interpolate(struct graymodel *gm, double x, double y)
float quad_decode(apriltag_family_t *family, image_u8_t *im, struct quad *quad, struct quick_decode_entry *entry, image_u8_t *im_samples)
image_u8x3_t * image_u8x3_create(unsigned int width, unsigned int height)
static void zarray_get(const zarray_t *za, int idx, void *p)
void workerpool_run(workerpool_t *wp)
void workerpool_destroy(workerpool_t *wp)
void image_u8x3_destroy(image_u8x3_t *im)
#define HOMOGRAPHY_COMPUTE_FLAG_SVD
struct quad * quad_copy(struct quad *quad)
void image_u8_destroy(image_u8_t *im)
double quad_goodness(apriltag_family_t *family, image_u8_t *im, struct quad *quad)
zarray_t * g2d_polygon_create_zeros(int sz)
static void refine_edges(apriltag_detector_t *td, image_u8_t *im_orig, struct quad *quad)
workerpool_t * workerpool_create(int nthreads)
void quick_decode_init(apriltag_family_t *family, int maxhamming)
int image_u8x3_write_pnm(const image_u8x3_t *im, const char *path)
void apriltag_detector_destroy(apriltag_detector_t *td)
static void postscript_image(FILE *f, image_u8_t *im)
static void zarray_clear(zarray_t *za)
image_u8_t * apriltag_to_image(apriltag_family_t *fam, int idx)
struct quick_decode_entry * entries
zarray_t * apriltag_quad_gradient(apriltag_detector_t *td, image_u8_t *im)
void image_u8_darken(image_u8_t *im)
void apriltag_detector_add_family_bits(apriltag_detector_t *td, apriltag_family_t *fam, int bits_corrected)
static void timeprofile_clear(timeprofile_t *tp)
double optimize_quad_generic(apriltag_family_t *family, image_u8_t *im, struct quad *quad0, float *stepsizes, int nstepsizes, double(*score)(apriltag_family_t *family, image_u8_t *im, struct quad *quad, void *user), void *user)
void apriltag_detector_clear_families(apriltag_detector_t *td)
matd_t * homography_compute(zarray_t *correspondences, int flags)
void image_u8_draw_line(image_u8_t *im, float x0, float y0, float x1, float y1, int v, int width)
static void timeprofile_destroy(timeprofile_t *tp)
static void quick_decode_codeword(apriltag_family_t *tf, uint64_t rcode, struct quick_decode_entry *entry)
double score_decodability(apriltag_family_t *family, image_u8_t *im, struct quad *quad, void *user)
static void zarray_add(zarray_t *za, const void *p)
void image_u8x3_draw_line(image_u8x3_t *im, float x0, float y0, float x1, float y1, uint8_t rgb[3], int width)
zarray_t * apriltag_detector_detect(apriltag_detector_t *td, image_u8_t *im_orig)
apriltag_family_t * family
int g2d_polygon_overlaps_polygon(const zarray_t *polya, const zarray_t *polyb)