feat: require measured calibration target border
This commit is contained in:
parent
b9e4309842
commit
c8447c66c4
7 changed files with 19 additions and 8 deletions
|
|
@ -59,6 +59,7 @@ Tooling continues to validate the frozen Science v1 requirements, including:
|
|||
- exact ChArUco 9 x 7 / DICT_5X5_100 target identity;
|
||||
- 30.000 mm squares and 21.000 mm markers;
|
||||
- ten physical square measurements and instrument resolution;
|
||||
- measured free white border of at least 30 mm, supplied explicitly by the session;
|
||||
- immutable target, optical-state, solver and evidence digests;
|
||||
- accepted and rejected view evidence;
|
||||
- field-region, distance and angle diversity;
|
||||
|
|
|
|||
|
|
@ -519,6 +519,8 @@ Calibration Evidence Solver v1 implements the external OpenCV 5.x evidence path
|
|||
Calibration Solver Preflight v1. It remains outside the Lardon3D runtime and Project DB and its
|
||||
deterministic synthetic CPU1 self-test is validated.
|
||||
|
||||
The solver session contract now also requires explicit measured `white_border >= 30 mm` evidence. This closes the previous gap between the physical target requirement and the future coordinator input; no default border width is inferred.
|
||||
|
||||
A bounded Tooling correction aligned planarity handling with Calibration Science v1: Science v1
|
||||
defines a categorical physical planarity attestation, not a numeric flatness threshold. Tooling
|
||||
therefore rejects invented finite `target_flatness_mm` values. `L3DCALB1` v1 and Calibration
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ User-facing TUI/control language PASS
|
|||
External SSD controller VALIDATED
|
||||
Calibration Solver Preflight v1 PASS
|
||||
Calibration Evidence Solver v1 IMPLEMENTED/VALIDATED
|
||||
Calibration solver white-border evidence PASS/FROZEN
|
||||
Calibration Tooling planarity alignment PASS/FROZEN
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ CALIBRATION_TOOLING_V1=PASS/FROZEN
|
|||
CALIBRATION_TOOLING_PLANARITY_ALIGNMENT=PASS/FROZEN
|
||||
CALIBRATION_BOOTSTRAP_V1=PASS/FROZEN
|
||||
CALIBRATION_EVIDENCE_SOLVER_V1=IMPLEMENTED/VALIDATED
|
||||
CALIBRATION_SOLVER_WHITE_BORDER_V1=PASS/FROZEN
|
||||
CALIBRATION_WORKFLOW=IN_PROGRESS
|
||||
CURRENT_CALIBRATION_NEXT=WORKFLOW_COORDINATOR
|
||||
```
|
||||
|
|
@ -22,6 +23,8 @@ A bounded corrective review established that Calibration Science v1 defines targ
|
|||
|
||||
The external `tools/calibration_evidence_solver/` implementation is present and validated by its deterministic synthetic CPU1 self-test. It remains external to the Lardon3D runtime and Project DB.
|
||||
|
||||
Its session v1 now requires an explicit measured `white_border` of at least 30 mm. No default border width may be invented by the solver or the future coordinator.
|
||||
|
||||
## CURRENT
|
||||
|
||||
Historical S21 and A6000 Engine Bay campaigns:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ Un fichier texte ASCII, sans commentaire ni espace dans les chemins, contient :
|
|||
L3DCAL_SESSION_V1
|
||||
target <target-id> <generator-sha256> DICT_5X5_100 9 7 30 21
|
||||
measurement <instrument-id> <resolution-mm> <10-real-square-mm-values>
|
||||
white_border <measured-free-white-border-mm>
|
||||
planarity PASS <planarity-evidence-sha256>
|
||||
decoder <decoder-identity> <decoder-version>
|
||||
optical_state <optical-state-sha256> <complete-state-token>
|
||||
|
|
@ -37,9 +38,10 @@ Il y a entre 1 et 4096 lignes `image`, chaque source SHA est unique, et chaque
|
|||
image a exactement une preuve pré-solve, clipping et coordinate. Les dix
|
||||
mesures réelles doivent être à 0.30 mm de 30.000 mm et leur étendue ne doit pas
|
||||
dépasser 0.20 mm; l'instrument doit annoncer une résolution de 0.1 mm ou
|
||||
meilleure. `planarity` est une attestation PASS hachée : Science v1 impose une
|
||||
planche rigide plane mais ne fixe pas de seuil numérique que l'outil pourrait
|
||||
inventer. `optical_state` est un jeton atomique complet du manifeste d'état
|
||||
meilleure. `white_border` archive la bordure blanche physique libre mesurée et
|
||||
doit être d'au moins 30 mm; aucune valeur par défaut n'est inventée.
|
||||
`planarity` est une attestation PASS hachée : Science v1 impose une planche
|
||||
rigide plane mais ne fixe pas de seuil numérique que l'outil pourrait inventer. `optical_state` est un jeton atomique complet du manifeste d'état
|
||||
optique; aucune valeur inconnue n'est acceptée par convention.
|
||||
|
||||
Les `coordinate_point` consomment exactement les `N` comparaisons annoncées.
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -50,10 +50,10 @@ constexpr int kSquaresX = 9, kSquaresY = 7;
|
|||
struct SessionEvidence {
|
||||
std::string target_id, instrument, decoder, decoder_version;
|
||||
std::array<unsigned char, 32> generator_hash{}, planarity_hash{};
|
||||
double resolution_mm = -1, planarity_pass = 0;
|
||||
double resolution_mm = -1, planarity_pass = 0, white_border_mm = -1;
|
||||
std::array<double, 10> measurements{};
|
||||
bool target = false, measurement = false, planarity = false;
|
||||
bool decoder_set = false, optical_state = false;
|
||||
bool white_border = false, decoder_set = false, optical_state = false;
|
||||
std::string optical_state_fields;
|
||||
};
|
||||
|
||||
|
|
@ -140,6 +140,7 @@ bool read_session(const std::string& path,std::vector<View>* views,std::array<un
|
|||
if(!(s>>m)||!finite(m)){*why="measurement values";return false;}
|
||||
}
|
||||
evidence->measurement=true;
|
||||
} else if(tag=="white_border") { if(evidence->white_border || !(s>>evidence->white_border_mm) || !finite(evidence->white_border_mm) || evidence->white_border_mm < 30.0) {*why="white border evidence";return false;} evidence->white_border=true;
|
||||
} else if(tag=="planarity") { std::string result,h; if(evidence->planarity || !(s>>result>>h) || !hex(h,&evidence->planarity_hash) || (result!="PASS"&&result!="FAIL")) {*why="planarity evidence";return false;} evidence->planarity=true; evidence->planarity_pass=result=="PASS";
|
||||
} else if(tag=="decoder") { if(evidence->decoder_set || !(s>>evidence->decoder>>evidence->decoder_version) || evidence->decoder.size()>128 || evidence->decoder_version.size()>128 || !json_token(evidence->decoder) || !json_token(evidence->decoder_version)) {*why="decoder identity/version";return false;} evidence->decoder_set=true;
|
||||
} else if(tag=="optical_state") { std::string h; if(evidence->optical_state || !(s>>h>>evidence->optical_state_fields) || !hex(h,optical) || evidence->optical_state_fields.size()>1024 || !json_token(evidence->optical_state_fields) || evidence->optical_state_fields=="UNKNOWN") {*why="optical-state evidence";return false;} evidence->optical_state=true; have=true;
|
||||
|
|
@ -150,7 +151,7 @@ bool read_session(const std::string& path,std::vector<View>* views,std::array<un
|
|||
else if(tag=="distance") { std::string h;std::array<unsigned char,32>a{};double meters=0;int band=-1;if(!(s>>h>>meters>>band)||!hex(h,&a)||!finite(meters)||meters<=0||band<0||band>2){*why="distance evidence";return false;}View*v=find_view(views,a);if(!v||v->measured_distance>0){*why="distance source";return false;}v->measured_distance=meters;v->declared_distance_band=band; }
|
||||
else {*why="unknown session record";return false;}
|
||||
}
|
||||
if(!have||!evidence->target||!evidence->measurement||!evidence->planarity||!evidence->planarity_pass||!evidence->decoder_set||!evidence->optical_state||views->empty()||views->size()>kMaxViews){*why="required session evidence";return false;}
|
||||
if(!have||!evidence->target||!evidence->measurement||!evidence->white_border||!evidence->planarity||!evidence->planarity_pass||!evidence->decoder_set||!evidence->optical_state||views->empty()||views->size()>kMaxViews){*why="required session evidence";return false;}
|
||||
double lo=std::numeric_limits<double>::infinity(),hi=-lo;for(double m:evidence->measurements){lo=std::min(lo,m);hi=std::max(hi,m);if(std::abs(m-30.0)>.30){*why="target measurement tolerance";return false;}}if(hi-lo>.20){*why="target measurement range";return false;}
|
||||
std::sort(views->begin(),views->end(),[](const View&a,const View&b){return a.hash<b.hash;});
|
||||
for(size_t i=1;i<views->size();++i) {
|
||||
|
|
@ -335,7 +336,7 @@ bool synthetic_test() {
|
|||
double delta=0;for(auto ray:std::array<cv::Point2d,5>{{{0,0},{-.7,-.7},{.7,-.7},{-.7,.7},{.7,.7}}}){auto eval=[](const Params&p,cv::Point2d q){double r2=q.x*q.x+q.y*q.y,rad=1+p.k1*r2+p.k2*r2*r2;return cv::Point2d(p.fx*(q.x*rad+2*p.p1*q.x*q.y+p.p2*(r2+2*q.x*q.x))+p.cx,p.fy*(q.y*rad+p.p1*(r2+2*q.y*q.y)+2*p.p2*q.x*q.y)+p.cy);};delta=std::max(delta,cv::norm(eval(a.p,ray)-eval(f.p,ray)));}
|
||||
double iq=0,oq=0;for(const auto&x:v){iq=std::max(iq,x.image_conversion_max);oq=std::max(oq,x.object_conversion_max);}
|
||||
double rr=0,rm=0;size_t rh=0,rc=0;if(!residuals(&v,all,a,&rr,&rm,&rh,&rc,&why))return false;
|
||||
SessionEvidence evidence; evidence.target=true;evidence.measurement=true;evidence.planarity=true;evidence.planarity_pass=1;evidence.decoder_set=true;evidence.optical_state=true;evidence.target_id="synthetic";evidence.instrument="synthetic";evidence.decoder="synthetic_decoder";evidence.decoder_version="1";evidence.optical_state_fields="synthetic_only";evidence.resolution_mm=.1;evidence.measurements.fill(30.0);
|
||||
SessionEvidence evidence; evidence.target=true;evidence.measurement=true;evidence.white_border=true;evidence.planarity=true;evidence.planarity_pass=1;evidence.decoder_set=true;evidence.optical_state=true;evidence.target_id="synthetic";evidence.instrument="synthetic";evidence.decoder="synthetic_decoder";evidence.decoder_version="1";evidence.optical_state_fields="synthetic_only";evidence.resolution_mm=.1;evidence.white_border_mm=30.0;evidence.measurements.fill(30.0);
|
||||
Solve runs[3]={a,b,c};std::array<unsigned char,32> optical{};std::string bundle_why;
|
||||
const std::filesystem::path left=std::filesystem::temp_directory_path()/"l3dcal_byte_identity_left";
|
||||
const std::filesystem::path right=std::filesystem::temp_directory_path()/"l3dcal_byte_identity_right";std::error_code ec;std::filesystem::remove_all(left.string()+".bundle",ec);std::filesystem::remove_all(right.string()+".bundle",ec);
|
||||
|
|
@ -355,6 +356,7 @@ bool manifest_negative_tests() {
|
|||
x<<"L3DCAL_SESSION_V1\n"
|
||||
<<"target board "<<h<<" DICT_5X5_100 9 7 30 21\n"
|
||||
<<"measurement caliper 0.1 30 30 30 30 30 30 30 30 30 30\n"
|
||||
<<"white_border 30\n"
|
||||
<<"planarity PASS "<<h<<"\n"
|
||||
<<"decoder qualified_decoder 1\n"
|
||||
<<"optical_state "<<h<<" body_objective_zoom_focus_stabilization_format_pipeline\n"
|
||||
|
|
@ -374,7 +376,7 @@ bool manifest_negative_tests() {
|
|||
const std::string good=make("");
|
||||
bool ok=parse(good); if(!ok)std::cerr<<"negative good\n";
|
||||
auto altered=[&](const std::string& from,const std::string& to){std::string t=good;const size_t n=t.find(from);if(n==std::string::npos)return false;t.replace(n,from.size(),to);return !parse(t);};
|
||||
const bool n1=altered("target board", "target_bad board"),n2=altered("planarity PASS", "planarity FAIL"),n3=altered(" 20 0 0\ncoordinate_point", " 19 0 0\ncoordinate_point"),n4=altered("qualified_decoder 1 0 100", "qualified_decoder 1 90 100");ok=ok&&n1&&n2&&n3&&n4;
|
||||
const bool n1=altered("target board", "target_bad board"),n2=altered("planarity PASS", "planarity FAIL"),n3=altered(" 20 0 0\ncoordinate_point", " 19 0 0\ncoordinate_point"),n4=altered("qualified_decoder 1 0 100", "qualified_decoder 1 90 100"),n5=altered("white_border 30", "white_border 29");ok=ok&&n1&&n2&&n3&&n4&&n5;
|
||||
std::error_code ec;std::filesystem::remove(p,ec);return ok;
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
|||
Loading…
Reference in a new issue