53 return (2654435761 * x) >> 32;
66 # define M_PI 3.141592653589793238462643383279502884196 122 #define MAYBE_SWAP(arr,apos,bpos) \ 123 if (arr[apos].theta > arr[bpos].theta) { \ 124 tmp = arr[apos]; arr[apos] = arr[bpos]; arr[bpos] = tmp; \ 181 struct pt _tmp_stack[stacksz];
182 struct pt *tmp = _tmp_stack;
186 tmp = malloc(
sizeof(
struct pt) * sz);
189 memcpy(tmp, pts,
sizeof(
struct pt) * sz);
194 struct pt *as = &tmp[0];
195 struct pt *bs = &tmp[asz];
200 #define MERGE(apos,bpos) \ 201 if (as[apos].theta < bs[bpos].theta) \ 202 pts[outpos++] = as[apos++]; \ 204 pts[outpos++] = bs[bpos++]; 206 int apos = 0, bpos = 0, outpos = 0;
207 while (apos + 8 < asz && bpos + 8 < bsz) {
212 while (apos < asz && bpos < bsz) {
217 memcpy(&pts[outpos], &as[apos], (asz-apos)*
sizeof(
struct pt));
219 memcpy(&pts[outpos], &bs[bpos], (bsz-bpos)*
sizeof(
struct pt));
232 void fit_line(
struct line_fit_pt *lfps,
int sz,
int i0,
int i1,
double *lineparm,
double *err,
double *mse)
235 assert(i0 >= 0 && i1 >= 0 && i0 < sz && i1 < sz);
237 double Mx, My, Mxx, Myy, Mxy, W;
253 Mxx -= lfps[i0-1].
Mxx;
254 Mxy -= lfps[i0-1].
Mxy;
255 Myy -= lfps[i0-1].
Myy;
263 Mx = lfps[sz-1].
Mx - lfps[i0-1].
Mx;
264 My = lfps[sz-1].
My - lfps[i0-1].
My;
265 Mxx = lfps[sz-1].
Mxx - lfps[i0-1].
Mxx;
266 Mxy = lfps[sz-1].
Mxy - lfps[i0-1].
Mxy;
267 Myy = lfps[sz-1].
Myy - lfps[i0-1].
Myy;
268 W = lfps[sz-1].
W - lfps[i0-1].
W;
277 N = sz - i0 + i1 + 1;
284 double Cxx = Mxx / W - Ex*Ex;
285 double Cxy = Mxy / W - Ex*Ey;
286 double Cyy = Myy / W - Ey*Ey;
296 double normal_theta = .5 * atan2f(-2*Cxy, (Cyy - Cxx));
297 nx = cosf(normal_theta);
298 ny = sinf(normal_theta);
302 double tx = (Cyy - Cxx);
303 double mag = ty*ty + tx*tx;
309 double norm = sqrtf(ty*ty + tx*tx);
319 }
else if (tx < -1) {
324 ny = sqrtf((1 - tx)/2);
325 nx = sqrtf((1 + tx)/2);
351 *err = nx*nx*N*Cxx + 2*nx*ny*N*Cxy + ny*ny*N*Cyy;
355 *mse = nx*nx*Cxx + 2*nx*ny*Cxy + ny*ny*Cyy;
360 struct pt *a = (
struct pt*) _a;
361 struct pt *b = (
struct pt*) _b;
368 const double *a = _a;
369 const double *b = _b;
371 return ((*a) < (*b)) ? 1 : -1;
405 int ksz =
imin(20, sz / 12);
415 for (
int i = 0; i < sz; i++) {
416 fit_line(lfps, sz, (i + sz - ksz) % sz, (i + ksz) % sz, NULL, &errs[i], NULL);
437 double cutoff = 0.05;
438 int fsz = sqrt(-log(cutoff)*2*sigma*sigma) + 1;
445 for (
int i = 0; i < fsz; i++) {
447 f[i] = exp(-j*j/(2*sigma*sigma));
450 for (
int iy = 0; iy < sz; iy++) {
453 for (
int i = 0; i < fsz; i++) {
454 acc += errs[(iy + i - fsz / 2 + sz) % sz] * f[i];
459 memcpy(errs, y,
sizeof(y));
463 double maxima_errs[sz];
466 for (
int i = 0; i < sz; i++) {
467 if (errs[i] > errs[(i+1)%sz] && errs[i] > errs[(i+sz-1)%sz]) {
469 maxima_errs[nmaxima] = errs[i];
481 if (nmaxima > max_nmaxima) {
482 double maxima_errs_copy[nmaxima];
483 memcpy(maxima_errs_copy, maxima_errs,
sizeof(maxima_errs_copy));
488 double maxima_thresh = maxima_errs_copy[max_nmaxima];
490 for (
int in = 0; in < nmaxima; in++) {
491 if (maxima_errs[in] <= maxima_thresh)
493 maxima[out++] = maxima[in];
499 double best_error = HUGE_VALF;
501 double err01, err12, err23, err30;
502 double mse01, mse12, mse23, mse30;
503 double params01[4], params12[4], params23[4], params30[4];
508 for (
int m0 = 0; m0 < nmaxima - 3; m0++) {
511 for (
int m1 = m0+1; m1 < nmaxima - 2; m1++) {
514 fit_line(lfps, sz, i0, i1, params01, &err01, &mse01);
519 for (
int m2 = m1+1; m2 < nmaxima - 1; m2++) {
522 fit_line(lfps, sz, i1, i2, params12, &err12, &mse12);
526 double dot = params01[2]*params12[2] + params01[3]*params12[3];
527 if (fabs(dot) > max_dot)
530 for (
int m3 = m2+1; m3 < nmaxima; m3++) {
533 fit_line(lfps, sz, i2, i3, params23, &err23, &mse23);
537 fit_line(lfps, sz, i3, i0, params30, &err30, &mse30);
541 double err = err01 + err12 + err23 + err30;
542 if (err < best_error) {
544 best_indices[0] = i0;
545 best_indices[1] = i1;
546 best_indices[2] = i2;
547 best_indices[3] = i3;
554 if (best_error == HUGE_VALF)
557 for (
int i = 0; i < 4; i++)
558 indices[i] = best_indices[i];
560 if (best_error / sz < td->qtp.max_line_fit_mse)
579 int rvalloc_size = 3*sz;
585 for (
int i = 0; i < sz; i++) {
607 while (nvertices > 4) {
608 assert(rvalloc_pos < rvalloc_size);
665 for (
int i = 0;
i < sz;
i++) {
666 if (segs[
i].is_vertex) {
692 int32_t xmax = 0, xmin = INT32_MAX, ymax = 0, ymin = INT32_MAX;
694 for (
int pidx = 0; pidx <
zarray_size(cluster); pidx++) {
698 xmax =
imax(xmax, p->
x);
699 xmin =
imin(xmin, p->
x);
701 ymax =
imax(ymax, p->
y);
702 ymin =
imin(ymin, p->
y);
710 double cx = (xmin + xmax) * 0.5 + 0.05118;
711 double cy = (ymin + ymax) * 0.5 + -0.028581;
715 for (
int pidx = 0; pidx <
zarray_size(cluster); pidx++) {
719 double dx = p->
x - cx;
720 double dy = p->
y - cy;
722 p->
theta = atan2f(dy, dx);
724 dot += dx*p->
gx + dy*p->
gy;
736 ptsort((
struct pt*) cluster->
data, zarray_size(cluster));
745 for (
int i = 1; i < sz; i++) {
750 if (p->
x != last->
x || p->
y != last->
y) {
755 memcpy(out, p,
sizeof(
struct pt));
764 cluster->
size = outpos;
781 struct pt v[nbuckets][ASSOC];
782 memset(v, 0,
sizeof(v));
785 for (
int i = 0; i < sz; i++) {
792 assert(bucket >= 0 && bucket < nbuckets);
794 for (
int i = 0; i <
ASSOC; i++) {
795 if (v[bucket][i].
theta == 0) {
804 for (
int i = 0; i < nbuckets; i++) {
805 for (
int j = 0; j <
ASSOC; j++) {
806 if (v[i][j].
theta != 0) {
826 for (
int i = 0; i < sz; i++) {
831 memcpy(&lfps[i], &lfps[i-1],
sizeof(
struct line_fit_pt));
837 double x = p->
x * .5 + delta;
838 double y = p->
y * .5 + delta;
841 for (
int dy = -1; dy <= 1; dy++) {
844 if (iy < 0 || iy + 1 >= im->
height)
847 for (
int dx = -1; dx <= 1; dx++) {
850 if (ix < 0 || ix + 1 >= im->
width)
853 int grad_x = im->
buf[iy * im->
stride + ix + 1] -
856 int grad_y = im->
buf[(iy+1) * im->
stride + ix] -
859 W = sqrtf(grad_x*grad_x + grad_y*grad_y) + 1;
862 double fx = ix + .5, fy = iy + .5;
863 lfps[i].
Mx += W * fx;
864 lfps[i].
My += W * fy;
865 lfps[i].
Mxx += W * fx * fx;
866 lfps[i].
Mxy += W * fx * fy;
867 lfps[i].
Myy += W * fy * fy;
874 double x = p->
x * .5 + delta;
875 double y = p->
y * .5 + delta;
879 if (ix > 0 && ix+1 < im->
width && iy > 0 && iy+1 < im->
height) {
880 int grad_x = im->
buf[iy * im->
stride + ix + 1] -
883 int grad_y = im->
buf[(iy+1) * im->
stride + ix] -
887 W = sqrt(grad_x*grad_x + grad_y*grad_y) + 1;
890 double fx =
x, fy =
y;
891 lfps[i].
Mx += W * fx;
892 lfps[i].
My += W * fy;
893 lfps[i].
Mxx += W * fx * fx;
894 lfps[i].
Mxy += W * fx * fy;
895 lfps[i].
Myy += W * fy * fy;
917 for (
int i = 0; i < 4; i++) {
921 quad->
p[i][0] = .5*p->
x;
922 quad->
p[i][1] = .5*p->
y;
930 for (
int i = 0; i < 4; i++) {
932 int i1 = indices[(i+1)&3];
943 i1 = (i1 + sz - t) % sz;
948 fit_line(lfps, sz, i0, i1, lines[i], NULL, &err);
956 for (
int i = 0; i < 4; i++) {
972 double A00 = lines[i][3], A01 = -lines[(i+1)&3][3];
973 double A10 = -lines[i][2], A11 = lines[(i+1)&3][2];
974 double B0 = -lines[i][0] + lines[(i+1)&3][0];
975 double B1 = -lines[i][1] + lines[(i+1)&3][1];
977 double det = A00 * A11 - A10 * A01;
980 double W00 = A11 / det, W01 = -A01 / det;
981 if (fabs(det) < 0.001) {
987 double L0 = W00*B0 + W01*B1;
990 quad->
p[i][0] = lines[i][0] + L0*A00;
991 quad->
p[i][1] = lines[i][1] + L0*A10;
996 double W10 = -A10 / det, W11 = A00 / det;
997 double L1 = W10*B0 + W11*B1;
999 double x = lines[(i+1)&3][0] - L1*A10;
1000 double y = lines[(i+1)&3][1] - L1*A11;
1001 assert(fabs(x - quad->
p[i][0]) < 0.001 &&
1002 fabs(y - quad->
p[i][1]) < 0.001);
1014 double length[3], p;
1015 for (
int i = 0; i < 3; i++) {
1017 int idxb = (i+1) % 3;
1018 length[i] = sqrt(
sq(quad->
p[idxb][0] - quad->
p[idxa][0]) +
1019 sq(quad->
p[idxb][1] - quad->
p[idxa][1]));
1021 p = (length[0] + length[1] + length[2]) / 2;
1023 area += sqrt(p*(p-length[0])*(p-length[1])*(p-length[2]));
1026 for (
int i = 0; i < 3; i++) {
1027 int idxs[] = { 2, 3, 0, 2 };
1029 int idxb = idxs[i+1];
1030 length[i] = sqrt(
sq(quad->
p[idxb][0] - quad->
p[idxa][0]) +
1031 sq(quad->
p[idxb][1] - quad->
p[idxa][1]));
1033 p = (length[0] + length[1] + length[2]) / 2;
1035 area += sqrt(p*(p-length[0])*(p-length[1])*(p-length[2]));
1051 for (
int i = 0; i < 4; i++) {
1052 int i0 = i, i1 = (i+1)&3, i2 = (i+2)&3;
1054 double theta0 = atan2f(quad->
p[i0][1] - quad->
p[i1][1],
1055 quad->
p[i0][0] - quad->
p[i1][0]);
1056 double theta1 = atan2f(quad->
p[i2][1] - quad->
p[i1][1],
1057 quad->
p[i2][0] - quad->
p[i1][0]);
1059 double dtheta = theta0 - theta1;
1070 if (total < 6.2 || total > 6.4) {
1093 #define DO_UNIONFIND(dx, dy) if (im->buf[y*s + dy*s + x + dx] == v) unionfind_connect(uf, y*w + x, y*w + dy*w + x + dx); 1097 assert(y+1 < im->
height);
1099 for (
int x = 1;
x < w - 1;
x++) {
1100 uint8_t v = im->
buf[y*s +
x];
1123 for (
int y = task->
y0; y < task->
y1; y++) {
1135 int w = task->
w,
h = task->
h;
1137 for (
int cidx = task->
cidx0; cidx < task->
cidx1; cidx++) {
1156 memset(&quad, 0,
sizeof(
struct quad));
1158 if (
fit_quad(td, task->
im, cluster, &quad)) {
1159 pthread_mutex_lock(&td->
mutex);
1162 pthread_mutex_unlock(&td->
mutex);
1174 assert(threshim->
stride == s);
1199 const int tilesz = 4;
1203 int tw = w / tilesz;
1204 int th = h / tilesz;
1206 uint8_t *im_max = calloc(tw*th,
sizeof(uint8_t));
1207 uint8_t *im_min = calloc(tw*th,
sizeof(uint8_t));
1210 for (
int ty = 0; ty < th; ty++) {
1211 for (
int tx = 0; tx < tw; tx++) {
1212 uint8_t
max = 0,
min = 255;
1214 for (
int dy = 0; dy < tilesz; dy++) {
1216 for (
int dx = 0; dx < tilesz; dx++) {
1218 uint8_t v = im->
buf[(ty*tilesz+dy)*s + tx*tilesz + dx];
1226 im_max[ty*tw+tx] =
max;
1227 im_min[ty*tw+tx] =
min;
1235 uint8_t *im_max_tmp = calloc(tw*th,
sizeof(uint8_t));
1236 uint8_t *im_min_tmp = calloc(tw*th,
sizeof(uint8_t));
1238 for (
int ty = 0; ty < th; ty++) {
1239 for (
int tx = 0; tx < tw; tx++) {
1240 uint8_t
max = 0,
min = 255;
1242 for (
int dy = -1; dy <= 1; dy++) {
1243 if (ty+dy < 0 || ty+dy >= th)
1245 for (
int dx = -1; dx <= 1; dx++) {
1246 if (tx+dx < 0 || tx+dx >= tw)
1249 uint8_t m = im_max[(ty+dy)*tw+tx+dx];
1252 m = im_min[(ty+dy)*tw+tx+dx];
1258 im_max_tmp[ty*tw + tx] =
max;
1259 im_min_tmp[ty*tw + tx] =
min;
1264 im_max = im_max_tmp;
1265 im_min = im_min_tmp;
1268 for (
int ty = 0; ty < th; ty++) {
1269 for (
int tx = 0; tx < tw; tx++) {
1271 int min = im_min[ty*tw + tx];
1272 int max = im_max[ty*tw + tx];
1275 if (max - min < td->qtp.min_white_black_diff) {
1276 for (
int dy = 0; dy < tilesz; dy++) {
1277 int y = ty*tilesz + dy;
1279 for (
int dx = 0; dx < tilesz; dx++) {
1280 int x = tx*tilesz + dx;
1282 threshim->
buf[y*s+x] = 127;
1292 uint8_t thresh = min + (max -
min) / 2;
1294 for (
int dy = 0; dy < tilesz; dy++) {
1295 int y = ty*tilesz + dy;
1297 for (
int dx = 0; dx < tilesz; dx++) {
1298 int x = tx*tilesz + dx;
1300 uint8_t v = im->
buf[y*s+x];
1302 threshim->
buf[y*s+x] = 255;
1304 threshim->
buf[y*s+x] = 0;
1312 for (
int y = 0; y < h; y++) {
1318 if (y >= th*tilesz) {
1325 int ty = y / tilesz;
1329 for (
int x = x0; x < w; x++) {
1330 int tx = x / tilesz;
1334 int max = im_max[ty*tw + tx];
1335 int min = im_min[ty*tw + tx];
1336 int thresh = min + (max -
min) / 2;
1338 uint8_t v = im->
buf[y*s+x];
1340 threshim->
buf[y*s+x] = 255;
1342 threshim->
buf[y*s+x] = 0;
1355 for (
int y = 1; y + 1 < h; y++) {
1356 for (
int x = 1; x + 1 < w; x++) {
1358 for (
int dy = -1; dy <= 1; dy++) {
1359 for (
int dx = -1; dx <= 1; dx++) {
1360 uint8_t v = threshim->
buf[(y+dy)*s + x + dx];
1369 for (
int y = 1; y + 1 < h; y++) {
1370 for (
int x = 1; x + 1 < w; x++) {
1372 for (
int dy = -1; dy <= 1; dy++) {
1373 for (
int dx = -1; dx <= 1; dx++) {
1374 uint8_t v = tmp->
buf[(y+dy)*s + x + dx];
1379 threshim->
buf[y*s+x] =
min;
1399 assert(threshim->
stride == s);
1402 assert((tilesz & 1) == 0);
1404 int tw = w/tilesz + 1;
1405 int th = h/tilesz + 1;
1407 uint8_t *im_max[4], *im_min[4];
1408 for (
int i = 0; i < 4; i++) {
1409 im_max[i] = calloc(tw*th,
sizeof(uint8_t));
1410 im_min[i] = calloc(tw*th,
sizeof(uint8_t));
1413 for (
int ty = 0; ty < th; ty++) {
1414 for (
int tx = 0; tx < tw; tx++) {
1416 uint8_t
max[4] = { 0, 0, 0, 0};
1417 uint8_t
min[4] = { 255, 255, 255, 255 };
1419 for (
int dy = 0; dy < tilesz; dy++) {
1420 if (ty*tilesz+dy >= h)
1423 for (
int dx = 0; dx < tilesz; dx++) {
1424 if (tx*tilesz+dx >= w)
1428 int idx = (2*(dy&1) + (dx&1));
1430 uint8_t v = im->
buf[(ty*tilesz+dy)*s + tx*tilesz + dx];
1438 for (
int i = 0; i < 4; i++) {
1439 im_max[i][ty*tw+tx] = max[i];
1440 im_min[i][ty*tw+tx] = min[i];
1445 for (
int ty = 0; ty < th; ty++) {
1446 for (
int tx = 0; tx < tw; tx++) {
1448 uint8_t
max[4] = { 0, 0, 0, 0};
1449 uint8_t
min[4] = { 255, 255, 255, 255 };
1451 for (
int dy = -1; dy <= 1; dy++) {
1452 if (ty+dy < 0 || ty+dy >= th)
1454 for (
int dx = -1; dx <= 1; dx++) {
1455 if (tx+dx < 0 || tx+dx >= tw)
1458 for (
int i = 0; i < 4; i++) {
1459 uint8_t m = im_max[i][(ty+dy)*tw+tx+dx];
1462 m = im_min[i][(ty+dy)*tw+tx+dx];
1476 for (
int i = 0; i < 4; i++) {
1477 thresh[i] = min[i] + (max[i] - min[i]) / 2;
1480 for (
int dy = 0; dy < tilesz; dy++) {
1481 int y = ty*tilesz + dy;
1485 for (
int dx = 0; dx < tilesz; dx++) {
1486 int x = tx*tilesz + dx;
1491 int idx = (2*(y&1) + (x&1));
1493 uint8_t v = im->
buf[y*s+x];
1494 threshim->
buf[y*s+x] = v > thresh[idx];
1500 for (
int i = 0; i < 4; i++) {
1518 int ts = threshim->
stride;
1529 for (
int y = 0; y < h - 1; y++) {
1539 for (
int i = 0; i < sz; i += chunksize) {
1545 tasks[ntasks].
y0 = i;
1546 tasks[ntasks].
y1 =
imin(sz, i + chunksize - 1);
1547 tasks[ntasks].
h =
h;
1548 tasks[ntasks].
w =
w;
1549 tasks[ntasks].
s = ts;
1550 tasks[ntasks].
uf =
uf;
1551 tasks[ntasks].
im = threshim;
1560 for (
int i = 0; i + 1 < ntasks; i++) {
1568 int nclustermap = 2*w*h - 1;
1572 for (
int y = 1; y < h-1; y++) {
1573 for (
int x = 1; x < w-1; x++) {
1575 uint8_t v0 = threshim->
buf[y*ts + x];
1602 #define DO_CONN(dx, dy) \ 1604 uint8_t v1 = threshim->buf[y*ts + dy*ts + x + dx]; \ 1606 if (v0 + v1 == 255) { \ 1607 uint64_t rep1 = unionfind_get_representative(uf, y*w + dy*w + x + dx); \ 1608 uint64_t clusterid; \ 1610 clusterid = (rep1 << 32) + rep0; \ 1612 clusterid = (rep0 << 32) + rep1; \ 1615 uint32_t clustermap_bucket = u64hash_2(clusterid) % nclustermap; \ 1616 struct uint64_zarray_entry *entry = clustermap[clustermap_bucket]; \ 1617 while (entry && entry->id != clusterid) { \ 1618 entry = entry->next; \ 1622 entry = calloc(1, sizeof(struct uint64_zarray_entry)); \ 1623 entry->id = clusterid; \ 1624 entry->cluster = zarray_create(sizeof(struct pt)); \ 1625 entry->next = clustermap[clustermap_bucket]; \ 1626 clustermap[clustermap_bucket] = entry; \ 1629 struct pt p = { .x = 2*x + dx, .y = 2*y + dy, .gx = dx*((int) v1-v0), .gy = dy*((int) v1-v0)}; \ 1630 zarray_add(entry->cluster, &p); \ 1651 uint32_t *colors = (uint32_t*) calloc(w*h,
sizeof(*colors));
1653 for (
int y = 0; y < h; y++) {
1654 for (
int x = 0; x < w; x++) {
1660 uint32_t color = colors[v];
1661 uint8_t r = color >> 16,
1666 const int bias = 50;
1667 r = bias + (random() % (200-bias));
1668 g = bias + (random() % (200-bias));
1669 b = bias + (random() % (200-bias));
1670 colors[v] = (r << 16) | (g << 8) | b;
1691 for (
int i = 0; i < nclustermap; i++) {
1711 const int bias = 50;
1712 r = bias + (random() % (200-bias));
1713 g = bias + (random() % (200-bias));
1714 b = bias + (random() % (200-bias));
1734 for (
int i = 0; i < nclustermap; i++) {
1749 struct quad_task tasks[sz / chunksize + 1];
1752 for (
int i = 0; i < sz; i += chunksize) {
1753 tasks[ntasks].
td =
td;
1754 tasks[ntasks].
cidx0 = i;
1755 tasks[ntasks].
cidx1 =
imin(sz, i + chunksize);
1756 tasks[ntasks].
h =
h;
1757 tasks[ntasks].
w =
w;
1760 tasks[ntasks].
im =
im;
1771 FILE *f = fopen(
"debug_lines.ps",
"w");
1772 fprintf(f,
"%%!PS\n\n");
1779 double scale = fmin(612.0/im->
width, 792.0/im2->
height);
1780 fprintf(f,
"%.15f %.15f scale\n", scale, scale);
1781 fprintf(f,
"0 %d translate\n", im2->
height);
1782 fprintf(f,
"1 -1 scale\n");
1793 for (
int i = 0; i < 3; i++)
1794 rgb[i] = bias + (random() % (255-bias));
1796 fprintf(f,
"%f %f %f setrgbcolor\n", rgb[0]/255.0f, rgb[1]/255.0f, rgb[2]/255.0f);
1797 fprintf(f,
"%.15f %.15f moveto %.15f %.15f lineto %.15f %.15f lineto %.15f %.15f lineto %.15f %.15f lineto stroke\n",
1798 q->
p[0][0], q->
p[0][1],
1799 q->
p[1][0], q->
p[1][1],
1800 q->
p[2][0], q->
p[2][1],
1801 q->
p[3][0], q->
p[3][1],
1802 q->
p[0][0], q->
p[0][1]);
static unionfind_t * unionfind_create(uint32_t maxid)
#define APRILTAG_TASKS_PER_THREAD_TARGET
static void zarray_get_volatile(const zarray_t *za, int idx, void *p)
int quad_segment_agg(apriltag_detector_t *td, zarray_t *cluster, struct line_fit_pt *lfps, int indices[4])
static void timeprofile_stamp(timeprofile_t *tp, const char *name)
static int zarray_size(const zarray_t *za)
static uint32_t unionfind_get_representative(unionfind_t *uf, uint32_t id)
static void zarray_destroy(zarray_t *za)
static void zarray_set(zarray_t *za, int idx, const void *p, void *outp)
int image_u8_write_pnm(const image_u8_t *im, const char *path)
image_u8_t * threshold_bayer(apriltag_detector_t *td, image_u8_t *im)
image_u8_t * image_u8_create(unsigned int width, unsigned int height)
static int imax(int a, int b)
static void ptsort(struct pt *pts, int sz)
#define MAYBE_SWAP(arr, apos, bpos)
struct uint64_zarray_entry * next
void zmaxheap_destroy(zmaxheap_t *heap)
static uint32_t unionfind_get_set_size(unionfind_t *uf, uint32_t id)
static zarray_t * zarray_create(size_t el_sz)
void zmaxheap_add(zmaxheap_t *heap, void *p, float v)
#define MERGE(apos, bpos)
struct apriltag_quad_thresh_params qtp
zarray_t * apriltag_quad_thresh(apriltag_detector_t *td, image_u8_t *im)
void workerpool_add_task(workerpool_t *wp, void(*f)(void *p), void *p)
int fit_quad(apriltag_detector_t *td, image_u8_t *im, zarray_t *cluster, struct quad *quad)
image_u8_t * image_u8_copy(const image_u8_t *in)
int zmaxheap_remove_max(zmaxheap_t *heap, void *p, float *v)
image_u8_t * image_u8_create_alignment(unsigned int width, unsigned int height, unsigned int alignment)
static double sq(double v)
static void do_unionfind_task(void *p)
int pt_compare_theta(const void *_a, const void *_b)
static void do_quad_task(void *p)
static void unionfind_destroy(unionfind_t *uf)
static int imin(int a, int b)
static void do_unionfind_line(unionfind_t *uf, image_u8_t *im, int h, int w, int s, int y)
static void zarray_truncate(zarray_t *za, int sz)
#define DO_UNIONFIND(dx, dy)
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)
int quad_segment_maxima(apriltag_detector_t *td, zarray_t *cluster, struct line_fit_pt *lfps, int indices[4])
void image_u8x3_destroy(image_u8x3_t *im)
void image_u8_destroy(image_u8_t *im)
int err_compare_descending(const void *_a, const void *_b)
image_u8_t * threshold(apriltag_detector_t *td, image_u8_t *im)
void fit_line(struct line_fit_pt *lfps, int sz, int i0, int i1, double *lineparm, double *err, double *mse)
int image_u8x3_write_pnm(const image_u8x3_t *im, const char *path)
static void postscript_image(FILE *f, image_u8_t *im)
void image_u8_darken(image_u8_t *im)
static uint32_t u64hash_2(uint64_t x)
zmaxheap_t * zmaxheap_create(size_t el_sz)
static void zarray_add(zarray_t *za, const void *p)