calibration: freeze tooling v1
This commit is contained in:
parent
591059f396
commit
9006e8ba15
6 changed files with 559 additions and 0 deletions
|
|
@ -145,4 +145,32 @@ advances the selected-execution cursor itself, and retains its published `image_
|
|||
generic Task progress can become durable. Its reservation owns one CPU thread, one I/O slot and a
|
||||
conservative 2 GiB working allowance for the bounded 40 MP decoder and publication buffers only for
|
||||
the callback lifetime; this operational admission bound is not a scientific Capture-count limit.
|
||||
|
||||
## Calibration Tooling v1
|
||||
|
||||
**PASS / FROZEN.** `calibration_tooling.h` is the bounded production bridge
|
||||
between a completed external `CALIBRATION_SCIENCE_V1` evidence bundle and this
|
||||
importer. It does not solve calibration, parse an unbounded user document, own
|
||||
an acquisition session, or add a persistent schema. The caller supplies a
|
||||
borrowed manifest bounded to 4,096 views and 4,096 selected image bindings,
|
||||
with hashes for the target, optical state and four required evidence artifacts.
|
||||
It declares and checks the frozen ChArUco family, `9 x 7` geometry,
|
||||
`DICT_5X5_100`, 30.000 mm squares, 21.000 mm markers, 270.000 x 210.000 mm
|
||||
active area and at least a 30.000 mm white border; the target hash binds the
|
||||
corresponding immutable physical-evidence record.
|
||||
Each view records an accepted/rejected decision and rejected views retain a
|
||||
nonzero rejection reason; accepted statistics alone are evaluated. Each entry
|
||||
carries the same optical-state manifest hash and remains in the exact selected
|
||||
item order required by the importer (it is not reordered by image id).
|
||||
The validator applies every hard Science v1 acceptance rule before allocating
|
||||
or calling Project DB. The producer writes the exact existing `L3DCALB1` v1
|
||||
little-endian record into caller-owned storage (at most 600,000 bytes), hashes
|
||||
it deterministically, and invokes only
|
||||
`lardon3d_calibration_bootstrap_import(...)`.
|
||||
|
||||
Invalid evidence therefore creates no calibration row and never reaches
|
||||
`READY`. A valid exact retry reuses the frozen importer’s immutable
|
||||
calibrations, scope and selected-execution attachment. Tooling stops at
|
||||
`READY`; it never creates a Sparse SfM Task, and it cannot retro-calibrate the
|
||||
historical S21 campaign.
|
||||
A higher-level selected-execution coordinator remains separate scope.
|
||||
|
|
|
|||
|
|
@ -147,6 +147,12 @@ provenance requis pour les **futures** campagnes connues-calibrées. Il ne
|
|||
réhabilite aucune campagne historique : S21 Engine Bay reste définitivement
|
||||
non rétro-calibrable. Voir [Calibration Science v1](../architecture/calibration_science_v1.md).
|
||||
|
||||
`CALIBRATION_TOOLING_V1=PASS/FROZEN` ajoute le pont opérationnel borné entre
|
||||
un bundle d'évidence Science v1 déjà acquis et l'importeur immuable `L3DCALB1`
|
||||
v1. Il valide les HARD REJECTS, produit l'artefact déterministe et s'arrête à
|
||||
la transition `CALIBRATION → READY`; il ne résout aucune calibration, ne lance
|
||||
pas Sparse SfM et ne rétro-calibre pas S21.
|
||||
|
||||
## PHOTO QUALITY TRIAGE / ACQUISITION SELECTION — PASS / FROZEN
|
||||
|
||||
L'étape qualité canonique implémentée se place après la découverte bornée, les
|
||||
|
|
|
|||
141
include/lardon3d/calibration_tooling.h
Normal file
141
include/lardon3d/calibration_tooling.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#ifndef LARDON3D_CALIBRATION_TOOLING_H
|
||||
#define LARDON3D_CALIBRATION_TOOLING_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <lardon3d/calibration_bootstrap.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
LARDON3D_CALIBRATION_TOOLING_VERSION = 1,
|
||||
LARDON3D_CALIBRATION_TOOLING_MAX_VIEWS = 4096,
|
||||
LARDON3D_CALIBRATION_TOOLING_MAX_COORDINATE_CHECKS = 81920,
|
||||
LARDON3D_CALIBRATION_TOOLING_TARGET_MEASUREMENTS = 10,
|
||||
LARDON3D_CALIBRATION_TOOLING_VALIDATION_FLAGS = 15,
|
||||
LARDON3D_CALIBRATION_TOOLING_TARGET_CHARUCO_9X7_DICT_5X5_100 = 1,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LARDON3D_CALIBRATION_TOOLING_OK = 0,
|
||||
LARDON3D_CALIBRATION_TOOLING_INVALID_ARGUMENT,
|
||||
LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED,
|
||||
LARDON3D_CALIBRATION_TOOLING_CAPACITY,
|
||||
LARDON3D_CALIBRATION_TOOLING_ENCODING_ERROR,
|
||||
LARDON3D_CALIBRATION_TOOLING_IMPORT_ERROR,
|
||||
} Lardon3DCalibrationToolingResult;
|
||||
|
||||
/* One solver-reported view. `quadrant` is 0..3 for frame quadrants and 4 for
|
||||
* the centre. `distance_band` is the declared near/mid/far band 0..2.
|
||||
* Rejected views retain their source identity and a nonzero rejection reason;
|
||||
* only accepted views contribute to the frozen acceptance statistics. The
|
||||
* manifest is caller-owned and borrowed only during validation/production. */
|
||||
typedef struct {
|
||||
unsigned char source_sha256[32];
|
||||
uint32_t accepted;
|
||||
uint32_t rejection_reason;
|
||||
uint32_t holdout;
|
||||
uint32_t quadrant;
|
||||
uint32_t distance_band;
|
||||
uint32_t orientation_degrees;
|
||||
uint32_t target_corner_quadrant_mask;
|
||||
uint32_t corner_count;
|
||||
uint32_t residual_count;
|
||||
uint32_t high_residual_count;
|
||||
double target_occupancy;
|
||||
double normal_angle_degrees;
|
||||
double distance_metres;
|
||||
double corner_rms_px;
|
||||
double clipped_fraction;
|
||||
double reprojection_rmse_px;
|
||||
double maximum_residual_px;
|
||||
} Lardon3DCalibrationToolingView;
|
||||
|
||||
/* Every selected image has exactly one artifact entry in selected-item order.
|
||||
* `fit_parameters` are the deterministic 80% fit result used to verify `maximum_parameter_delta`; the
|
||||
* published parameters are the complete-set result. */
|
||||
typedef struct {
|
||||
uint64_t image_id;
|
||||
unsigned char representation_sha256[32];
|
||||
unsigned char optical_state_sha256[32];
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
double fx, fy, cx, cy, k1, k2, p1, p2;
|
||||
double fit_fx, fit_fy, fit_cx, fit_cy, fit_k1, fit_k2, fit_p1, fit_p2;
|
||||
double repeated_parameters[3][8];
|
||||
uint32_t support_images;
|
||||
uint32_t support_observations;
|
||||
double reprojection_rmse_px;
|
||||
double maximum_parameter_delta;
|
||||
uint32_t validation_flags;
|
||||
} Lardon3DCalibrationToolingEntry;
|
||||
|
||||
typedef struct {
|
||||
unsigned char source_sha256[32];
|
||||
uint32_t orientation_degrees;
|
||||
double dx_px;
|
||||
double dy_px;
|
||||
} Lardon3DCalibrationToolingCoordinateCheck;
|
||||
|
||||
/* This is an operational, bounded view of a completed Science v1 bundle. WHY:
|
||||
* the solver remains external, so this API validates its immutable evidence
|
||||
* rather than importing a solver-private format. CONTRACT: all pointers are
|
||||
* borrowed; each digest is SHA-256; no field is persisted by this API except
|
||||
* through the frozen bootstrap importer. INVARIANT: entries are in selected
|
||||
* item order and never include Tracks, poses, or reconstruction results. */
|
||||
typedef struct {
|
||||
unsigned char target_sha256[32];
|
||||
unsigned char optical_state_sha256[32];
|
||||
unsigned char solver_executable_sha256[32];
|
||||
unsigned char solver_configuration_sha256[32];
|
||||
unsigned char initialization_evidence_sha256[32];
|
||||
unsigned char validation_evidence_sha256[32];
|
||||
uint32_t target_family;
|
||||
uint32_t target_squares_x;
|
||||
uint32_t target_squares_y;
|
||||
double target_square_length_mm;
|
||||
double target_marker_length_mm;
|
||||
double target_active_width_mm;
|
||||
double target_active_height_mm;
|
||||
double target_white_border_mm;
|
||||
double target_measurements_mm[LARDON3D_CALIBRATION_TOOLING_TARGET_MEASUREMENTS];
|
||||
double measurement_resolution_mm;
|
||||
double target_flatness_mm;
|
||||
double holdout_rmse_px;
|
||||
double holdout_maximum_residual_px;
|
||||
uint32_t extra_distortion_coefficient_count;
|
||||
const Lardon3DCalibrationToolingView *views;
|
||||
size_t view_count;
|
||||
const Lardon3DCalibrationToolingEntry *entries;
|
||||
size_t entry_count;
|
||||
const Lardon3DCalibrationToolingCoordinateCheck *coordinate_checks;
|
||||
size_t coordinate_check_count;
|
||||
} Lardon3DCalibrationToolingEvidence;
|
||||
|
||||
/* Validate all CALIBRATION_SCIENCE_V1 hard rejects. No allocations, DB access,
|
||||
* solver execution, or persistent writes occur. */
|
||||
Lardon3DCalibrationToolingResult lardon3d_calibration_tooling_validate(
|
||||
const Lardon3DCalibrationToolingEvidence *evidence);
|
||||
|
||||
/* Encode exactly L3DCALB1 v1 into caller storage and return its SHA-256. The
|
||||
* output is deterministic for identical evidence. `written` may be NULL. */
|
||||
Lardon3DCalibrationToolingResult lardon3d_calibration_tooling_produce(
|
||||
const Lardon3DCalibrationToolingEvidence *evidence, unsigned char *artifact,
|
||||
size_t artifact_capacity, size_t *written, unsigned char artifact_sha256[32]);
|
||||
|
||||
/* Validate, produce, then invoke only the frozen production importer. A failed
|
||||
* validation/encoding never reaches the DB. Import semantics, including its
|
||||
* permitted immutable-row recovery behavior, remain owned by that importer. */
|
||||
Lardon3DCalibrationToolingResult lardon3d_calibration_tooling_import(
|
||||
Lardon3DProjectDb *database, uint64_t execution_id,
|
||||
const Lardon3DCalibrationToolingEvidence *evidence, unsigned char *artifact,
|
||||
size_t artifact_capacity, size_t *written, Lardon3DCalibrationBootstrapOutput *output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
18
meson.build
18
meson.build
|
|
@ -11,6 +11,8 @@ project(
|
|||
],
|
||||
)
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
add_project_arguments(
|
||||
'-D_POSIX_C_SOURCE=200809L',
|
||||
'-Wpedantic',
|
||||
|
|
@ -177,6 +179,7 @@ lardon3d_app = executable(
|
|||
'src/project_db.c', 'src/project_db_sparse_sfm.c',
|
||||
'src/optical_profiles.c',
|
||||
'src/calibration_bootstrap.c',
|
||||
'src/calibration_tooling.c',
|
||||
'src/sparse_sfm_geometry.cpp',
|
||||
'src/sparse_sfm_incremental.cpp',
|
||||
'src/sparse_sfm_bundle_adjustment.cpp',
|
||||
|
|
@ -877,6 +880,21 @@ calibration_bootstrap_test = executable(
|
|||
|
||||
test('calibration-bootstrap', calibration_bootstrap_test, timeout: 30)
|
||||
|
||||
calibration_tooling_test = executable(
|
||||
'test-calibration-tooling',
|
||||
sources: [
|
||||
'tests/test_calibration_tooling.c',
|
||||
'src/calibration_tooling.c', 'src/calibration_bootstrap.c',
|
||||
'src/project_db.c', 'src/project_db_sparse_sfm.c',
|
||||
'src/task.c', 'src/resource_governor.c', 'src/resource_snapshot.c',
|
||||
],
|
||||
c_args: ['-DLARDON3D_PROJECT_DB_TESTING'],
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: [threads, sqlite3, openssl, cc.find_library('m')],
|
||||
)
|
||||
|
||||
test('calibration-tooling', calibration_tooling_test, timeout: 30)
|
||||
|
||||
optical_profiles_test = executable(
|
||||
'test-optical-profiles',
|
||||
sources: [
|
||||
|
|
|
|||
234
src/calibration_tooling.c
Normal file
234
src/calibration_tooling.c
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
#include <lardon3d/calibration_tooling.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
enum { kHeaderSize = 152, kEntrySize = 140, kMinimumViews = 40, kMinimumCorners = 1600 };
|
||||
|
||||
static bool nonzero(const unsigned char value[32]) {
|
||||
unsigned char any = 0;
|
||||
for (size_t i = 0; i < 32; ++i) any |= value[i];
|
||||
return any != 0;
|
||||
}
|
||||
static bool finite_value(double value) { return isfinite(value); }
|
||||
static void put_u32(unsigned char *p, uint32_t value) {
|
||||
for (size_t i = 0; i < 4; ++i) p[i] = (unsigned char)(value >> (8u * i));
|
||||
}
|
||||
static void put_u64(unsigned char *p, uint64_t value) {
|
||||
for (size_t i = 0; i < 8; ++i) p[i] = (unsigned char)(value >> (8u * i));
|
||||
}
|
||||
static void put_f64(unsigned char *p, double value) {
|
||||
uint64_t bits = 0; memcpy(&bits, &value, sizeof(bits)); put_u64(p, bits);
|
||||
}
|
||||
static bool digest(const unsigned char *p, size_t n, unsigned char out[32]) {
|
||||
unsigned int length = 0;
|
||||
return EVP_Digest(p, n, out, &length, EVP_sha256(), NULL) == 1 && length == 32;
|
||||
}
|
||||
static bool parameters_valid(const Lardon3DCalibrationToolingEntry *v, bool fit) {
|
||||
const double *p = fit ? &v->fit_fx : &v->fx;
|
||||
return p[0] > 0.0 && p[1] > 0.0 && p[2] >= 0.0 && p[3] >= 0.0 &&
|
||||
p[2] < (double)v->width && p[3] < (double)v->height &&
|
||||
finite_value(p[0]) && finite_value(p[1]) && finite_value(p[2]) && finite_value(p[3]) &&
|
||||
finite_value(p[4]) && finite_value(p[5]) && finite_value(p[6]) && finite_value(p[7]);
|
||||
}
|
||||
static int angle_class(double degrees) {
|
||||
if (degrees < 20.0 || degrees > 60.0) return -1;
|
||||
return degrees <= 35.0 ? 0 : (degrees <= 50.0 ? 1 : 2);
|
||||
}
|
||||
static unsigned int popcount4(uint32_t value) {
|
||||
unsigned int count = 0;
|
||||
for (unsigned int bit = 0; bit < 4; ++bit) count += (value >> bit) & 1u;
|
||||
return count;
|
||||
}
|
||||
static bool projected_delta_ok(const Lardon3DCalibrationToolingEntry *v) {
|
||||
static const double rays[5][2] = {{0, 0}, {-0.7, -0.7}, {0.7, -0.7},
|
||||
{-0.7, 0.7}, {0.7, 0.7}};
|
||||
const double *a = &v->fx, *b = &v->fit_fx;
|
||||
double maximum = 0.0;
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
double x = rays[i][0], y = rays[i][1], r2 = x*x + y*y;
|
||||
double ax = x*(1+a[4]*r2+a[5]*r2*r2)+2*a[6]*x*y+a[7]*(r2+2*x*x);
|
||||
double ay = y*(1+a[4]*r2+a[5]*r2*r2)+a[6]*(r2+2*y*y)+2*a[7]*x*y;
|
||||
double bx = x*(1+b[4]*r2+b[5]*r2*r2)+2*b[6]*x*y+b[7]*(r2+2*x*x);
|
||||
double by = y*(1+b[4]*r2+b[5]*r2*r2)+b[6]*(r2+2*y*y)+2*b[7]*x*y;
|
||||
double delta = hypot(a[0]*ax+a[2] - (b[0]*bx+b[2]),
|
||||
a[1]*ay+a[3] - (b[1]*by+b[3]));
|
||||
if (!finite_value(delta)) return false;
|
||||
if (delta > maximum) maximum = delta;
|
||||
}
|
||||
return finite_value(v->maximum_parameter_delta) &&
|
||||
fabs(v->maximum_parameter_delta - maximum) <= 1e-12 && maximum <= 0.10;
|
||||
}
|
||||
|
||||
Lardon3DCalibrationToolingResult lardon3d_calibration_tooling_validate(
|
||||
const Lardon3DCalibrationToolingEvidence *e) {
|
||||
if (!e || !e->views || !e->entries || !e->coordinate_checks || e->view_count > LARDON3D_CALIBRATION_TOOLING_MAX_VIEWS ||
|
||||
e->entry_count == 0 || e->entry_count > 4096 || e->coordinate_check_count > LARDON3D_CALIBRATION_TOOLING_MAX_COORDINATE_CHECKS)
|
||||
return LARDON3D_CALIBRATION_TOOLING_INVALID_ARGUMENT;
|
||||
if (!nonzero(e->target_sha256) || !nonzero(e->optical_state_sha256) ||
|
||||
!nonzero(e->solver_executable_sha256) || !nonzero(e->solver_configuration_sha256) ||
|
||||
!nonzero(e->initialization_evidence_sha256) || !nonzero(e->validation_evidence_sha256) ||
|
||||
e->target_family != LARDON3D_CALIBRATION_TOOLING_TARGET_CHARUCO_9X7_DICT_5X5_100 ||
|
||||
e->target_squares_x != 9 || e->target_squares_y != 7 ||
|
||||
!finite_value(e->target_square_length_mm) || e->target_square_length_mm != 30.0 ||
|
||||
!finite_value(e->target_marker_length_mm) || e->target_marker_length_mm != 21.0 ||
|
||||
!finite_value(e->target_active_width_mm) || e->target_active_width_mm != 270.0 ||
|
||||
!finite_value(e->target_active_height_mm) || e->target_active_height_mm != 210.0 ||
|
||||
!finite_value(e->target_white_border_mm) || e->target_white_border_mm < 30.0 ||
|
||||
e->extra_distortion_coefficient_count != 0 || !finite_value(e->measurement_resolution_mm) ||
|
||||
e->measurement_resolution_mm <= 0 || e->measurement_resolution_mm > 0.1 ||
|
||||
!finite_value(e->target_flatness_mm) || e->target_flatness_mm < 0 || e->target_flatness_mm > 0.20)
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
double lo = 30.0, hi = 30.0;
|
||||
for (size_t i = 0; i < LARDON3D_CALIBRATION_TOOLING_TARGET_MEASUREMENTS; ++i) {
|
||||
if (!finite_value(e->target_measurements_mm[i]) || fabs(e->target_measurements_mm[i] - 30.0) > 0.30)
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
if (e->target_measurements_mm[i] < lo) lo = e->target_measurements_mm[i];
|
||||
if (e->target_measurements_mm[i] > hi) hi = e->target_measurements_mm[i];
|
||||
}
|
||||
if (hi - lo > 0.20 || !finite_value(e->holdout_rmse_px) || !finite_value(e->holdout_maximum_residual_px) ||
|
||||
e->holdout_rmse_px < 0 || e->holdout_maximum_residual_px < 0 ||
|
||||
e->holdout_rmse_px > 0.75 || e->holdout_maximum_residual_px > 1.50)
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
uint64_t corners = 0, residuals = 0, high = 0;
|
||||
size_t accepted_views = 0;
|
||||
uint32_t quadrant[5] = {0}, distance[3] = {0}, angles[3] = {0}, inclined = 0;
|
||||
size_t fit_views = 0, holdout_views = 0, fit_quadrant[4] = {0};
|
||||
double min_distance = INFINITY, max_distance = 0.0;
|
||||
for (size_t i = 0; i < e->view_count; ++i) {
|
||||
const Lardon3DCalibrationToolingView *v = &e->views[i];
|
||||
if (!nonzero(v->source_sha256) || v->accepted > 1 || v->holdout > 1 ||
|
||||
(!v->accepted && v->rejection_reason == 0) ||
|
||||
(v->accepted && v->rejection_reason != 0))
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
if (!v->accepted) {
|
||||
if (v->holdout != 0) return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
continue;
|
||||
}
|
||||
if (v->quadrant > 4 || v->distance_band > 2 ||
|
||||
(v->orientation_degrees != 0 && v->orientation_degrees != 90 &&
|
||||
v->orientation_degrees != 180 && v->orientation_degrees != 270) ||
|
||||
popcount4(v->target_corner_quadrant_mask) < 3 ||
|
||||
v->corner_count < 16 || !finite_value(v->target_occupancy) || v->target_occupancy < .20 || v->target_occupancy > .80 ||
|
||||
!finite_value(v->normal_angle_degrees) || !finite_value(v->distance_metres) || v->distance_metres <= 0 ||
|
||||
!finite_value(v->corner_rms_px) || v->corner_rms_px < 0 || v->corner_rms_px > .25 || !finite_value(v->clipped_fraction) || v->clipped_fraction < 0 || v->clipped_fraction > .01 ||
|
||||
!finite_value(v->reprojection_rmse_px) || v->reprojection_rmse_px < 0 || v->reprojection_rmse_px > .75 ||
|
||||
!finite_value(v->maximum_residual_px) || v->maximum_residual_px < 0 || v->maximum_residual_px > 1.50)
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
if (v->high_residual_count > v->residual_count || UINT64_MAX - corners < v->corner_count || UINT64_MAX - residuals < v->residual_count || UINT64_MAX - high < v->high_residual_count)
|
||||
return LARDON3D_CALIBRATION_TOOLING_CAPACITY;
|
||||
++accepted_views;
|
||||
corners += v->corner_count; residuals += v->residual_count; high += v->high_residual_count;
|
||||
++quadrant[v->quadrant]; ++distance[v->distance_band];
|
||||
int class_index = angle_class(v->normal_angle_degrees);
|
||||
if (class_index >= 0) { ++angles[class_index]; ++inclined; }
|
||||
if (v->holdout) ++holdout_views;
|
||||
else { ++fit_views; if (v->quadrant < 4) ++fit_quadrant[v->quadrant]; }
|
||||
if (v->distance_metres < min_distance) min_distance = v->distance_metres;
|
||||
if (v->distance_metres > max_distance) max_distance = v->distance_metres;
|
||||
}
|
||||
if (accepted_views < kMinimumViews || corners < kMinimumCorners || quadrant[0] < 6 || quadrant[1] < 6 || quadrant[2] < 6 || quadrant[3] < 6 || quadrant[4] < 8 ||
|
||||
distance[0] < 8 || distance[1] < 8 || distance[2] < 8 || max_distance / min_distance < 1.5 ||
|
||||
inclined < 24 || angles[0] < 6 || angles[1] < 6 || angles[2] < 6 || fit_views < 32 || holdout_views < 8 ||
|
||||
fit_quadrant[0] < 4 || fit_quadrant[1] < 4 || fit_quadrant[2] < 4 || fit_quadrant[3] < 4 ||
|
||||
residuals == 0 || high * 100 > residuals)
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
for (size_t i = 0; i < e->view_count; ++i) {
|
||||
const Lardon3DCalibrationToolingView *v = &e->views[i];
|
||||
if (!v->accepted) continue;
|
||||
size_t rank = 0;
|
||||
int class_index = angle_class(v->normal_angle_degrees);
|
||||
for (size_t other = 0; other < e->view_count; ++other) {
|
||||
const Lardon3DCalibrationToolingView *candidate = &e->views[other];
|
||||
if (!candidate->accepted || candidate->quadrant != v->quadrant ||
|
||||
candidate->distance_band != v->distance_band ||
|
||||
angle_class(candidate->normal_angle_degrees) != class_index) continue;
|
||||
int compare = memcmp(candidate->source_sha256, v->source_sha256, 32);
|
||||
if (compare == 0 && other != i) return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
if (compare < 0) ++rank;
|
||||
}
|
||||
if (v->holdout != (rank % 5 == 4)) return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
}
|
||||
for (size_t i = 0; i < e->coordinate_check_count; ++i) {
|
||||
const Lardon3DCalibrationToolingCoordinateCheck *c = &e->coordinate_checks[i];
|
||||
if (!nonzero(c->source_sha256) || (c->orientation_degrees != 0 && c->orientation_degrees != 90 &&
|
||||
c->orientation_degrees != 180 && c->orientation_degrees != 270) ||
|
||||
!finite_value(c->dx_px) || !finite_value(c->dy_px) || fabs(c->dx_px) > .01 || fabs(c->dy_px) > .01)
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
}
|
||||
for (size_t view_index = 0; view_index < e->view_count; ++view_index) {
|
||||
const Lardon3DCalibrationToolingView *v = &e->views[view_index];
|
||||
if (!v->accepted) continue;
|
||||
size_t matches = 0;
|
||||
for (size_t check_index = 0; check_index < e->coordinate_check_count; ++check_index) {
|
||||
const Lardon3DCalibrationToolingCoordinateCheck *c = &e->coordinate_checks[check_index];
|
||||
if (memcmp(c->source_sha256, v->source_sha256, 32) == 0) {
|
||||
if (c->orientation_degrees != v->orientation_degrees)
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
++matches;
|
||||
}
|
||||
}
|
||||
if (matches < 20) return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
}
|
||||
for (size_t i = 0; i < e->entry_count; ++i) {
|
||||
const Lardon3DCalibrationToolingEntry *v = &e->entries[i];
|
||||
if (!v->image_id || !nonzero(v->representation_sha256) ||
|
||||
memcmp(v->optical_state_sha256, e->optical_state_sha256, 32) != 0 ||
|
||||
!v->width || !v->height ||
|
||||
!parameters_valid(v, false) || !parameters_valid(v, true) || !v->support_images || !v->support_observations ||
|
||||
!finite_value(v->reprojection_rmse_px) || v->reprojection_rmse_px < 0 || v->reprojection_rmse_px > .50 ||
|
||||
v->validation_flags != LARDON3D_CALIBRATION_TOOLING_VALIDATION_FLAGS || !projected_delta_ok(v))
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
for (size_t previous = 0; previous < i; ++previous)
|
||||
if (v->image_id == e->entries[previous].image_id)
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
const double published[8] = {v->fx,v->fy,v->cx,v->cy,v->k1,v->k2,v->p1,v->p2};
|
||||
for (size_t repeat = 0; repeat < 3; ++repeat)
|
||||
for (size_t parameter = 0; parameter < 8; ++parameter)
|
||||
if (!finite_value(v->repeated_parameters[repeat][parameter]) ||
|
||||
v->repeated_parameters[repeat][parameter] != published[parameter])
|
||||
return LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED;
|
||||
}
|
||||
return LARDON3D_CALIBRATION_TOOLING_OK;
|
||||
}
|
||||
|
||||
Lardon3DCalibrationToolingResult lardon3d_calibration_tooling_produce(
|
||||
const Lardon3DCalibrationToolingEvidence *e, unsigned char *artifact,
|
||||
size_t capacity, size_t *written, unsigned char hash[32]) {
|
||||
if (written) *written = 0;
|
||||
if (!artifact || !hash) return LARDON3D_CALIBRATION_TOOLING_INVALID_ARGUMENT;
|
||||
Lardon3DCalibrationToolingResult valid = lardon3d_calibration_tooling_validate(e);
|
||||
if (valid != LARDON3D_CALIBRATION_TOOLING_OK) return valid;
|
||||
if (e->entry_count > (SIZE_MAX - kHeaderSize) / kEntrySize) return LARDON3D_CALIBRATION_TOOLING_CAPACITY;
|
||||
size_t size = kHeaderSize + e->entry_count * kEntrySize;
|
||||
if (size > LARDON3D_CALIBRATION_BOOTSTRAP_MAX_BYTES || capacity < size) return LARDON3D_CALIBRATION_TOOLING_CAPACITY;
|
||||
size_t at = 0; memcpy(artifact + at, "L3DCALB1", 8); at += 8;
|
||||
put_u32(artifact + at, 1); at += 4; put_u32(artifact + at, 1); at += 4; put_u32(artifact + at, 1); at += 4; put_u32(artifact + at, (uint32_t)e->entry_count); at += 4;
|
||||
memcpy(artifact + at, e->solver_executable_sha256, 32); at += 32; memcpy(artifact + at, e->solver_configuration_sha256, 32); at += 32;
|
||||
memcpy(artifact + at, e->initialization_evidence_sha256, 32); at += 32; memcpy(artifact + at, e->validation_evidence_sha256, 32); at += 32;
|
||||
for (size_t i = 0; i < e->entry_count; ++i) {
|
||||
const Lardon3DCalibrationToolingEntry *v = &e->entries[i];
|
||||
put_u64(artifact + at, v->image_id); at += 8; memcpy(artifact + at, v->representation_sha256, 32); at += 32;
|
||||
put_u32(artifact + at, v->width); at += 4; put_u32(artifact + at, v->height); at += 4;
|
||||
const double values[8] = {v->fx,v->fy,v->cx,v->cy,v->k1,v->k2,v->p1,v->p2};
|
||||
for (size_t j = 0; j < 8; ++j) { put_f64(artifact + at, values[j]); at += 8; }
|
||||
put_u32(artifact + at, v->support_images); at += 4; put_u32(artifact + at, v->support_observations); at += 4;
|
||||
put_f64(artifact + at, v->reprojection_rmse_px); at += 8; put_f64(artifact + at, v->maximum_parameter_delta); at += 8;
|
||||
put_u32(artifact + at, v->validation_flags); at += 4;
|
||||
}
|
||||
if (at != size || !digest(artifact, size, hash)) return LARDON3D_CALIBRATION_TOOLING_ENCODING_ERROR;
|
||||
if (written) *written = size;
|
||||
return LARDON3D_CALIBRATION_TOOLING_OK;
|
||||
}
|
||||
|
||||
Lardon3DCalibrationToolingResult lardon3d_calibration_tooling_import(
|
||||
Lardon3DProjectDb *db, uint64_t execution_id, const Lardon3DCalibrationToolingEvidence *e,
|
||||
unsigned char *artifact, size_t capacity, size_t *written, Lardon3DCalibrationBootstrapOutput *out) {
|
||||
unsigned char hash[32];
|
||||
Lardon3DCalibrationToolingResult result = lardon3d_calibration_tooling_produce(e, artifact, capacity, written, hash);
|
||||
if (result != LARDON3D_CALIBRATION_TOOLING_OK || !db || !execution_id || !out) return result == LARDON3D_CALIBRATION_TOOLING_OK ? LARDON3D_CALIBRATION_TOOLING_INVALID_ARGUMENT : result;
|
||||
return lardon3d_calibration_bootstrap_import(db, execution_id, artifact, *written, hash, out) == LARDON3D_CALIBRATION_BOOTSTRAP_OK ?
|
||||
LARDON3D_CALIBRATION_TOOLING_OK : LARDON3D_CALIBRATION_TOOLING_IMPORT_ERROR;
|
||||
}
|
||||
132
tests/test_calibration_tooling.c
Normal file
132
tests/test_calibration_tooling.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#include <sqlite3.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <lardon3d/calibration_tooling.h>
|
||||
|
||||
#define CHECK(x) do { if (!(x)) { fprintf(stderr, "tooling failure %d: %s\n", __LINE__, #x); return false; } } while (0)
|
||||
|
||||
static bool sql(const char *path, const char *text) {
|
||||
sqlite3 *db = NULL; if (sqlite3_open(path, &db) != SQLITE_OK) return false;
|
||||
int rc = sqlite3_exec(db, text, NULL, NULL, NULL); return sqlite3_close(db) == SQLITE_OK && rc == SQLITE_OK;
|
||||
}
|
||||
static bool scalar(const char *path, const char *text, int *value) {
|
||||
sqlite3 *db = NULL; sqlite3_stmt *statement = NULL;
|
||||
if (sqlite3_open(path, &db) != SQLITE_OK || sqlite3_prepare_v2(db, text, -1, &statement, NULL) != SQLITE_OK) {
|
||||
if (statement) sqlite3_finalize(statement);
|
||||
if (db) sqlite3_close(db);
|
||||
return false;
|
||||
}
|
||||
bool ok = sqlite3_step(statement) == SQLITE_ROW;
|
||||
if (ok) *value = sqlite3_column_int(statement, 0);
|
||||
return sqlite3_finalize(statement) == SQLITE_OK && sqlite3_close(db) == SQLITE_OK && ok;
|
||||
}
|
||||
static void hashes(unsigned char value[32], unsigned char seed) { memset(value, seed, 32); }
|
||||
static void params(double output[8]) { const double p[8] = {3000,3001,2000,1100,.01,-.01,.001,-.001}; memcpy(output,p,sizeof(p)); }
|
||||
|
||||
/* Synthetic only: these values model an already-completed external session and
|
||||
* never represent a physical calibration or a real project. */
|
||||
static void fixture(Lardon3DCalibrationToolingEvidence *e, Lardon3DCalibrationToolingView views[60],
|
||||
Lardon3DCalibrationToolingEntry entries[1], Lardon3DCalibrationToolingCoordinateCheck coordinates[1200]) {
|
||||
memset(e, 0, sizeof(*e)); memset(views, 0, sizeof(Lardon3DCalibrationToolingView)*60);
|
||||
memset(entries, 0, sizeof(Lardon3DCalibrationToolingEntry)); memset(coordinates, 0, sizeof(Lardon3DCalibrationToolingCoordinateCheck)*1200);
|
||||
hashes(e->target_sha256,1); hashes(e->optical_state_sha256,2); hashes(e->solver_executable_sha256,3); hashes(e->solver_configuration_sha256,4); hashes(e->initialization_evidence_sha256,5); hashes(e->validation_evidence_sha256,6);
|
||||
e->target_family=LARDON3D_CALIBRATION_TOOLING_TARGET_CHARUCO_9X7_DICT_5X5_100; e->target_squares_x=9; e->target_squares_y=7;
|
||||
e->target_square_length_mm=30; e->target_marker_length_mm=21; e->target_active_width_mm=270; e->target_active_height_mm=210; e->target_white_border_mm=30;
|
||||
for (size_t i=0;i<10;++i) e->target_measurements_mm[i]=30.0;
|
||||
e->measurement_resolution_mm=.1; e->target_flatness_mm=.1; e->holdout_rmse_px=.4; e->holdout_maximum_residual_px=.8;
|
||||
for (size_t i=0;i<60;++i) {
|
||||
static const uint32_t quadrants[10]={0,0,1,1,2,2,3,3,4,4};
|
||||
static const uint32_t distances[10]={0,1,2,0,1,2,0,1,2,0};
|
||||
static const double angles[10]={25,40,55,25,40,55,25,40,55,25};
|
||||
size_t group=i/6; hashes(views[i].source_sha256,(unsigned char)(i+20)); views[i].accepted=1; views[i].holdout=(i%6)==4; views[i].quadrant=quadrants[group];
|
||||
views[i].distance_band=distances[group]; views[i].target_corner_quadrant_mask=7; views[i].corner_count=40; views[i].residual_count=40; views[i].target_occupancy=.4;
|
||||
views[i].normal_angle_degrees=angles[group]; views[i].distance_metres=1.0+(double)distances[group]*.3;
|
||||
views[i].corner_rms_px=.1; views[i].clipped_fraction=0; views[i].reprojection_rmse_px=.4; views[i].maximum_residual_px=.8;
|
||||
}
|
||||
entries[0].image_id=1; hashes(entries[0].representation_sha256,0x11); hashes(entries[0].optical_state_sha256,2); entries[0].width=4000; entries[0].height=2250;
|
||||
double p[8]; params(p); memcpy(&entries[0].fx,p,sizeof(p)); memcpy(&entries[0].fit_fx,p,sizeof(p));
|
||||
for (size_t repeat=0;repeat<3;++repeat) memcpy(entries[0].repeated_parameters[repeat],p,sizeof(p));
|
||||
entries[0].support_images=60; entries[0].support_observations=2400; entries[0].reprojection_rmse_px=.4; entries[0].maximum_parameter_delta=0; entries[0].validation_flags=15;
|
||||
for(size_t i=0;i<1200;++i) { memcpy(coordinates[i].source_sha256,views[i/20].source_sha256,32); coordinates[i].orientation_degrees=0; coordinates[i].dx_px=.001; coordinates[i].dy_px=-.001; }
|
||||
e->views=views; e->view_count=60; e->entries=entries; e->entry_count=1; e->coordinate_checks=coordinates; e->coordinate_check_count=1200;
|
||||
}
|
||||
|
||||
static bool rejects_major_cases(void) {
|
||||
Lardon3DCalibrationToolingEvidence e; Lardon3DCalibrationToolingView v[60]; Lardon3DCalibrationToolingEntry x[1]; Lardon3DCalibrationToolingCoordinateCheck c[1200];
|
||||
fixture(&e,v,x,c); CHECK(lardon3d_calibration_tooling_validate(&e)==LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
e.view_count=39; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); e.view_count=60;
|
||||
v[0].corner_count=1; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); v[0].corner_count=40;
|
||||
for (size_t i=0;i<3;++i) v[i].quadrant=4;
|
||||
CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
for (size_t i=0;i<3;++i) v[i].quadrant=0;
|
||||
for (size_t i=0;i<9;++i) v[i*3].normal_angle_degrees=1;
|
||||
CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
for (size_t i=0;i<9;++i) v[i*3].normal_angle_degrees=25;
|
||||
for (size_t i=0;i<7;++i) v[i*3].distance_band=1;
|
||||
CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
for (size_t i=0;i<7;++i) v[i*3].distance_band=0;
|
||||
e.target_marker_length_mm=20; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); e.target_marker_length_mm=21;
|
||||
e.target_measurements_mm[0]=31; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); e.target_measurements_mm[0]=30;
|
||||
v[0].corner_rms_px=.3; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); v[0].corner_rms_px=.1;
|
||||
x[0].reprojection_rmse_px=.6; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); x[0].reprojection_rmse_px=.4;
|
||||
v[0].reprojection_rmse_px=.8; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); v[0].reprojection_rmse_px=.4;
|
||||
v[0].maximum_residual_px=2; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); v[0].maximum_residual_px=.8;
|
||||
v[0].high_residual_count=40; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); v[0].high_residual_count=0;
|
||||
e.holdout_rmse_px=.8; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); e.holdout_rmse_px=.4;
|
||||
x[0].repeated_parameters[1][0]+=1; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); x[0].repeated_parameters[1][0]-=1;
|
||||
x[0].maximum_parameter_delta=.2; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); x[0].maximum_parameter_delta=0;
|
||||
fixture(&e,v,x,c); for (size_t i=18;i<60;++i) v[i].normal_angle_degrees=0;
|
||||
CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
fixture(&e,v,x,c); v[4].holdout=0;
|
||||
CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
fixture(&e,v,x,c); v[0].corner_rms_px=-.1;
|
||||
CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
fixture(&e,v,x,c); x[0].reprojection_rmse_px=-.1;
|
||||
CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
fixture(&e,v,x,c); memset(e.solver_configuration_sha256,0,32);
|
||||
CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
fixture(&e,v,x,c);
|
||||
v[0].accepted=0; v[0].rejection_reason=7; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); v[0].accepted=1; v[0].rejection_reason=0;
|
||||
memset(e.optical_state_sha256,0,32); CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); hashes(e.optical_state_sha256,2);
|
||||
e.coordinate_check_count=1199; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); e.coordinate_check_count=1200;
|
||||
x[0].width=0; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); x[0].width=4000;
|
||||
x[0].fx=0; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); x[0].fx=3000;
|
||||
x[0].cx=4000; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK); x[0].cx=2000;
|
||||
e.extra_distortion_coefficient_count=1; CHECK(lardon3d_calibration_tooling_validate(&e)!=LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool run(void) {
|
||||
CHECK(rejects_major_cases());
|
||||
Lardon3DCalibrationToolingEvidence e; Lardon3DCalibrationToolingView views[60]; Lardon3DCalibrationToolingEntry entries[1]; Lardon3DCalibrationToolingCoordinateCheck coords[1200]; fixture(&e,views,entries,coords);
|
||||
unsigned char a[292], b[292], ha[32], hb[32]; size_t na=0, nb=0;
|
||||
CHECK(lardon3d_calibration_tooling_produce(&e,a,sizeof(a),&na,ha)==LARDON3D_CALIBRATION_TOOLING_OK);
|
||||
CHECK(lardon3d_calibration_tooling_produce(&e,b,sizeof(b),&nb,hb)==LARDON3D_CALIBRATION_TOOLING_OK && na==292 && na==nb && memcmp(a,b,na)==0 && memcmp(ha,hb,32)==0);
|
||||
CHECK(lardon3d_calibration_tooling_produce(&e,b,291,&nb,hb)==LARDON3D_CALIBRATION_TOOLING_CAPACITY);
|
||||
char dir[]="/tmp/lardon3d-calibration-tooling-XXXXXX"; CHECK(mkdtemp(dir)); char path[512]; CHECK(snprintf(path,sizeof(path),"%s/project.db",dir)>0);
|
||||
Lardon3DProjectDb *db=NULL; char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY]; CHECK(lardon3d_project_db_open(path,&db,error)==LARDON3D_PROJECT_DB_OK); lardon3d_project_db_close(db);
|
||||
CHECK(sql(path,"INSERT INTO scansets VALUES(1,'s',1,1); INSERT INTO tasks VALUES(1,'q','photo_quality.triage',1,5,5,100,1,0,0,0,0,1); INSERT INTO tasks VALUES(2,'c','acquisition_campaign.run',1,5,5,100,1,0,0,0,0,1); INSERT INTO photo_quality_triage_tasks VALUES(1,1,2,1,X'01'); INSERT INTO photo_quality_triage_results VALUES(1,1,0,1,0,1,0,100,100,100,100,1,1,0,0,1,1,0,'GOOD'); INSERT INTO acquisition_campaign_tasks VALUES(2,1,2,2,X'02'); INSERT INTO captures VALUES(1,1,1); INSERT INTO acquisition_campaign_captures VALUES(2,2,1); INSERT INTO image_assets VALUES(1,X'1111111111111111111111111111111111111111111111111111111111111111','assets/images/11/1111111111111111111111111111111111111111111111111111111111111111',1,1,1); INSERT INTO images VALUES(1,1,1,'a.jpg','/a.jpg',NULL,1); INSERT INTO capture_images VALUES(1,1);"));
|
||||
CHECK(lardon3d_project_db_open(path,&db,error)==LARDON3D_PROJECT_DB_OK); Lardon3DProjectDbSelectedExecutionItem item={.item_index=0,.quality_group_id=1,.campaign_group_id=2,.capture_id=1,.representation_source=LARDON3D_SELECTED_REPRESENTATION_SOURCE_IMAGE}; Lardon3DProjectDbSelectedExecution execution;
|
||||
CHECK(lardon3d_project_db_create_selected_execution(db,1,2,&item,1,1,&execution)==LARDON3D_PROJECT_DB_OK); CHECK(lardon3d_project_db_record_selected_representation(db,execution.execution_id,0,1,1)==LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DProjectDbSelectedExecutionItem selected; Lardon3DProjectDbImage image; Lardon3DProjectDbImageAsset asset;
|
||||
CHECK(lardon3d_project_db_load_selected_execution_item(db,execution.execution_id,0,&selected)==LARDON3D_PROJECT_DB_OK && selected.has_image && selected.image_id==1);
|
||||
CHECK(lardon3d_project_db_load_image(db,1,&image,&asset)==LARDON3D_PROJECT_DB_OK && memcmp(asset.sha256,entries[0].representation_sha256,32)==0);
|
||||
entries[0].fx=0;
|
||||
CHECK(lardon3d_calibration_tooling_import(db,execution.execution_id,&e,a,sizeof(a),&na,&(Lardon3DCalibrationBootstrapOutput){0})==LARDON3D_CALIBRATION_TOOLING_SCIENCE_REJECTED);
|
||||
entries[0].fx=3000;
|
||||
lardon3d_project_db_close(db);
|
||||
int count=0; CHECK(scalar(path,"SELECT COUNT(*) FROM sparse_calibrations",&count) && count==0);
|
||||
CHECK(scalar(path,"SELECT COUNT(*) FROM sparse_calibration_scopes",&count) && count==0);
|
||||
CHECK(lardon3d_project_db_open(path,&db,error)==LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DCalibrationBootstrapOutput output; CHECK(lardon3d_calibration_tooling_import(db,execution.execution_id,&e,a,sizeof(a),&na,&output)==LARDON3D_CALIBRATION_TOOLING_OK); uint64_t scope=output.scope.scope_id;
|
||||
CHECK(lardon3d_calibration_tooling_import(db,execution.execution_id,&e,a,sizeof(a),&na,&output)==LARDON3D_CALIBRATION_TOOLING_OK && output.scope.scope_id==scope);
|
||||
Lardon3DSparseCalibrationMember member; size_t member_count=0; uint64_t next=0;
|
||||
CHECK(lardon3d_sparse_calibration_scope_list_members(db,scope,0,&member,1,&member_count,&next)==LARDON3D_PROJECT_DB_OK && member_count==1 && next==1 && member.image_id==1);
|
||||
CHECK(lardon3d_project_db_load_selected_execution(db,execution.execution_id,&execution)==LARDON3D_PROJECT_DB_OK && execution.stage==LARDON3D_SELECTED_EXECUTION_READY && execution.calibration_scope_id==scope);
|
||||
lardon3d_project_db_close(db); CHECK(unlink(path)==0); CHECK(rmdir(dir)==0); return true;
|
||||
}
|
||||
int main(void) { return run()?EXIT_SUCCESS:EXIT_FAILURE; }
|
||||
Loading…
Reference in a new issue