From: srowen Date: Wed, 19 Mar 2008 17:09:27 +0000 (+0000) Subject: Fixed bug in rotation code for BufferedImageMonochromeBitmapSource; fixed "SKIP_N_BAR... X-Git-Url: http://git.rot13.org/?p=zxing.git;a=commitdiff_plain;h=32c496d9cb28846630b234526058bf205b1da7b5 Fixed bug in rotation code for BufferedImageMonochromeBitmapSource; fixed "SKIP_N_BARCODES" behavior to ignore barcodes already found. git-svn-id: http://zxing.googlecode.com/svn/trunk@297 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- diff --git a/android/src/com/google/zxing/client/android/RGBMonochromeBitmapSource.java b/android/src/com/google/zxing/client/android/RGBMonochromeBitmapSource.java index 3b9cac91..962c9055 100755 --- a/android/src/com/google/zxing/client/android/RGBMonochromeBitmapSource.java +++ b/android/src/com/google/zxing/client/android/RGBMonochromeBitmapSource.java @@ -19,6 +19,7 @@ package com.google.zxing.client.android; import android.graphics.Bitmap; import com.google.zxing.BlackPointEstimationMethod; import com.google.zxing.MonochromeBitmapSource; +import com.google.zxing.ReaderException; import com.google.zxing.common.BitArray; import com.google.zxing.common.BlackPointEstimator; @@ -77,7 +78,7 @@ final class RGBMonochromeBitmapSource implements MonochromeBitmapSource { return image.width(); } - public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) { + public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException { if (!method.equals(lastMethod) || argument != lastArgument) { int width = image.width(); int height = image.height(); diff --git a/android/src/com/google/zxing/client/android/YUVMonochromeBitmapSource.java b/android/src/com/google/zxing/client/android/YUVMonochromeBitmapSource.java index 4c173d67..b50e16cc 100755 --- a/android/src/com/google/zxing/client/android/YUVMonochromeBitmapSource.java +++ b/android/src/com/google/zxing/client/android/YUVMonochromeBitmapSource.java @@ -19,6 +19,7 @@ package com.google.zxing.client.android; import android.graphics.Bitmap; import com.google.zxing.BlackPointEstimationMethod; import com.google.zxing.MonochromeBitmapSource; +import com.google.zxing.ReaderException; import com.google.zxing.common.BitArray; import com.google.zxing.common.BlackPointEstimator; @@ -79,7 +80,7 @@ final class YUVMonochromeBitmapSource implements MonochromeBitmapSource { return image.width(); } - public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) { + public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException { if (!method.equals(lastMethod) || argument != lastArgument) { int width = image.width(); int height = image.height(); diff --git a/core/src/com/google/zxing/common/BlackPointEstimator.java b/core/src/com/google/zxing/common/BlackPointEstimator.java index c5bc0edb..a9fc7933 100644 --- a/core/src/com/google/zxing/common/BlackPointEstimator.java +++ b/core/src/com/google/zxing/common/BlackPointEstimator.java @@ -16,6 +16,8 @@ package com.google.zxing.common; +import com.google.zxing.ReaderException; + /** *

Encapsulates logic that estimates the optimal "black point", the luminance value * which is the best line between "white" and "black" in a grayscale image.

