More lights, show plane

This commit is contained in:
Thomas Forgione 2024-06-22 21:32:44 +02:00
parent 0f424ad039
commit d7f5edc4bc
7 changed files with 70 additions and 13 deletions

View File

@ -92,7 +92,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)
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 value as dictionnary
return { return {
@ -102,6 +103,10 @@ def calibrate(input_dir: str):
'directions': estimated_lights[i].tolist(), 'directions': estimated_lights[i].tolist(),
} for i, (name, position) in enumerate(zip(image_names, light_positions))], } for i, (name, position) in enumerate(zip(image_names, light_positions))],
'spheres': sphere_centers.tolist(), '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: with open('data/calibration.json', 'w') as f:
json.dump(calib, f, indent=4) json.dump(calib, f, indent=4)
print(calib)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -22,10 +22,18 @@
</div> </div>
</div> </div>
<div> <div>
<label class="checkbox"> <div>
<input type="checkbox" id="show-lines"> <label class="checkbox">
Afficher les droites <input type="checkbox" id="show-lines">
</label> Afficher les directions de la lumière pour chaque sphère
</label>
</div>
<div>
<label class="checkbox">
<input type="checkbox" id="show-plane">
Afficher le plan contenant les sphères
</label>
</div>
</div> </div>
</div> </div>
</section> </section>

View File

@ -17,6 +17,17 @@ export interface Led {
directions: Vector3[]; 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. * Type for the calibration data.
*/ */
@ -26,4 +37,7 @@ export interface Calibration {
/** Position of the spheres. */ /** Position of the spheres. */
spheres: Vector3[]; spheres: Vector3[];
/** The coordinates of the plane that best fit the spheres. */
plane: Plane;
} }

View File

@ -31,7 +31,7 @@ export default class CameraObject extends THREE.Object3D {
// Faces // Faces
{ {
let material = new THREE.MeshPhongMaterial({color: 0xffffff}); let material = new THREE.MeshPhongMaterial({color: 0x00ff00});
material.transparent = true; material.transparent = true;
material.opacity = 0.8; material.opacity = 0.8;
@ -117,7 +117,7 @@ export default class CameraObject extends THREE.Object3D {
*/ */
hover(): void { hover(): void {
this.mesh.material.opacity = 1; 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 { unHover(): void {
this.mesh.material.opacity = 0.8; this.mesh.material.opacity = 0.8;
this.lines.material.color.setHex(0x990000); this.lines.material.color.setHex(0x999999);
} }
} }

View File

@ -46,12 +46,15 @@ export class Engine {
/** HTML element on which the renderer will be added. */ /** HTML element on which the renderer will be added. */
domElement: HTMLElement; 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; showLinesCheckbox: HTMLInputElement;
/** HTML span where we will show the name of the current selected led. */ /** HTML span where we will show the name of the current selected led. */
selectedObject: HTMLElement; 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. */ /** HTML image where we will show the real photo corresponding to the selected led. */
ledView: HTMLImageElement; ledView: HTMLImageElement;
@ -73,6 +76,9 @@ export class Engine {
/** Object containing all the representations of the spheres (white). */ /** Object containing all the representations of the spheres (white). */
spheres: THREE.Object3D; spheres: THREE.Object3D;
/** The plane that approximates the plane containing the spheres. */
plane: THREE.Mesh<THREE.PlaneGeometry, THREE.MeshPhongMaterial>;
/** Axes that will be shown to help the visualisation of the scene. */ /** Axes that will be shown to help the visualisation of the scene. */
axes: THREE.AxesHelper; axes: THREE.AxesHelper;
@ -123,6 +129,7 @@ export class Engine {
*/ */
initHtml(): void { initHtml(): void {
this.showLinesCheckbox = getInputElementById('show-lines'); this.showLinesCheckbox = getInputElementById('show-lines');
this.showPlaneCheckbox = getInputElementById('show-plane');
this.selectedObject = getElementById('selected-object'); this.selectedObject = getElementById('selected-object');
this.ledView = getImageElementById('led-view'); this.ledView = getImageElementById('led-view');
} }
@ -152,10 +159,17 @@ export class Engine {
} }
this.scene.add(this.spheres); 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.axes = new THREE.AxesHelper(10);
this.scene.add(this.axes); 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.scene.add(this.ambientLight);
this.renderer = new THREE.WebGLRenderer({antialias: true, alpha: true}); 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('pointermove', (e) => this.onPointerMove(e));
window.addEventListener('pointerup', () => this.onPointerUp()); window.addEventListener('pointerup', () => this.onPointerUp());
this.showLinesCheckbox.addEventListener('change', () => this.leds.setShowLines(this.showLinesCheckbox.checked)); this.showLinesCheckbox.addEventListener('change', () => this.leds.setShowLines(this.showLinesCheckbox.checked));
this.showPlaneCheckbox.addEventListener('change', () => this.plane.visible = this.showPlaneCheckbox.checked);
document.addEventListener('keyup', (e) => { document.addEventListener('keyup', (e) => {
switch (e.code) { switch (e.code) {
case "ArrowDown": case "ArrowDown":

View File

@ -56,7 +56,7 @@ export class Led extends THREE.Mesh<THREE.SphereGeometry, THREE.MeshBasicMateria
this.lines.visible = false; this.lines.visible = false;
this.add(this.lines); this.add(this.lines);
this.light = new THREE.PointLight(0xffffff, 100); this.light = new THREE.PointLight(0xffffff, 1000);
this.light.visible = false; this.light.visible = false;
this.add(this.light); this.add(this.light);
} }

View File

@ -505,3 +505,20 @@ def estimate_light(normals, grey_levels, treshold=(0, 1)):
validity_mask = np.logical_and(grey_levels > treshold[0], grey_levels < treshold[1]) validity_mask = np.logical_and(grey_levels > treshold[0], grey_levels < treshold[1])
lights = weighted_least_squares(normals, grey_levels, validity_mask) lights = weighted_least_squares(normals, grey_levels, validity_mask)
return lights 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