Acquisitore: calibrazione densa su C2/grab/pagina, test (#84)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jbf7qKuxsnAVjxthRy7dnB
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
Cosa fa: una pagina sola, autonoma e offline (niente CDN, JS e CSS inline), in
|
||||
italiano. Parla con le rotte dello stesso servizio (/camera/sources,
|
||||
/camera/calibration, /camera/calibrate).
|
||||
#84: calibrazione densa, un solo dato dell'operatore (lato dello scacco in mm):
|
||||
scacchiera che riempie il campo, griglia trovata da sola, mappa di distorsione.
|
||||
Dipende da: niente. E' una stringa, cosi' il pacchetto compilato non ha file dati.
|
||||
"""
|
||||
|
||||
@@ -41,20 +43,18 @@ PAGINA = """<!doctype html>
|
||||
<div class="scheda">
|
||||
<div class="riga">
|
||||
<div><label for="sorgente">Sorgente</label><select id="sorgente"></select></div>
|
||||
<div><label for="cols">Angoli interni in orizzontale</label><input id="cols" type="number" min="2" value="9"></div>
|
||||
<div><label for="rows">Angoli interni in verticale</label><input id="rows" type="number" min="2" value="6"></div>
|
||||
<div><label for="quadrato">Lato del quadrato (mm)</label><input id="quadrato" type="number" min="0.001" step="any" value="2"></div>
|
||||
<div><label for="quadrato">Lato dello scacco (mm)</label><input id="quadrato" type="number" min="0.001" step="any" value="2"></div>
|
||||
</div>
|
||||
<p style="font-size:.85rem;color:#4b5563;margin:10px 0 0">
|
||||
Gli angoli interni sono quelli dove si toccano quattro quadrati: una scacchiera di 10 x 7 quadrati ha 9 x 6 angoli.
|
||||
Tenere la scacchiera piana e ferma, ben illuminata.</p>
|
||||
Servono una scacchiera che riempie tutto il campo della camera, piana, ferma e ben illuminata, e il lato di uno scacco.
|
||||
La griglia si trova da sola; il risultato corregge anche la distorsione dell'ottica.</p>
|
||||
</div>
|
||||
|
||||
<div class="scheda">
|
||||
<div class="riga">
|
||||
<button id="acquisisci">Acquisisci e calcola</button>
|
||||
<button id="acquisisci">Acquisisci e calibra</button>
|
||||
<div><label for="file">oppure un file immagine</label><input id="file" type="file" accept="image/*"></div>
|
||||
<button id="carica" class="secondario">Carica immagine e calcola</button>
|
||||
<button id="carica" class="secondario">Carica immagine e calibra</button>
|
||||
</div>
|
||||
<div id="messaggio" class="messaggio"></div>
|
||||
</div>
|
||||
@@ -64,7 +64,7 @@ PAGINA = """<!doctype html>
|
||||
<table id="tabella"></table>
|
||||
<div id="avviso" class="avviso"></div>
|
||||
<div class="riga" style="margin-top:10px">
|
||||
<button id="salva">Salva per questa sorgente</button>
|
||||
<button id="salva">Salva</button>
|
||||
<span style="font-size:.85rem;color:#4b5563">Da camera, salvando si acquisisce e si calcola di nuovo: tenere la scacchiera ferma.</span>
|
||||
</div>
|
||||
<img id="overlay" alt="Angoli trovati sulla scacchiera">
|
||||
@@ -95,12 +95,19 @@ function numero(v, cifre) { return Number(v).toFixed(cifre); }
|
||||
function righe(d) {
|
||||
return [
|
||||
["Scala", numero(d.px_per_mm, 4) + " px/mm (" + numero(d.mm_per_px, 5) + " mm/px)"],
|
||||
["Metodo", d.metodo !== "densa" ? "planare (senza correzione della distorsione)" : "densa (immagine raddrizzata)"],
|
||||
["Griglia trovata", d.cols + " x " + d.rows + " angoli (" + d.n_corners + ")"]
|
||||
].concat(d.metodo !== "densa" ? [
|
||||
["Errore di riproiezione (RMS)", numero(d.rms_px, 3) + " px"],
|
||||
["Variazione di scala nell'area", numero(d.scale_spread_pct, 2) + " %"],
|
||||
["Angoli trovati", d.n_corners + " (" + d.cols + " x " + d.rows + ")"],
|
||||
["Lato del quadrato", d.square_mm + " mm"],
|
||||
["Variazione di scala nell'area", numero(d.scale_spread_pct, 2) + " %"]
|
||||
] : [
|
||||
["Residuo massimo", numero(d.residuo_max_px, 3) + " px"],
|
||||
["Residuo RMS", numero(d.residuo_rms_px, 3) + " px"],
|
||||
["Copertura del campo", numero(d.copertura_pct, 1) + " %"]
|
||||
]).concat([
|
||||
["Lato dello scacco", d.square_mm + " mm"],
|
||||
["Immagine", d.image_width + " x " + d.image_height + " px"]
|
||||
];
|
||||
]);
|
||||
}
|
||||
|
||||
function tabella(el, d) {
|
||||
@@ -157,9 +164,19 @@ async function aggiornaStato() {
|
||||
}
|
||||
|
||||
function parametri() {
|
||||
return {
|
||||
cols: $("cols").value, rows: $("rows").value, quadrato: $("quadrato").value
|
||||
};
|
||||
return { quadrato: $("quadrato").value };
|
||||
}
|
||||
|
||||
// avvisi sulla qualita' (solo calibrazione densa): copertura bassa o residuo alto
|
||||
function avvisi(d) {
|
||||
var a = [];
|
||||
if (d.metodo !== "densa") {
|
||||
if (d.scale_spread_pct > 1) a.push("Attenzione: la scala varia di " + numero(d.scale_spread_pct, 2) + " % nell'area: scacchiera inclinata o ottica non telecentrica.");
|
||||
} else {
|
||||
if (d.copertura_pct < 70) a.push("Attenzione: la scacchiera copre solo il " + numero(d.copertura_pct, 1) + " % del campo (meno del 70 %): la correzione ai bordi non e' misurata.");
|
||||
if (d.residuo_max_px > 0.5) a.push("Attenzione: residuo massimo " + numero(d.residuo_max_px, 3) + " px (oltre 0,5 px): scacchiera non piana, sfocata o con scacchi irregolari.");
|
||||
}
|
||||
return a.join(" ");
|
||||
}
|
||||
|
||||
async function calcola(conFile, salva) {
|
||||
@@ -168,8 +185,6 @@ async function calcola(conFile, salva) {
|
||||
var p = parametri();
|
||||
var f = new FormData();
|
||||
f.append("source", sorgente);
|
||||
f.append("cols", p.cols);
|
||||
f.append("rows", p.rows);
|
||||
f.append("square_mm", p.quadrato);
|
||||
f.append("save", salva ? "true" : "false");
|
||||
if (conFile) {
|
||||
@@ -186,11 +201,9 @@ async function calcola(conFile, salva) {
|
||||
ultimo = { conFile: conFile, dati: d };
|
||||
tabella($("tabella"), d);
|
||||
$("overlay").src = "data:image/png;base64," + d.overlay_png;
|
||||
$("avviso").textContent = d.scale_spread_pct > 1
|
||||
? "Attenzione: la scala varia di " + numero(d.scale_spread_pct, 2) + " % nell'area: scacchiera inclinata o ottica non telecentrica."
|
||||
: "";
|
||||
$("avviso").textContent = avvisi(d);
|
||||
$("risultato").hidden = false;
|
||||
messaggio(d.saved ? "Calibrazione salvata." : "Calcolo riuscito: controllare e salvare.", "ok");
|
||||
messaggio(d.saved ? "Calibrazione salvata." : "Calibrazione riuscita: controllare e salvare.", "ok");
|
||||
if (d.saved) aggiornaStato();
|
||||
} catch (e) {
|
||||
messaggio("Servizio non raggiungibile.", "errore");
|
||||
|
||||
Reference in New Issue
Block a user