adding result points to sampler

This commit is contained in:
Henry Schimke
2023-04-22 11:44:37 -05:00
parent d3ce9fcb90
commit 789719d3eb
10 changed files with 148 additions and 91 deletions

View File

@@ -13,7 +13,7 @@ exclude = [
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
regex = "1.7.1" regex = "1.8.0"
fancy-regex = "0.11" fancy-regex = "0.11"
once_cell = "1.17.1" once_cell = "1.17.1"
encoding = "0.2" encoding = "0.2"

View File

@@ -83,6 +83,14 @@ impl BitArray {
(self.bits[i / 32] & (1 << (i & 0x1F))) != 0 (self.bits[i / 32] & (1 << (i & 0x1F))) != 0
} }
pub fn try_get(&self, i:usize) -> Option<bool> {
if (i / 32) >= self.bits.len() {
None
}else {
Some(self.get(i))
}
}
/** /**
* Sets bit i. * Sets bit i.
* *

View File

@@ -222,6 +222,10 @@ impl BitMatrix {
// ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 // ((self.bits[offset] >> (x & 0x1f)) & 1) != 0
} }
pub fn get_index<T: Into<usize>>(&self, index: T) -> bool {
todo!()
}
#[inline(always)] #[inline(always)]
fn get_offset(&self, y: u32, x: u32) -> usize { fn get_offset(&self, y: u32, x: u32) -> usize {
y as usize * self.row_size + (x as usize / 32) y as usize * self.row_size + (x as usize / 32)
@@ -748,6 +752,19 @@ impl fmt::Display for BitMatrix {
} }
} }
impl From<&BitMatrix> for Vec<bool> {
fn from(value: &BitMatrix) -> Self {
let mut arr = vec![false;(value.width * value.height) as usize];
for x in 0..value.width {
for y in 0..value.height {
let insert_pos = ((y * value.width) + x )as usize;
arr[insert_pos] = value.get(x, y);
}
}
arr
}
}
#[cfg(feature = "image")] #[cfg(feature = "image")]
/// This should only be used if you *know* that the `DynamicImage` is binary. /// This should only be used if you *know* that the `DynamicImage` is binary.
impl TryFrom<image::DynamicImage> for BitMatrix { impl TryFrom<image::DynamicImage> for BitMatrix {

View File

@@ -68,7 +68,7 @@ pub fn ReadSymmetricPattern<const N: usize, Cursor: BitMatrixCursorTrait>(
for i in 0..=s_2 { for i in 0..=s_2 {
// for (int i = 0; i <= s_2; ++i) { // for (int i = 0; i <= s_2; ++i) {
if !next(cur, i) != 0 || !next(&mut cuo, -i) != 0 { if !next(cur, i) == 0 || !next(&mut cuo, -i) == 0 {
return None; return None;
} }
} }
@@ -124,14 +124,14 @@ pub fn CheckSymmetricPattern<
} }
} }
if !(IsPattern( if IsPattern(
&PatternView::new(&res), &PatternView::new(&res),
&FixedPattern::<LEN, SUM, false>::with_reference(pattern), &FixedPattern::<LEN, SUM, false>::with_reference(pattern),
None, None,
0.0, 0.0,
0.0, 0.0,
Some(RELAXED_THRESHOLD), Some(RELAXED_THRESHOLD),
) != 0.0) ) == 0.0
{ {
return 0; return 0;
} }
@@ -220,9 +220,9 @@ pub fn CenterOfRing(
n += 1; n += 1;
// find out if we come full circle around the center. 8 bits have to be set in the end. // find out if we come full circle around the center. 8 bits have to be set in the end.
neighbourMask |= 1 neighbourMask |= (1
<< (4.0 + Point::dot(Point::bresenhamDirection(cur.p() - center), point(1.0, 3.0))) << (4.0 + Point::dot(Point::round(Point::bresenhamDirection(cur.p() - center)), point(1.0, 3.0)))
as u32; as u32);
if !cur.stepAlongEdge(edgeDir, None) { if !cur.stepAlongEdge(edgeDir, None) {
return None; return None;

View File

@@ -182,7 +182,7 @@ impl<'a> EdgeTracer<'_> {
EdgeTracer { EdgeTracer {
img: image, img: image,
p, p,
d, d: Point::bresenhamDirection(d), //d,
history: None, history: None,
state: 0, state: 0,
} }

View File

@@ -1,5 +1,3 @@
use crate::common::BitArray;
use super::BitMatrixCursorTrait; use super::BitMatrixCursorTrait;
pub struct FastEdgeToEdgeCounter { pub struct FastEdgeToEdgeCounter {
@@ -7,66 +5,77 @@ pub struct FastEdgeToEdgeCounter {
// int stride = 0; // int stride = 0;
// int stepsToBorder = 0; // int stepsToBorder = 0;
p: u32, // = nullptr; p: u32, // = nullptr;
stride: u32, // = 0; stride: isize, // = 0;
stepsToBorder: u32, // = 0; stepsToBorder: i32, // = 0;
arr: BitArray, //arr: BitArray,
_arr: isize,
under_arry: Vec<bool>,
} }
impl FastEdgeToEdgeCounter { impl FastEdgeToEdgeCounter {
pub fn new<T: BitMatrixCursorTrait>(cur: &T) -> Self { pub fn new<T: BitMatrixCursorTrait>(cur: &T) -> Self {
let stride = cur.d().y as u32 * cur.img().width() as u32 + cur.d().x as u32; let stride = cur.d().y as isize * cur.img().width() as isize + cur.d().x as isize;
let p = /*cur.img().getRow(cur.p().y).begin()*/ 0 + cur.p().x as u32; let p = ((cur.p().y as isize * cur.img().width() as isize).abs() as i32 + cur.p().x as i32) as u32; // P IS SET WRONG IN REVERSE
let maxStepsX = if cur.d().x != 0.0 { let maxStepsX = if cur.d().x != 0.0 {
(if cur.d().x > 0.0 { if cur.d().x > 0.0 {
cur.img().width() - 1 - cur.p().x as u32 cur.img().width() - 1 - cur.p().x as u32
} else { } else {
cur.p().x as u32 cur.p().x as u32
}) }
} else { } else {
u32::MAX u32::MAX
}; };
let maxStepsY = if cur.d().y != 0.0 { let maxStepsY = if cur.d().y != 0.0 {
(if cur.d().y > 0.0 { if cur.d().y > 0.0 {
cur.img().height() - 1 - cur.p().y as u32 cur.img().height() - 1 - cur.p().y as u32
} else { } else {
cur.p().y as u32 cur.p().y as u32
}) }
} else { } else {
u32::MAX u32::MAX
}; };
let stepsToBorder = std::cmp::min(maxStepsX, maxStepsY); let stepsToBorder = std::cmp::min(maxStepsX, maxStepsY) as i32;
Self { Self {
p, p,
stride, stride,
stepsToBorder, stepsToBorder,
arr: cur.img().getRow(cur.p().y as u32), _arr: cur.p().y as isize * stride as isize, //cur.img().getRow(cur.p().y as u32),
under_arry: cur.img().into(),
} }
} }
pub fn stepToNextEdge(&mut self, range: u32) -> u32 { pub fn stepToNextEdge(&mut self, range: u32) -> u32 {
let maxSteps = std::cmp::min(self.stepsToBorder, range); let maxSteps = std::cmp::min(self.stepsToBorder, range as i32);
let mut steps = 0; let mut steps = 0;
loop { loop {
steps += 1; steps += 1;
if (steps > maxSteps) { if steps > maxSteps {
if (maxSteps == self.stepsToBorder) { if maxSteps == self.stepsToBorder {
break; break false;
} else { } else {
return 0; return 0;
} }
} }
if !(self.arr.get((self.p + steps * self.stride) as usize)
== self.arr.get((self.p + 0) as usize))
{
break;
}
} // while (p[steps * stride] == p[0]);
self.p += steps * self.stride; let idx_pt = self.get_array_check_index(steps);
if !(self.under_arry[idx_pt]
== self.under_arry[self.p as usize])
{
break true;
}
}; // while (p[steps * stride] == p[0]);
self.p = (self.p as isize + (steps as isize * self.stride)).abs() as u32;
self.stepsToBorder -= steps; self.stepsToBorder -= steps;
return steps; return steps as u32;
}
#[inline(always)]
fn get_array_check_index(&self, steps: i32) -> usize {
(self.p as isize + (steps as isize * self.stride)) as usize
} }
} }

