This commit is contained in:
Thomas Forgione 2024-07-12 14:42:35 +02:00
parent aa55934bf0
commit 31610f6100
10 changed files with 114 additions and 66 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
db.sqlite
.device
data
data-keep
node_modules
static/calibration-visualiser.*

17
app.py
View File

@ -21,6 +21,12 @@ def get_calibration(conn: sqlite3.Connection) -> Optional[db.Calibration]:
return db.Calibration.get_from_id(calibration_id, conn)
@app.context_processor
def inject_stage_and_region():
conn = db.get()
return dict(calibration=get_calibration(conn))
@app.route("/")
def hello_world():
conn = db.get()
@ -40,7 +46,7 @@ def create_object():
def object(id: int):
conn = db.get()
object = db.Object.get_from_id(id, conn)
return render_template('object.html', object=object, calibration=get_calibration(conn))
return render_template('object.html', object=object)
@app.route('/scan/<id>')
@ -90,10 +96,17 @@ def scan_calibration(id: int):
@app.route("/api/calibrate/<id>")
def run_calibration(id: int):
conn = db.get()
db.Calibration.get_from_id(id, conn)
calib = db.Calibration.get_from_id(id, conn)
if calib is None:
return 'oops', 404
calibration_json = calibration.calibrate(join(config.CALIBRATION_DIR, str(id)))
with open(join(config.CALIBRATION_DIR, str(id), 'calibration.json'), 'w') as f:
json.dump(calibration_json, f, indent=4)
with conn:
calib.state = db.CalibrationState.IsComputed
calib.save(conn)
return 'ok'

View File

