perfect images of aztec pass, real world fail

This commit is contained in:
Henry Schimke
2022-09-29 17:46:23 -05:00
parent 0048f68594
commit 4e88a2ca6c
15 changed files with 843 additions and 494 deletions

View File

@@ -67,6 +67,16 @@ fn test_error_in_parameter_locator_not_compact() {
test_error_in_parameter_locator(&format!("{}{}{}", alphabet, alphabet, alphabet));
}
#[test]
fn test_aztec_rxing_result_sample() {
let matrix = BitMatrix::parse_strings(TEST_BARCODE, "X ", " ").expect("string parse success");
let r = Detector::new(matrix).detect(false);
assert!(r.is_ok());
let r = r.expect("result already tested as ok");
let res = decoder::decode(&r).expect("decode success");
assert_eq!("Histórico", res.getText());
}
// Test that we can tolerate errors in the parameter locator bits
fn test_error_in_parameter_locator(data: &str) {
let aztec = encoder::encoder::encode(data, 25, encoder::encoder::DEFAULT_AZTEC_LAYERS)
@@ -260,3 +270,80 @@ fn get_orientation_points(code: &AztecCode) -> Vec<Point> {
}
return result;
}
const TEST_BARCODE: &str = r" X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
";

View File

@@ -177,8 +177,8 @@ fn testAztecWriter() {
);
// Test AztecWriter defaults
let data = "In ut magna vel mauris malesuada";
// let writer = AztecWriter{};
let matrix = AztecWriter::encode(data, &BarcodeFormat::AZTEC, 0, 0).expect("matrix must exist");
let writer = AztecWriter{};
let matrix = writer.encode(data, &BarcodeFormat::AZTEC, 0, 0).expect("matrix must exist");
let aztec = encoder::encode(
data,
encoder::DEFAULT_EC_PERCENT,
@@ -732,7 +732,7 @@ fn testWriter(
EncodeHintType::ERROR_CORRECTION,
EncodeHintValue::ErrorCorrection(ecc_percent.to_string()),
);
let mut matrix = AztecWriter::encode_with_hints(data, &BarcodeFormat::AZTEC, 0, 0, &hints)
let mut matrix = AztecWriter{}.encode_with_hints(data, &BarcodeFormat::AZTEC, 0, 0, &hints)
.expect("encoder created");
let cset = match charset {

View File

@@ -20,7 +20,7 @@ use crate::{
common::{DecoderRXingResult, DetectorRXingResult},
exceptions::Exceptions,
BarcodeFormat, BinaryBitmap, DecodeHintType, DecodeHintValue, RXingResult,
RXingResultMetadataType, Reader, RXingResultMetadataValue,
RXingResultMetadataType, RXingResultMetadataValue, Reader,
};
use super::{decoder, detector::Detector};
@@ -40,7 +40,7 @@ impl Reader for AztecReader {
* @throws NotFoundException if a Data Matrix code cannot be found
* @throws FormatException if a Data Matrix code cannot be decoded
*/
fn decode(&self,image: &BinaryBitmap) -> Result<RXingResult, Exceptions> {
fn decode(&self, image: &BinaryBitmap) -> Result<RXingResult, Exceptions> {
self.decode_with_hints(image, &HashMap::new())
}
@@ -52,11 +52,19 @@ impl Reader for AztecReader {
// let notFoundException = None;
// let formatException = None;
let mut detector = Detector::new(image.getBlackMatrix()?.clone());
let mut points;
let mut decoderRXingResult: DecoderRXingResult;
let points;
let decoderRXingResult: DecoderRXingResult;
// try {
let detectorRXingResult = detector.detect(false)?;
let detectorRXingResult = if let Ok(det) = detector.detect(false) {
det
} else if let Ok(det) = detector.detect(true) {
det
} else {
return Err(Exceptions::NotFoundException(
"barcode not found".to_owned(),
));
};
points = detectorRXingResult.getPoints();
decoderRXingResult = decoder::decode(&detectorRXingResult)?;
@@ -67,9 +75,9 @@ impl Reader for AztecReader {
// }
// if (decoderRXingResult == null) {
// try {
let detectorRXingResult = detector.detect(true)?;
points = detectorRXingResult.getPoints();
decoderRXingResult = decoder::decode(&detectorRXingResult)?;
// let detectorRXingResult = detector.detect(true)?;
// points = detectorRXingResult.getPoints();
// decoderRXingResult = decoder::decode(&detectorRXingResult)?;
// } catch (NotFoundException | FormatException e) {
// if (notFoundException != null) {
// throw notFoundException;
@@ -101,19 +109,26 @@ impl Reader for AztecReader {
.as_millis(),
);
let byteSegments = decoderRXingResult.getByteSegments();
if !byteSegments.is_empty() {
result.putMetadata(RXingResultMetadataType::BYTE_SEGMENTS, RXingResultMetadataValue::ByteSegments(byteSegments.clone()));
result.putMetadata(
RXingResultMetadataType::BYTE_SEGMENTS,
RXingResultMetadataValue::ByteSegments(byteSegments.clone()),
);
}
let ecLevel = decoderRXingResult.getECLevel();
if !ecLevel.is_empty() {
result.putMetadata(RXingResultMetadataType::ERROR_CORRECTION_LEVEL, RXingResultMetadataValue::ErrorCorrectionLevel(ecLevel.to_owned()));
result.putMetadata(
RXingResultMetadataType::ERROR_CORRECTION_LEVEL,
RXingResultMetadataValue::ErrorCorrectionLevel(ecLevel.to_owned()),
);
}
result.putMetadata(
RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
RXingResultMetadataValue::SymbologyIdentifier(format!("]z{}", decoderRXingResult.getSymbologyModifier())),
RXingResultMetadataValue::SymbologyIdentifier(format!(
"]z{}",
decoderRXingResult.getSymbologyModifier()
)),
);
Ok(result)

View File

@@ -21,12 +21,12 @@
// import java.awt.image.BufferedImage;
// import java.awt.image.WritableRaster;
use image::{DynamicImage, Luma};
use image::{DynamicImage, Luma, GenericImage, EncodableLayout};
use imageproc::geometric_transformations::rotate_about_center;
use crate::LuminanceSource;
static MINUS_45_IN_RADIANS: f32 = -0.7853981633974483; // Math.toRadians(-45.0)
const MINUS_45_IN_RADIANS: f32 = -0.7853981633974483; // Math.toRadians(-45.0)
/**
* This LuminanceSource implementation is meant for J2SE clients and our blackbox unit tests.
@@ -97,9 +97,10 @@ impl BufferedImageLuminanceSource {
// }
// }
Self {
image: image,
image: DynamicImage::from(image.to_luma8()),
width: width,
height: height,
left: left,
@@ -189,8 +190,8 @@ impl LuminanceSource for BufferedImageLuminanceSource {
let img = rotate_about_center(
&self.image.to_luma8(),
MINUS_45_IN_RADIANS,
imageproc::geometric_transformations::Interpolation::Bicubic,
Luma([0; 1]),
imageproc::geometric_transformations::Interpolation::Nearest,
Luma([255; 1]),
);
let new_img = DynamicImage::from(img);

View File

@@ -3829,37 +3829,38 @@ impl Binarizer for HybridBinarizer {
&& height >= HybridBinarizer::MINIMUM_DIMENSION
{
let luminances = source.getMatrix();
let mut subWidth = width >> HybridBinarizer::BLOCK_SIZE_POWER;
let mut sub_width = width >> HybridBinarizer::BLOCK_SIZE_POWER;
if (width & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
subWidth += 1;
sub_width += 1;
}
let mut subHeight = height >> HybridBinarizer::BLOCK_SIZE_POWER;
let mut sub_height = height >> HybridBinarizer::BLOCK_SIZE_POWER;
if (height & HybridBinarizer::BLOCK_SIZE_MASK) != 0 {
subHeight += 1;
sub_height += 1;
}
let blackPoints = Self::calculateBlackPoints(
let black_points = Self::calculateBlackPoints(
&luminances,
subWidth as u32,
subHeight as u32,
sub_width as u32,
sub_height as u32,
width as u32,
height as u32,
);
let mut newMatrix = BitMatrix::new(width as u32, height as u32)?;
let mut new_matrix = BitMatrix::new(width as u32, height as u32)?;
Self::calculateThresholdForBlock(
&luminances,
subWidth as u32,
subHeight as u32,
sub_width as u32,
sub_height as u32,
width as u32,
height as u32,
&blackPoints,
&mut newMatrix,
&black_points,
&mut new_matrix,
);
matrix = newMatrix;
matrix = new_matrix;
} else {
// If the image is too small, fall back to the global histogram approach.
matrix = self.ghb.getBlackMatrix()?;
}
// dbg!(matrix.to_string());
Ok(matrix)
}
@@ -3997,16 +3998,16 @@ impl HybridBinarizer {
if xoffset > maxXOffset as u32 {
xoffset = maxXOffset as u32;
}
let mut sum = 0;
let mut min = 0xFF;
let mut max = 0;
let mut sum = 0u32;
let mut min = 0;
let mut max = 0xFF;
let mut offset = yoffset * width + xoffset;
for yy in 0..HybridBinarizer::BLOCK_SIZE {
// for (int yy = 0, offset = yoffset * width + xoffset; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) {
for xx in 0..HybridBinarizer::BLOCK_SIZE {
// for (int xx = 0; xx < HybridBinarizer::BLOCK_SIZE; xx++) {
let pixel = luminances[offset as usize + xx];
sum += pixel;
sum += pixel as u32;
// still looking for good contrast
if pixel < min {
min = pixel;
@@ -4023,7 +4024,7 @@ impl HybridBinarizer {
// for (yy++, offset += width; yy < HybridBinarizer::BLOCK_SIZE; yy++, offset += width) {
for xx in 0..HybridBinarizer::BLOCK_SIZE {
// for (int xx = 0; xx < BLOCK_SIZE; xx++) {
sum += luminances[offset as usize + xx];
sum += luminances[offset as usize + xx] as u32;
}
offset += width;
}
@@ -4041,7 +4042,7 @@ impl HybridBinarizer {
//
// The default assumption is that the block is light/background. Since no estimate for
// the level of dark pixels exists locally, use half the min for the block.
average = min / 2;
average = min as u32 / 2;
if y > 0 && x > 0 {
// Correct the "white background" assumption for blocks that have neighbors by comparing
@@ -4051,16 +4052,16 @@ impl HybridBinarizer {
// the boundaries is used for the interior.
// The (min < bp) is arbitrary but works better than other heuristics that were tried.
let averageNeighborBlackPoint = (blackPoints[y as usize - 1][x as usize]
let average_neighbor_black_point = (blackPoints[y as usize - 1][x as usize]
+ (2 * blackPoints[y as usize][x as usize - 1])
+ blackPoints[y as usize - 1][x as usize - 1])
/ 4;
if (min < averageNeighborBlackPoint) {
average = averageNeighborBlackPoint;
if (min < average_neighbor_black_point) {
average = average_neighbor_black_point as u32;
}
}
}
blackPoints[y as usize][x as usize] = average;
blackPoints[y as usize][x as usize] = average as u8;
}
}
return blackPoints

View File

@@ -1,13 +1,15 @@
mod aztec;
mod client;
mod common;
pub mod aztec;
pub mod client;
pub mod common;
mod exceptions;
#[cfg(feature = "image")]
mod BufferedImageLuminanceSource;
pub use exceptions::Exceptions;
#[cfg(feature = "image")]
pub use BufferedImageLuminanceSource::*;
mod buffered_image_luminance_source;
#[cfg(feature = "image")]
pub use buffered_image_luminance_source::*;
use crate::common::{BitArray, BitMatrix};
use exceptions::*;
@@ -454,7 +456,7 @@ pub enum EncodeHintValue {
* @author dswitkin@google.com (Daniel Switkin)
* @see Reader#decode(BinaryBitmap,java.util.Map)
*/
#[derive(Eq, PartialEq, Hash, Debug)]
#[derive(Eq, PartialEq, Hash, Debug, Clone, Copy)]
pub enum DecodeHintType {
/**
* Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
@@ -558,7 +560,7 @@ pub enum DecodeHintType {
* @see DecodeHintType#NEED_RESULT_POINT_CALLBACK
*/
pub type RXingResultPointCallback = fn(&RXingResultPoint);
#[derive(Clone)]
pub enum DecodeHintValue {
/**
* Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
@@ -671,6 +673,7 @@ pub trait Writer {
* @throws WriterException if contents cannot be encoded legally in a format
*/
fn encode(
&self,
contents: &str,
format: &BarcodeFormat,
width: i32,
@@ -687,6 +690,7 @@ pub trait Writer {
* @throws WriterException if contents cannot be encoded legally in a format
*/
fn encode_with_hints(
&self,
contents: &str,
format: &BarcodeFormat,
width: i32,
@@ -735,7 +739,7 @@ pub trait Reader {
* @throws ChecksumException if a potential barcode is found but does not pass its checksum
* @throws FormatException if a potential barcode is found but format is invalid
*/
fn decode(image: &BinaryBitmap) -> Result<RXingResult, Exceptions>;
fn decode(&self, image: &BinaryBitmap) -> Result<RXingResult, Exceptions>;
/**
* Locates and decodes a barcode in some format within an image. This method also accepts
@@ -752,6 +756,7 @@ pub trait Reader {
* @throws FormatException if a potential barcode is found but format is invalid
*/
fn decode_with_hints(
&self,
image: &BinaryBitmap,
hints: &HashMap<DecodeHintType, DecodeHintValue>,
) -> Result<RXingResult, Exceptions>;
@@ -760,7 +765,7 @@ pub trait Reader {
* Resets any internal state the implementation has after a decode, to prepare it
* for reuse.
*/
fn reset();
fn reset(&self);
}
/*
@@ -787,7 +792,7 @@ pub trait Reader {
*
* @author Sean Owen
*/
#[derive(Eq, PartialEq, Hash)]
#[derive(Eq, PartialEq, Hash, Debug)]
pub enum RXingResultMetadataType {
/**
* Unspecified, application-specific metadata. Maps to an unspecified {@link Object}.
@@ -867,11 +872,32 @@ pub enum RXingResultMetadataType {
SYMBOLOGY_IDENTIFIER,
}
impl From<String> for RXingResultMetadataType {
fn from(in_str: String) -> Self {
match in_str.as_str() {
"OTHER" => RXingResultMetadataType::OTHER,
"ORIENTATION" => RXingResultMetadataType::ORIENTATION,
"BYTE_SEGMENTS" => RXingResultMetadataType::BYTE_SEGMENTS,
"ERROR_CORRECTION_LEVEL"=> RXingResultMetadataType::ERROR_CORRECTION_LEVEL,
"ISSUE_NUMBER"=> RXingResultMetadataType::ISSUE_NUMBER,
"SUGGESTED_PRICE"=> RXingResultMetadataType::SUGGESTED_PRICE,
"POSSIBLE_COUNTRY"=> RXingResultMetadataType::POSSIBLE_COUNTRY,
"UPC_EAN_EXTENSION"=>RXingResultMetadataType::UPC_EAN_EXTENSION,
"PDF417_EXTRA_METADATA"=> RXingResultMetadataType::PDF417_EXTRA_METADATA,
"STRUCTURED_APPEND_SEQUENCE"=> RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE,
"STRUCTURED_APPEND_PARITY"=>RXingResultMetadataType::STRUCTURED_APPEND_PARITY,
"SYMBOLOGY_IDENTIFIER"=>RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
_ => RXingResultMetadataType::OTHER,
}
}
}
#[derive(Debug,PartialEq, Eq)]
pub enum RXingResultMetadataValue {
/**
* Unspecified, application-specific metadata. Maps to an unspecified {@link Object}.
*/
OTHER,
OTHER(String),
/**
* Denotes the likely approximate orientation of the barcode in the image. This value