From 22cabc297540be3cced12b1a1039701d02e32897 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Tue, 30 May 2023 16:11:42 -0500 Subject: [PATCH] ported changes from c++ f80a9b923a14827cc78bb96703676c14ac61c1ed --- src/common/default_grid_sampler.rs | 38 ++++++++++++++++------------- src/common/perspective_transform.rs | 4 +++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/common/default_grid_sampler.rs b/src/common/default_grid_sampler.rs index 46bb135..5b1441e 100644 --- a/src/common/default_grid_sampler.rs +++ b/src/common/default_grid_sampler.rs @@ -19,7 +19,7 @@ // import com.google.zxing.NotFoundException; use crate::common::Result; -use crate::{point_f, Exceptions, Point}; +use crate::{point, point_f, Exceptions, Point}; use super::{BitMatrix, GridSampler, SamplerControl}; @@ -42,22 +42,17 @@ impl GridSampler for DefaultGridSampler { } for SamplerControl { p0, p1, transform } in controls { - // To deal with remaining examples (see #251 and #267) of "numercial instabilities" that have not been - // prevented with the Quadrilateral.h:IsConvex() check, we check for all boundary points of the grid to - // be inside. - let isInside = - |p: Point| -> bool { image.is_in(transform.transform_point(p.centered())) }; - for y in (p0.y as i32)..(p1.y as i32) { - // for (int y = y0; y < y1; ++y) - if !isInside(point_f(p0.x, y as f32)) || !isInside(point_f(p1.x - 1.0, y as f32)) { - return Err(Exceptions::NOT_FOUND); - } - } - for x in (p0.x as i32)..(p1.x as i32) { - // for (int x = x0; x < x1; ++x) - if !isInside(point_f(x as f32, p0.y)) || !isInside(point_f(x as f32, p1.y - 1.0)) { - return Err(Exceptions::NOT_FOUND); - } + // Precheck the corners of every roi to bail out early if the grid is "obviously" not completely inside the image + let isInside = |x: f32, y: f32| { + image.is_in(transform.transform_point(Point::centered(point(x, y)))) + }; + if (!transform.isValid() + || !isInside(p0.x, p0.y) + || !isInside(p1.x - 1.0, p0.y) + || !isInside(p1.x - 1.0, p1.y - 1.0) + || !isInside(p0.x, p1.y - 1.0)) + { + return Err(Exceptions::NOT_FOUND); } } @@ -73,6 +68,15 @@ impl GridSampler for DefaultGridSampler { if image.get_point(p) { bits.set(x as u32, y as u32); } + + // Due to a "numerical instability" in the PerspectiveTransform generation/application it has been observed + // that even though all boundary grid points get projected inside the image, it can still happen that an + // inner grid points is not. See #563. A true perspective transformation cannot have this property. + // The following check takes 100% care of the issue and turned out to be less of a performance impact than feared. + // TODO: Check some mathematical/numercial property of mod2Pix to determine if it is a perspective transforation. + if (!image.is_in(p)) { + return Err(Exceptions::NOT_FOUND); + } } } } diff --git a/src/common/perspective_transform.rs b/src/common/perspective_transform.rs index 4d1e1a0..a0a05b5 100644 --- a/src/common/perspective_transform.rs +++ b/src/common/perspective_transform.rs @@ -176,6 +176,10 @@ impl PerspectiveTransform { self.a11 * self.a22 - self.a12 * self.a21, ) } + + pub fn isValid(&self) -> bool { + !self.a33.is_nan() + } } impl Mul for PerspectiveTransform {