From d7f5edc4bc218380c2ea69831733c7d56602cb6e Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Sat, 22 Jun 2024 21:32:44 +0200 Subject: [PATCH] More lights, show plane --- calibration.py | 9 ++++++--- templates/calibration.html | 16 ++++++++++++---- ts/Calibration.ts | 14 ++++++++++++++ ts/CameraObject.ts | 6 +++--- ts/Engine.ts | 19 +++++++++++++++++-- ts/Led.ts | 2 +- utils.py | 17 +++++++++++++++++ 7 files changed, 70 insertions(+), 13 deletions(-) diff --git a/calibration.py b/calibration.py index c24b025..c1c3bb9 100755 --- a/calibration.py +++ b/calibration.py @@ -92,7 +92,8 @@ def calibrate(input_dir: str): # Calculate the positions of the light sources light_positions = utils.lines_intersections(sphere_centers, estimated_lights) - print(estimated_lights) + # Calculate plane parameters from the sphere centers and intersect camera rays with the plane + plane_normal, plane_alpha = utils.plane_parameters_from_points(sphere_centers) # Return value as dictionnary return { @@ -102,6 +103,10 @@ def calibrate(input_dir: str): 'directions': estimated_lights[i].tolist(), } for i, (name, position) in enumerate(zip(image_names, light_positions))], 'spheres': sphere_centers.tolist(), + 'plane': { + 'normal': plane_normal.tolist(), + 'alpha': plane_alpha.tolist(), + } } @@ -115,8 +120,6 @@ def main(): with open('data/calibration.json', 'w') as f: json.dump(calib, f, indent=4) - print(calib) - if __name__ == '__main__': main() diff --git a/templates/calibration.html b/templates/calibration.html index b785b26..f0e20fa 100644 --- a/templates/calibration.html +++ b/templates/calibration.html @@ -22,10 +22,18 @@
- +
+ +
+
+ +
diff --git a/ts/Calibration.ts b/ts/Calibration.ts index e7d418c..49a5dc6 100644 --- a/ts/Calibration.ts +++ b/ts/Calibration.ts @@ -17,6 +17,17 @@ export interface Led { directions: Vector3[]; } +/** + * A 3D plane. + */ +export interface Plane { + /** The normal of the plane. */ + normal: Vector3; + + /** The offset of the plane. */ + alpha: number; +} + /** * Type for the calibration data. */ @@ -26,4 +37,7 @@ export interface Calibration { /** Position of the spheres. */ spheres: Vector3[]; + + /** The coordinates of the plane that best fit the spheres. */ + plane: Plane; } diff --git a/ts/CameraObject.ts b/ts/CameraObject.ts index 3ab834c..cc24c89 100644 --- a/ts/CameraObject.ts +++ b/ts/CameraObject.ts @@ -31,7 +31,7 @@ export default class CameraObject extends THREE.Object3D { // Faces { - let material = new THREE.MeshPhongMaterial({color: 0xffffff}); + let material = new THREE.MeshPhongMaterial({color: 0x00ff00}); material.transparent = true; material.opacity = 0.8; @@ -117,7 +117,7 @@ export default class CameraObject extends THREE.Object3D { */ hover(): void { this.mesh.material.opacity = 1; - this.lines.material.color.setHex(0xff0000); + this.lines.material.color.setHex(0xffffff); } /** @@ -125,7 +125,7 @@ export default class CameraObject extends THREE.Object3D { */ unHover(): void { this.mesh.material.opacity = 0.8; - this.lines.material.color.setHex(0x990000); + this.lines.material.color.setHex(0x999999); } } diff --git a/ts/Engine.ts b/ts/Engine.ts index 9a31eba..8abf411 100644 --- a/ts/Engine.ts +++ b/ts/Engine.ts @@ -46,12 +46,15 @@ export class Engine { /** HTML element on which the renderer will be added. */ domElement: HTMLElement; - /** Checkbox indicating whether wants to show the lines from the spheres to the lights. */ + /** Checkbox indicating whether the user wants to show the lines from the spheres to the lights. */ showLinesCheckbox: HTMLInputElement; /** HTML span where we will show the name of the current selected led. */ selectedObject: HTMLElement; + /** HTML element indicating whether the user wants to show the plane containing all spheres. */ + showPlaneCheckbox: HTMLInputElement; + /** HTML image where we will show the real photo corresponding to the selected led. */ ledView: HTMLImageElement; @@ -73,6 +76,9 @@ export class Engine { /** Object containing all the representations of the spheres (white). */ spheres: THREE.Object3D; + /** The plane that approximates the plane containing the spheres. */ + plane: THREE.Mesh; + /** Axes that will be shown to help the visualisation of the scene. */ axes: THREE.AxesHelper; @@ -123,6 +129,7 @@ export class Engine { */ initHtml(): void { this.showLinesCheckbox = getInputElementById('show-lines'); + this.showPlaneCheckbox = getInputElementById('show-plane'); this.selectedObject = getElementById('selected-object'); this.ledView = getImageElementById('led-view'); } @@ -152,10 +159,17 @@ export class Engine { } this.scene.add(this.spheres); + let normal = new THREE.Vector3(-calibration.plane.normal[1], -calibration.plane.normal[0], calibration.plane.normal[2]); + this.plane = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), new THREE.MeshPhongMaterial({ color: 0x0000ff, side: THREE.DoubleSide, transparent: true, opacity: 0.5 })); + this.plane.lookAt(normal); + this.plane.position.set(0, 0, -calibration.plane.alpha / calibration.plane.normal[2]); + this.plane.visible = this.showPlaneCheckbox.checked; + this.scene.add(this.plane); + this.axes = new THREE.AxesHelper(10); this.scene.add(this.axes); - this.ambientLight = new THREE.AmbientLight(0xffffff, 0.15); + this.ambientLight = new THREE.AmbientLight(0xffffff, 1); this.scene.add(this.ambientLight); this.renderer = new THREE.WebGLRenderer({antialias: true, alpha: true}); @@ -186,6 +200,7 @@ export class Engine { window.addEventListener('pointermove', (e) => this.onPointerMove(e)); window.addEventListener('pointerup', () => this.onPointerUp()); this.showLinesCheckbox.addEventListener('change', () => this.leds.setShowLines(this.showLinesCheckbox.checked)); + this.showPlaneCheckbox.addEventListener('change', () => this.plane.visible = this.showPlaneCheckbox.checked); document.addEventListener('keyup', (e) => { switch (e.code) { case "ArrowDown": diff --git a/ts/Led.ts b/ts/Led.ts index a857bb9..774687a 100644 --- a/ts/Led.ts +++ b/ts/Led.ts @@ -56,7 +56,7 @@ export class Led extends THREE.Mesh treshold[0], grey_levels < treshold[1]) lights = weighted_least_squares(normals, grey_levels, validity_mask) return lights + + +def plane_parameters_from_points(points): + """Computes the parameters of a plane from a set of points. + + Args: + points (Array ..., dim): Coordinates of the points used to define the plane. + + Returns: + Array ..., dim: Normal vector to the plane. + Array ...: Plane constant alpha. + """ + homogeneous = to_homogeneous(points) + E = np.einsum('...ki,...kj->...ij', homogeneous, homogeneous) + L = matrix_kernel(E) + n, alpha = L[..., :-1], L[..., -1] + return n, alpha