Filters work with cleaner homography, basic map zoom
This commit is contained in:
parent
8cc79b24a7
commit
d2fa6e007c
2 changed files with 38 additions and 20 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Reference in a new issue