@ -1,7 +1,9 @@
from os.path import join
MODE = 'debug'
DATA_DIR = 'data'
CALIBRATION_DIR = join(DATA_DIR, 'calibration')
CALIBRATION_DIR = join(DATA_DIR, 'calibrations')
OBJECT_DIR = join(DATA_DIR, 'objects')
LEDS_UUIDS = [
'ac59350e-3787-46d2-88fa-743c1d34fe86',

67
db.py
View File

@ -3,9 +3,17 @@
from enum import IntEnum
from flask import g
import os
from os.path import join
import shutil
import sqlite3
import sys
from typing import Optional
if __name__ != '__main__':
from . import config
else:
import config
def get() -> sqlite3.Connection:
if 'db' not in g:
@ -40,7 +48,8 @@ def init_app(app):
class CalibrationState(IntEnum):
Empty = 0
HasData = 1
IsValidated = 2
IsComputed = 2
IsValidated = 3
class Calibration:
@ -59,7 +68,9 @@ class Calibration:
'INSERT INTO calibration(state) VALUES (?) RETURNING ' + Calibration.select_args() + ';',
[int(CalibrationState.Empty)]
)
return Calibration.from_row(response.fetchone())
calibration = Calibration.from_row(response.fetchone())
os.makedirs(join(config.CALIBRATION_DIR, str(calibration.id)))
return calibration
@staticmethod
def from_row(row: sqlite3.Row) -> 'Calibration':
@ -96,7 +107,7 @@ class Acquisition:
cur = db.cursor()
cur.execute(
'UPDATE acquisition SET calibration_id = ?, object_id = ? WHERE id = ?',
[self.calibration_id, self.objct_id, self.id]
[self.calibration_id, self.object_id, self.id]
)
@staticmethod
@ -146,7 +157,9 @@ class Object:
'INSERT INTO object(name) VALUES (?) RETURNING ' + Object.select_args() + ';',
[name]
)
return Object.from_row(response.fetchone())
object = Object.from_row(response.fetchone())
os.makedirs(join(config.OBJECT_DIR, str(object.id)))
return object
@staticmethod
def get_from_id(object_id: int, db: sqlite3.Connection) -> Optional['Object']:
@ -176,6 +189,10 @@ class Object:
def main():
if config.MODE != 'debug':
print('Can only reset db in debug mode')
sys.exit(1)
db = sqlite3.connect(
os.environ.get('DATABASE_PATH', 'db.sqlite'),
detect_types=sqlite3.PARSE_DECLTYPES,
@ -183,28 +200,32 @@ def main():
db.row_factory = sqlite3.Row
init(db)
if os.path.isdir(config.DATA_DIR):
shutil.rmtree(config.DATA_DIR)
# Create a new object
with db:
object = Object.create('Mon premier objet', db)
calibration = Calibration.create(db)
object.add_acquisition(calibration.id, db)
object.add_acquisition(calibration.id, db)
object.add_acquisition(calibration.id, db)
calibration = Calibration.create(db)
object.add_acquisition(calibration.id, db)
object.add_acquisition(calibration.id, db)
object.add_acquisition(calibration.id, db)
Object.create('Mon premier objet', db)
# calibration = Calibration.create(db)
# object.add_acquisition(calibration.id, db)
# object.add_acquisition(calibration.id, db)
# object.add_acquisition(calibration.id, db)
# calibration = Calibration.create(db)
# object.add_acquisition(calibration.id, db)
# object.add_acquisition(calibration.id, db)
# object.add_acquisition(calibration.id, db)
object = Object.create('Mon deuxième objet', db)
calibration = Calibration.create(db)
object.add_acquisition(calibration.id, db)
object.add_acquisition(calibration.id, db)
object.add_acquisition(calibration.id, db)
calibration = Calibration.create(db)
object.add_acquisition(calibration.id, db)
object.add_acquisition(calibration.id, db)
object.add_acquisition(calibration.id, db)
Object.create('Mon deuxième objet', db)
# calibration = Calibration.create(db)
# object.add_acquisition(calibration.id, db)
# object.add_acquisition(calibration.id, db)
# object.add_acquisition(calibration.id, db)
# calibration = Calibration.create(db)
# object.add_acquisition(calibration.id, db)
# object.add_acquisition(calibration.id, db)
# object.add_acquisition(calibration.id, db)
if __name__ == '__main__':
main()
if len(sys.argv) > 1 and sys.argv[1] == 'reset':
main()

View File

@ -35,7 +35,7 @@ def scan(output_dir: str):
# capture(img)
# For debug purposes
shutil.copyfile(join(config.DATA_DIR, 'small', led + '.jpg'), img)
shutil.copyfile(join('data-keep/small', led + '.jpg'), img)
delta = time.time() - start

View File

@ -22,8 +22,28 @@
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-end">
<a class="navbar-item" href="/">
Page 1
<a class="navbar-item" href="#">
{% if calibration is none or calibration.state == 0 %}
<span class="tags has-addons">
<span class="tag is-dark">étalonnage</span>
<span class="tag is-danger">aucune donnée</span>
</span>
{% elif calibration.state == 1 %}
<span class="tags has-addons">
<span class="tag is-dark">étalonnage</span>
<span class="tag is-warning">non calculé</span>
</span>
{% elif calibration.state == 2 %}
<span class="tags has-addons">
<span class="tag is-dark">étalonnage</span>
<span class="tag is-warning">non validé</span>
</span>
{% elif calibration.state == 3 %}
<a href="/calibration/{{ object.id }}" class="tags has-addons">
<span class="tag is-dark">étalonnage</span>
<span class="tag is-success">fait</span>
</a>
{% endif %}
</a>
</div>
</div>

View File

@ -30,8 +30,8 @@
</div>
</div>
<progress id="progress-bar" class="progress is-link" style="display: none;" value="0" max="1000"></progress>
<div id="calibrate" style="display: none;">
<p>Si les données d'étalonnage conviennent, appuyez sur le bouton ci-dessous pour procéder à l'étalonnage du scanner</p>
<div id="calibrate" {% if calibration.state == 0 %}style="display: none;" {% endif %}>
<p>Si les données d'étalonnage conviennent, appuyez sur le bouton ci-dessous pour procéder à l'étalonnage du scanner.</p>
<button id="calibrate-button" class="button is-link">Étalonner le scanner</button>
<p id="calibration-info"></p>
</div>
@ -74,6 +74,20 @@
buttons.forEach(x => x.removeAttribute('disabled'));
});
// If we already have calibration images, we show them right now
if ({% if calibration.state > 0 %}true{% else %}false{% endif %}) {
let cell, img;
{% for led in leds %}
cell = document.createElement('div');
cell.classList.add('cell');
img = document.createElement('img');
img.classList.add('is-loading');
img.src = '/data/calibration/{{ calibration.id }}/{{ led }}.jpg?v=0';
cell.appendChild(img);
grid.appendChild(cell);
{% endfor %}
}
scanButton.addEventListener('click', async () => {
scanIndex++;
progress = 0;
@ -103,7 +117,7 @@
cell.classList.add('cell');
let img = document.createElement('img');
img.classList.add('is-loading');
img.src = '/data/calibration/{{ calibration.id }}/' + uuid + '.jpg?v=' + scanIndex;
img.src = '/data/calibrations/{{ calibration.id }}/' + uuid + '.jpg?v=' + scanIndex;
cell.appendChild(img);
grid.appendChild(cell);
}

View File

@ -24,7 +24,7 @@
<div class="field">
<label class="label">Nom de l'objet</label>
<div class="control">
<input class="input" type="text" name="name" placeholder="Nom de l'objet">
<input class="input" type="text" name="name" placeholder="Nom de l'objet" required>
</div>
</div>

View File

@ -4,34 +4,6 @@
<section class="section">
<div class="container">
<h1 class="title">{{ object.name }}</h1>
{#
<div class="field is-grouped is-grouped-multiline">
<div class="control">
{% if calibration is none or calibration.state == 0 %}
<span class="tags has-addons">
<span class="tag is-dark">étalonnage</span>
<span class="tag is-danger">aucune donnée</span>
</span>
{% elif calibration.state == 1 %}
<span class="tags has-addons">
<span class="tag is-dark">étalonnage</span>
<span class="tag is-warning">pas fait</span>
</span>
{% elif calibration.state == 2 %}
<a href="/calibration/{{ object.id }}" class="tags has-addons">
<span class="tag is-dark">étalonnage</span>
<span class="tag is-success">fait</span>
</a>
{% endif %}
</div>
</div>
{% if calibration is none or calibration.state == 0 %}
<div class="field is-grouped">
<a href="/calibrate/{{ object.id }}" class="button is-link">Étalonner le scanner</a>
<a href="#" title="Non implémenté" disabled="disabled" class="button is-link">Utiliser le dernier étalonnage connu</a>
</div>
{% endif %}
#}
{% if calibration %}
<a href="/scan/{{ object.id }}" class="button is-link">Faire un scan</a>
{% else %}

View File

@ -44,7 +44,7 @@ function getImageElementById(id: string): HTMLImageElement {
*/
export class Engine {
/** The id of the object to scan. */
objectId: number;
calibrationId: number;
/** HTML element on which the renderer will be added. */
domElement: HTMLElement;
@ -105,15 +105,15 @@ export class Engine {
/** Initialises the engine. */
static async create(domId: string) {
let objectId = parseInt(window.location.pathname.split('/')[2], 10);
let calibrationId = parseInt(window.location.pathname.split('/')[2], 10);
let domElement = getElementById(domId);
let engine = new Engine();
engine.objectId = objectId;
engine.calibrationId = calibrationId;
engine.domElement = domElement;
engine.initHtml();
let request = await fetch('/data/calibration/' + objectId + '/calibration.json');
let request = await fetch(engine.dataPath('calibration.json'));
let calibration = await request.json();
engine.initScene(calibration);
engine.initListeners();
@ -130,6 +130,11 @@ export class Engine {
return this.domElement === document.body ? window.innerHeight : this.domElement.offsetHeight;
}
/** Returns the url of calibration assets. */
dataPath(path: string): string {
return '/data/calibrations/' + this.calibrationId + '/' + path;
}
/**
* Initialises the HTML components of the engine.
*/
@ -296,7 +301,7 @@ export class Engine {
showImage(led: Led): void {
if (led.on) {
this.selectedObject.innerText = led.name.split('.')[0] + ' (' + (<number> this.leds.currentLedIndex + 1) + '/' + this.leds.leds.length + ')';
this.ledView.src = '/data/calibration/' + this.objectId + '/' + led.name;
this.ledView.src = this.dataPath(led.name);
this.ledView.style.display = 'block';
} else {
this.selectedObject.innerText = 'aucune';