@@ -43,8 +45,9 @@ public final class BlackPointEstimator { * than 0.0; 1.0 is a good "default" * @return index within argument of bucket corresponding to brightest values which should be * considered "black" + * @throws ReaderException if "black" and "white" appear to be very close in luminance in the image */ - public static int estimate(int[] histogram, float biasTowardsWhite) { + public static int estimate(int[] histogram, float biasTowardsWhite) throws ReaderException{ if (Float.isNaN(biasTowardsWhite) || biasTowardsWhite <= 0.0f) { throw new IllegalArgumentException("Illegal biasTowardsWhite: " + biasTowardsWhite); @@ -83,6 +86,15 @@ public final class BlackPointEstimator { secondPeak = temp; } + // Kind of aribtrary; if the two peaks are very close, then we figure there is so little + // dynamic range in the image, that discriminating black and white is too error-prone. + // Decoding the image/line is either pointless, or may in some cases lead to a false positive + // for 1D formats, which are relatively lenient. + // We arbitrarily say "close" is "fewer than 1/8 of the total histogram buckets apart" + if (secondPeak - firstPeak < histogram.length >> 3) { + throw new ReaderException("Too little dynamic range in luminance"); + } + // Find a valley between them that is low and closer to the white peak int bestValley = secondPeak - 1; int bestValleyScore = -1; diff --git a/core/src/com/google/zxing/oned/AbstractOneDReader.java b/core/src/com/google/zxing/oned/AbstractOneDReader.java index e5effa60..53a04a31 100644 --- a/core/src/com/google/zxing/oned/AbstractOneDReader.java +++ b/core/src/com/google/zxing/oned/AbstractOneDReader.java @@ -82,20 +82,19 @@ public abstract class AbstractOneDReader implements OneDReader { // the middle. So we'd scan row middle, then middle - rowStep, then middle + rowStep, // then middle - 2*rowStep, etc. // rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily decided - // that moving up and down by about 1/16 of the image is pretty good. + // that moving up and down by about 1/16 of the image is pretty good; we try more of the image if + // "trying harder" int middle = height >> 1; - int rowStep; - if (tryHarder) { - rowStep = 2; // Look at every other line if "trying harder" - } else { - rowStep = Math.max(1, height >> 4); - } + int rowStep = Math.max(1, height >> (tryHarder ? 7 : 4)); int maxLines; if (tryHarder || barcodesToSkip > 0) { maxLines = height; // Look at the whole image; looking for more than one barcode } else { maxLines = 7; } + + Result lastResult = null; + for (int x = 0; x < maxLines; x++) { int rowStepsAboveOrBelow = (x + 1) >> 1; @@ -105,34 +104,40 @@ public abstract class AbstractOneDReader implements OneDReader { break; } - image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber); + try { + image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber); + } catch (ReaderException re) { + continue; + } image.getBlackRow(rowNumber, row, 0, width); - try { - Result result = decodeRow(rowNumber, row, hints); - if (barcodesToSkip > 0) { // See if we should skip and keep looking - barcodesToSkip--; - } else { - return result; + for (int attempt = 0; attempt < 2; attempt++) { + if (attempt == 1) { // trying again? + if (tryHarder) { // only if "trying harder" + row.reverse(); // reverse the row and continue + } else { + break; + } } - } catch (ReaderException re) { - if (tryHarder) { - row.reverse(); // try scanning the row backwards - try { - Result result = decodeRow(rowNumber, row, hints); + try { + Result result = decodeRow(rowNumber, row, hints); + if (lastResult == null || !lastResult.getText().equals(result.getText())) { + // Found new barcode, not just the last one again if (barcodesToSkip > 0) { // See if we should skip and keep looking barcodesToSkip--; + lastResult = result; // Remember what we just saw } else { - // Found it, but upside-down: - result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180)); + if (attempt == 1) { + // Found it, but upside-down: + result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180)); + } return result; } - } catch (ReaderException re2) { - // continue } + } catch (ReaderException re) { + // continue } } - } throw new ReaderException("No barcode found"); diff --git a/javame/src/com/google/zxing/client/j2me/LCDUIImageMonochromeBitmapSource.java b/javame/src/com/google/zxing/client/j2me/LCDUIImageMonochromeBitmapSource.java index 5be7c58d..e3f05489 100644 --- a/javame/src/com/google/zxing/client/j2me/LCDUIImageMonochromeBitmapSource.java +++ b/javame/src/com/google/zxing/client/j2me/LCDUIImageMonochromeBitmapSource.java @@ -18,6 +18,7 @@ package com.google.zxing.client.j2me; import com.google.zxing.BlackPointEstimationMethod; import com.google.zxing.MonochromeBitmapSource; +import com.google.zxing.ReaderException; import com.google.zxing.common.BitArray; import com.google.zxing.common.BlackPointEstimator; @@ -77,7 +78,7 @@ public final class LCDUIImageMonochromeBitmapSource implements MonochromeBitmapS return width; } - public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) { + public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException { if (!method.equals(lastMethod) || argument != lastArgument) { int[] histogram = new int[LUMINANCE_BUCKETS]; float biasTowardsWhite = 1.0f; diff --git a/javase/src/com/google/zxing/client/j2se/BufferedImageMonochromeBitmapSource.java b/javase/src/com/google/zxing/client/j2se/BufferedImageMonochromeBitmapSource.java index 5030d7bf..a4a0e649 100644 --- a/javase/src/com/google/zxing/client/j2se/BufferedImageMonochromeBitmapSource.java +++ b/javase/src/com/google/zxing/client/j2se/BufferedImageMonochromeBitmapSource.java @@ -18,6 +18,7 @@ package com.google.zxing.client.j2se; import com.google.zxing.BlackPointEstimationMethod; import com.google.zxing.MonochromeBitmapSource; +import com.google.zxing.ReaderException; import com.google.zxing.common.BitArray; import com.google.zxing.common.BlackPointEstimator; @@ -51,6 +52,10 @@ public final class BufferedImageMonochromeBitmapSource implements MonochromeBitm lastArgument = 0; } + public BufferedImage getImage() { + return image; + } + public boolean isBlack(int x, int y) { return computeRGBLuminance(image.getRGB(x, y)) < blackPoint; } @@ -78,7 +83,7 @@ public final class BufferedImageMonochromeBitmapSource implements MonochromeBitm return image.getWidth(); } - public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) { + public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException { if (!method.equals(lastMethod) || argument != lastArgument) { int width = image.getWidth(); int height = image.getHeight(); @@ -120,8 +125,9 @@ public final class BufferedImageMonochromeBitmapSource implements MonochromeBitm throw new IllegalStateException("Rotate not supported"); } // 90 degrees counterclockwise: - AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, image.getHeight()); + AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, image.getWidth()); BufferedImageOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + // Note width/height are flipped since we are rotating 90 degrees: BufferedImage rotatedImage = new BufferedImage(image.getHeight(), image.getWidth(), image.getType()); op.filter(image, rotatedImage); return new BufferedImageMonochromeBitmapSource(rotatedImage);