Skip to content

Commit f5b733e

Browse files
committed
update maxicode detector for experimental_features
1 parent 0b08b3a commit f5b733e

File tree

1 file changed

+111
-138
lines changed

1 file changed

+111
-138
lines changed

src/maxicode/detector.rs

+111-138
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(dead_code)]
12
use num::integer::Roots;
23

34
use crate::{
@@ -132,82 +133,84 @@ impl<'a> Circle<'_> {
132133
}
133134

134135
/// detect an ellipse, and try to find defining points of it.
135-
pub fn detect_ellipse(&self) -> ((f32, f32), ((f32, f32), (f32, f32), (f32, f32), (f32, f32))) {
136-
if (self.image.get(self.center.0 + self.radius, self.center.1)
137-
&& self.image.get(self.center.0, self.center.1 + self.radius)
138-
&& self.image.get(self.center.0 - self.radius, self.center.1)
139-
&& self.image.get(self.center.0, self.center.1 - self.radius))
140-
|| self.horizontal_buckets[5] == self.vertical_buckets[5]
141-
{
142-
// probably allready a circle, or we already have true center
143-
144-
//self.center
145-
todo!()
146-
} else {
147-
// this looks like an ellipse, do ellipse magic
148-
// find semi-major and semi-minor axi
149-
let mut lengths = [(0, 0.0, [(0.0_f32, 0.0); 2]); 72];
150-
let mut circle_points = Vec::new();
151-
for i_rotation in 0..72 {
152-
let rotation = i_rotation as f32 * 5.0;
153-
let (length, points) = self.find_width_at_degree(rotation);
154-
circle_points.extend_from_slice(&points);
155-
lengths[i_rotation] = (length, rotation, points);
156-
}
157-
lengths.sort_by_key(|e| e.0);
158-
let major_axis = lengths.last().unwrap();
159-
let minor_axis = lengths.first().unwrap();
160-
161-
// // find foci
162-
let linear_eccentricity =
163-
((major_axis.0 / 2).pow(2) - (minor_axis.0 / 2).pow(2)).sqrt();
136+
/// returns (ellipse, center, semi_major, semi_minor, linear_eccentricity)
137+
pub fn detect_ellipse(&self) -> (bool, (u32, u32), u32, u32, u32) {
138+
// find semi-major and semi-minor axi
139+
let mut lengths = [(0, 0.0, [(0.0_f32, 0.0); 2]); 72];
140+
let mut circle_points = Vec::new();
141+
for i_rotation in 0..72 {
142+
let rotation = i_rotation as f32 * 5.0;
143+
let (length, points) = self.find_width_at_degree(rotation);
144+
circle_points.extend_from_slice(&points);
145+
lengths[i_rotation] = (length, rotation, points);
146+
}
147+
lengths.sort_by_key(|e| e.0);
148+
let major_axis = lengths.last().unwrap();
149+
let minor_axis = lengths.first().unwrap();
164150

165-
if linear_eccentricity == 0 {
166-
// it's a circle afterall, and we're probably at the center of it
151+
// // find foci
152+
let linear_eccentricity = ((major_axis.0 / 2).pow(2) - (minor_axis.0 / 2).pow(2)).sqrt();
167153

168-
//self.center
169-
todo!()
170-
} else {
171-
//it's an elipse, or we're off center, so we need to fix that problem
172-
// let mut good_points = 0;
173-
// let mut bad_points = 0;
174-
let mut found_all_on_ellipse = true;
175-
for point in &circle_points {
176-
let check_result = Self::check_ellipse_point(
177-
self.center,
178-
point,
179-
major_axis.0 / 2,
180-
minor_axis.0 / 2,
181-
);
182-
if check_result > 1.0 {
183-
//&& check_result - Self::ALLOWABLE_ELLIPSE_SLIP > 1.0 {
184-
// a point is off the ellipse
185-
// bad_points += 1;
186-
found_all_on_ellipse = false;
187-
break;
188-
} /*else {
189-
good_points += 1;
190-
}*/
191-
}
192-
if !found_all_on_ellipse {
193-
// probably a circle that we wrongly accused of being an ellipse,
194-
// try to find the center of that circle given two points on circumference
195-
// let point_1 = major_axis.2[0];
196-
// let point_2 = minor_axis.2[1];
197-
// let point_3 = circle_points[((major_axis.0 + 3 + minor_axis.0 + 7) / 2) as usize];
198-
let [point_1, point_2] = self.find_width_at_degree(0.0).1;
199-
let point_3 = self.find_width_at_degree(90.0).1[0];
200-
let guessed_center_point = Self::find_center(point_1, point_2, point_3);
201-
// (
202-
// guessed_center_point.0.round() as u32,
203-
// guessed_center_point.1.round() as u32,
204-
// )
205-
todo!()
154+
if linear_eccentricity == 0 {
155+
// it's a circle afterall, and we're probably at the center of it
156+
(false, self.center, self.radius, self.radius, 0)
157+
} else {
158+
//it's an elipse, or we're off center, so we need to fix that problem
159+
let mut good_points = 0;
160+
let mut bad_points = 0;
161+
let mut found_all_on_ellipse = true;
162+
for point in &circle_points {
163+
let check_result = Self::check_ellipse_point(
164+
self.center,
165+
point,
166+
major_axis.0 / 2,
167+
minor_axis.0 / 2,
168+
);
169+
if check_result > 1.0 {
170+
// a point is off the ellipse
171+
bad_points += 1;
172+
found_all_on_ellipse = false;
173+
// break;
206174
} else {
207-
// maybe an actual ellipse
208-
todo!()
175+
good_points += 1;
209176
}
210177
}
178+
if !found_all_on_ellipse
179+
&& (good_points as f32 / (good_points + bad_points) as f32) < 0.8
180+
{
181+
// probably a circle that we wrongly accused of being an ellipse,
182+
// try to find the center of that circle given three points on circumference
183+
let [point_1, point_2] = self.find_width_at_degree(0.0).1;
184+
let point_3 = self.find_width_at_degree(90.0).1[0];
185+
let guessed_center_point = Self::find_center(point_1, point_2, point_3);
186+
(
187+
false,
188+
(guessed_center_point.0 as u32, guessed_center_point.1 as u32),
189+
self.radius,
190+
self.radius,
191+
0,
192+
)
193+
} else {
194+
// this is a real ellipse
195+
196+
// find ellipse center
197+
let [point_1, point_2] = self.find_width_at_degree(0.0).1;
198+
let point_3 = self.find_width_at_degree(90.0).1[0];
199+
let ellipse_center = Self::calculate_ellipse_center(
200+
major_axis.0 as f32,
201+
minor_axis.0 as f32,
202+
point_1,
203+
point_2,
204+
point_3,
205+
);
206+
(
207+
true,
208+
(ellipse_center.0 as u32, ellipse_center.1 as u32),
209+
major_axis.0 / 2,
210+
minor_axis.0 / 2,
211+
linear_eccentricity,
212+
)
213+
}
211214
}
212215
}
213216

@@ -230,6 +233,32 @@ impl<'a> Circle<'_> {
230233
(x.abs(), y.abs())
231234
}
232235

236+
fn calculate_ellipse_center(
237+
a: f32,
238+
_b: f32,
239+
p1: (f32, f32),
240+
p2: (f32, f32),
241+
p3: (f32, f32),
242+
) -> (f32, f32) {
243+
let x1 = p1.0;
244+
let y1 = p1.1;
245+
let x2 = p2.0;
246+
let y2 = p2.1;
247+
let x3 = p3.0;
248+
let y3 = p3.1;
249+
250+
let ma = (x1 * x1 + y1 * y1 - a * a) / 2.0;
251+
let mb = (x2 * x2 + y2 * y2 - a * a) / 2.0;
252+
let mc = (x3 * x3 + y3 * y3 - a * a) / 2.0;
253+
254+
let determinant = (x1 * y2 + x2 * y3 + x3 * y1) - (y1 * x2 + y2 * x3 + y3 * x1);
255+
256+
let x = (ma * y2 + mb * y3 + mc * y1) / determinant;
257+
let y = (x1 * mb + x2 * mc + x3 * ma) / determinant;
258+
259+
(x, y)
260+
}
261+
233262
fn check_ellipse_point(
234263
center: (u32, u32),
235264
point: &(f32, f32),
@@ -248,7 +277,7 @@ impl<'a> Circle<'_> {
248277
// count left
249278
while {
250279
let point = get_point(self.center, (x, y), rotation);
251-
!self.image.get(point.0 as u32, point.1 as u32)
280+
!self.image.get(point.0 as u32, point.1 as u32) && x > 0
252281
} {
253282
x -= 1;
254283
length += 1;
@@ -274,67 +303,6 @@ impl<'a> Circle<'_> {
274303
],
275304
)
276305
}
277-
278-
// fn find_cercumference(&self) -> (u32, Vec<(u32, u32)>) {
279-
// let mut x = self.center.0;
280-
// let mut y = self.center.1;
281-
// let mut points = Vec::new();
282-
// let mut circumference = 0;
283-
284-
// // back up to the left wall
285-
// while !self.image.get(x, y) {
286-
// x -= 1;
287-
// }
288-
// x -= 1;
289-
290-
// // this is our first point
291-
// points.push((x, y));
292-
293-
// let start_x = x;
294-
// let start_y = y;
295-
296-
// loop {
297-
298-
// if x == start_x && y == start_y {
299-
// break;
300-
// }
301-
// circumference += 1;
302-
// points.push((x, y));
303-
// }
304-
305-
// (circumference, points)
306-
// }
307-
// fn find_area(&self) -> u32 {
308-
// let mut pixel_area = 0;
309-
310-
// let mut x = self.center.0;
311-
// let mut y = self.center.1;
312-
313-
// // move to one end
314-
// while !self.image.get(x, y) {
315-
// y -= 1;
316-
// }
317-
318-
// // work our way to the opposite side
319-
// while !self.image.get(x, y) {
320-
// // count left
321-
// x = self.center.0;
322-
// while !self.image.get(x, y) {
323-
// x -= 1;
324-
// pixel_area += 1;
325-
// }
326-
// // count right
327-
// x = self.center.0 + 1;
328-
// while !self.image.get(x, y) {
329-
// x += 1;
330-
// pixel_area += 1;
331-
// }
332-
333-
// y += 1;
334-
// }
335-
336-
// pixel_area
337-
// }
338306
}
339307

340308
pub fn detect(image: &BitMatrix, try_harder: bool) -> Result<MaxicodeDetectionResult, Exceptions> {
@@ -737,20 +705,25 @@ fn box_symbol(image: &BitMatrix, circle: &mut Circle) -> Result<[(f32, f32); 4],
737705
RXingResultPoint::new(right_boundary as f32, top_boundary as f32),
738706
];
739707

708+
#[allow(unused_mut)]
740709
let mut result_box = naive_box;
741710

711+
// check and see if we're dealing with an ellipse
712+
#[cfg(feature = "experimental_features")]
713+
let (is_ellipse, _, _, _, _) = circle.detect_ellipse();
714+
#[cfg(feature = "experimental_features")]
715+
if is_ellipse {
716+
// we don't deal with ellipses yet
717+
return Err(Exceptions::NotFoundException(None));
718+
}
719+
742720
#[cfg(feature = "experimental_features")]
743721
for scale in ACCEPTED_SCALES {
744722
if let Some(found_rotation) = attempt_rotation_box(image, circle, &naive_box, scale) {
745723
result_box = found_rotation;
746724
break;
747725
}
748726
}
749-
// let result_box = if let Some(found_rotation) = attempt_rotation_box(image, circle, &naive_box) {
750-
// found_rotation
751-
// } else {
752-
// naive_box
753-
// };
754727

755728
Ok([
756729
(result_box[0].x, result_box[0].y),

0 commit comments

Comments
 (0)