57 # define M_PI 3.141592653589793238462643383279502884196 61 static inline void srandom(
unsigned int seed)
66 static inline long int random(
void)
72 #define APRILTAG_U64_ONE ((uint64_t) 1) 107 gm->
B[0] += x * gray;
108 gm->
B[1] += y * gray;
119 return gm->
C[0]*x + gm->
C[1]*y + gm->
C[2];
144 if (numBits % 4 == 1) {
148 w = ((w >> l) << (p/4 + l)) | (w >> (3 * p/ 4 + l) << l) | (w & l);
165 struct quad *q = calloc(1,
sizeof(
struct quad));
166 memcpy(q, quad,
sizeof(
struct quad));
176 uint32_t bucket = code % qd->
nentries;
179 bucket = (bucket + 1) % qd->
nentries;
200 assert(family->
impl == NULL);
201 assert(family->
ncodes < 65536);
204 int capacity = family->
ncodes;
206 int nbits = family->
nbits;
209 capacity += family->
ncodes * nbits;
212 capacity += family->
ncodes * nbits * (nbits-1);
215 capacity += family->
ncodes * nbits * (nbits-1) * (nbits-2);
224 debug_print(
"Failed to allocate hamming decode table\n");
229 for (
int i = 0; i < qd->
nentries; i++)
234 for (
int i = 0; i < family->
ncodes; i++) {
235 uint64_t code = family->
codes[i];
240 if (maxhamming >= 1) {
242 for (
int j = 0; j < nbits; j++)
246 if (maxhamming >= 2) {
248 for (
int j = 0; j < nbits; j++)
249 for (
int k = 0; k < j; k++)
253 if (maxhamming >= 3) {
255 for (
int j = 0; j < nbits; j++)
256 for (
int k = 0; k < j; k++)
257 for (
int m = 0; m < k; m++)
261 if (maxhamming > 3) {
262 debug_print(
"\"maxhamming\" beyond 3 not supported\n");
279 for (
int i = 0; i < qd->
nentries; i++) {
288 longest_run =
imax(longest_run, run);
292 printf(
"quick decode: longest run: %d, average run %.3f\n", longest_run, 1.0 * run_sum / run_count);
303 for (
int ridx = 0; qd != NULL && ridx < 4; ridx++) {
305 for (
int bucket = rcode % qd->
nentries;
307 bucket = (bucket + 1) % qd->
nentries) {
330 return a->
id - b->
id;
375 pthread_mutex_init(&td->
mutex, NULL);
426 c[0][0], c[0][1], 1, 0, 0, 0, -c[0][0]*c[0][2], -c[0][1]*c[0][2], c[0][2],
427 0, 0, 0, c[0][0], c[0][1], 1, -c[0][0]*c[0][3], -c[0][1]*c[0][3], c[0][3],
428 c[1][0], c[1][1], 1, 0, 0, 0, -c[1][0]*c[1][2], -c[1][1]*c[1][2], c[1][2],
429 0, 0, 0, c[1][0], c[1][1], 1, -c[1][0]*c[1][3], -c[1][1]*c[1][3], c[1][3],
430 c[2][0], c[2][1], 1, 0, 0, 0, -c[2][0]*c[2][2], -c[2][1]*c[2][2], c[2][2],
431 0, 0, 0, c[2][0], c[2][1], 1, -c[2][0]*c[2][3], -c[2][1]*c[2][3], c[2][3],
432 c[3][0], c[3][1], 1, 0, 0, 0, -c[3][0]*c[3][2], -c[3][1]*c[3][2], c[3][2],
433 0, 0, 0, c[3][0], c[3][1], 1, -c[3][0]*c[3][3], -c[3][1]*c[3][3], c[3][3],
436 double epsilon = 1e-10;
439 for (
int col = 0; col < 8; col++) {
442 int max_val_idx = -1;
443 for (
int row = col; row < 8; row++) {
444 double val = fabs(A[row*9 + col]);
451 if (max_val < epsilon) {
457 if (max_val_idx != col) {
458 for (
int i = col; i < 9; i++) {
459 double tmp = A[col*9 + i];
460 A[col*9 + i] = A[max_val_idx*9 + i];
461 A[max_val_idx*9 + i] = tmp;
466 for (
int i = col + 1; i < 8; i++) {
467 double f = A[i*9 + col]/A[col*9 + col];
469 for (
int j = col + 1; j < 9; j++) {
470 A[i*9 + j] -= f*A[col*9 + j];
476 for (
int col = 7; col >=0; col--) {
478 for (
int i = col + 1; i < 8; i++) {
479 sum += A[col*9 + i]*A[i*9 + 8];
481 A[col*9 + 8] = (A[col*9 + 8] - sum)/A[col*9 + col];
483 return matd_create_data(3, 3, (
double[]) { A[8], A[17], A[26], A[35], A[44], A[53], A[62], A[71], 1 });
491 double corr_arr[4][4];
493 for (
int i = 0; i < 4; i++) {
494 corr_arr[i][0] = (i==0 || i==3) ? -1 : 1;
495 corr_arr[i][1] = (i==0 || i==1) ? -1 : 1;
496 corr_arr[i][2] = quad->
p[i][0];
497 corr_arr[i][3] = quad->
p[i][1];
507 if (quad->
H != NULL) {
509 if (quad->
Hinv != NULL) {
520 int x1 = floor(px - 0.5);
521 int x2 = ceil(px - 0.5);
522 double x = px - 0.5 - x1;
523 int y1 = floor(py - 0.5);
524 int y2 = ceil(py - 0.5);
525 double y = py - 0.5 - y1;
526 if (x1 < 0 || x2 >= im->
width || y1 < 0 || y2 >= im->
height) {
529 return im->
buf[y1*im->
stride + x1]*(1-x)*(1-y) +
536 double *sharpened = malloc(
sizeof(
double)*size*size);
543 for (
int y = 0; y < size; y++) {
544 for (
int x = 0; x < size; x++) {
545 sharpened[y*size + x] = 0;
546 for (
int i = 0; i < 3; i++) {
547 for (
int j = 0; j < 3; j++) {
548 if ((y + i - 1) < 0 || (y + i - 1) > size - 1 || (x + j - 1) < 0 || (x + j - 1) > size - 1) {
551 sharpened[y*size + x] += values[(y + i - 1)*size + (x + j - 1)]*kernel[i*3 + j];
558 for (
int y = 0; y < size; y++) {
559 for (
int x = 0; x < size; x++) {
560 values[y*size + x] = values[y*size + x] + td->
decode_sharpening*sharpened[y*size + x];
627 for (
int pattern_idx = 0; pattern_idx <
sizeof(patterns)/(5*
sizeof(
float)); pattern_idx ++) {
628 float *pattern = &patterns[pattern_idx * 5];
630 int is_white = pattern[4];
633 double tagx01 = (pattern[0] + i*pattern[2]) / (family->
width_at_border);
634 double tagy01 = (pattern[1] + i*pattern[3]) / (family->
width_at_border);
636 double tagx = 2*(tagx01-0.5);
637 double tagy = 2*(tagy01-0.5);
645 if (ix < 0 || iy < 0 || ix >= im->
width || iy >= im->
height)
651 im_samples->
buf[iy*im_samples->
stride + ix] = (1-is_white)*255;
668 blackmodel.
C[2] = blackmodel.
B[2]/4;
682 float black_score = 0, white_score = 0;
683 float black_score_count = 1, white_score_count = 1;
688 for (
int i = 0; i < family->
nbits; i++) {
689 int bity = family->
bit_y[i];
690 int bitx = family->
bit_x[i];
696 double tagx = 2*(tagx01-0.5);
697 double tagy = 2*(tagy01-0.5);
709 values[family->
total_width*(bity - min_coord) + bitx - min_coord] = v - thresh;
714 im_samples->
buf[iy*im_samples->
stride + ix] = (v < thresh) * 255;
721 for (
int i = 0; i < family->
nbits; i++) {
722 int bity = family->
bit_y[i];
723 int bitx = family->
bit_x[i];
724 rcode = (rcode << 1);
725 double v = values[(bity - min_coord)*family->
total_width + bitx - min_coord];
739 return fmin(white_score / white_score_count, black_score / black_score_count);
746 for (
int edge = 0; edge < 4; edge++) {
747 int a = edge, b = (edge + 1) & 3;
750 double nx = quad->
p[b][1] - quad->
p[a][1];
751 double ny = -quad->
p[b][0] + quad->
p[a][0];
752 double mag = sqrt(nx*nx + ny*ny);
764 int nsamples =
imax(16, mag / 8);
767 double Mx = 0, My = 0, Mxx = 0, Mxy = 0, Myy = 0, N = 0;
769 for (
int s = 0; s < nsamples; s++) {
773 double alpha = (1.0 + s) / (nsamples + 1);
774 double x0 = alpha*quad->
p[a][0] + (1-alpha)*quad->
p[b][0];
775 double y0 = alpha*quad->
p[a][1] + (1-alpha)*quad->
p[b][1];
794 for (
double n = -range; n <= range; n += 0.25) {
804 int x1 = x0 + (n + grange)*nx;
805 int y1 = y0 + (n + grange)*ny;
806 if (x1 < 0 || x1 >= im_orig->
width || y1 < 0 || y1 >= im_orig->
height)
809 int x2 = x0 + (n - grange)*nx;
810 int y2 = y0 + (n - grange)*ny;
811 if (x2 < 0 || x2 >= im_orig->
width || y2 < 0 || y2 >= im_orig->
height)
814 int g1 = im_orig->
buf[y1*im_orig->
stride + x1];
815 int g2 = im_orig->
buf[y2*im_orig->
stride + x2];
820 double weight = (g2 - g1)*(g2 - g1);
831 double n0 = Mn / Mcount;
834 double bestx = x0 + n0*nx;
835 double besty = y0 + n0*ny;
847 double Ex = Mx / N, Ey = My / N;
848 double Cxx = Mxx / N - Ex*Ex;
849 double Cxy = Mxy / N - Ex*Ey;
850 double Cyy = Myy / N - Ey*Ey;
853 double normal_theta = .5 * atan2f(-2*Cxy, (Cyy - Cxx));
854 nx = cosf(normal_theta);
855 ny = sinf(normal_theta);
863 for (
int i = 0; i < 4; i++) {
866 double A00 = lines[i][3], A01 = -lines[(i+1)&3][3];
867 double A10 = -lines[i][2], A11 = lines[(i+1)&3][2];
868 double B0 = -lines[i][0] + lines[(i+1)&3][0];
869 double B1 = -lines[i][1] + lines[(i+1)&3][1];
871 double det = A00 * A11 - A10 * A01;
874 if (fabs(det) > 0.001) {
876 double W00 = A11 / det, W01 = -A01 / det;
878 double L0 = W00*B0 + W01*B1;
882 quad->
p[(i+1)&3][0] = lines[i][0] + L0*A00;
883 quad->
p[(i+1)&3][1] = lines[i][1] + L0*A10;
897 for (
int quadidx = task->
i0; quadidx < task->
i1; quadidx++) {
898 struct quad *quad_original;
928 if (decision_margin >= 0 && entry.
hamming < 255) {
937 double c = cos(theta), s = sin(theta);
957 for (
int i = 0; i < 4; i++) {
958 int tcx = (i == 1 || i == 2) ? 1 : -1;
959 int tcy = (i < 2) ? 1 : -1;
969 pthread_mutex_lock(&td->
mutex);
971 pthread_mutex_unlock(&td->
mutex);
1013 if (td->
wp == NULL) {
1044 int ksz = 4 * sigma;
1058 for (
int y = 0; y < orig->
height; y++) {
1059 for (
int x = 0; x < orig->
width; x++) {
1060 int vorig = orig->
buf[y*orig->
stride + x];
1061 int vblur = quad_im->
buf[y*quad_im->
stride + x];
1063 int v = 2*vorig - vblur;
1069 quad_im->
buf[y*quad_im->
stride + x] = (uint8_t) v;
1091 for (
int j = 0; j < 4; j++) {
1103 if (quad_im != im_orig)
1123 const int bias = 100;
1124 int color = bias + (random() % (255-bias));
1146 for (
int i = 0; i <
zarray_size(quads); i+= chunksize) {
1147 tasks[ntasks].
i0 = i;
1150 tasks[ntasks].
td =
td;
1151 tasks[ntasks].
im = im_orig;
1164 if (im_samples != NULL) {
1181 const int bias = 100;
1182 int color = bias + (random() % (255-bias));
1204 for (
int i0 = 0; i0 <
zarray_size(detections); i0++) {
1209 for (
int k = 0; k < 4; k++)
1212 for (
int i1 = i0+1; i1 <
zarray_size(detections); i1++) {
1220 for (
int k = 0; k < 4; k++)
1232 for (
int i = 0; i < 4; i++) {
1240 debug_print(
"uh oh, no preference for overlappingdetection\n");
1279 FILE *f = fopen(
"debug_output.ps",
"w");
1280 fprintf(f,
"%%!PS\n\n");
1281 double scale = fmin(612.0/darker->
width, 792.0/darker->
height);
1282 fprintf(f,
"%f %f scale\n", scale, scale);
1283 fprintf(f,
"0 %d translate\n", darker->
height);
1284 fprintf(f,
"1 -1 scale\n");
1289 for (
int i = 0; i <
zarray_size(detections); i++) {
1296 for (
int j = 0; j < 3; j++) {
1297 rgb[j] = bias + (random() % (255-bias));
1300 fprintf(f,
"%f %f %f setrgbcolor\n", rgb[0]/255.0f, rgb[1]/255.0f, rgb[2]/255.0f);
1301 fprintf(f,
"%f %f moveto %f %f lineto %f %f lineto %f %f lineto %f %f lineto stroke\n",
1302 det->
p[0][0], det->
p[0][1],
1303 det->
p[1][0], det->
p[1][1],
1304 det->
p[2][0], det->
p[2][1],
1305 det->
p[3][0], det->
p[3][1],
1306 det->
p[0][0], det->
p[0][1]);
1309 fprintf(f,
"showpage\n");
1319 for (
int y = 0; y < im_orig->
height; y++) {
1320 for (
int x = 0; x < im_orig->
width; x++) {
1329 for (
int i = 0; i <
zarray_size(detections); i++) {
1336 for (
int j = 0; j < 3; j++) {
1337 rgb[j] = bias + (random() % (255-bias));
1340 for (
int j = 0; j < 4; j++) {
1341 int k = (j + 1) & 3;
1343 det->
p[j][0], det->
p[j][1], det->
p[k][0], det->
p[k][1],
1344 (uint8_t[]) { rgb[0], rgb[1], rgb[2] },
1355 FILE *f = fopen(
"debug_quads.ps",
"w");
1356 fprintf(f,
"%%!PS\n\n");
1363 double scale = fmin(612.0/darker->
width, 792.0/darker->
height);
1364 fprintf(f,
"%f %f scale\n", scale, scale);
1365 fprintf(f,
"0 %d translate\n", darker->
height);
1366 fprintf(f,
"1 -1 scale\n");
1379 for (
int j = 0; j < 3; j++) {
1380 rgb[j] = bias + (random() % (255-bias));
1383 fprintf(f,
"%f %f %f setrgbcolor\n", rgb[0]/255.0f, rgb[1]/255.0f, rgb[2]/255.0f);
1384 fprintf(f,
"%f %f moveto %f %f lineto %f %f lineto %f %f lineto %f %f lineto stroke\n",
1385 q->
p[0][0], q->
p[0][1],
1386 q->
p[1][0], q->
p[1][1],
1387 q->
p[2][0], q->
p[2][1],
1388 q->
p[3][0], q->
p[3][1],
1389 q->
p[0][0], q->
p[0][1]);
1392 fprintf(f,
"showpage\n");
1417 for (
int i = 0; i <
zarray_size(detections); i++) {
1429 assert(fam != NULL);
1430 assert(idx >= 0 && idx < fam->ncodes);
1432 uint64_t code = fam->
codes[idx];
1437 int white_border_start = (fam->
total_width - white_border_width)/2;
1439 for (
int i = 0; i < white_border_width - 1; i += 1) {
1440 im->
buf[white_border_start*im->
stride + white_border_start + i] = 255;
1441 im->
buf[(white_border_start + i)*im->
stride + fam->
total_width - 1 - white_border_start] = 255;
1442 im->
buf[(fam->
total_width - 1 - white_border_start)*im->
stride + white_border_start + i + 1] = 255;
1443 im->
buf[(white_border_start + 1 + i)*im->
stride + white_border_start] = 255;
1447 for (
int i = 0; i < fam->
nbits; i++) {
static void graymodel_add(struct graymodel *gm, double x, double y, double gray)
void workerpool_add_task(workerpool_t *wp, void(*f)(void *p), void *p)
#define APRILTAG_TASKS_PER_THREAD_TARGET
static void zarray_get_volatile(const zarray_t *za, int idx, void *p)
static double value_for_pixel(image_u8_t *im, double px, double py)
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 image_u8_darken(image_u8_t *im)
void workerpool_destroy(workerpool_t *wp)
static void timeprofile_stamp(timeprofile_t *tp, const char *name)
image_u8_t * image_u8_decimate(image_u8_t *im, float ffactor)
#define debug_print(fmt,...)
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)
workerpool_t * workerpool_create(int nthreads)
static void homography_project(const matd_t *H, double x, double y, double *ox, double *oy)
int image_u8x3_write_pnm(const image_u8x3_t *im, const char *path)
static void zarray_destroy(zarray_t *za)
static void zarray_set(zarray_t *za, int idx, const void *p, void *outp)
static void quick_decode_uninit(apriltag_family_t *fam)
static void sharpen(apriltag_detector_t *td, double *values, int size)
apriltag_detector_t * apriltag_detector_create()
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)
image_u8_t * image_u8_copy(const image_u8_t *in)
zarray_t * g2d_polygon_create_zeros(int sz)
static zarray_t * zarray_create(size_t el_sz)
int g2d_polygon_overlaps_polygon(const zarray_t *polya, const zarray_t *polyb)
static uint64_t rotate90(uint64_t w, int numBits)
static float quad_decode(apriltag_detector_t *td, apriltag_family_t *family, image_u8_t *im, struct quad *quad, struct quick_decode_entry *entry, image_u8_t *im_samples)
static void quick_decode_add(struct quick_decode *qd, uint64_t code, int id, int hamming)
struct apriltag_quad_thresh_params qtp
static void quad_destroy(struct quad *quad)
image_u8x3_t * image_u8x3_create(unsigned int width, unsigned int height)
void workerpool_run(workerpool_t *wp)
void apriltag_detector_remove_family(apriltag_detector_t *td, apriltag_family_t *fam)
void apriltag_detection_destroy(apriltag_detection_t *det)
int image_u8_write_pnm(const image_u8_t *im, const char *path)
static timeprofile_t * timeprofile_create()
matd_t * matd_create_data(int rows, int cols, const TYPE *data)
void image_u8_gaussian_blur(image_u8_t *im, double sigma, int ksz)
static int imin(int a, int b)
static matd_t * homography_compute2(double c[4][4])
zarray_t * apriltag_quad_thresh(apriltag_detector_t *td, image_u8_t *im)
static void graymodel_init(struct graymodel *gm)
void matd_destroy(matd_t *m)
static int quad_update_homographies(struct quad *quad)
static void zarray_get(const zarray_t *za, int idx, void *p)
image_u8_t * image_u8_create(unsigned int width, unsigned int height)
void image_u8_destroy(image_u8_t *im)
int workerpool_get_nthreads(workerpool_t *wp)
void image_u8x3_draw_line(image_u8x3_t *im, float x0, float y0, float x1, float y1, uint8_t rgb[3], int width)
matd_t * matd_create(int rows, int cols)
static void refine_edges(apriltag_detector_t *td, image_u8_t *im_orig, struct quad *quad)
matd_t * matd_inverse(const matd_t *x)
static double graymodel_interpolate(struct graymodel *gm, double x, double y)
static int prefer_smaller(int pref, double q0, double q1)
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
void apriltag_detector_add_family_bits(apriltag_detector_t *td, apriltag_family_t *fam, int bits_corrected)
static void timeprofile_clear(timeprofile_t *tp)
void apriltag_detector_clear_families(apriltag_detector_t *td)
matd_t * matd_copy(const matd_t *m)
matd_t * matd_op(const char *expr,...)
static void quick_decode_init(apriltag_family_t *family, int maxhamming)
static void timeprofile_destroy(timeprofile_t *tp)
void image_u8x3_destroy(image_u8x3_t *im)
static void quick_decode_codeword(apriltag_family_t *tf, uint64_t rcode, struct quick_decode_entry *entry)
void image_u8_draw_line(image_u8_t *im, float x0, float y0, float x1, float y1, int v, int width)
static void zarray_add(zarray_t *za, const void *p)
zarray_t * apriltag_detector_detect(apriltag_detector_t *td, image_u8_t *im_orig)
static void graymodel_solve(struct graymodel *gm)
apriltag_family_t * family
static struct quad * quad_copy(struct quad *quad)