lardon3d/tests/test_precision_consolidation.c

1625 lines
61 KiB
C

/*
* Tests de durcissement et finalisation de la consolidation ORB/SIFT
* intra-image. Couvre : zero-features, rayon, grid boundary, support_count,
* mismatch, grand set, idempotence, concurrence, stress, pagination,
* fingerprint et quality comparison.
*/
#include <dirent.h>
#include <errno.h>
#include <math.h>
#include <pthread.h>
#include <sched.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <lardon3d/feature_store.h>
#include <lardon3d/feature_task.h>
#include <lardon3d/image_catalog.h>
#include <lardon3d/precision_features.h>
#include <lardon3d/project.h>
#include <lardon3d/project_db.h>
#include <lardon3d/sift_task.h>
#include <lardon3d/task_queue.h>
#define CHECK(x) \
do { \
if (!(x)) { \
fprintf(stderr, "FAIL line %d: %s\n", __LINE__, #x); \
return false; \
} \
} while (0)
/* -- Utilities -- */
static bool join_path(char out[PATH_MAX], const char *a, const char *b) {
int n = snprintf(out, PATH_MAX, "%s/%s", a, b);
return n > 0 && (size_t)n < PATH_MAX;
}
static bool remove_tree(const char *p) {
struct stat s;
if (lstat(p, &s) != 0) return errno == ENOENT;
if (!S_ISDIR(s.st_mode)) return unlink(p) == 0;
DIR *d = opendir(p);
if (!d) return false;
bool ok = true;
for (struct dirent *e = readdir(d); e; e = readdir(d)) {
if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue;
char c[PATH_MAX];
if (!join_path(c, p, e->d_name) || !remove_tree(c)) ok = false;
}
if (closedir(d) || rmdir(p)) ok = false;
return ok;
}
static bool write_pgm(const char *p) {
FILE *f = fopen(p, "wb");
if (!f) return false;
fprintf(f, "P5\n192 192\n255\n");
for (unsigned y = 0; y < 192; y++) {
for (unsigned x = 0; x < 192; x++) {
unsigned base = ((((x / 12) ^ (y / 12)) & 1U) != 0U) ? 205U : 35U;
unsigned texture = (x * 17U + y * 29U + (x * y) % 37U) % 43U;
int dx = (int)x - 96, dy = (int)y - 96;
unsigned ring = (dx * dx + dy * dy > 32 * 32 &&
dx * dx + dy * dy < 42 * 42)
? 45U
: 0U;
unsigned char v = (unsigned char)(base + texture + ring > 255U
? 255U
: base + texture + ring);
if (fwrite(&v, 1, 1, f) != 1) {
fclose(f);
return false;
}
}
}
return fclose(f) == 0;
}
static bool write_uniform_pgm(const char *path) {
FILE *file = fopen(path, "wb");
if (!file) return false;
bool ok = fprintf(file, "P5\n192 192\n255\n") > 0;
unsigned char row[192];
memset(row, 127, sizeof(row));
for (size_t y = 0; ok && y < 192; ++y)
ok = fwrite(row, 1, sizeof(row), file) == sizeof(row);
return fclose(file) == 0 && ok;
}
static bool write_gaussian_blob_pgm(const char *path) {
FILE *f = fopen(path, "wb");
if (!f) return false;
fprintf(f, "P5\n192 192\n255\n");
for (unsigned y = 0; y < 192; y++) {
for (unsigned x = 0; x < 192; x++) {
double dx = (double)x - 96.0, dy = (double)y - 96.0;
double r2 = (dx * dx + dy * dy) / (40.0 * 40.0);
double v = 200.0 * exp(-r2) + 30.0;
unsigned char c = (unsigned char)(v > 255.0 ? 255.0 : v);
if (fwrite(&c, 1, 1, f) != 1) {
fclose(f);
return false;
}
}
}
return fclose(f) == 0;
}
static bool write_large_pgm(const char *path) {
FILE *f = fopen(path, "wb");
if (!f) return false;
fprintf(f, "P5\n512 512\n255\n");
for (unsigned y = 0; y < 512; y++) {
for (unsigned x = 0; x < 512; x++) {
unsigned base = (((x / 8) ^ (y / 8)) & 1U) ? 210U : 30U;
unsigned t1 = (x * 13U + y * 31U) % 67U;
unsigned t2 = ((x + y) * 7U + (x * y) % 53U) % 41U;
int dx = (int)x - 256, dy = (int)y - 256;
unsigned ring = (dx * dx + dy * dy > 80 * 80 &&
dx * dx + dy * dy < 120 * 120)
? 50U
: 0U;
unsigned v = base + t1 + t2 + ring;
unsigned char c = (unsigned char)(v > 255U ? 255U : v);
if (fwrite(&c, 1, 1, f) != 1) {
fclose(f);
return false;
}
}
}
return fclose(f) == 0;
}
static bool runtime(Lardon3DAppState *s) {
s->hardware_profile = (Lardon3DHardwareProfile){
.logical_cpu_count = 64,
.page_size_bytes = 4096,
.memory_total_bytes = UINT64_MAX,
.cpu_architecture = "test"};
Lardon3DResourcePolicy p = {.maximum_cpu_load_ratio = 1,
.maximum_io_pressure_avg10 = 100,
.io_slot_capacity = 2};
s->resource_governor =
lardon3d_resource_governor_create(&s->hardware_profile, &p);
s->task_queue = s->resource_governor
? lardon3d_task_queue_create(s->resource_governor, 4)
: NULL;
return s->task_queue != NULL;
}
static bool wait_state(Lardon3DTaskQueue *q, uint64_t id,
Lardon3DTaskState wanted,
Lardon3DTaskSnapshot *out) {
struct timespec deadline;
if (clock_gettime(CLOCK_MONOTONIC, &deadline) != 0) return false;
deadline.tv_sec += 5;
for (;;) {
if (lardon3d_task_queue_get(q, id, out) && out->state == wanted)
return true;
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now) != 0 || now.tv_sec > deadline.tv_sec ||
(now.tv_sec == deadline.tv_sec && now.tv_nsec >= deadline.tv_nsec))
return false;
sched_yield();
}
}
/* -- Concurrency types -- */
typedef struct {
Lardon3DAppState *state;
uint64_t orb_id;
uint64_t sift_id;
Lardon3DFeatureConsolidationParameters params;
Lardon3DProjectDbFeatureSupportSet support;
Lardon3DProjectDbResult result;
} ConsolidationCtx;
static void *consolidate_thread(void *ud) {
ConsolidationCtx *ctx = ud;
ctx->result = lardon3d_consolidate_orb_sift(
ctx->state, ctx->orb_id, ctx->sift_id, &ctx->params,
&ctx->support);
return NULL;
}
static bool find_feature_set(Lardon3DProjectDb *db, uint64_t image_id,
const char *kind,
const unsigned char fp[32],
Lardon3DProjectDbFeatureSet *out) {
return lardon3d_project_db_find_feature_set(db, image_id, kind, 1, fp,
out) ==
LARDON3D_PROJECT_DB_OK;
}
/* -- Tests -- */
static bool test_zero_features_both_empty(void) {
char root[] = "/tmp/lardon3d-consol-zero-both-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "uniform.pgm") &&
write_uniform_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) && lardon3d_project_create(&state, "ZeroBoth"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(&state, image.image_id,
&orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED, &snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(&state, image.image_id,
&sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED, &snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params, sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb", orb_fp,
&orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift", sift_fp,
&sift_set));
CHECK(orb_set.feature_count == 0 && sift_set.feature_count == 0);
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
Lardon3DProjectDbResult r = lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id, sift_set.feature_set_id, &cp, &pub);
CHECK(r == LARDON3D_PROJECT_DB_OK);
CHECK(pub.group_count == 0);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_zero_features_both_empty\n");
return true;
}
static bool test_zero_orb_only_sift(void) {
char root[] = "/tmp/lardon3d-consol-zero-orb-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "blob.pgm") &&
write_gaussian_blob_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) && lardon3d_project_create(&state, "ZeroOrb"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(&state,
image.image_id,
&orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED, &snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(&state, image.image_id,
&sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED, &snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params, sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
CHECK(sift_set.feature_count > 0);
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id, sift_set.feature_set_id,
&cp, &pub) == LARDON3D_PROJECT_DB_OK);
Lardon3DProjectDbFeatureSupportGroup groups[256];
uint32_t listed = 0;
uint64_t after = 0;
if (orb_set.feature_count == 0) {
/* Path zero-ORB : chaque SIFT isolé devient un groupe. */
CHECK(pub.group_count == sift_set.feature_count);
do {
size_t cnt = 0;
CHECK(lardon3d_project_db_list_feature_support_groups(
state.project_db, pub.feature_support_set_id, after,
groups, 256, &cnt) == LARDON3D_PROJECT_DB_OK);
if (cnt == 0) break;
for (size_t i = 0; i < cnt; ++i) {
CHECK(groups[i].support_count == 1);
CHECK(!groups[i].has_second_feature);
after = groups[i].feature_support_group_id;
}
listed += (uint32_t)cnt;
} while (listed < pub.group_count);
CHECK(listed == pub.group_count);
} else {
/* FAST a tout de même détecté des coins sur le blob : la
consolidation doit fonctionner et produire des groupes valides. */
CHECK(pub.group_count > 0);
do {
size_t cnt = 0;
CHECK(lardon3d_project_db_list_feature_support_groups(
state.project_db, pub.feature_support_set_id, after,
groups, 256, &cnt) == LARDON3D_PROJECT_DB_OK);
if (cnt == 0) break;
for (size_t i = 0; i < cnt; ++i) {
CHECK(groups[i].support_count == 1 ||
groups[i].support_count == 2);
after = groups[i].feature_support_group_id;
}
listed += (uint32_t)cnt;
} while (listed < pub.group_count);
CHECK(listed == pub.group_count);
}
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_zero_orb_only_sift\n");
return true;
}
static bool test_zero_sift_only_orb(void) {
char root[] = "/tmp/lardon3d-consol-zero-sift-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) && lardon3d_project_create(&state, "ZeroSift"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(&state, image.image_id,
&orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED, &snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED, &snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params, sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb", orb_fp,
&orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
CHECK(orb_set.feature_count > 0);
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id, sift_set.feature_set_id,
&cp, &pub) == LARDON3D_PROJECT_DB_OK);
if (sift_set.feature_count == 0) {
CHECK(pub.group_count == orb_set.feature_count);
} else {
CHECK(pub.group_count > 0);
}
Lardon3DProjectDbFeatureSupportGroup groups[256];
uint32_t listed = 0;
uint64_t after = 0;
do {
size_t cnt = 0;
CHECK(lardon3d_project_db_list_feature_support_groups(
state.project_db, pub.feature_support_set_id, after,
groups, 256, &cnt) == LARDON3D_PROJECT_DB_OK);
if (cnt == 0) break;
for (size_t i = 0; i < cnt; ++i) {
CHECK(groups[i].support_count == 1 ||
groups[i].support_count == 2);
after = groups[i].feature_support_group_id;
}
listed += (uint32_t)cnt;
} while (listed < pub.group_count);
CHECK(listed == pub.group_count);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_zero_sift_only_orb\n");
return true;
}
static bool test_radius_boundaries(void) {
Lardon3DFeatureConsolidationParameters p;
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = 0.5};
CHECK(lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = 64.0};
CHECK(lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = 4.0};
CHECK(lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = 0.49};
CHECK(!lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = 64.01};
CHECK(!lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = -1.0};
CHECK(!lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = 0.0};
CHECK(!lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = NAN};
CHECK(!lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = INFINITY};
CHECK(!lardon3d_feature_consolidation_parameters_valid(&p));
p = (Lardon3DFeatureConsolidationParameters){
.association_radius_pixels = -INFINITY};
CHECK(!lardon3d_feature_consolidation_parameters_valid(&p));
fprintf(stderr, " PASS test_radius_boundaries\n");
return true;
}
static bool test_different_radius_different_result(void) {
char root[] = "/tmp/lardon3d-consol-radius-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) && lardon3d_project_create(&state, "Radius"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(&state, image.image_id,
&orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED, &snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(&state, image.image_id,
&sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED, &snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params, sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb", orb_fp,
&orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
Lardon3DFeatureConsolidationParameters cp_small = {
.association_radius_pixels = 2.0};
Lardon3DProjectDbFeatureSupportSet pub_small;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id, sift_set.feature_set_id,
&cp_small, &pub_small) == LARDON3D_PROJECT_DB_OK);
Lardon3DFeatureConsolidationParameters cp_large = {
.association_radius_pixels = 8.0};
Lardon3DProjectDbFeatureSupportSet pub_large;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id, sift_set.feature_set_id,
&cp_large, &pub_large) == LARDON3D_PROJECT_DB_OK);
unsigned char fp_small[32], fp_large[32];
lardon3d_feature_consolidation_fingerprint(&cp_small, fp_small);
lardon3d_feature_consolidation_fingerprint(&cp_large, fp_large);
CHECK(memcmp(fp_small, fp_large, 32) != 0);
CHECK(pub_small.feature_support_set_id !=
pub_large.feature_support_set_id);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr,
" PASS test_different_radius_different_result\n");
return true;
}
static bool test_support_count_values(void) {
char root[] = "/tmp/lardon3d-consol-supp-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "SupportCount"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(&state, image.image_id,
&orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED, &snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(&state, image.image_id,
&sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED, &snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params, sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb", orb_fp,
&orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id, sift_set.feature_set_id,
&cp, &pub) == LARDON3D_PROJECT_DB_OK);
CHECK(pub.group_count > 0);
bool has_pair = false;
Lardon3DProjectDbFeatureSupportGroup groups[256];
uint32_t listed = 0;
uint64_t after = 0;
do {
size_t cnt = 0;
CHECK(lardon3d_project_db_list_feature_support_groups(
state.project_db, pub.feature_support_set_id, after,
groups, 256, &cnt) == LARDON3D_PROJECT_DB_OK);
if (cnt == 0) break;
for (size_t i = 0; i < cnt; ++i) {
CHECK(groups[i].support_count == 1 ||
groups[i].support_count == 2);
CHECK(groups[i].distance_pixels >= 0.0);
CHECK(groups[i].distance_pixels <=
cp.association_radius_pixels);
has_pair |= (groups[i].support_count == 2);
after = groups[i].feature_support_group_id;
}
listed += (uint32_t)cnt;
} while (listed < pub.group_count);
CHECK(listed == pub.group_count);
CHECK(has_pair);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_support_count_values\n");
return true;
}
static bool test_mismatch_different_image(void) {
char root[] = "/tmp/lardon3d-consol-mismatch-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char src1[PATH_MAX], src2[PATH_MAX];
CHECK(join_path(src1, root, "a.pgm") && write_pgm(src1));
CHECK(join_path(src2, root, "b.pgm") && write_large_pgm(src2));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "Mismatch"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage img1, img2;
Lardon3DProjectDbImageAsset a1, a2;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, src1, 0, &img1,
&a1) == LARDON3D_IMAGE_CATALOG_IMPORTED);
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, src2, 0, &img2,
&a2) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task1 = 0, orb_task2 = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, img1.image_id, &orb_params, &orb_task1) &&
lardon3d_project_enqueue_feature_extract(
&state, img2.image_id, &orb_params, &orb_task2));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task1, TASK_COMPLETED,
&snap) &&
wait_state(state.task_queue, orb_task2, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(&state, img1.image_id,
&sift_params,
&sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED,
&snap));
unsigned char fp1[32], fp2[32], sfp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, fp1);
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, fp2);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params, sfp);
Lardon3DProjectDbFeatureSet orb1, orb2, sift1;
CHECK(find_feature_set(state.project_db, img1.image_id, "orb",
fp1, &orb1));
CHECK(find_feature_set(state.project_db, img2.image_id, "orb",
fp2, &orb2));
CHECK(find_feature_set(state.project_db, img1.image_id, "sift",
sfp, &sift1));
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
Lardon3DProjectDbResult r = lardon3d_consolidate_orb_sift(
&state, orb2.feature_set_id, sift1.feature_set_id, &cp,
&pub);
CHECK(r == LARDON3D_PROJECT_DB_INVALID_ARGUMENT);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_mismatch_different_image\n");
return true;
}
static bool test_mismatch_wrong_extractor(void) {
char root[] = "/tmp/lardon3d-consol-mismatch-ext-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "MismatchExt"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
unsigned char fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, fp);
Lardon3DProjectDbFeatureSet orb_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
fp, &orb_set));
/* first == second */
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
Lardon3DProjectDbResult r = lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id, orb_set.feature_set_id,
&cp, &pub);
CHECK(r == LARDON3D_PROJECT_DB_INVALID_ARGUMENT);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_mismatch_wrong_extractor\n");
return true;
}
static bool test_large_set(void) {
char root[] = "/tmp/lardon3d-consol-large-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "large.pgm") &&
write_large_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "LargeSet"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {4096, 8, 12};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 4096;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED,
&snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params,
orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params,
sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
CHECK(orb_set.feature_count > 0 && sift_set.feature_count > 0);
struct timespec t0, t1;
clock_gettime(CLOCK_MONOTONIC, &t0);
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id,
sift_set.feature_set_id, &cp,
&pub) == LARDON3D_PROJECT_DB_OK);
clock_gettime(CLOCK_MONOTONIC, &t1);
double elapsed = (t1.tv_sec - t0.tv_sec) +
(t1.tv_nsec - t0.tv_nsec) / 1e9;
CHECK(pub.group_count > 0);
CHECK(elapsed < 10.0);
Lardon3DProjectDbFeatureSupportGroup groups[256];
uint32_t listed = 0;
uint64_t after = 0;
do {
size_t cnt = 0;
CHECK(lardon3d_project_db_list_feature_support_groups(
state.project_db, pub.feature_support_set_id,
after, groups, 256, &cnt) ==
LARDON3D_PROJECT_DB_OK);
if (cnt == 0) break;
for (size_t i = 0; i < cnt; ++i) {
CHECK(isfinite(groups[i].x) && isfinite(groups[i].y));
CHECK(groups[i].support_count >= 1 &&
groups[i].support_count <= 2);
after = groups[i].feature_support_group_id;
}
listed += (uint32_t)cnt;
} while (listed < pub.group_count);
fprintf(stderr,
" PASS test_large_set (%u ORB, %u SIFT, "
"%u groups, %.3fs)\n",
orb_set.feature_count, sift_set.feature_count,
pub.group_count, elapsed);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
return true;
}
static bool test_idempotent(void) {
char root[] = "/tmp/lardon3d-consol-idem-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "Idempotent"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED,
&snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params,
orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params,
sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub1, pub2;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id,
sift_set.feature_set_id, &cp,
&pub1) == LARDON3D_PROJECT_DB_OK);
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id,
sift_set.feature_set_id, &cp,
&pub2) == LARDON3D_PROJECT_DB_OK);
CHECK(pub1.feature_support_set_id ==
pub2.feature_support_set_id);
CHECK(pub1.group_count == pub2.group_count);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_idempotent\n");
return true;
}
static bool test_concurrent_identical(void) {
char root[] = "/tmp/lardon3d-consol-conc-id-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "ConcIdentical"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED,
&snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params,
orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params,
sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
ConsolidationCtx ctx[2] = {
{.state = &state,
.orb_id = orb_set.feature_set_id,
.sift_id = sift_set.feature_set_id,
.params = cp},
{.state = &state,
.orb_id = orb_set.feature_set_id,
.sift_id = sift_set.feature_set_id,
.params = cp}};
pthread_t threads[2];
CHECK(pthread_create(&threads[0], NULL, consolidate_thread,
&ctx[0]) == 0 &&
pthread_create(&threads[1], NULL, consolidate_thread,
&ctx[1]) == 0 &&
pthread_join(threads[0], NULL) == 0 &&
pthread_join(threads[1], NULL) == 0);
CHECK(ctx[0].result == LARDON3D_PROJECT_DB_OK);
CHECK(ctx[1].result == LARDON3D_PROJECT_DB_OK);
CHECK(ctx[0].support.feature_support_set_id ==
ctx[1].support.feature_support_set_id);
CHECK(ctx[0].support.group_count ==
ctx[1].support.group_count);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_concurrent_identical\n");
return true;
}
static bool test_concurrent_different(void) {
char root[] = "/tmp/lardon3d-consol-conc-diff-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "ConcDifferent"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params1 =
lardon3d_sift_precision_classic_v1(false);
sift_params1.max_features = 496;
uint64_t sift_task1 = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params1,
&sift_task1));
CHECK(wait_state(state.task_queue, sift_task1, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params2 = sift_params1;
sift_params2.max_features = 497;
uint64_t sift_task2 = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params2,
&sift_task2));
CHECK(wait_state(state.task_queue, sift_task2, TASK_COMPLETED,
&snap));
unsigned char orb_fp[32], sfp1[32], sfp2[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params,
orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params1,
sfp1);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params2,
sfp2);
Lardon3DProjectDbFeatureSet orb_set, sift_set1, sift_set2;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sfp1, &sift_set1));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sfp2, &sift_set2));
CHECK(sift_set1.feature_set_id != sift_set2.feature_set_id);
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
ConsolidationCtx ctx[2] = {
{.state = &state,
.orb_id = orb_set.feature_set_id,
.sift_id = sift_set1.feature_set_id,
.params = cp},
{.state = &state,
.orb_id = orb_set.feature_set_id,
.sift_id = sift_set2.feature_set_id,
.params = cp}};
pthread_t threads[2];
CHECK(pthread_create(&threads[0], NULL, consolidate_thread,
&ctx[0]) == 0 &&
pthread_create(&threads[1], NULL, consolidate_thread,
&ctx[1]) == 0 &&
pthread_join(threads[0], NULL) == 0 &&
pthread_join(threads[1], NULL) == 0);
CHECK(ctx[0].result == LARDON3D_PROJECT_DB_OK);
CHECK(ctx[1].result == LARDON3D_PROJECT_DB_OK);
CHECK(ctx[0].support.feature_support_set_id !=
ctx[1].support.feature_support_set_id);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_concurrent_different\n");
return true;
}
static bool test_fingerprint(void) {
lardon3d_feature_consolidation_fingerprint(NULL, NULL);
Lardon3DFeatureConsolidationParameters p = {
.association_radius_pixels = 4.0};
unsigned char fp1[32];
lardon3d_feature_consolidation_fingerprint(&p, fp1);
bool non_zero = false;
for (int i = 0; i < 32; ++i) non_zero |= (fp1[i] != 0);
CHECK(non_zero);
Lardon3DFeatureConsolidationParameters q = {
.association_radius_pixels = 8.0};
unsigned char fp2[32];
lardon3d_feature_consolidation_fingerprint(&q, fp2);
CHECK(memcmp(fp1, fp2, 32) != 0);
unsigned char fp3[32];
lardon3d_feature_consolidation_fingerprint(&p, fp3);
CHECK(memcmp(fp1, fp3, 32) == 0);
fprintf(stderr, " PASS test_fingerprint\n");
return true;
}
static bool test_quality_comparison(void) {
Lardon3DProjectDbFeatureSupportGroup isolated = {
.feature_support_group_id = 10, .support_count = 1};
Lardon3DProjectDbFeatureSupportGroup confirmed = {
.feature_support_group_id = 5, .support_count = 2};
CHECK(lardon3d_feature_support_higher_quality(&confirmed,
&isolated));
CHECK(!lardon3d_feature_support_higher_quality(&isolated,
&confirmed));
Lardon3DProjectDbFeatureSupportGroup a = {
.feature_support_group_id = 3, .support_count = 2};
Lardon3DProjectDbFeatureSupportGroup b = {
.feature_support_group_id = 7, .support_count = 2};
CHECK(lardon3d_feature_support_higher_quality(&a, &b));
CHECK(!lardon3d_feature_support_higher_quality(&b, &a));
CHECK(!lardon3d_feature_support_higher_quality(NULL, &isolated));
CHECK(
!lardon3d_feature_support_higher_quality(&isolated, NULL));
fprintf(stderr, " PASS test_quality_comparison\n");
return true;
}
static bool test_pagination_exhaustive(void) {
char root[] = "/tmp/lardon3d-consol-page-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "Pagination"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED,
&snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params,
orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params,
sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id,
sift_set.feature_set_id, &cp,
&pub) == LARDON3D_PROJECT_DB_OK);
CHECK(pub.group_count > 0);
uint32_t listed = 0;
uint64_t after = 0;
do {
Lardon3DProjectDbFeatureSupportGroup g;
size_t cnt = 0;
CHECK(lardon3d_project_db_list_feature_support_groups(
state.project_db, pub.feature_support_set_id,
after, &g, 1, &cnt) == LARDON3D_PROJECT_DB_OK);
if (cnt == 0) break;
CHECK(g.feature_support_group_id > after);
after = g.feature_support_group_id;
listed += (uint32_t)cnt;
} while (listed < pub.group_count);
CHECK(listed == pub.group_count);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_pagination_exhaustive\n");
return true;
}
static bool test_stress(void) {
char root[] = "/tmp/lardon3d-consol-stress-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "Stress"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED,
&snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params,
orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params,
sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
uint32_t reference_groups = 0;
uint64_t reference_id = 0;
for (int i = 0; i < 10; ++i) {
Lardon3DProjectDbFeatureSupportSet pub;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id,
sift_set.feature_set_id, &cp,
&pub) == LARDON3D_PROJECT_DB_OK);
if (i == 0) {
reference_groups = pub.group_count;
reference_id = pub.feature_support_set_id;
} else {
CHECK(pub.feature_support_set_id == reference_id);
CHECK(pub.group_count == reference_groups);
}
}
fprintf(stderr,
" PASS test_stress (10 iterations, %u groups)\n",
reference_groups);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
return true;
}
static bool test_db_first_equals_second(void) {
char root[] = "/tmp/lardon3d-consol-db-eq-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "DBEqual"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
unsigned char fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params, fp);
Lardon3DProjectDbFeatureSet set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
fp, &set));
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
CHECK(lardon3d_consolidate_orb_sift(
&state, set.feature_set_id, set.feature_set_id,
&cp, &pub) == LARDON3D_PROJECT_DB_INVALID_ARGUMENT);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_db_first_equals_second\n");
return true;
}
static bool test_radius_min_max_work(void) {
char root[] = "/tmp/lardon3d-consol-rad-mm-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "RadiusMinMax"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED,
&snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params,
orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params,
sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
Lardon3DFeatureConsolidationParameters cp_min = {
.association_radius_pixels = 0.5};
Lardon3DProjectDbFeatureSupportSet pub_min;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id,
sift_set.feature_set_id, &cp_min,
&pub_min) == LARDON3D_PROJECT_DB_OK);
Lardon3DFeatureConsolidationParameters cp_max = {
.association_radius_pixels = 64.0};
Lardon3DProjectDbFeatureSupportSet pub_max;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id,
sift_set.feature_set_id, &cp_max,
&pub_max) == LARDON3D_PROJECT_DB_OK);
CHECK(pub_min.feature_support_set_id !=
pub_max.feature_support_set_id);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_radius_min_max_work\n");
return true;
}
static bool test_support_count_orb_only_indices(void) {
char root[] = "/tmp/lardon3d-consol-sc-idx-XXXXXX";
CHECK(mkdtemp(root) &&
setenv("LARDON3D_PROJECTS_ROOT", root, 1) == 0);
char source[PATH_MAX];
CHECK(join_path(source, root, "texture.pgm") && write_pgm(source));
Lardon3DAppState state;
lardon3d_app_state_init(&state);
CHECK(runtime(&state) &&
lardon3d_project_create(&state, "SCIdx"));
Lardon3DProjectDbScanSet scanset;
CHECK(lardon3d_image_catalog_create_scanset(&state, "A", &scanset));
Lardon3DProjectDbImage image;
Lardon3DProjectDbImageAsset asset;
CHECK(lardon3d_image_catalog_import_file(
&state, scanset.scanset_id, source, 0, &image,
&asset) == LARDON3D_IMAGE_CATALOG_IMPORTED);
Lardon3DFeatureExtractorParameters orb_params = {512, 4, 10};
uint64_t orb_task = 0;
CHECK(lardon3d_project_enqueue_feature_extract(
&state, image.image_id, &orb_params, &orb_task));
Lardon3DTaskSnapshot snap;
CHECK(wait_state(state.task_queue, orb_task, TASK_COMPLETED,
&snap));
Lardon3DSiftExtractorParameters sift_params =
lardon3d_sift_precision_classic_v1(false);
sift_params.max_features = 512;
uint64_t sift_task = 0;
CHECK(lardon3d_project_enqueue_sift_extract(
&state, image.image_id, &sift_params, &sift_task));
CHECK(wait_state(state.task_queue, sift_task, TASK_COMPLETED,
&snap));
unsigned char orb_fp[32], sift_fp[32];
lardon3d_feature_extractor_parameter_fingerprint(&orb_params,
orb_fp);
lardon3d_sift_extractor_parameter_fingerprint(&sift_params,
sift_fp);
Lardon3DProjectDbFeatureSet orb_set, sift_set;
CHECK(find_feature_set(state.project_db, image.image_id, "orb",
orb_fp, &orb_set));
CHECK(find_feature_set(state.project_db, image.image_id, "sift",
sift_fp, &sift_set));
CHECK(orb_set.feature_count > 0 && sift_set.feature_count > 0);
Lardon3DFeatureConsolidationParameters cp =
lardon3d_feature_consolidation_v1();
Lardon3DProjectDbFeatureSupportSet pub;
CHECK(lardon3d_consolidate_orb_sift(
&state, orb_set.feature_set_id,
sift_set.feature_set_id, &cp,
&pub) == LARDON3D_PROJECT_DB_OK);
CHECK(pub.group_count > 0);
Lardon3DProjectDbFeatureSupportGroup groups[256];
uint32_t listed = 0;
uint64_t after = 0;
do {
size_t cnt = 0;
CHECK(lardon3d_project_db_list_feature_support_groups(
state.project_db, pub.feature_support_set_id,
after, groups, 256, &cnt) ==
LARDON3D_PROJECT_DB_OK);
if (cnt == 0) break;
for (size_t i = 0; i < cnt; ++i) {
CHECK(groups[i].support_count == 1 ||
groups[i].support_count == 2);
CHECK(groups[i].first_feature_index <
(groups[i].first_member_from_second_set
? sift_set.feature_count
: orb_set.feature_count));
if (groups[i].has_second_feature) {
CHECK(groups[i].second_feature_index <
(groups[i].first_member_from_second_set
? orb_set.feature_count
: sift_set.feature_count));
}
after = groups[i].feature_support_group_id;
}
listed += (uint32_t)cnt;
} while (listed < pub.group_count);
CHECK(listed == pub.group_count);
lardon3d_task_queue_destroy(state.task_queue);
state.task_queue = NULL;
lardon3d_project_close(&state);
lardon3d_resource_governor_destroy(state.resource_governor);
CHECK(remove_tree(root));
fprintf(stderr, " PASS test_support_count_orb_only_indices\n");
return true;
}
/* -- Main -- */
typedef bool (*test_fn)(void);
typedef struct {
const char *name;
test_fn fn;
} TestEntry;
int main(void) {
static const TestEntry tests[] = {
{"zero_features_both_empty", test_zero_features_both_empty},
{"zero_orb_only_sift", test_zero_orb_only_sift},
{"zero_sift_only_orb", test_zero_sift_only_orb},
{"radius_boundaries", test_radius_boundaries},
{"different_radius_different_result",
test_different_radius_different_result},
{"support_count_values", test_support_count_values},
{"mismatch_different_image",
test_mismatch_different_image},
{"mismatch_wrong_extractor",
test_mismatch_wrong_extractor},
{"large_set", test_large_set},
{"idempotent", test_idempotent},
{"concurrent_identical", test_concurrent_identical},
{"concurrent_different", test_concurrent_different},
{"fingerprint", test_fingerprint},
{"quality_comparison", test_quality_comparison},
{"pagination_exhaustive", test_pagination_exhaustive},
{"stress", test_stress},
{"db_first_equals_second",
test_db_first_equals_second},
{"radius_min_max_work", test_radius_min_max_work},
{"support_count_orb_only_indices",
test_support_count_orb_only_indices},
};
size_t pass = 0, fail = 0;
size_t total = sizeof(tests) / sizeof(tests[0]);
for (size_t i = 0; i < total; ++i) {
fprintf(stderr, "[%zu/%zu] %s ... ", i + 1, total,
tests[i].name);
if (tests[i].fn()) {
++pass;
} else {
++fail;
fprintf(stderr, "FAILED\n");
}
}
fprintf(stderr,
"\n=== Results: %zu passed, %zu failed out of %zu "
"===\n",
pass, fail, total);
return fail ? 1 : 0;
}