Implement pillow distortion correction
This commit is contained in:
parent
150b3b7fd8
commit
7c3968d2dc
3 changed files with 54 additions and 37 deletions
|
@ -727,8 +727,10 @@ fn update(_app: &App, model: &mut GuiModel, update: Update) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Pincushion / Pillow / Barrel distortion. Generally, only needed for the x-axis
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.add(egui::Slider::new(&mut stream_config.config.filters.pincushion.k_x, 0.0..=2.).text("Pincushion x"))
|
.add(egui::Slider::new(&mut stream_config.config.filters.pincushion.k_x, -0.5..=0.5).text("Pincushion x"))
|
||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
let factor = stream_config.config.filters.pincushion.k_x;
|
let factor = stream_config.config.filters.pincushion.k_x;
|
||||||
|
@ -738,7 +740,17 @@ fn update(_app: &App, model: &mut GuiModel, update: Update) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.add(egui::Slider::new(&mut stream_config.config.filters.pincushion.k_y, 0.0..=2.).text("Pincushion y"))
|
.add(egui::Slider::new(&mut stream_config.config.filters.pincushion.k_x2, -0.2..=0.2).text("Higher order pincushion x"))
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
let factor = stream_config.config.filters.pincushion.k_x2;
|
||||||
|
stream_config.stream.send(move |laser_model: &mut LaserModel| {
|
||||||
|
laser_model.config.filters.pincushion.k_x2 = factor;
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.add(egui::Slider::new(&mut stream_config.config.filters.pincushion.k_y, -0.5..=0.5).text("Pincushion y"))
|
||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
let factor = stream_config.config.filters.pincushion.k_y;
|
let factor = stream_config.config.filters.pincushion.k_y;
|
||||||
|
@ -747,6 +759,16 @@ fn update(_app: &App, model: &mut GuiModel, update: Update) {
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.add(egui::Slider::new(&mut stream_config.config.filters.pincushion.k_y2, -0.2..=0.2).text("Higher order pincushion y"))
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
let factor = stream_config.config.filters.pincushion.k_y2;
|
||||||
|
stream_config.stream.send(move |laser_model: &mut LaserModel| {
|
||||||
|
laser_model.config.filters.pincushion.k_y2 = factor;
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.checkbox(&mut stream_config.config.filters.crop.enabled ,"Crop")
|
.checkbox(&mut stream_config.config.filters.crop.enabled ,"Crop")
|
||||||
|
|
|
@ -34,7 +34,9 @@ pub struct ScaleFilter {
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct PincushionFilter {
|
pub struct PincushionFilter {
|
||||||
pub k_x: f32,
|
pub k_x: f32,
|
||||||
pub k_y: f32
|
pub k_x2: f32,
|
||||||
|
pub k_y: f32,
|
||||||
|
pub k_y2: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Serialize, Deserialize, Clone, Debug)]
|
// #[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
@ -95,7 +97,7 @@ impl Default for PointFilters {
|
||||||
homography: HomographyFilter::default(),
|
homography: HomographyFilter::default(),
|
||||||
dim: DimFilter{intensity: 0.5},
|
dim: DimFilter{intensity: 0.5},
|
||||||
scale: ScaleFilter { factor: 1. },
|
scale: ScaleFilter { factor: 1. },
|
||||||
pincushion: PincushionFilter{k_x: 1., k_y: 1.},
|
pincushion: PincushionFilter{k_x: 0.,k_x2: 0., k_y: 0., k_y2: 0.},
|
||||||
crop: CropFilter{ enabled: true },
|
crop: CropFilter{ enabled: true },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,42 +318,35 @@ impl Filter for PincushionFilter {
|
||||||
|
|
||||||
|
|
||||||
// formula by Ilya Sinenko: https://hackernoon.com/galvo-scanner-pillow-and-barrel-distortions-correction
|
// formula by Ilya Sinenko: https://hackernoon.com/galvo-scanner-pillow-and-barrel-distortions-correction
|
||||||
// x_angle = atan(x_cord / (sqrt(pow(d,2)+pow(y_cord,2))+e))
|
// who states: x_angle = atan(x_cord / (sqrt(pow(d,2)+pow(y_cord,2))+e))
|
||||||
|
// let x = (p[0] / (p[1].abs() + self.k_x )).atan();
|
||||||
|
// let new_position = [x, p[1]];
|
||||||
|
|
||||||
let x = (p[0] / (p[1].abs() + self.k_x )).atan();
|
// Adapted from https://www.geeks3d.com/20140213/glsl-shader-library-fish-eye-and-dome-and-barrel-distortion-post-processing-filters/2/
|
||||||
return [x, p[1]];
|
// let mut radius = (p[0].powi(2) + p[1].powi(2)).sqrt();
|
||||||
|
// let new_position = if radius > 0. {
|
||||||
let mut radius = (p[0].powi(2) + p[1].powi(2)).sqrt();
|
// let theta = p[1].atan2(p[0]);
|
||||||
let new_position = if radius > 0. {
|
// let radius_x = radius.powf(self.k_x);
|
||||||
let theta = p[1].atan2(p[0]);
|
// let radius_y = radius.powf(self.k_y);
|
||||||
let radius_x = radius.powf(self.k_x);
|
// let x = radius_x * theta.cos();
|
||||||
let radius_y = radius.powf(self.k_y);
|
// let y = radius_y * theta.sin();
|
||||||
let x = radius_x * theta.cos();
|
// [x, y]
|
||||||
let y = radius_y * theta.sin();
|
// } else {
|
||||||
[x, y]
|
// p
|
||||||
} else {
|
// };
|
||||||
p
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// // Convert to polar coords:
|
// Apply Brown-Conrady model of distortion
|
||||||
// // float radius = length(v);
|
|
||||||
// if (radius > 0)
|
|
||||||
// {
|
|
||||||
// float theta = atan(v.y,v.x);
|
|
||||||
|
|
||||||
// // Distort:
|
// https://en.wikipedia.org/wiki/Distortion_(optics)#Software_correction
|
||||||
// radius = pow(radius, BarrelPower);
|
// calculate radius (though we might be able to get away, just using p[1] and p[0]
|
||||||
|
// as we calculate axes independently)
|
||||||
|
let radius = (p[0].powi(2) + p[1].powi(2)).sqrt();
|
||||||
|
|
||||||
// // Convert back to Cartesian:
|
let new_position = [
|
||||||
// v.x = radius * cos(theta);
|
p[0] * (1. + self.k_x * radius.powi(2)+ self.k_x2 * radius.powi(4)),
|
||||||
// v.y = radius * sin(theta);
|
p[1] * (1. + self.k_y * radius.powi(2)+ self.k_y2 * radius.powi(4))
|
||||||
// p.xy = v.xy * p.w;
|
];
|
||||||
// }
|
|
||||||
// let new_position = [
|
|
||||||
// p[0] * (1. + self.k_x * p[0].powi(2)),
|
|
||||||
// p[1] * (1. + self.k_y * p[1].powi(2))
|
|
||||||
// ];
|
|
||||||
|
|
||||||
laser::Point {
|
laser::Point {
|
||||||
position: new_position,
|
position: new_position,
|
||||||
|
|
|
@ -164,7 +164,7 @@ impl StreamSource{
|
||||||
color: [0., 0., 0.],
|
color: [0., 0., 0.],
|
||||||
weight: 0,
|
weight: 0,
|
||||||
});
|
});
|
||||||
for j in (0..=0xFFF).step_by(0xFFF / 50) {
|
for j in (0..=0xFFF).step_by(0xFFF / 10) {
|
||||||
points.push(laser::Point{
|
points.push(laser::Point{
|
||||||
position:[i as f32, j as f32],
|
position:[i as f32, j as f32],
|
||||||
color: [1.,1.,1.],
|
color: [1.,1.,1.],
|
||||||
|
@ -180,7 +180,7 @@ impl StreamSource{
|
||||||
color: [0., 0., 0.],
|
color: [0., 0., 0.],
|
||||||
weight: 0,
|
weight: 0,
|
||||||
});
|
});
|
||||||
for j in (0..=0xFFF).step_by(0xFFF / 50) {
|
for j in (0..=0xFFF).step_by(0xFFF / 10) {
|
||||||
points.push(laser::Point{
|
points.push(laser::Point{
|
||||||
position:[j as f32, i as f32],
|
position:[j as f32, i as f32],
|
||||||
color: [1.,1.,1.],
|
color: [1.,1.,1.],
|
||||||
|
|
Loading…
Reference in a new issue