Working
This commit is contained in:
parent
b1ddbe23ee
commit
f6f34d6260
|
|
@ -1,7 +1,7 @@
|
||||||
db.sqlite
|
|
||||||
.device
|
.device
|
||||||
data
|
data
|
||||||
data-keep
|
data-*
|
||||||
|
secret.py
|
||||||
node_modules
|
node_modules
|
||||||
static/calibration-visualiser.*
|
static/calibration-visualiser.*
|
||||||
|
|
||||||
|
|
|
||||||
63
app.py
63
app.py
|
|
@ -9,7 +9,17 @@ import uuid
|
||||||
from . import db, config, scanner, calibration
|
from . import db, config, scanner, calibration
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config['SECRET_KEY'] = os.urandom(20).hex()
|
|
||||||
|
# Manage secret key
|
||||||
|
try:
|
||||||
|
from . import secret
|
||||||
|
app.config['SECRET_KEY'] = secret.SECRET_KEY
|
||||||
|
except ImportError:
|
||||||
|
# Secret key file does not exist, create it
|
||||||
|
secret = os.urandom(50).hex()
|
||||||
|
with open('secret.py', 'w') as f:
|
||||||
|
f.write(f'SECRET_KEY = "{secret}"')
|
||||||
|
app.config['SECRET_KEY'] = secret
|
||||||
|
|
||||||
|
|
||||||
def get_calibration(conn: sqlite3.Connection) -> db.Calibration:
|
def get_calibration(conn: sqlite3.Connection) -> db.Calibration:
|
||||||
|
|
@ -51,19 +61,45 @@ def object(id: int):
|
||||||
@app.route('/scan/<id>')
|
@app.route('/scan/<id>')
|
||||||
def scan(id: int):
|
def scan(id: int):
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
|
print(session)
|
||||||
object = db.Object.get_from_id(id, conn)
|
object = db.Object.get_from_id(id, conn)
|
||||||
return render_template('object.html', object=object)
|
return render_template('object.html', object=object)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/calibrate/")
|
@app.route("/calibrate/")
|
||||||
def calibrate():
|
def calibrate():
|
||||||
print(session)
|
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
if 'calibration_id' not in session:
|
if 'calibration_id' not in session:
|
||||||
with conn:
|
with conn:
|
||||||
calibration = db.Calibration.create(conn)
|
calibration = db.Calibration.create(conn)
|
||||||
session['calibration_id'] = calibration.id
|
session['calibration_id'] = calibration.id
|
||||||
return render_template('calibrate.html', leds=config.LEDS_UUIDS)
|
else:
|
||||||
|
calibration = db.Calibration.get_from_id(session['calibration_id'], conn)
|
||||||
|
|
||||||
|
if calibration.state in [db.CalibrationState.Empty, db.CalibrationState.HasData]:
|
||||||
|
return render_template('calibrate.html', leds=config.LEDS_UUIDS)
|
||||||
|
else:
|
||||||
|
return render_template('calibration.html', calibration=calibration)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/new-calibration")
|
||||||
|
def new_calibration():
|
||||||
|
conn = db.get()
|
||||||
|
with conn:
|
||||||
|
calibration = db.Calibration.create(conn)
|
||||||
|
session['calibration_id'] = calibration.id
|
||||||
|
|
||||||
|
return redirect('/calibrate')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/cancel-calibration")
|
||||||
|
def cancel_calibration():
|
||||||
|
conn = db.get()
|
||||||
|
calibration = db.Calibration.get_from_id(session['calibration_id'], conn)
|
||||||
|
calibration.state = db.CalibrationState.HasData
|
||||||
|
with conn:
|
||||||
|
calibration.save(conn)
|
||||||
|
return redirect('/calibrate')
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/preview/<id>")
|
@app.route("/api/preview/<id>")
|
||||||
|
|
@ -102,9 +138,19 @@ def scan_calibration():
|
||||||
return app.response_class(generate(), mimetype='text/plain')
|
return app.response_class(generate(), mimetype='text/plain')
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/calibrate/<id>")
|
@app.route('/api/use-last-calibration')
|
||||||
def run_calibration(id: int):
|
def use_last_calibration():
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
|
calibration = db.Calibration.get_last(conn)
|
||||||
|
session['calibration_id'] = calibration.id
|
||||||
|
print(session);
|
||||||
|
return 'ok'
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/calibrate")
|
||||||
|
def run_calibration():
|
||||||
|
conn = db.get()
|
||||||
|
id = session['calibration_id']
|
||||||
calib = db.Calibration.get_from_id(id, conn)
|
calib = db.Calibration.get_from_id(id, conn)
|
||||||
if calib is None:
|
if calib is None:
|
||||||
return 'oops', 404
|
return 'oops', 404
|
||||||
|
|
@ -133,13 +179,6 @@ def validate_calibration():
|
||||||
return redirect('/')
|
return redirect('/')
|
||||||
|
|
||||||
|
|
||||||
@app.route("/calibration/<id>")
|
|
||||||
def calibration_page(id: int):
|
|
||||||
conn = db.get()
|
|
||||||
calibration = db.Calibration.get_from_id(id, conn)
|
|
||||||
return render_template('calibration.html', calibration=calibration)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/static/<path:path>')
|
@app.route('/static/<path:path>')
|
||||||
def send_static(path):
|
def send_static(path):
|
||||||
return send_from_directory('static', path)
|
return send_from_directory('static', path)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ def print_error(msg: str):
|
||||||
|
|
||||||
def calibrate(input_dir: str):
|
def calibrate(input_dir: str):
|
||||||
# Load all images
|
# Load all images
|
||||||
image_names = sorted(os.listdir(input_dir))
|
image_names = list(filter(lambda x: x != 'calibration.json', sorted(os.listdir(input_dir))))
|
||||||
images = [np.asarray(Image.open(os.path.join(input_dir, x))) for x in image_names]
|
images = [np.asarray(Image.open(os.path.join(input_dir, x))) for x in image_names]
|
||||||
|
|
||||||
# Camera parameters
|
# Camera parameters
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
from os.path import join
|
from os.path import join
|
||||||
|
|
||||||
MODE = 'debug'
|
|
||||||
DATA_DIR = 'data'
|
DATA_DIR = 'data'
|
||||||
|
BACKUPS_DIR = 'data-backups'
|
||||||
CALIBRATION_DIR = join(DATA_DIR, 'calibrations')
|
CALIBRATION_DIR = join(DATA_DIR, 'calibrations')
|
||||||
OBJECT_DIR = join(DATA_DIR, 'objects')
|
OBJECT_DIR = join(DATA_DIR, 'objects')
|
||||||
|
DATABASE_PATH = join(DATA_DIR, 'db.sqlite')
|
||||||
|
SECRET_KEY = 'tobedefined'
|
||||||
|
|
||||||
LEDS_UUIDS = [
|
LEDS_UUIDS = [
|
||||||
'ac59350e-3787-46d2-88fa-743c1d34fe86',
|
'ac59350e-3787-46d2-88fa-743c1d34fe86',
|
||||||
|
|
|
||||||
49
db.py
49
db.py
|
|
@ -1,12 +1,12 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
from datetime import datetime
|
||||||
from flask import g
|
from flask import g
|
||||||
import os
|
import os
|
||||||
from os.path import join
|
from os.path import join
|
||||||
import shutil
|
import shutil
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import sys
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
if __name__ != '__main__':
|
if __name__ != '__main__':
|
||||||
|
|
@ -18,7 +18,7 @@ else:
|
||||||
def get() -> sqlite3.Connection:
|
def get() -> sqlite3.Connection:
|
||||||
if 'db' not in g:
|
if 'db' not in g:
|
||||||
g.db = sqlite3.connect(
|
g.db = sqlite3.connect(
|
||||||
os.environ.get('DATABASE_PATH', 'db.sqlite'),
|
config.DATABASE_PATH,
|
||||||
detect_types=sqlite3.PARSE_DECLTYPES,
|
detect_types=sqlite3.PARSE_DECLTYPES,
|
||||||
)
|
)
|
||||||
g.db.row_factory = sqlite3.Row
|
g.db.row_factory = sqlite3.Row
|
||||||
|
|
@ -69,11 +69,15 @@ class Calibration:
|
||||||
[int(CalibrationState.Empty)]
|
[int(CalibrationState.Empty)]
|
||||||
)
|
)
|
||||||
calibration = Calibration.from_row(response.fetchone())
|
calibration = Calibration.from_row(response.fetchone())
|
||||||
|
if calibration is None:
|
||||||
|
return None
|
||||||
os.makedirs(join(config.CALIBRATION_DIR, str(calibration.id)))
|
os.makedirs(join(config.CALIBRATION_DIR, str(calibration.id)))
|
||||||
return calibration
|
return calibration
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_row(row: sqlite3.Row) -> 'Calibration':
|
def from_row(row: Optional['sqlite3.Row']) -> Optional['Calibration']:
|
||||||
|
if row is None:
|
||||||
|
return None
|
||||||
return Calibration(*row)
|
return Calibration(*row)
|
||||||
|
|
||||||
def save(self, db: sqlite3.Connection):
|
def save(self, db: sqlite3.Connection):
|
||||||
|
|
@ -92,6 +96,15 @@ class Calibration:
|
||||||
)
|
)
|
||||||
return Calibration.from_row(response.fetchone())
|
return Calibration.from_row(response.fetchone())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_last(db: sqlite3.Connection) -> Optional['Calibration']:
|
||||||
|
cur = db.cursor()
|
||||||
|
response = cur.execute(
|
||||||
|
'SELECT ' + Calibration.select_args() + ' FROM calibration WHERE state = 3 ORDER BY id DESC LIMIT 1;',
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
return Calibration.from_row(response.fetchone())
|
||||||
|
|
||||||
|
|
||||||
Calibration.Dummy = Calibration(-1, CalibrationState.Empty)
|
Calibration.Dummy = Calibration(-1, CalibrationState.Empty)
|
||||||
|
|
||||||
|
|
@ -114,7 +127,9 @@ class Acquisition:
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_row(row: sqlite3.Row) -> 'Acquisition':
|
def from_row(row: Optional[sqlite3.Row]) -> Optional['Acquisition']:
|
||||||
|
if row is None:
|
||||||
|
return None
|
||||||
return Acquisition(*row)
|
return Acquisition(*row)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -150,7 +165,9 @@ class Object:
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_row(row: sqlite3.Row) -> 'Object':
|
def from_row(row: Optional[sqlite3.Row]) -> Optional['Object']:
|
||||||
|
if row is None:
|
||||||
|
return None
|
||||||
return Object(*row)
|
return Object(*row)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -192,20 +209,25 @@ class Object:
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if config.MODE != 'debug':
|
# Move current data to backup dir
|
||||||
print('Can only reset db in debug mode')
|
if os.path.isdir(config.DATA_DIR):
|
||||||
sys.exit(1)
|
# Ensure backup dir exists
|
||||||
|
os.makedirs(config.BACKUPS_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
now = datetime.now()
|
||||||
|
dest = join(config.BACKUPS_DIR, f'{now.year}-{now.month:02}-{now.day:02}--{now.hour:02}-{now.minute:02}-{now.second:02}')
|
||||||
|
shutil.move(config.DATA_DIR, dest)
|
||||||
|
|
||||||
|
# Create new empty data dir
|
||||||
|
os.makedirs(config.DATA_DIR, exist_ok=True)
|
||||||
|
|
||||||
db = sqlite3.connect(
|
db = sqlite3.connect(
|
||||||
os.environ.get('DATABASE_PATH', 'db.sqlite'),
|
config.DATABASE_PATH,
|
||||||
detect_types=sqlite3.PARSE_DECLTYPES,
|
detect_types=sqlite3.PARSE_DECLTYPES,
|
||||||
)
|
)
|
||||||
db.row_factory = sqlite3.Row
|
db.row_factory = sqlite3.Row
|
||||||
init(db)
|
init(db)
|
||||||
|
|
||||||
if os.path.isdir(config.DATA_DIR):
|
|
||||||
shutil.rmtree(config.DATA_DIR)
|
|
||||||
|
|
||||||
# Create a new object
|
# Create a new object
|
||||||
with db:
|
with db:
|
||||||
Object.create('Mon premier objet', db)
|
Object.create('Mon premier objet', db)
|
||||||
|
|
@ -230,5 +252,4 @@ def main():
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) > 1 and sys.argv[1] == 'reset':
|
main()
|
||||||
main()
|
|
||||||
|
|
|
||||||
|
|
@ -22,30 +22,30 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="navbarBasicExample" class="navbar-menu">
|
<div id="navbarBasicExample" class="navbar-menu">
|
||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
<a id="calibration-tag-0" class="calibration-tag navbar-item" href="#" {% if calibration.state != 0 %}style="display: none;"{% endif %}>
|
<a id="calibration-tag-0" class="calibration-tag navbar-item" href="/calibrate/" {% if calibration.state != 0 %}style="display: none;"{% endif %}>
|
||||||
<span id="calibration-tag-0" class="tags has-addons">
|
<span id="calibration-tag-0" class="tags has-addons">
|
||||||
<span class="tag is-dark">étalonnage</span>
|
<span class="tag is-dark">étalonnage</span>
|
||||||
<span class="tag is-danger">aucune donnée</span>
|
<span class="tag is-danger">aucune donnée</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a id="calibration-tag-1" class="calibration-tag navbar-item" href="#" {% if calibration.state != 1 %}style="display: none;"{% endif %}>
|
<a id="calibration-tag-1" class="calibration-tag navbar-item" href="/calibrate/" {% if calibration.state != 1 %}style="display: none;"{% endif %}>
|
||||||
<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">non calculé</span>
|
<span class="tag is-warning">non calculé</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a id="calibration-tag-2" class="calibration-tag navbar-item" href="#" {% if calibration.state != 2 %}style="display: none;"{% endif %}>
|
<a id="calibration-tag-2" class="calibration-tag navbar-item" href="/calibrate/" {% if calibration.state != 2 %}style="display: none;"{% endif %}>
|
||||||
<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">non validé</span>
|
<span class="tag is-warning">non validé</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<span id="calibration-tag-3" class="calibration-tag navbar-item" href="#" {% if calibration.state != 3 %}style="display: none;"{% endif %}>
|
<a id="calibration-tag-3" class="calibration-tag navbar-item" href="/calibrate" {% if calibration.state != 3 %}style="display: none;"{% endif %}>
|
||||||
<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-success">validé</span>
|
<span class="tag is-success">validé</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -131,8 +131,8 @@
|
||||||
calibrateButton.addEventListener('click', async () => {
|
calibrateButton.addEventListener('click', async () => {
|
||||||
calibrateButton.classList.add('is-loading');
|
calibrateButton.classList.add('is-loading');
|
||||||
|
|
||||||
await fetch('/api/calibrate/{{ calibration.id }}');
|
await fetch('/api/calibrate');
|
||||||
window.location.href = '/calibration/{{ calibration.id }}';
|
window.location.reload();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<h2 class="title is-3">Vue de la LED selectionnée</h2>
|
<h2 class="title is-3">Vue de la LED selectionnée</h2>
|
||||||
<div>
|
<div>
|
||||||
<img id="led-view">
|
<img id="led-view" style="width: 100%">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -41,13 +41,24 @@
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="field is-grouped is-grouped-right">
|
<div class="field is-horizontal is-grouped is-grouped-right">
|
||||||
<div class="control">
|
{% if calibration.state == CalibrationState.IsValidated %}
|
||||||
<a href="/calibrate" class="button">Retourner à la page d'acquisition</a>
|
<div class="control">
|
||||||
</div>
|
<button disabled class="button">
|
||||||
<div class="control">
|
Cet étalonnage a déjà été validé
|
||||||
<a href="/validate-calibration" class="button is-link">Valider l'étalonnage</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<a href="/new-calibration" class="button is-link">Créer un nouvel étalonnage</a>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="control">
|
||||||
|
<a href="/cancel-calibration" class="button">Retourner à la page d'acquisition</a>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<a href="/validate-calibration" class="button is-link">Valider l'étalonnage</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -77,5 +88,6 @@
|
||||||
{% endblock extracss %}
|
{% endblock extracss %}
|
||||||
|
|
||||||
{% block extrajs %}
|
{% block extrajs %}
|
||||||
|
<script>window.CALIBRATION_ID = {{ calibration.id }};</script>
|
||||||
<script src="/static/calibration-visualiser.js"></script>
|
<script src="/static/calibration-visualiser.js"></script>
|
||||||
{% endblock extrajs %}
|
{% endblock extrajs %}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<a href="/calibrate/" class="button is-link">Étalonner le scanner</a>
|
<a href="/calibrate/" class="button is-link">Étalonner le scanner</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<a href="/calibrate/" class="button is-link">Réutiliser le dernier étalonnage</a>
|
<button id="use-last-calibration-button" href="/use-last-calibration/" class="button is-link">Réutiliser le dernier étalonnage</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -41,5 +41,10 @@
|
||||||
modal.classList.remove('is-active');
|
modal.classList.remove('is-active');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
document.getElementById('use-last-calibration-button').addEventListener('click', async () => {
|
||||||
|
let resp = await fetch('/api/use-last-calibration');
|
||||||
|
await resp.text();
|
||||||
|
window.location.href = '/scan/{{ object.id }}';
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endif %}{% endblock %}
|
{% endif %}{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,13 @@ function getImageElementById(id: string): HTMLImageElement {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
/** This global variable must be set before including this script in the HTML page. */
|
||||||
|
CALIBRATION_ID: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class that manages the interface for the calibration visualisation.
|
* The class that manages the interface for the calibration visualisation.
|
||||||
*/
|
*/
|
||||||
|
|
@ -105,7 +112,7 @@ export class Engine {
|
||||||
|
|
||||||
/** Initialises the engine. */
|
/** Initialises the engine. */
|
||||||
static async create(domId: string) {
|
static async create(domId: string) {
|
||||||
let calibrationId = parseInt(window.location.pathname.split('/')[2], 10);
|
let calibrationId = window.CALIBRATION_ID;
|
||||||
|
|
||||||
let domElement = getElementById(domId);
|
let domElement = getElementById(domId);
|
||||||
let engine = new Engine();
|
let engine = new Engine();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue