Working on calibration
This commit is contained in:
parent
8676b21969
commit
658fcd57c3
31
app.py
31
app.py
|
|
@ -30,14 +30,23 @@ def create_object():
|
||||||
def object(id: int):
|
def object(id: int):
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
object = db.Object.get_from_id(id, conn)
|
object = db.Object.get_from_id(id, conn)
|
||||||
return render_template('object.html', object=object)
|
calibration = object.calibration(conn)
|
||||||
|
return render_template('object.html', object=object, calibration=calibration)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/calibrate/<id>")
|
@app.route("/calibrate/<id>")
|
||||||
def calibrate(id: int):
|
def calibrate(id: int):
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
object = db.Object.get_from_id(id, conn)
|
object = db.Object.get_from_id(id, conn)
|
||||||
return render_template('calibrate.html', object=object)
|
if object.calibration_id is None:
|
||||||
|
with conn:
|
||||||
|
calibration = db.Calibration.create(conn)
|
||||||
|
object.calibration_id = calibration.id
|
||||||
|
object.save(conn)
|
||||||
|
else:
|
||||||
|
calibration = object.calibration(conn)
|
||||||
|
|
||||||
|
return render_template('calibrate.html', object=object, calibration=calibration, leds=config.LEDS_UUIDS)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/preview/<id>")
|
@app.route("/api/preview/<id>")
|
||||||
|
|
@ -54,22 +63,26 @@ def preview(id: int):
|
||||||
@app.route("/api/scan-for-calibration/<id>")
|
@app.route("/api/scan-for-calibration/<id>")
|
||||||
def scan_calibration(id: int):
|
def scan_calibration(id: int):
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
db.Object.get_from_id(id, conn)
|
calibration = db.Calibration.get_from_id(id, conn)
|
||||||
|
|
||||||
def generate():
|
def generate():
|
||||||
length = len(config.LEDS_UUIDS)
|
length = len(config.LEDS_UUIDS)
|
||||||
for index, led_uuid in enumerate(scanner.scan(join(config.DATA_DIR, id, 'calibration'))):
|
for index, led_uuid in enumerate(scanner.scan(join(config.CALIBRATION_DIR, id))):
|
||||||
yield f"{led_uuid},{(index+1)/length}\n"
|
yield f"{led_uuid},{(index+1)/length}\n"
|
||||||
|
|
||||||
|
with conn:
|
||||||
|
calibration.state = db.CalibrationState.HasData
|
||||||
|
calibration.save(conn)
|
||||||
|
|
||||||
return app.response_class(generate(), mimetype='text/plain')
|
return app.response_class(generate(), mimetype='text/plain')
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/calibrate/<id>")
|
@app.route("/api/calibrate/<id>")
|
||||||
def run_calibration(id: int):
|
def run_calibration(id: int):
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
db.Object.get_from_id(id, conn)
|
db.Calibration.get_from_id(id, conn)
|
||||||
calibration_json = calibration.calibrate(join(config.DATA_DIR, str(id), 'calibration'))
|
calibration_json = calibration.calibrate(join(config.CALIBRATION_DIR, str(id)))
|
||||||
with open(join(config.DATA_DIR, str(id), 'calibration.json'), 'w') as f:
|
with open(join(config.CALIBRATION_DIR, str(id), 'calibration.json'), 'w') as f:
|
||||||
json.dump(calibration_json, f, indent=4)
|
json.dump(calibration_json, f, indent=4)
|
||||||
return 'ok'
|
return 'ok'
|
||||||
|
|
||||||
|
|
@ -77,8 +90,8 @@ def run_calibration(id: int):
|
||||||
@app.route("/calibration/<id>")
|
@app.route("/calibration/<id>")
|
||||||
def calibration_page(id: int):
|
def calibration_page(id: int):
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
object = db.Object.get_from_id(id, conn)
|
calibration = db.Calibration.get_from_id(id, conn)
|
||||||
return render_template('calibration.html', object=object)
|
return render_template('calibration.html', calibration=calibration)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/static/<path:path>')
|
@app.route('/static/<path:path>')
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
from os.path import join
|
||||||
|
|
||||||
DATA_DIR = 'data'
|
DATA_DIR = 'data'
|
||||||
|
CALIBRATION_DIR = join(DATA_DIR, 'calibration')
|
||||||
|
|
||||||
LEDS_UUIDS = [
|
LEDS_UUIDS = [
|
||||||
'ac59350e-3787-46d2-88fa-743c1d34fe86',
|
'ac59350e-3787-46d2-88fa-743c1d34fe86',
|
||||||
|
|
|
||||||
72
db.py
72
db.py
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
from flask import g
|
from flask import g
|
||||||
import os
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
@ -13,6 +14,8 @@ def get() -> sqlite3.Connection:
|
||||||
detect_types=sqlite3.PARSE_DECLTYPES,
|
detect_types=sqlite3.PARSE_DECLTYPES,
|
||||||
)
|
)
|
||||||
g.db.row_factory = sqlite3.Row
|
g.db.row_factory = sqlite3.Row
|
||||||
|
cur = g.db.cursor()
|
||||||
|
cur.execute('PRAGMA foreign_keys = on')
|
||||||
|
|
||||||
return g.db
|
return g.db
|
||||||
|
|
||||||
|
|
@ -43,34 +46,75 @@ if __name__ == '__main__':
|
||||||
init(db)
|
init(db)
|
||||||
|
|
||||||
|
|
||||||
|
class CalibrationState(IntEnum):
|
||||||
|
Empty = 0
|
||||||
|
HasData = 1
|
||||||
|
IsValidated = 2
|
||||||
|
|
||||||
|
|
||||||
|
class Calibration:
|
||||||
|
@staticmethod
|
||||||
|
def select_args() -> str:
|
||||||
|
return 'id, state'
|
||||||
|
|
||||||
|
def __init__(self, calibration_id: int, state: int):
|
||||||
|
self.id = calibration_id
|
||||||
|
self.state = CalibrationState(state)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create(db: sqlite3.Connection) -> 'Calibration':
|
||||||
|
cur = db.cursor()
|
||||||
|
response = cur.execute(
|
||||||
|
'INSERT INTO calibration(state) VALUES (?) RETURNING ' + Calibration.select_args() + ';',
|
||||||
|
[int(CalibrationState.Empty)]
|
||||||
|
)
|
||||||
|
return Calibration.from_row(response.fetchone())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_row(row: sqlite3.Row) -> 'Calibration':
|
||||||
|
return Calibration(*row)
|
||||||
|
|
||||||
|
def save(self, db: sqlite3.Connection):
|
||||||
|
cur = db.cursor()
|
||||||
|
cur.execute(
|
||||||
|
'UPDATE calibration SET state = ? WHERE id = ?',
|
||||||
|
[int(self.state), self.id]
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_from_id(calibration_id: int, db: sqlite3.Connection) -> Optional['Calibration']:
|
||||||
|
cur = db.cursor()
|
||||||
|
response = cur.execute(
|
||||||
|
'SELECT ' + Calibration.select_args() + ' FROM calibration WHERE id = ?;',
|
||||||
|
[calibration_id]
|
||||||
|
)
|
||||||
|
return Calibration.from_row(response.fetchone())
|
||||||
|
|
||||||
|
|
||||||
class Object:
|
class Object:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def select_args() -> str:
|
def select_args() -> str:
|
||||||
return 'id, name, calibrated'
|
return 'id, name, calibration_id'
|
||||||
|
|
||||||
def __init__(self, object_id: int, name: str, calibrated: int):
|
def __init__(self, object_id: int, name: str, calibration: int):
|
||||||
self.id = object_id
|
self.id = object_id
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.calibration_id = calibration
|
||||||
# 0 means no data available
|
|
||||||
# 1 means data available but calibration not done
|
|
||||||
# 2 means calibration done
|
|
||||||
self.calibrated = calibrated
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(name: str, db: sqlite3.Connection) -> 'Object':
|
def create(name: str, db: sqlite3.Connection) -> 'Object':
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
response = cur.execute(
|
response = cur.execute(
|
||||||
'INSERT INTO object(name, calibrated) VALUES (?, ?) RETURNING ' + Object.select_args() + ';',
|
'INSERT INTO object(name, calibration_id) VALUES (?, ?) RETURNING ' + Object.select_args() + ';',
|
||||||
[name, 0]
|
[name, None]
|
||||||
)
|
)
|
||||||
return Object.from_row(response.fetchone())
|
return Object.from_row(response.fetchone())
|
||||||
|
|
||||||
def save(self, db: sqlite3.Connection):
|
def save(self, db: sqlite3.Connection):
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
cur.execute(
|
cur.execute(
|
||||||
'UPDATE object SET name = ? WHERE id = ?',
|
'UPDATE object SET name = ?, calibration_id = ? WHERE id = ?',
|
||||||
[self.name, self.id]
|
[self.name, self.calibration_id, self.id]
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -94,3 +138,9 @@ class Object:
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
return list(map(Object.from_row, response.fetchall()))
|
return list(map(Object.from_row, response.fetchall()))
|
||||||
|
|
||||||
|
def calibration(self, db: sqlite3.Connection) -> Optional[Calibration]:
|
||||||
|
if self.calibration_id is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return Calibration.get_from_id(self.calibration_id, db)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
DROP TABLE IF EXISTS object;
|
DROP TABLE IF EXISTS object;
|
||||||
|
DROP TABLE IF EXISTS calibration;
|
||||||
|
|
||||||
|
CREATE TABLE calibration (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
state INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE object (
|
CREATE TABLE object (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
calibrated INT NOT NULL
|
calibration_id INTEGER,
|
||||||
|
CONSTRAINT fk_calibration FOREIGN KEY(calibration_id) REFERENCES calibration(id)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<progress id="progress-bar" class="progress is-link" style="display: none;" value="0" max="1000"></progress>
|
<progress id="progress-bar" class="progress is-link" style="display: none;" value="0" max="1000"></progress>
|
||||||
<div id="calibrate" style="display: none;">
|
<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>
|
<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>
|
<button id="calibrate-button" class="button is-link">Étalonner le scanner</button>
|
||||||
<p id="calibration-info"></p>
|
<p id="calibration-info"></p>
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
|
|
||||||
{% block extrajs %}
|
{% block extrajs %}
|
||||||
<script>
|
<script>
|
||||||
let scanIndex = 0;
|
let scanIndex = 1;
|
||||||
let progress = 0;
|
let progress = 0;
|
||||||
let previewButton = document.getElementById('preview-button');
|
let previewButton = document.getElementById('preview-button');
|
||||||
let scanButton = document.getElementById('scan-button');
|
let scanButton = document.getElementById('scan-button');
|
||||||
|
|
@ -74,6 +74,20 @@
|
||||||
buttons.forEach(x => x.removeAttribute('disabled'));
|
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 () => {
|
scanButton.addEventListener('click', async () => {
|
||||||
scanIndex++;
|
scanIndex++;
|
||||||
progress = 0;
|
progress = 0;
|
||||||
|
|
@ -84,7 +98,7 @@
|
||||||
progressBar.style.display = "block";
|
progressBar.style.display = "block";
|
||||||
grid.innerHTML = '';
|
grid.innerHTML = '';
|
||||||
|
|
||||||
let response = await fetch('/api/scan-for-calibration/{{ object.id }}');
|
let response = await fetch('/api/scan-for-calibration/{{ calibration.id }}');
|
||||||
let reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
let reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
@ -103,7 +117,7 @@
|
||||||
cell.classList.add('cell');
|
cell.classList.add('cell');
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
img.classList.add('is-loading');
|
img.classList.add('is-loading');
|
||||||
img.src = '/data/{{ object.id }}/calibration/' + uuid + '.jpg?v=' + scanIndex;
|
img.src = '/data/calibration/{{ calibration.id }}/' + uuid + '.jpg?v=' + scanIndex;
|
||||||
cell.appendChild(img);
|
cell.appendChild(img);
|
||||||
grid.appendChild(cell);
|
grid.appendChild(cell);
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +127,7 @@
|
||||||
calibrateButton.classList.add('is-loading');
|
calibrateButton.classList.add('is-loading');
|
||||||
|
|
||||||
await fetch('/api/calibrate/{{ object.id }}');
|
await fetch('/api/calibrate/{{ object.id }}');
|
||||||
window.location.href = '/calibration/{{ object.id }}';
|
window.location.href = '/calibration/{{ calibration.id }}';
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="title is-2">Visualisation de l'étalonnage de {{ object.name }}</h1>
|
<h1 class="title is-2">Visualisation de l'étalonnage {{ calibration.id }}</h1>
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<h2 class="title is-3">Positions 3D des LEDs</h2>
|
<h2 class="title is-3">Positions 3D des LEDs</h2>
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,17 @@
|
||||||
<h1 class="title">{{ object.name }}</h1>
|
<h1 class="title">{{ object.name }}</h1>
|
||||||
<div class="field is-grouped is-grouped-multiline">
|
<div class="field is-grouped is-grouped-multiline">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
{% if object.calibrated == 0 %}
|
{% if calibration is none or calibration.state == 0 %}
|
||||||
<span class="tags has-addons">
|
<span class="tags has-addons">
|
||||||
<span class="tag is-dark">étalonnage</span>
|
<span class="tag is-dark">étalonnage</span>
|
||||||
<span class="tag is-danger">données manquantes</span>
|
<span class="tag is-danger">aucune donnée</span>
|
||||||
</span>
|
</span>
|
||||||
{% elif object.calibrated == 1 %}
|
{% elif calibration.state == 1 %}
|
||||||
<span class="tags has-addons">
|
<span class="tags has-addons">
|
||||||
<span class="tag is-dark">étalonnage</span>
|
<span class="tag is-dark">étalonnage</span>
|
||||||
<span class="tag is-warning">pas fait</span>
|
<span class="tag is-warning">pas fait</span>
|
||||||
</span>
|
</span>
|
||||||
{% elif object.calibrated == 2 %}
|
{% elif calibration.state == 2 %}
|
||||||
<a href="/calibration/{{ object.id }}" class="tags has-addons">
|
<a href="/calibration/{{ object.id }}" class="tags has-addons">
|
||||||
<span class="tag is-dark">étalonnage</span>
|
<span class="tag is-dark">étalonnage</span>
|
||||||
<span class="tag is-success">fait</span>
|
<span class="tag is-success">fait</span>
|
||||||
|
|
@ -24,8 +24,11 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if object.calibrated == 0 %}
|
{% if calibration is none or calibration.state == 0 %}
|
||||||
<a href="/calibrate/{{ object.id }}" class="button is-link">Étalonner le scanner</a>
|
<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 %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ export class Engine {
|
||||||
engine.domElement = domElement;
|
engine.domElement = domElement;
|
||||||
engine.initHtml();
|
engine.initHtml();
|
||||||
|
|
||||||
let request = await fetch('/data/' + objectId + '/calibration.json');
|
let request = await fetch('/data/calibration/' + objectId + '/calibration.json');
|
||||||
let calibration = await request.json();
|
let calibration = await request.json();
|
||||||
engine.initScene(calibration);
|
engine.initScene(calibration);
|
||||||
engine.initListeners();
|
engine.initListeners();
|
||||||
|
|
@ -296,7 +296,7 @@ export class Engine {
|
||||||
showImage(led: Led): void {
|
showImage(led: Led): void {
|
||||||
if (led.on) {
|
if (led.on) {
|
||||||
this.selectedObject.innerText = led.name.split('.')[0] + ' (' + (<number> this.leds.currentLedIndex + 1) + '/' + this.leds.children.length + ')';
|
this.selectedObject.innerText = led.name.split('.')[0] + ' (' + (<number> this.leds.currentLedIndex + 1) + '/' + this.leds.children.length + ')';
|
||||||
this.ledView.src = '/data/' + this.objectId + '/calibration/' + led.name;
|
this.ledView.src = '/data/calibration/' + this.objectId + '/' + led.name;
|
||||||
this.ledView.style.display = 'block';
|
this.ledView.style.display = 'block';
|
||||||
} else {
|
} else {
|
||||||
this.selectedObject.innerText = 'aucune';
|
this.selectedObject.innerText = 'aucune';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue