Skip to content

Commit 57d5243

Browse files
committed
Cache unionfind structure across detect calls and lazy-initialize size array
1 parent 3057666 commit 57d5243

File tree

6 files changed

+98
-5
lines changed

6 files changed

+98
-5
lines changed

apriltag.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,8 @@ void apriltag_detector_destroy(apriltag_detector_t *td)
411411
apriltag_detector_clear_families(td);
412412

413413
zarray_destroy(td->tag_families);
414+
if (td->cached_uf)
415+
unionfind_destroy(td->cached_uf);
414416
free(td);
415417
}
416418

apriltag.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern "C" {
3939
#include "common/workerpool.h"
4040
#include "common/timeprofile.h"
4141
#include "common/pthreads_cross.h"
42+
#include "common/unionfind.h"
4243

4344
#define APRILTAG_TASKS_PER_THREAD_TARGET 10
4445

@@ -188,6 +189,9 @@ struct apriltag_detector
188189

189190
// Used for thread safety.
190191
pthread_mutex_t mutex;
192+
193+
// Cached unionfind structure (reused across detect calls)
194+
unionfind_t *cached_uf;
191195
};
192196

193197
// Represents the detection of a tag. These are returned to the user

apriltag_quad_thresh.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,7 +1511,17 @@ image_u8_t *threshold_bayer(apriltag_detector_t *td, image_u8_t *im)
15111511
}
15121512

15131513
unionfind_t* connected_components(apriltag_detector_t *td, image_u8_t* threshim, int w, int h, int ts) {
1514-
unionfind_t *uf = unionfind_create(w * h);
1514+
uint32_t maxid = w * h;
1515+
if (td->cached_uf) {
1516+
if (td->cached_uf->maxid >= maxid) {
1517+
unionfind_reset(td->cached_uf);
1518+
} else {
1519+
unionfind_resize(td->cached_uf, maxid);
1520+
}
1521+
} else {
1522+
td->cached_uf = unionfind_create(maxid);
1523+
}
1524+
unionfind_t *uf = td->cached_uf;
15151525

15161526
if (td->nthreads <= 1) {
15171527
do_unionfind_first_line(uf, threshim, w, ts);
@@ -2004,8 +2014,6 @@ zarray_t *apriltag_quad_thresh(apriltag_detector_t *td, image_u8_t *im)
20042014

20052015
timeprofile_stamp(td->tp, "fit quads to clusters");
20062016

2007-
unionfind_destroy(uf);
2008-
20092017
for (int i = 0; i < zarray_size(clusters); i++) {
20102018
zarray_t *cluster;
20112019
zarray_get(clusters, i, &cluster);

common/unionfind.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,28 @@ struct unionfind
4444
uint32_t *size;
4545
};
4646

47+
static inline void unionfind_reset(unionfind_t *uf)
48+
{
49+
memset(uf->parent, 0xff, (uf->maxid+1) * sizeof(uint32_t));
50+
// uf->size is lazily initialized in unionfind_get_representative
51+
}
52+
4753
static inline unionfind_t *unionfind_create(uint32_t maxid)
4854
{
4955
unionfind_t *uf = (unionfind_t*) calloc(1, sizeof(unionfind_t));
5056
uf->maxid = maxid;
5157
uf->parent = (uint32_t *) malloc((maxid+1) * sizeof(uint32_t) * 2);
52-
memset(uf->parent, 0xff, (maxid+1) * sizeof(uint32_t));
5358
uf->size = uf->parent + (maxid+1);
54-
memset(uf->size, 0, (maxid+1) * sizeof(uint32_t));
59+
unionfind_reset(uf);
60+
return uf;
61+
}
62+
63+
static inline unionfind_t *unionfind_resize(unionfind_t *uf, uint32_t maxid)
64+
{
65+
uf->maxid = maxid;
66+
uf->parent = (uint32_t *) realloc(uf->parent, (maxid+1) * sizeof(uint32_t) * 2);
67+
uf->size = uf->parent + (maxid+1);
68+
unionfind_reset(uf);
5569
return uf;
5670
}
5771

@@ -85,6 +99,7 @@ static inline uint32_t unionfind_get_representative(unionfind_t *uf, uint32_t id
8599
// unititialized node, so set to self
86100
if (uf->parent[id] == 0xffffffff) {
87101
uf->parent[id] = id;
102+
uf->size[id] = 0;
88103
return id;
89104
}
90105

test/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,11 @@ endif()
4848

4949
add_test(NAME test_quick_decode COMMAND test_quick_decode)
5050

51+
add_executable(test_multiple_sizes test_multiple_sizes.c)
52+
target_link_libraries(test_multiple_sizes ${PROJECT_NAME})
53+
54+
add_test(NAME test_multiple_sizes
55+
COMMAND $<TARGET_FILE:test_multiple_sizes> data/33369213973_9d9bb4cc96_c.jpg
56+
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
57+
)
58+

test/test_multiple_sizes.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <apriltag.h>
4+
#include <tag36h11.h>
5+
#include <common/pjpeg.h>
6+
7+
// This test verifies that the cached data inside the detector handle size changes
8+
9+
int main(int argc, char *argv[])
10+
{
11+
if (argc != 2) {
12+
fprintf(stderr, "Usage: %s <image.jpg>\n", argv[0]);
13+
return EXIT_FAILURE;
14+
}
15+
16+
pjpeg_t *pjpeg = pjpeg_create_from_file(argv[1], 0, NULL);
17+
if (pjpeg == NULL) {
18+
fprintf(stderr, "Failed to load %s\n", argv[1]);
19+
return EXIT_FAILURE;
20+
}
21+
image_u8_t *im = pjpeg_to_u8_baseline(pjpeg);
22+
23+
apriltag_family_t *tf = tag36h11_create();
24+
apriltag_detector_t *td = apriltag_detector_create();
25+
apriltag_detector_add_family(td, tf);
26+
td->refine_edges = false;
27+
28+
// First detect with quad_decimate=2
29+
td->quad_decimate = 2;
30+
zarray_t *dets1 = apriltag_detector_detect(td, im);
31+
int n1 = zarray_size(dets1);
32+
printf("decimate=2: %d detections\n", n1);
33+
apriltag_detections_destroy(dets1);
34+
35+
// Now detect with quad_decimate=1
36+
td->quad_decimate = 1;
37+
zarray_t *dets2 = apriltag_detector_detect(td, im);
38+
int n2 = zarray_size(dets2);
39+
printf("decimate=1: %d detections\n", n2);
40+
apriltag_detections_destroy(dets2);
41+
42+
// Then detect with quad_decimate=2 again
43+
td->quad_decimate = 2;
44+
zarray_t *dets3 = apriltag_detector_detect(td, im);
45+
int n3 = zarray_size(dets3);
46+
printf("decimate=2: %d detections\n", n3);
47+
apriltag_detections_destroy(dets3);
48+
49+
image_u8_destroy(im);
50+
pjpeg_destroy(pjpeg);
51+
apriltag_detector_destroy(td);
52+
tag36h11_destroy(tf);
53+
54+
printf("PASS\n");
55+
return EXIT_SUCCESS;
56+
}

0 commit comments

Comments
 (0)