Started working on server
This commit is contained in:
parent
3d5d0a6d32
commit
cfe4a2aa54
|
|
@ -0,0 +1,34 @@
|
||||||
|
from flask import Flask, render_template, send_from_directory
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def hello_world():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/calibration")
|
||||||
|
def calibration():
|
||||||
|
return render_template('calibration.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/calibration-data")
|
||||||
|
def calibration_data():
|
||||||
|
# Return dummy output
|
||||||
|
return {
|
||||||
|
'led_0040': [-5.55700564, 8.14046472, 10.54967666],
|
||||||
|
'led_0090': [-7.06683588, 3.12804841, 6.68884105],
|
||||||
|
'led_0070': [4.75589064, -4.53847239, 4.59339772],
|
||||||
|
'led_0020': [-2.70015523, -9.65693344, 9.3807489],
|
||||||
|
'led_0050': [3.26747465, 9.09127322, 8.52493055],
|
||||||
|
'led_0010': [4.69548335, -7.92767838, 7.98930158],
|
||||||
|
'led_0030': [-7.78342731, -3.88182141, 8.52941532],
|
||||||
|
'led_0060': [9.8648123, 3.14267492, 10.09358765],
|
||||||
|
'led_0080': [-3.3681401, -7.6538693, 6.36718535],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/static/<path:path>')
|
||||||
|
def send_static(path):
|
||||||
|
return send_from_directory('static', path)
|
||||||
|
|
@ -18,7 +18,9 @@ def print_error(msg: str):
|
||||||
|
|
||||||
|
|
||||||
def calibrate(input_dir: str):
|
def calibrate(input_dir: str):
|
||||||
images = [np.asarray(Image.open(os.path.join(input_dir, x))) for x in os.listdir(input_dir)]
|
# Load all images
|
||||||
|
image_names = os.listdir(input_dir)
|
||||||
|
images = [np.asarray(Image.open(os.path.join(input_dir, x))) for x in image_names]
|
||||||
|
|
||||||
# Camera parameters
|
# Camera parameters
|
||||||
nu, nv, nc = images[0].shape
|
nu, nv, nc = images[0].shape
|
||||||
|
|
@ -88,7 +90,8 @@ def calibrate(input_dir: str):
|
||||||
# Calculate the positions of the light sources
|
# Calculate the positions of the light sources
|
||||||
light_positions = utils.lines_intersections(sphere_centers, estimated_lights)
|
light_positions = utils.lines_intersections(sphere_centers, estimated_lights)
|
||||||
|
|
||||||
return light_positions
|
# Return value as dictionnary
|
||||||
|
return dict(zip(image_names, light_positions))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,211 @@
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||||
|
|
||||||
|
class Pyramid extends THREE.Object3D {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
let width = 1;
|
||||||
|
let height = 1;
|
||||||
|
let length = 2;
|
||||||
|
|
||||||
|
let vertices = [
|
||||||
|
new THREE.Vector3( 0, 0, 0),
|
||||||
|
new THREE.Vector3( width, height, length),
|
||||||
|
new THREE.Vector3(-width, height, length),
|
||||||
|
new THREE.Vector3(-width, -height, length),
|
||||||
|
new THREE.Vector3( width, -height, length),
|
||||||
|
]
|
||||||
|
|
||||||
|
// Faces
|
||||||
|
{
|
||||||
|
let material = new THREE.MeshPhongMaterial({color: 0xffffff});
|
||||||
|
material.transparent = true;
|
||||||
|
material.opacity = 0.8;
|
||||||
|
|
||||||
|
let geometry = new THREE.BufferGeometry();
|
||||||
|
let faces = [
|
||||||
|
// Sides of the pyramid
|
||||||
|
[0, 2, 1],
|
||||||
|
[0, 3, 2],
|
||||||
|
[0, 4, 3],
|
||||||
|
[0, 1, 4],
|
||||||
|
|
||||||
|
// Base of the pyramid
|
||||||
|
[1, 2, 3],
|
||||||
|
[1, 3, 4],
|
||||||
|
]
|
||||||
|
|
||||||
|
let buffer = new Float32Array(3 * 3 * faces.length);
|
||||||
|
|
||||||
|
for (let faceIndex in faces) {
|
||||||
|
let face = faces[faceIndex];
|
||||||
|
buffer[faceIndex * 3 * 3 + 0] = vertices[face[0]].x;
|
||||||
|
buffer[faceIndex * 3 * 3 + 1] = vertices[face[0]].y;
|
||||||
|
buffer[faceIndex * 3 * 3 + 2] = vertices[face[0]].z;
|
||||||
|
|
||||||
|
buffer[faceIndex * 3 * 3 + 3] = vertices[face[1]].x;
|
||||||
|
buffer[faceIndex * 3 * 3 + 4] = vertices[face[1]].y;
|
||||||
|
buffer[faceIndex * 3 * 3 + 5] = vertices[face[1]].z;
|
||||||
|
|
||||||
|
buffer[faceIndex * 3 * 3 + 6] = vertices[face[2]].x;
|
||||||
|
buffer[faceIndex * 3 * 3 + 7] = vertices[face[2]].y;
|
||||||
|
buffer[faceIndex * 3 * 3 + 8] = vertices[face[2]].z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
geometry.setAttribute('position', new THREE.BufferAttribute(buffer, 3));
|
||||||
|
const mesh = new THREE.Mesh(geometry, material);
|
||||||
|
this.add(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lines
|
||||||
|
{
|
||||||
|
let material = new THREE.LineBasicMaterial({color: 0xff0000});
|
||||||
|
let geometry = new THREE.BufferGeometry();
|
||||||
|
|
||||||
|
let width = 1;
|
||||||
|
let height = 1;
|
||||||
|
let length = 2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let lines = [
|
||||||
|
[0, 1],
|
||||||
|
[0, 2],
|
||||||
|
[0, 3],
|
||||||
|
[0, 4],
|
||||||
|
[1, 2],
|
||||||
|
[2, 3],
|
||||||
|
[3, 4],
|
||||||
|
[4, 1],
|
||||||
|
]
|
||||||
|
|
||||||
|
let buffer = new Float32Array(2 * 3 * lines.length);
|
||||||
|
|
||||||
|
for (let lineIndex in lines) {
|
||||||
|
let line = lines[lineIndex];
|
||||||
|
buffer[lineIndex * 2 * 3 + 0] = vertices[line[0]].x;
|
||||||
|
buffer[lineIndex * 2 * 3 + 1] = vertices[line[0]].y;
|
||||||
|
buffer[lineIndex * 2 * 3 + 2] = vertices[line[0]].z;
|
||||||
|
|
||||||
|
buffer[lineIndex * 2 * 3 + 3] = vertices[line[1]].x;
|
||||||
|
buffer[lineIndex * 2 * 3 + 4] = vertices[line[1]].y;
|
||||||
|
buffer[lineIndex * 2 * 3 + 5] = vertices[line[1]].z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
geometry.setAttribute('position', new THREE.BufferAttribute(buffer, 3));
|
||||||
|
const mesh = new THREE.Line(geometry, material);
|
||||||
|
this.add(mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let renderer, scene, camera, controls, leds, cameraObject, domElement, raycaster, pointer, selectedObject;
|
||||||
|
|
||||||
|
async function init(dataPath, domElementArg = document.body) {
|
||||||
|
let request = await fetch('/api/calibration-data');
|
||||||
|
let data = await request.json();
|
||||||
|
|
||||||
|
domElement = domElementArg;
|
||||||
|
let w = domElement === document.body ? window.innerWidth : domElement.offsetWidth;
|
||||||
|
let h = domElement === document.body ? window.innerHeight : domElement.offsetHeight;
|
||||||
|
|
||||||
|
raycaster = new THREE.Raycaster();
|
||||||
|
|
||||||
|
camera = new THREE.PerspectiveCamera(45, w / h, 0.001, 1000);
|
||||||
|
camera.position.set(0, 0, -50);
|
||||||
|
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
|
||||||
|
leds = new THREE.Object3D();
|
||||||
|
|
||||||
|
for (let key in data) {
|
||||||
|
let row = data[key];
|
||||||
|
const geometry = new THREE.SphereGeometry(1, 32, 16);
|
||||||
|
const material = new THREE.MeshPhongMaterial({ color: 0xffff00 });
|
||||||
|
let sphere = new THREE.Mesh(geometry, material);
|
||||||
|
sphere.position.x = row[0];
|
||||||
|
sphere.position.y = row[1];
|
||||||
|
sphere.position.z = row[2];
|
||||||
|
sphere.name = key
|
||||||
|
leds.add(sphere);
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.add(leds);
|
||||||
|
|
||||||
|
cameraObject = new Pyramid();
|
||||||
|
scene.add(cameraObject);
|
||||||
|
|
||||||
|
const axesHelper = new THREE.AxesHelper(10);
|
||||||
|
scene.add(axesHelper);
|
||||||
|
|
||||||
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
|
||||||
|
scene.add(directionalLight);
|
||||||
|
|
||||||
|
const ambientLight = new THREE.AmbientLight(0xffffff, 0.25);
|
||||||
|
scene.add(ambientLight);
|
||||||
|
|
||||||
|
renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
|
||||||
|
renderer.setAnimationLoop(animate);
|
||||||
|
|
||||||
|
selectedObject = document.getElementById('selected-object');
|
||||||
|
|
||||||
|
// Add listeners
|
||||||
|
controls = new OrbitControls(camera, renderer.domElement);
|
||||||
|
controls.update();
|
||||||
|
|
||||||
|
window.addEventListener('pointermove', onPointerMove);
|
||||||
|
window.addEventListener('resize', onWindowResize, false);
|
||||||
|
onWindowResize();
|
||||||
|
|
||||||
|
domElement.appendChild(renderer.domElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate(time) {
|
||||||
|
controls.update();
|
||||||
|
|
||||||
|
|
||||||
|
if (pointer !== undefined) {
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersects = raycaster.intersectObjects(leds.children);
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
for (let led of leds.children) {
|
||||||
|
if (led === intersects[0].object) {
|
||||||
|
led.material.color.setHex(0xff0000);
|
||||||
|
selectedObject.innerText = led.name;
|
||||||
|
} else {
|
||||||
|
led.material.color.setHex(0xffff00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWindowResize() {
|
||||||
|
let w = domElement === document.body ? window.innerWidth : domElement.offsetWidth;
|
||||||
|
let h = domElement === document.body ? window.innerHeight : domElement.offsetHeight;
|
||||||
|
|
||||||
|
camera.aspect = w / h;
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
renderer.setSize(w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPointerMove(event) {
|
||||||
|
// calculate pointer position in normalized device coordinates
|
||||||
|
// (-1 to +1) for both components
|
||||||
|
|
||||||
|
if (pointer === undefined) {
|
||||||
|
pointer = new THREE.Vector2();
|
||||||
|
}
|
||||||
|
let w = domElement === document.body ? window.innerWidth : domElement.offsetWidth;
|
||||||
|
let h = domElement === document.body ? window.innerHeight : domElement.offsetHeight;
|
||||||
|
pointer.x = (event.offsetX / w) * 2 - 1;
|
||||||
|
pointer.y = - (event.offsetY / h) * 2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { init };
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>NenuScanner</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css">
|
||||||
|
{% block extracss %}
|
||||||
|
|
||||||
|
{% endblock extracss %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar has-shadow is-link is-boxed" role="navigation" aria-label="dropdown navigation">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<a class="navbar-item" href="/"><strong class="is-size-4">NenuScanner</strong></a>
|
||||||
|
|
||||||
|
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div id="navbarBasicExample" class="navbar-menu">
|
||||||
|
<div class="navbar-end">
|
||||||
|
<a class="navbar-item" href="/">
|
||||||
|
Page 1
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{% block content %}{% endblock content %}
|
||||||
|
{% block extrajs %}{% endblock extrajs %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">Visualisation de l'étalonnage</h1>
|
||||||
|
<div id="visualiser">
|
||||||
|
<div id="info">
|
||||||
|
Objet sélectionné : <span id="selected-object">aucun</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
{% block extracss %}
|
||||||
|
<style>
|
||||||
|
#visualiser {
|
||||||
|
height: 50vh;
|
||||||
|
border-color: var(--bulma-title-color);
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock extracss %}
|
||||||
|
|
||||||
|
{% block extrajs %}
|
||||||
|
<script type="importmap">{ "imports": {
|
||||||
|
"three": "https://unpkg.com/three/build/three.module.js",
|
||||||
|
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.165.0/examples/jsm/",
|
||||||
|
"CalibrationVisualiser": "/static/calibration-visualiser.js"
|
||||||
|
} }</script>
|
||||||
|
<script type="module">
|
||||||
|
import { init } from './static/calibration-visualiser.js';
|
||||||
|
init('coucou', document.getElementById('visualiser'));
|
||||||
|
</script>
|
||||||
|
{% endblock extrajs %}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">Bienvenue sur NenuScanner</h1>
|
||||||
|
<p>
|
||||||
|
<a href="/calibration">Cliquez ici pour visualiser l'étalonnage!</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endblock content %}
|
||||||
Loading…
Reference in New Issue