mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
update maxicode detector for experimental_features
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
use num::integer::Roots;
|
use num::integer::Roots;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -132,82 +133,84 @@ impl<'a> Circle<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// detect an ellipse, and try to find defining points of it.
|
/// 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))) {
|
/// returns (ellipse, center, semi_major, semi_minor, linear_eccentricity)
|
||||||
if (self.image.get(self.center.0 + self.radius, self.center.1)
|
pub fn detect_ellipse(&self) -> (bool, (u32, u32), u32, u32, u32) {
|
||||||
&& self.image.get(self.center.0, self.center.1 + self.radius)
|
// find semi-major and semi-minor axi
|
||||||
&& self.image.get(self.center.0 - self.radius, self.center.1)
|
let mut lengths = [(0, 0.0, [(0.0_f32, 0.0); 2]); 72];
|
||||||
&& self.image.get(self.center.0, self.center.1 - self.radius))
|
let mut circle_points = Vec::new();
|
||||||
|| self.horizontal_buckets[5] == self.vertical_buckets[5]
|
for i_rotation in 0..72 {
|
||||||
{
|
let rotation = i_rotation as f32 * 5.0;
|
||||||
// probably allready a circle, or we already have true center
|
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
|
// // find foci
|
||||||
todo!()
|
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 {
|
} else {
|
||||||
// this looks like an ellipse, do ellipse magic
|
//it's an elipse, or we're off center, so we need to fix that problem
|
||||||
// find semi-major and semi-minor axi
|
let mut good_points = 0;
|
||||||
let mut lengths = [(0, 0.0, [(0.0_f32, 0.0); 2]); 72];
|
let mut bad_points = 0;
|
||||||
let mut circle_points = Vec::new();
|
let mut found_all_on_ellipse = true;
|
||||||
for i_rotation in 0..72 {
|
for point in &circle_points {
|
||||||
let rotation = i_rotation as f32 * 5.0;
|
let check_result = Self::check_ellipse_point(
|
||||||
let (length, points) = self.find_width_at_degree(rotation);
|
self.center,
|
||||||
circle_points.extend_from_slice(&points);
|
point,
|
||||||
lengths[i_rotation] = (length, rotation, points);
|
major_axis.0 / 2,
|
||||||
}
|
minor_axis.0 / 2,
|
||||||
lengths.sort_by_key(|e| e.0);
|
);
|
||||||
let major_axis = lengths.last().unwrap();
|
if check_result > 1.0 {
|
||||||
let minor_axis = lengths.first().unwrap();
|
// a point is off the ellipse
|
||||||
|
bad_points += 1;
|
||||||
// // find foci
|
found_all_on_ellipse = false;
|
||||||
let linear_eccentricity =
|
// break;
|
||||||
((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!()
|
|
||||||
} else {
|
} else {
|
||||||
// maybe an actual ellipse
|
good_points += 1;
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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())
|
(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(
|
fn check_ellipse_point(
|
||||||
center: (u32, u32),
|
center: (u32, u32),
|
||||||
point: &(f32, f32),
|
point: &(f32, f32),
|
||||||
@@ -248,7 +277,7 @@ impl<'a> Circle<'_> {
|
|||||||
// count left
|
// count left
|
||||||
while {
|
while {
|
||||||
let point = get_point(self.center, (x, y), rotation);
|
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;
|
x -= 1;
|
||||||
length += 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> {
|
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),
|
RXingResultPoint::new(right_boundary as f32, top_boundary as f32),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut result_box = naive_box;
|
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")]
|
#[cfg(feature = "experimental_features")]
|
||||||
for scale in ACCEPTED_SCALES {
|
for scale in ACCEPTED_SCALES {
|
||||||
if let Some(found_rotation) = attempt_rotation_box(image, circle, &naive_box, scale) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// let result_box = if let Some(found_rotation) = attempt_rotation_box(image, circle, &naive_box) {
|
|
||||||
// found_rotation
|
|
||||||
// } else {
|
|
||||||
// naive_box
|
|
||||||
// };
|
|
||||||
|
|
||||||
Ok([
|
Ok([
|
||||||
(result_box[0].x, result_box[0].y),
|
(result_box[0].x, result_box[0].y),
|
||||||
|
|||||||
Reference in New Issue
Block a user