Filters work with cleaner homography, basic map zoom

This commit is contained in:
Ruben van de Ven 2025-07-04 14:11:22 +02:00
parent 8cc79b24a7
commit d2fa6e007c
2 changed files with 38 additions and 20 deletions

View file

@ -22,6 +22,8 @@ use std::time::{Instant, Duration};
use std::collections::HashMap; use std::collections::HashMap;
use serde::{Serialize,Deserialize}; use serde::{Serialize,Deserialize};
use nannou::winit::dpi::PhysicalPosition;
use homography::find_homography; use homography::find_homography;
use cv_core::FeatureMatch; use cv_core::FeatureMatch;
// use opencv::prelude::Mat; // use opencv::prelude::Mat;
@ -313,7 +315,7 @@ fn model(app: &App) -> GuiModel {
.new_window() .new_window()
.size(1024, 768) .size(1024, 768)
// .key_pressed(key_pressed) // .key_pressed(key_pressed)
// .mouse_wheel(canvas_zoom) .mouse_wheel(map_wheel_zoom)
.mouse_pressed(map_mouse_pressed) .mouse_pressed(map_mouse_pressed)
.mouse_released(map_mouse_released) .mouse_released(map_mouse_released)
.mouse_moved(map_mouse_moved) .mouse_moved(map_mouse_moved)
@ -743,7 +745,7 @@ fn update(_app: &App, model: &mut GuiModel, update: Update) {
} }
if ui if ui
.add(egui::Slider::new(&mut selected_config.filters.scale.factor, 0.0..=2.).text("Scale")) .add(egui::Slider::new(&mut selected_config.filters.scale.factor, 0.001..=2.).text("Scale"))
.changed() .changed()
{ {
let factor = selected_config.filters.scale.factor; let factor = selected_config.filters.scale.factor;
@ -835,8 +837,9 @@ fn view_line_canvas(app: &App, model: &GuiModel, frame: Frame) {
// get canvas to draw on // get canvas to draw on
let draw = app.draw(); let draw = app.draw();
// set background to blue // LaserPoints supports a mode that sends points directly into the laser
// if this mode is enabled by the sender, set background to blue
// Red if nothing is sending / not for too long.
let bgcolor = match model.current_lines.space { let bgcolor = match model.current_lines.space {
CoordinateSpace::Laser => MEDIUMSLATEBLUE, CoordinateSpace::Laser => MEDIUMSLATEBLUE,
_ => match model.connected{ _ => match model.connected{
@ -852,13 +855,13 @@ fn view_line_canvas(app: &App, model: &GuiModel, frame: Frame) {
let translate_x = model.canvas_translate.x; let translate_x = model.canvas_translate.x;
let translate_y = model.canvas_translate.y; let translate_y = model.canvas_translate.y;
// background grid
draw_grid(&draw, &win, scale, 1.); draw_grid(&draw, &win, scale, 1.);
// let t = app.time;
// let n_points = 10;
let thickness = 2.0; let thickness = 2.0;
draw.ellipse() // draw origin indicator
draw.ellipse()
.x_y(0. + translate_x, 0. + translate_y) .x_y(0. + translate_x, 0. + translate_y)
.radius(3.) .radius(3.)
.color(BLUE); .color(BLUE);
@ -868,9 +871,9 @@ fn view_line_canvas(app: &App, model: &GuiModel, frame: Frame) {
.color(RED) .color(RED)
.points([0. * scale + translate_x, 0. * -scale + translate_y].into(), [1. * scale + translate_x, 0. * -scale + translate_y].into()); .points([0. * scale + translate_x, 0. * -scale + translate_y].into(), [1. * scale + translate_x, 0. * -scale + translate_y].into());
// let hz = ((app.mouse.x + win.right()) / win.w()).powi(4) * 1000.0;
// TODO refactor to using euclid::point2D for scale
// draw current laser lines
for line in &model.current_lines.lines{ for line in &model.current_lines.lines{
let vertices = line.points.iter().map(|p| { let vertices = line.points.iter().map(|p| {
let color = srgba(p.color.red, p.color.green, p.color.blue, p.color.alpha); let color = srgba(p.color.red, p.color.green, p.color.blue, p.color.alpha);
@ -885,6 +888,7 @@ fn view_line_canvas(app: &App, model: &GuiModel, frame: Frame) {
.points_colored(vertices); .points_colored(vertices);
} }
// show each configured laser in the canvas. Highlight the selected.
for (dac_id, config) in model.per_laser_config.iter() { for (dac_id, config) in model.per_laser_config.iter() {
let rect = shape_rect(LaserSpace::READY); let rect = shape_rect(LaserSpace::READY);
let points = config.filters.reverse(&rect); let points = config.filters.reverse(&rect);
@ -893,9 +897,12 @@ fn view_line_canvas(app: &App, model: &GuiModel, frame: Frame) {
let vertices = points.points.iter().map(|p| { let vertices = points.points.iter().map(|p| {
let color = if model.selected_stream == Some(dac_id.clone()) { let color = if model.selected_stream == Some(dac_id.clone()) {
srgba(1.,0.,0.,1.) // Srgba::hex("e52d9f");
// ORCHID. to_srgba()
srgba(229./255.,45./255.,159./255.,0.8)
} else { } else {
srgba(p.color[0], p.color[1], p.color[0], 0.5) // ORCHID;
srgba(1.,1.,1., 0.2)
}; };
let pos = [p.position[0] * scale + translate_x, p.position[1] * -scale + translate_y]; let pos = [p.position[0] * scale + translate_x, p.position[1] * -scale + translate_y];
@ -1094,7 +1101,7 @@ fn map_mouse_moved(_app: &App, model: &mut GuiModel, pos: Point2) {
let distorted_laser_corners: Vec<[f32;2]> = config.filters.reverse_without_homography(&laser_corners).into(); let distorted_laser_corners: Vec<[f32;2]> = config.filters.reverse_without_homography(&laser_corners).into();
// 4. find new homography: // 4. find new homography on pairs of points, and convert to compatible matrix type
let matches: Vec<FeatureMatch<nalgebra::Point2<f64>>> = world_corners.iter().zip(distorted_laser_corners).map(|(world, laser)| { let matches: Vec<FeatureMatch<nalgebra::Point2<f64>>> = world_corners.iter().zip(distorted_laser_corners).map(|(world, laser)| {
FeatureMatch( FeatureMatch(
nalgebra::Point2::new(world[0] as f64, world[1] as f64), nalgebra::Point2::new(world[0] as f64, world[1] as f64),
@ -1102,12 +1109,18 @@ fn map_mouse_moved(_app: &App, model: &mut GuiModel, pos: Point2) {
) )
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
let m = find_homography(matches).unwrap(); let m = find_homography(matches).unwrap();
let mat: Mat3 = Mat3::from_cols_array(&[m[0] as f32, m[1] as f32, m[2] as f32, m[3] as f32, m[4] as f32, m[5] as f32, m[6] as f32, m[7] as f32, m[8] as f32]); let mat: Mat3 = Mat3::from_cols_array(&[m[0] as f32, m[1] as f32, m[2] as f32, m[3] as f32, m[4] as f32, m[5] as f32, m[6] as f32, m[7] as f32, m[8] as f32]);
config.filters.homography.homography_matrix = mat; // 5. update config in Gui and laser stream threat
config.filters.homography.homography_matrix = mat.clone();
let selected_laser_stream = model.laser_streams.get(&dac_id);
if let Some(stream) = selected_laser_stream {
stream.send(move |laser_model: &mut LaserModel| {
laser_model.config.filters.homography.homography_matrix = mat;
}).unwrap();
}
} }
@ -1173,6 +1186,11 @@ fn map_mouse_released(_app: &App, model: &mut GuiModel, _button: MouseButton) {
model.canvas_dragging_corner = None; model.canvas_dragging_corner = None;
} }
fn mouse_wheel(_app: &App, _model: &mut GuiModel, _dt: MouseScrollDelta, _phase: TouchPhase) { fn map_wheel_zoom(_app: &App, model: &mut GuiModel, dt: MouseScrollDelta, _phase: TouchPhase) {
// canvas zoom let (x,y) = match dt {
MouseScrollDelta::PixelDelta(PhysicalPosition::<f64>{ x, y }) => (x as f32, y as f32),
MouseScrollDelta::LineDelta(x, y) => (x,y),
};
model.canvas_scale += y;
} }

View file

@ -149,7 +149,7 @@ impl Filter for HomographyFilter {
let s = 0xFFF as f32 / 2.; let s = 0xFFF as f32 / 2.;
let normalised_pos: [f32;2] = [new_position[0]/s - 1., new_position[1]/s - 1.]; let normalised_pos: [f32;2] = [new_position[0]/s - 1., new_position[1]/s - 1.];
laser::Point { laser::Point {
position: normalised_pos, position: new_position,
.. point.clone() .. point.clone()
} }
@ -165,9 +165,9 @@ impl Filter for HomographyFilter {
let inv_matrix = self.homography_matrix.inverse(); let inv_matrix = self.homography_matrix.inverse();
let projected_positions: Vec<laser::Point> = points.points.iter().map(|point| { let projected_positions: Vec<laser::Point> = points.points.iter().map(|point| {
let s = 0xFFF as f32 / 2.;
let p = point.position; let p = point.position;
let de_normalised_position: [f32;2] = [(p[0] + 1.)*s, (p[1]+1.)*s]; // let s = 0xFFF as f32 / 2.;
// let de_normalised_position: [f32;2] = [(p[0] + 1.)*s, (p[1]+1.)*s];
let new_position = match space { let new_position = match space {
CoordinateSpace::World => p, CoordinateSpace::World => p,
CoordinateSpace::Laser => apply_homography_matrix(inv_matrix, &p), CoordinateSpace::Laser => apply_homography_matrix(inv_matrix, &p),