mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-28 05:12:34 +00:00
DetectPureQR ported
This commit is contained in:
@@ -559,33 +559,6 @@ impl BitMatrix {
|
|||||||
Some([left, top, right - left + 1, bottom - top + 1])
|
Some([left, top, right - left + 1, bottom - top + 1])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn
|
|
||||||
findBoundingBox(&self, left:&mut u32, top:&mut u32, width:&mut u32, height:&mut u32, minSize:u32) -> bool
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
// let right;
|
|
||||||
// let bottom;
|
|
||||||
// if (!self.getTopLeftOnBitWithPosition(left, top) || !self.getBottomRightOnBitWithPosition(right, bottom) || bottom - top + 1 < minSize)
|
|
||||||
// {return false;}
|
|
||||||
|
|
||||||
// for (int y = top; y <= bottom; y++ ) {
|
|
||||||
// for (int x = 0; x < left; ++x)
|
|
||||||
// if (get(x, y)) {
|
|
||||||
// left = x;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// for (int x = _width-1; x > right; x--)
|
|
||||||
// if (get(x, y)) {
|
|
||||||
// right = x;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// width = right - left + 1;
|
|
||||||
// height = bottom - top + 1;
|
|
||||||
// return width >= minSize && height >= minSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is useful in detecting a corner of a 'pure' barcode.
|
* This is useful in detecting a corner of a 'pure' barcode.
|
||||||
*
|
*
|
||||||
|
|||||||
61
src/common/cpp_essentials/bitmatrix.rs
Normal file
61
src/common/cpp_essentials/bitmatrix.rs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
use crate::common::BitMatrix;
|
||||||
|
use crate::common::Result;
|
||||||
|
use crate::point;
|
||||||
|
|
||||||
|
impl BitMatrix {
|
||||||
|
pub fn Deflate(
|
||||||
|
&self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
top: f32,
|
||||||
|
left: f32,
|
||||||
|
subSampling: f32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let mut result = BitMatrix::new(width, height)?;
|
||||||
|
|
||||||
|
for y in 0..result.height() {
|
||||||
|
// for (int y = 0; y < result.height(); y++) {
|
||||||
|
let yOffset = top + y as f32 * subSampling;
|
||||||
|
for x in 0..result.width() {
|
||||||
|
// for (int x = 0; x < result.width(); x++) {
|
||||||
|
if (self.get_point(point(left + x as f32 * subSampling, yOffset))) {
|
||||||
|
result.set(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn findBoundingBox(
|
||||||
|
&self,
|
||||||
|
left: &mut u32,
|
||||||
|
top: &mut u32,
|
||||||
|
width: &mut u32,
|
||||||
|
height: &mut u32,
|
||||||
|
minSize: u32,
|
||||||
|
) -> bool {
|
||||||
|
todo!()
|
||||||
|
// let right;
|
||||||
|
// let bottom;
|
||||||
|
// if (!self.getTopLeftOnBitWithPosition(left, top) || !self.getBottomRightOnBitWithPosition(right, bottom) || bottom - top + 1 < minSize)
|
||||||
|
// {return false;}
|
||||||
|
|
||||||
|
// for (int y = top; y <= bottom; y++ ) {
|
||||||
|
// for (int x = 0; x < left; ++x)
|
||||||
|
// if (get(x, y)) {
|
||||||
|
// left = x;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// for (int x = _width-1; x > right; x--)
|
||||||
|
// if (get(x, y)) {
|
||||||
|
// right = x;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// width = right - left + 1;
|
||||||
|
// height = bottom - top + 1;
|
||||||
|
// return width >= minSize && height >= minSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -165,9 +165,7 @@ pub trait BitMatrixCursorTrait {
|
|||||||
|
|
||||||
fn d(&self) -> Point;
|
fn d(&self) -> Point;
|
||||||
|
|
||||||
|
fn readPattern<T>(&self, range: Option<u32>) -> Option<T> {
|
||||||
fn readPattern<T>(&self, range : Option<u32>) -> Option<T>
|
|
||||||
{
|
|
||||||
// let range = range.unwrap_or(0);
|
// let range = range.unwrap_or(0);
|
||||||
// let mut res :T;
|
// let mut res :T;
|
||||||
// for i in res.into_iter() {
|
// for i in res.into_iter() {
|
||||||
@@ -179,12 +177,14 @@ pub trait BitMatrixCursorTrait {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn readPatternFromBlack<T>(&self, maxWhitePrefix: i32, range: Option<u32>) -> Option<T> {
|
||||||
fn readPatternFromBlack<T>(&self, maxWhitePrefix:i32, range: Option<u32>) -> Option<T>
|
|
||||||
{
|
|
||||||
let range = range.unwrap_or(0);
|
let range = range.unwrap_or(0);
|
||||||
if (maxWhitePrefix != 0 && self.isWhite() && !self.stepToEdge(Some(1), Some(maxWhitePrefix), None) > 0)
|
if (maxWhitePrefix != 0
|
||||||
{return None;}
|
&& self.isWhite()
|
||||||
|
&& !self.stepToEdge(Some(1), Some(maxWhitePrefix), None) > 0)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
// return readPattern<ARRAY>(range);
|
// return readPattern<ARRAY>(range);
|
||||||
self.readPattern(Some(range))
|
self.readPattern(Some(range))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
mod bitmatrix;
|
||||||
pub mod bitmatrix_cursor;
|
pub mod bitmatrix_cursor;
|
||||||
pub mod bitmatrix_cursor_trait;
|
pub mod bitmatrix_cursor_trait;
|
||||||
pub mod concentric_finder;
|
pub mod concentric_finder;
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ impl std::ops::IndexMut<usize> for PatternRow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Vec<PatternType>> for PatternRow {
|
||||||
|
fn from(value: Vec<PatternType>) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for PatternView<'_> {
|
impl<'a> Iterator for PatternView<'_> {
|
||||||
type Item = PatternType;
|
type Item = PatternType;
|
||||||
|
|
||||||
|
|||||||
@@ -750,61 +750,102 @@ pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result<QRCodeDetect
|
|||||||
* around it. This is a specialized method that works exceptionally fast in this special
|
* around it. This is a specialized method that works exceptionally fast in this special
|
||||||
* case.
|
* case.
|
||||||
*/
|
*/
|
||||||
pub fn DetectPureQR( image:&BitMatrix) -> Result<QRCodeDetectorResult>
|
pub fn DetectPureQR(image: &BitMatrix) -> Result<QRCodeDetectorResult> {
|
||||||
{
|
|
||||||
type Pattern = Vec<PatternType>;
|
type Pattern = Vec<PatternType>;
|
||||||
|
|
||||||
// #ifdef PRINT_DEBUG
|
// #ifdef PRINT_DEBUG
|
||||||
// SaveAsPBM(image, "weg.pbm");
|
// SaveAsPBM(image, "weg.pbm");
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
const MIN_MODULES: u32 = Version::DimensionOfVersion(1, false);
|
const MIN_MODULES: u32 = Version::DimensionOfVersion(1, false);
|
||||||
const MAX_MODULES:u32 = Version::DimensionOfVersion(40, false);
|
const MAX_MODULES: u32 = Version::DimensionOfVersion(40, false);
|
||||||
|
|
||||||
let left;
|
let left;
|
||||||
let top;
|
let top;
|
||||||
let width;
|
let width;
|
||||||
let height;
|
let height;
|
||||||
|
|
||||||
if (!image.findBoundingBox(left, top, width, height, MIN_MODULES) || std::abs(width - height) > 1)
|
if (!image.findBoundingBox(left, top, width, height, MIN_MODULES)
|
||||||
{return Err(Exceptions::NOT_FOUND)}
|
|| (*width as i32 - *height as i32).abs() > 1)
|
||||||
let right = left + width - 1;
|
{
|
||||||
let bottom = top + height - 1;
|
return Err(Exceptions::NOT_FOUND);
|
||||||
|
}
|
||||||
|
let right = *left + *width - 1;
|
||||||
|
let bottom = *top + *height - 1;
|
||||||
|
|
||||||
let tl = point_i(*left, *top);
|
let tl = point_i(*left, *top);
|
||||||
let tr = point_i(*right, *top);
|
let tr = point_i(right, *top);
|
||||||
let bl = point_i(*left, *bottom);
|
let bl = point_i(*left, bottom);
|
||||||
let diagonal : Pattern;
|
let diagonal: Pattern;
|
||||||
// allow corners be moved one pixel inside to accommodate for possible aliasing artifacts
|
// allow corners be moved one pixel inside to accommodate for possible aliasing artifacts
|
||||||
for [p,d] in [[tl, point_i(1,1)], [tr, point(-1.0,1.0)], [bl, point(1.0,-1.0)]] {
|
for [p, d] in [
|
||||||
|
[tl, point_i(1, 1)],
|
||||||
|
[tr, point(-1.0, 1.0)],
|
||||||
|
[bl, point(1.0, -1.0)],
|
||||||
|
] {
|
||||||
// for (auto [p, d] : {std::pair(tl, PointI{1, 1}), {tr, {-1, 1}}, {bl, {1, -1}}}) {
|
// for (auto [p, d] : {std::pair(tl, PointI{1, 1}), {tr, {-1, 1}}, {bl, {1, -1}}}) {
|
||||||
diagonal = EdgeTracer::new(image, p, d).readPatternFromBlack(1, width / 3 + 1).ok_or(Exceptions::NOT_FOUND)?;
|
diagonal = EdgeTracer::new(image, p, d)
|
||||||
|
.readPatternFromBlack(1, Some(*width / 3 + 1))
|
||||||
|
.ok_or(Exceptions::NOT_FOUND)?;
|
||||||
// diagonal = BitMatrixCursorI(image, p, d).readPatternFromBlack<Pattern>(1, width / 3 + 1);
|
// diagonal = BitMatrixCursorI(image, p, d).readPatternFromBlack<Pattern>(1, width / 3 + 1);
|
||||||
if (!IsPattern(diagonal, PATTERN) != 0.0)
|
let view = PatternView::new(&diagonal.into());
|
||||||
{return Err(Exceptions::NOT_FOUND);}
|
if (!(IsPattern(&view, &PATTERN, None, 0.0, 0.0, None) != 0.0)) {
|
||||||
|
return Err(Exceptions::NOT_FOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let fpWidth = Reduce(diagonal);
|
let fpWidth = diagonal.iter().sum::<u16>() as i32; //Reduce(diagonal);
|
||||||
let dimension =
|
let dimension = EstimateDimension(
|
||||||
EstimateDimension(image, {tl + fpWidth / 2 * PointF(1, 1), fpWidth}, {tr + fpWidth / 2 * PointF(-1, 1), fpWidth}).dim;
|
image,
|
||||||
|
ConcentricPattern {
|
||||||
|
p: tl + fpWidth as f32 / 2.0 * point_i(1, 1),
|
||||||
|
size: fpWidth,
|
||||||
|
},
|
||||||
|
ConcentricPattern {
|
||||||
|
p: tr + fpWidth as f32 / 2.0 * point(-1.0, 1.0),
|
||||||
|
size: fpWidth,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.dim;
|
||||||
|
|
||||||
let moduleSize:f32 = float(width) / dimension;
|
let moduleSize: f32 = ((*width) as f32) / dimension as f32;
|
||||||
if (dimension < MIN_MODULES || dimension > MAX_MODULES ||
|
if (dimension < MIN_MODULES as i32
|
||||||
!image.isIn(PointF{left + moduleSize / 2 + (dimension - 1) * moduleSize,
|
|| dimension > MAX_MODULES as i32
|
||||||
top + moduleSize / 2 + (dimension - 1) * moduleSize}))
|
|| !image.is_in(point(
|
||||||
{return Err(Exceptions::NOT_FOUND);}
|
*left as f32 + moduleSize / 2.0 + (dimension - 1) as f32 * moduleSize as f32,
|
||||||
|
*top as f32 + moduleSize / 2.0 + (dimension - 1) as f32 * moduleSize,
|
||||||
|
)))
|
||||||
|
{
|
||||||
|
return Err(Exceptions::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
// #ifdef PRINT_DEBUG
|
// #ifdef PRINT_DEBUG
|
||||||
// LogMatrix log;
|
// LogMatrix log;
|
||||||
// LogMatrixWriter lmw(log, image, 5, "grid2.pnm");
|
// LogMatrixWriter lmw(log, image, 5, "grid2.pnm");
|
||||||
// for (int y = 0; y < dimension; y++)
|
// for (int y = 0; y < dimension; y++)
|
||||||
// for (int x = 0; x < dimension; x++)
|
// for (int x = 0; x < dimension; x++)
|
||||||
// log(PointF(left + (x + .5f) * moduleSize, top + (y + .5f) * moduleSize));
|
// log(PointF(left + (x + .5f) * moduleSize, top + (y + .5f) * moduleSize));
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// Now just read off the bits (this is a crop + subsample)
|
// Now just read off the bits (this is a crop + subsample)
|
||||||
return {Deflate(image, dimension, dimension, top + moduleSize / 2, left + moduleSize / 2, moduleSize),
|
Ok(QRCodeDetectorResult {
|
||||||
{{left, top}, {right, top}, {right, bottom}, {left, bottom}}};
|
bit_source: image.Deflate(
|
||||||
|
dimension as u32,
|
||||||
|
dimension as u32,
|
||||||
|
*top as f32 + moduleSize / 2.0,
|
||||||
|
*left as f32 + moduleSize / 2.0,
|
||||||
|
moduleSize,
|
||||||
|
)?,
|
||||||
|
result_points: vec![
|
||||||
|
point_i(*left, *top),
|
||||||
|
point_i(right, *top),
|
||||||
|
point_i(right, bottom),
|
||||||
|
point_i(*left, bottom),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
// return {Deflate(image, dimension, dimension, top + moduleSize / 2, left + moduleSize / 2, moduleSize),
|
||||||
|
// {{left, top}, {right, top}, {right, bottom}, {left, bottom}}};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn DetectPureMQR( image:&BitMatrix) -> Result<QRCodeDetectorResult>
|
pub fn DetectPureMQR( image:&BitMatrix) -> Result<QRCodeDetectorResult>
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ pub fn point_g<T: TryInto<f32>>(x: T, y: T) -> Option<Point> {
|
|||||||
Some(Point::new(x.try_into().ok()?, y.try_into().ok()?))
|
Some(Point::new(x.try_into().ok()?, y.try_into().ok()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn point_i(x: u32, y: u32) -> Point {
|
pub fn point_i<T: Into<i64>>(x: T, y: T) -> Point {
|
||||||
Point::new(x as f32, y as f32)
|
Point::new(x.into() as f32, y.into() as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Currently necessary because the external OneDReader proc macro uses it. */
|
/** Currently necessary because the external OneDReader proc macro uses it. */
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ fn test_binarizer_init_empty() {
|
|||||||
assert!(rxing::helpers::detect_multiple_in_luma(DATA.to_vec(), 665, 286).is_ok())
|
assert!(rxing::helpers::detect_multiple_in_luma(DATA.to_vec(), 665, 286).is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
static DATA: [u8; 190190] = [
|
const DATA: [u8; 190190] = [
|
||||||
220, 224, 216, 219, 221, 223, 221, 217, 216, 212, 203, 207, 213, 214, 208, 209, 218, 223, 221,
|
220, 224, 216, 219, 221, 223, 221, 217, 216, 212, 203, 207, 213, 214, 208, 209, 218, 223, 221,
|
||||||
218, 212, 210, 202, 204, 209, 203, 211, 212, 216, 220, 223, 223, 221, 220, 219, 219, 219, 217,
|
218, 212, 210, 202, 204, 209, 203, 211, 212, 216, 220, 223, 223, 221, 220, 219, 219, 219, 217,
|
||||||
214, 213, 215, 215, 213, 214, 214, 209, 203, 204, 212, 219, 221, 220, 225, 221, 208, 202, 205,
|
214, 213, 215, 215, 213, 214, 214, 209, 203, 204, 212, 219, 221, 220, 225, 221, 208, 202, 205,
|
||||||
|
|||||||
Reference in New Issue
Block a user