View File

@@ -60,17 +60,22 @@ impl From<Vec<PatternType>> for PatternRow {
} }
} }
impl<'a> Iterator for PatternView<'_> { pub struct PatternViewIterator<'a> {
pattern_view: &'a PatternView<'a>,
current_position: usize,
}
impl<'a> Iterator for PatternViewIterator<'_> {
type Item = PatternType; type Item = PatternType;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.current + 1 > self.count { if self.current_position + 1 > self.pattern_view.count {
return None; return None;
} }
self.current += 1; self.current_position += 1;
Some(*self.data.0.get(self.current + self.start)?) Some(*self.pattern_view.data.0.get(self.current_position - 1 + self.pattern_view.start + self.pattern_view.current)?)
} }
} }
@@ -82,7 +87,7 @@ pub struct PatternView<'a> {
current: usize, current: usize,
} }
impl<'a> PatternView<'_> { impl<'a> PatternView<'a> {
// A PatternRow always starts with the width of whitespace in front of the first black bar. // A PatternRow always starts with the width of whitespace in front of the first black bar.
// The first element of the PatternView is the first bar. // The first element of the PatternView is the first bar.
pub fn new(bars: &'a PatternRow) -> PatternView<'a> { pub fn new(bars: &'a PatternRow) -> PatternView<'a> {
@@ -126,6 +131,10 @@ impl<'a> PatternView<'_> {
// int sum(int n = 0) const { return std::accumulate(_data, _data + (n == 0 ? _size : n), 0); } // int sum(int n = 0) const { return std::accumulate(_data, _data + (n == 0 ? _size : n), 0); }
pub fn sum(&self, n: Option<usize>) -> PatternType { pub fn sum(&self, n: Option<usize>) -> PatternType {
if self.count == self.data.len() {
return self.data.0.iter().sum::<PatternType>();
}
let n = n.unwrap_or(self.count); let n = n.unwrap_or(self.count);
self.data self.data
@@ -137,6 +146,10 @@ impl<'a> PatternView<'_> {
.sum::<PatternType>() .sum::<PatternType>()
} }
pub fn iter(&'a self) -> PatternViewIterator<'a> {
PatternViewIterator { pattern_view: self, current_position: 0 }
}
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
self.count self.count
} }
@@ -149,8 +162,7 @@ impl<'a> PatternView<'_> {
self.data self.data
.0 .0
.iter() .iter()
.skip(self.start) .take(self.start + self.current)
.take(self.current)
.copied() .copied()
.sum::<PatternType>() /*return std::accumulate(_base, _data, 0);*/ .sum::<PatternType>() /*return std::accumulate(_base, _data, 0);*/
} }
@@ -170,8 +182,8 @@ impl<'a> PatternView<'_> {
} }
pub fn isValidWithN(&self, n: usize) -> bool { pub fn isValidWithN(&self, n: usize) -> bool {
!self.data.0.is_empty() !self.data.0.is_empty()
&& self.start <= self.current && self.start <= self.current + self.start
&& self.start + n <= (self.start + self.count) && self.current + n <= (self.data.0.len())
/*return _data && _data >= _base && _data + n <= _end;*/ /*return _data && _data >= _base && _data + n <= _end;*/
} }
pub fn isValid(&self) -> bool { pub fn isValid(&self) -> bool {
@@ -201,7 +213,7 @@ impl<'a> PatternView<'_> {
// return (acceptIfAtLastBar && isAtLastBar()) || _data[_size] >= sum() * scale; // return (acceptIfAtLastBar && isAtLastBar()) || _data[_size] >= sum() * scale;
// } // }
pub fn subView(&'a self, offset: usize, size: Option<usize>) -> PatternView<'a> { pub fn subView(&self, offset: usize, size: Option<usize>) -> PatternView<'a> {
let mut size = size.unwrap_or(0); let mut size = size.unwrap_or(0);
if size == 0 { if size == 0 {
size = self.count - offset; size = self.count - offset;
@@ -252,7 +264,7 @@ impl<'a> PatternView<'_> {
} }
pub fn extend(&mut self) { pub fn extend(&mut self) {
self.count = std::cmp::max(0, self.count - self.start) self.count = std::cmp::max(0, self.data.len() - (self.current + self.start))
} }
fn try_get_index(&self, index: isize) -> Option<PatternType> { fn try_get_index(&self, index: isize) -> Option<PatternType> {
@@ -275,6 +287,10 @@ impl<'a> std::ops::Index<isize> for PatternView<'_> {
type Output = PatternType; type Output = PatternType;
fn index(&self, index: isize) -> &Self::Output { fn index(&self, index: isize) -> &Self::Output {
if self.count == self.data.len() {
return &self.data[index.abs() as usize]
}
if index > self.data.0.len() as isize { if index > self.data.0.len() as isize {
panic!("array index out of bounds") panic!("array index out of bounds")
} }
@@ -294,6 +310,10 @@ impl<'a> std::ops::Index<usize> for PatternView<'_> {
type Output = PatternType; type Output = PatternType;
fn index(&self, index: usize) -> &Self::Output { fn index(&self, index: usize) -> &Self::Output {
if self.count == self.data.len() {
return &self.data[index]
}
if index > self.data.0.len() { if index > self.data.0.len() {
panic!("array index out of bounds") panic!("array index out of bounds")
} }
@@ -442,7 +462,7 @@ pub fn IsPattern<const LEN: usize, const SUM: usize, const SPARSE: bool>(
return 0.0; return 0.0;
} }
if (module_size_ref == 0.0) { if module_size_ref == 0.0 {
module_size_ref = module_size; module_size_ref = module_size;
} }
@@ -485,7 +505,7 @@ pub fn IsRightGuard<const N: usize, const SUM: usize, const IS_SPARCE: bool>(
} }
pub fn FindLeftGuardBy<'a, const LEN: usize, Pred: Fn(&PatternView, Option<f32>) -> bool>( pub fn FindLeftGuardBy<'a, const LEN: usize, Pred: Fn(&PatternView, Option<f32>) -> bool>(
view: &'a PatternView, view: PatternView<'a>,
minSize: usize, minSize: usize,
isGuard: Pred, isGuard: Pred,
) -> Result<PatternView<'a>> { ) -> Result<PatternView<'a>> {
@@ -517,7 +537,7 @@ pub fn FindLeftGuardBy<'a, const LEN: usize, Pred: Fn(&PatternView, Option<f32>)
} }
pub fn FindLeftGuard<'a, const LEN: usize, const SUM: usize, const IS_SPARCE: bool>( pub fn FindLeftGuard<'a, const LEN: usize, const SUM: usize, const IS_SPARCE: bool>(
view: &'a PatternView, view: PatternView<'a>,
minSize: usize, minSize: usize,
pattern: &FixedPattern<LEN, SUM, IS_SPARCE>, pattern: &FixedPattern<LEN, SUM, IS_SPARCE>,
minQuietZone: f32, minQuietZone: f32,
@@ -526,8 +546,8 @@ pub fn FindLeftGuard<'a, const LEN: usize, const SUM: usize, const IS_SPARCE: bo
// perform a fast plausability test for 1:1:3:1:1 pattern // perform a fast plausability test for 1:1:3:1:1 pattern
// dbg!(window[2], 2 as PatternType * std::cmp::max(window[0], window[4])); // dbg!(window[2], 2 as PatternType * std::cmp::max(window[0], window[4]));
// dbg!(window[2] < std::cmp::max(window[1], window[3])); // dbg!(window[2] < std::cmp::max(window[1], window[3]));
if (window[2] < 2 as PatternType * std::cmp::max(window[0], window[4]) if window[2] < 2 as PatternType * std::cmp::max(window[0], window[4])
|| window[2] < std::cmp::max(window[1], window[3])) || window[2] < std::cmp::max(window[1], window[3])
{ {
return false; return false;
} }

View File

@@ -36,7 +36,7 @@ impl GridSampler for DefaultGridSampler {
dimensionX: u32, dimensionX: u32,
dimensionY: u32, dimensionY: u32,
controls: &[SamplerControl], controls: &[SamplerControl],
) -> Result<BitMatrix> { ) -> Result<(BitMatrix,[Point;4])> {
if dimensionX <= 0 || dimensionY <= 0 { if dimensionX <= 0 || dimensionY <= 0 {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
} }
@@ -89,11 +89,11 @@ impl GridSampler for DefaultGridSampler {
Point::default() Point::default()
}; };
let _tl = projectCorner(point(0.0, 0.0)); let tl = projectCorner(point(0.0, 0.0));
let _tr = projectCorner(Point::from((dimensionX, 0))); let tr = projectCorner(Point::from((dimensionX, 0)));
let _bl = projectCorner(Point::from((dimensionX, dimensionY))); let bl = projectCorner(Point::from((dimensionX, dimensionY)));
let _br = projectCorner(Point::from((0, dimensionX))); let br = projectCorner(Point::from((0, dimensionX)));
Ok(bits) Ok((bits, [tl,tr,bl,br]))
} }
} }

View File

@@ -95,7 +95,7 @@ pub trait GridSampler {
dimensionY: u32, dimensionY: u32,
dst: Quadrilateral, dst: Quadrilateral,
src: Quadrilateral, src: Quadrilateral,
) -> Result<BitMatrix> { ) -> Result<(BitMatrix,[Point;4])> {
let transform = PerspectiveTransform::quadrilateralToQuadrilateral(dst, src)?; let transform = PerspectiveTransform::quadrilateralToQuadrilateral(dst, src)?;
self.sample_grid( self.sample_grid(
@@ -112,7 +112,7 @@ pub trait GridSampler {
dimensionX: u32, dimensionX: u32,
dimensionY: u32, dimensionY: u32,
controls: &[SamplerControl], controls: &[SamplerControl],
) -> Result<BitMatrix> { ) -> Result<(BitMatrix,[Point;4])> {
if dimensionX == 0 || dimensionY == 0 { if dimensionX == 0 || dimensionY == 0 {
return Err(Exceptions::NOT_FOUND); return Err(Exceptions::NOT_FOUND);
} }
@@ -172,7 +172,7 @@ pub trait GridSampler {
} }
// dbg!(bits.to_string()); // dbg!(bits.to_string());
Ok(bits) Ok((bits, [Point::default(), Point::default(), Point::default(), Point::default()]))
} }
/** /**

View File

@@ -37,6 +37,8 @@ pub type FinderPatternSets = Vec<FinderPatternSet>;
const PATTERN: FixedPattern<5, 7, false> = FixedPattern::new([1, 1, 3, 1, 1]); const PATTERN: FixedPattern<5, 7, false> = FixedPattern::new([1, 1, 3, 1, 1]);
/// Locate the finder patterns for the symbol.
/// This function can panic
pub fn FindFinderPatterns(image: &BitMatrix, tryHarder: bool) -> FinderPatterns { pub fn FindFinderPatterns(image: &BitMatrix, tryHarder: bool) -> FinderPatterns {
const MIN_SKIP: u32 = 3; // 1 pixel/module times 3 modules/center const MIN_SKIP: u32 = 3; // 1 pixel/module times 3 modules/center
const MAX_MODULES_FAST: u32 = 20 * 4 + 17; // support up to version 20 for mobile clients const MAX_MODULES_FAST: u32 = 20 * 4 + 17; // support up to version 20 for mobile clients
@@ -61,15 +63,12 @@ pub fn FindFinderPatterns(image: &BitMatrix, tryHarder: bool) -> FinderPatterns
let mut next: PatternView = PatternView::new(&row); let mut next: PatternView = PatternView::new(&row);
while { while {
if let Ok(next) = FindLeftGuard(&next, 0, &PATTERN, 0.5) { if let Ok(up_next) = FindLeftGuard(next, 0, &PATTERN, 0.5) {
next = up_next;
next.isValid() next.isValid()
} else { } else {
false false
} }
// let Ok(next) = FindLeftGuard(&next, 0, &PATTERN, 0.5) else {
// break;
// };
// next.isValid()
} { } {
let p = point( let p = point(
next.pixelsInFront() as f32 next.pixelsInFront() as f32
@@ -90,7 +89,7 @@ pub fn FindFinderPatterns(image: &BitMatrix, tryHarder: bool) -> FinderPatterns
image, image,
&PATTERN.into(), &PATTERN.into(),
p, p,
next.sum::<u16>() as i32 * 3, next.iter().sum::<u16>() as i32 * 3,
); // 3 for very skewed samples ); // 3 for very skewed samples
// Reduce(next) * 3); // 3 for very skewed samples // Reduce(next) * 3); // 3 for very skewed samples
if (pattern.is_some()) { if (pattern.is_some()) {
@@ -336,12 +335,13 @@ pub fn TraceLine(image: &BitMatrix, p: Point, d: Point, edge: i32) -> impl Regre
for dir in [Direction::Left, Direction::Right] { for dir in [Direction::Left, Direction::Right] {
// for (auto dir : {Direction::LEFT, Direction::RIGHT}) { // for (auto dir : {Direction::LEFT, Direction::RIGHT}) {
let mut c = EdgeTracer::new(image, curI.p, curI.direction(dir)); let mut c = EdgeTracer::new(image, curI.p, curI.direction(dir));
let stepCount = (Point::maxAbsComponent(cur.p - p)) as i32; let mut stepCount = (Point::maxAbsComponent(cur.p - p)) as i32;
loop { loop {
line.add(Point::centered(c.p)) line.add(Point::centered(c.p))
.expect("could not add point on line"); .expect("could not add point on line");
if !(--stepCount > 0 && c.stepAlongEdge(dir, Some(true))) { stepCount -= 1;
if !(stepCount > 0 && c.stepAlongEdge(dir, Some(true))) {
break; break;
} }
} //while (--stepCount > 0 && c.stepAlongEdge(dir, true)); } //while (--stepCount > 0 && c.stepAlongEdge(dir, true));
@@ -731,9 +731,10 @@ pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result<QRCodeDetect
} }
} }
let grid_sampler = DefaultGridSampler::default(); let grid_sampler = DefaultGridSampler::default();
let (sampled,rp) = grid_sampler.sample_grid(image, dimension as u32, dimension as u32, &rois)?;
let result = QRCodeDetectorResult::new( let result = QRCodeDetectorResult::new(
grid_sampler.sample_grid(image, dimension as u32, dimension as u32, &rois)?, sampled,
Vec::default(), rp.to_vec(),
); );
return Ok(result); return Ok(result);
// grid_sampler.sample_grid(image, dimension, dimension, &rois); // grid_sampler.sample_grid(image, dimension, dimension, &rois);
@@ -741,8 +742,7 @@ pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result<QRCodeDetect
} }
let grid_sampler = DefaultGridSampler::default(); let grid_sampler = DefaultGridSampler::default();
let result = QRCodeDetectorResult::new( let (sampled,rps) = grid_sampler.sample_grid(
grid_sampler.sample_grid(
image, image,
dimension as u32, dimension as u32,
dimension as u32, dimension as u32,
@@ -751,8 +751,10 @@ pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result<QRCodeDetect
p1: point_i(0, dimension as u32), p1: point_i(0, dimension as u32),
transform: mod2Pix, transform: mod2Pix,
}], }],
)?, )?;
Vec::default(), let result = QRCodeDetectorResult::new(
sampled,
rps.to_vec(),
); );
Ok(result) Ok(result)
// return SampleGrid(image, dimension, dimension, mod2Pix); // return SampleGrid(image, dimension, dimension, mod2Pix);
@@ -1018,8 +1020,7 @@ pub fn SampleMQR(image: &BitMatrix, fp: ConcentricPattern) -> Result<QRCodeDetec
} }
let grid_sampler = DefaultGridSampler::default(); let grid_sampler = DefaultGridSampler::default();
Ok(QRCodeDetectorResult::new( let (sample, rps) =grid_sampler.sample_grid(
grid_sampler.sample_grid(
image, image,
dim, dim,
dim, dim,
@@ -1028,8 +1029,10 @@ pub fn SampleMQR(image: &BitMatrix, fp: ConcentricPattern) -> Result<QRCodeDetec
p1: point_i(0, dim as u32), p1: point_i(0, dim as u32),
transform: bestPT, transform: bestPT,
}], }],
)?, )?;
Vec::default(), Ok(QRCodeDetectorResult::new(
sample,
rps.to_vec(),
)) ))
// SampleGrid(image, dim, dim, bestPT) // SampleGrid(image, dim, dim, bestPT)