update maxicode detector for experimental_features

This commit is contained in:
Henry Schimke
2023-01-26 10:36:50 -06:00
parent 0b08b3a7ee
commit f5b733ea85

View File

@@ -1,3 +1,4 @@
#![allow(dead_code)]
use num::integer::Roots;
use crate::{
@@ -132,82 +133,84 @@ impl<'a> Circle<'_> {
}
/// detect an ellipse, and try to find defining points of it.
pub fn detect_ellipse(&self) -> ((f32, f32), ((f32, f32), (f32, f32), (f32, f32), (f32, f32))) {
if (self.image.get(self.center.0 + self.radius, self.center.1)
&& self.image.get(self.center.0, self.center.1 + self.radius)
&& self.image.get(self.center.0 - self.radius, self.center.1)
&& self.image.get(self.center.0, self.center.1 - self.radius))
|| self.horizontal_buckets[5] == self.vertical_buckets[5]
{
// probably allready a circle, or we already have true center
/// returns (ellipse, center, semi_major, semi_minor, linear_eccentricity)
pub fn detect_ellipse(&self) -> (bool, (u32, u32), u32, u32, u32) {
// find semi-major and semi-minor axi
let mut lengths = [(0, 0.0, [(0.0_f32, 0.0); 2]); 72];
let mut circle_points = Vec::new();
for i_rotation in 0..72 {
let rotation = i_rotation as f32 * 5.0;
let (length, points) = self.find_width_at_degree(rotation);
circle_points.extend_from_slice(&points);
lengths[i_rotation] = (length, rotation, points);
}
lengths.sort_by_key(|e| e.0);
let major_axis = lengths.last().unwrap();
let minor_axis = lengths.first().unwrap();
//self.center
todo!()
// // find foci
let linear_eccentricity = ((major_axis.0 / 2).pow(2) - (minor_axis.0 / 2).pow(2)).sqrt();
if linear_eccentricity == 0 {
// it's a circle afterall, and we're probably at the center of it
(false, self.center, self.radius, self.radius, 0)
} else {
// this looks like an ellipse, do ellipse magic
// find semi-major and semi-minor axi
let mut lengths = [(0, 0.0, [(0.0_f32, 0.0); 2]); 72];
let mut circle_points = Vec::new();
for i_rotation in 0..72 {
let rotation = i_rotation as f32 * 5.0;
let (length, points) = self.find_width_at_degree(rotation);
circle_points.extend_from_slice(&points);
lengths[i_rotation] = (length, rotation, points);
}
lengths.sort_by_key(|e| e.0);
let major_axis = lengths.last().unwrap();
let minor_axis = lengths.first().unwrap();
// // find foci
let linear_eccentricity =
((major_axis.0 / 2).pow(2) - (minor_axis.0 / 2).pow(2)).sqrt();
if linear_eccentricity == 0 {
// it's a circle afterall, and we're probably at the center of it
//self.center
todo!()
} else {
//it's an elipse, or we're off center, so we need to fix that problem
// let mut good_points = 0;
// let mut bad_points = 0;
let mut found_all_on_ellipse = true;
for point in &circle_points {
let check_result = Self::check_ellipse_point(
self.center,
point,
major_axis.0 / 2,
minor_axis.0 / 2,
);
if check_result > 1.0 {
//&& check_result - Self::ALLOWABLE_ELLIPSE_SLIP > 1.0 {
// a point is off the ellipse
// bad_points += 1;
found_all_on_ellipse = false;
break;
} /*else {
good_points += 1;
}*/
}
if !found_all_on_ellipse {
// probably a circle that we wrongly accused of being an ellipse,
// try to find the center of that circle given two points on circumference
// let point_1 = major_axis.2[0];
// let point_2 = minor_axis.2[1];
// let point_3 = circle_points[((major_axis.0 + 3 + minor_axis.0 + 7) / 2) as usize];
let [point_1, point_2] = self.find_width_at_degree(0.0).1;
let point_3 = self.find_width_at_degree(90.0).1[0];
let guessed_center_point = Self::find_center(point_1, point_2, point_3);
// (
// guessed_center_point.0.round() as u32,
// guessed_center_point.1.round() as u32,
// )
todo!()
//it's an elipse, or we're off center, so we need to fix that problem
let mut good_points = 0;
let mut bad_points = 0;
let mut found_all_on_ellipse = true;
for point in &circle_points {
let check_result = Self::check_ellipse_point(
self.center,
point,
major_axis.0 / 2,
minor_axis.0 / 2,
);
if check_result > 1.0 {
// a point is off the ellipse
bad_points += 1;
found_all_on_ellipse = false;
// break;
} else {
// maybe an actual ellipse
todo!()
good_points += 1;
}
}
if !found_all_on_ellipse
&& (good_points as f32 / (good_points + bad_points) as f32) < 0.8
{
// probably a circle that we wrongly accused of being an ellipse,
// try to find the center of that circle given three points on circumference
let [point_1, point_2] = self.find_width_at_degree(0.0).1;
let point_3 = self.find_width_at_degree(90.0).1[0];
let guessed_center_point = Self::find_center(point_1, point_2, point_3);
(
false,
(guessed_center_point.0 as u32, guessed_center_point.1 as u32),
self.radius,
self.radius,
0,
)
} else {
// this is a real ellipse
// find ellipse center
let [point_1, point_2] = self.find_width_at_degree(0.0).1;
let point_3 = self.find_width_at_degree(90.0).1[0];
let ellipse_center = Self::calculate_ellipse_center(
major_axis.0 as f32,
minor_axis.0 as f32,
point_1,
point_2,
point_3,
);
(
true,
(ellipse_center.0 as u32, ellipse_center.1 as u32),
major_axis.0 / 2,
minor_axis.0 / 2,
linear_eccentricity,
)
}
}
}
@@ -230,6 +233,32 @@ impl<'a> Circle<'_> {
(x.abs(), y.abs())
}
fn calculate_ellipse_center(
a: f32,
_b: f32,
p1: (f32, f32),
p2: (f32, f32),
p3: (f32, f32),
) -> (f32, f32) {
let x1 = p1.0;
let y1 = p1.1;
let x2 = p2.0;
let y2 = p2.1;
let x3 = p3.0;
let y3 = p3.1;
let ma = (x1 * x1 + y1 * y1 - a * a) / 2.0;
let mb = (x2 * x2 + y2 * y2 - a * a) / 2.0;
let mc = (x3 * x3 + y3 * y3 - a * a) / 2.0;
let determinant = (x1 * y2 + x2 * y3 + x3 * y1) - (y1 * x2 + y2 * x3 + y3 * x1);
let x = (ma * y2 + mb * y3 + mc * y1) / determinant;
let y = (x1 * mb + x2 * mc + x3 * ma) / determinant;
(x, y)
}
fn check_ellipse_point(
center: (u32, u32),
point: &(f32, f32),
@@ -248,7 +277,7 @@ impl<'a> Circle<'_> {
// count left
while {
let point = get_point(self.center, (x, y), rotation);
!self.image.get(point.0 as u32, point.1 as u32)
!self.image.get(point.0 as u32, point.1 as u32) && x > 0
} {
x -= 1;
length += 1;
@@ -274,67 +303,6 @@ impl<'a> Circle<'_> {
],
)
}
// fn find_cercumference(&self) -> (u32, Vec<(u32, u32)>) {
// let mut x = self.center.0;
// let mut y = self.center.1;
// let mut points = Vec::new();
// let mut circumference = 0;
// // back up to the left wall
// while !self.image.get(x, y) {
// x -= 1;
// }
// x -= 1;
// // this is our first point
// points.push((x, y));
// let start_x = x;
// let start_y = y;
// loop {
// if x == start_x && y == start_y {
// break;
// }
// circumference += 1;
// points.push((x, y));
// }
// (circumference, points)
// }
// fn find_area(&self) -> u32 {
// let mut pixel_area = 0;
// let mut x = self.center.0;
// let mut y = self.center.1;
// // move to one end
// while !self.image.get(x, y) {
// y -= 1;
// }
// // work our way to the opposite side
// while !self.image.get(x, y) {
// // count left
// x = self.center.0;
// while !self.image.get(x, y) {
// x -= 1;
// pixel_area += 1;
// }
// // count right
// x = self.center.0 + 1;
// while !self.image.get(x, y) {
// x += 1;
// pixel_area += 1;
// }
// y += 1;
// }
// pixel_area
// }
}
pub fn detect(image: &BitMatrix, try_harder: bool) -> Result<MaxicodeDetectionResult, Exceptions> {
@@ -737,8 +705,18 @@ fn box_symbol(image: &BitMatrix, circle: &mut Circle) -> Result<[(f32, f32); 4],
RXingResultPoint::new(right_boundary as f32, top_boundary as f32),
];
#[allow(unused_mut)]
let mut result_box = naive_box;
// check and see if we're dealing with an ellipse
#[cfg(feature = "experimental_features")]
let (is_ellipse, _, _, _, _) = circle.detect_ellipse();
#[cfg(feature = "experimental_features")]
if is_ellipse {
// we don't deal with ellipses yet
return Err(Exceptions::NotFoundException(None));
}
#[cfg(feature = "experimental_features")]
for scale in ACCEPTED_SCALES {
if let Some(found_rotation) = attempt_rotation_box(image, circle, &naive_box, scale) {
@@ -746,11 +724,6 @@ fn box_symbol(image: &BitMatrix, circle: &mut Circle) -> Result<[(f32, f32); 4],
break;
}
}
// let result_box = if let Some(found_rotation) = attempt_rotation_box(image, circle, &naive_box) {
// found_rotation
// } else {
// naive_box
// };
Ok([
(result_box[0].x, result_box[0].y),