mirror of
https://github.com/zxing/zxing.git
synced 2025-02-02 05:41:08 -08:00
Fixed bug in rotation code for BufferedImageMonochromeBitmapSource; fixed "SKIP_N_BARCODES" behavior to ignore barcodes already found.
git-svn-id: https://zxing.googlecode.com/svn/trunk@297 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
efb0fb9e3b
commit
14a9eb7d20
|
@ -19,6 +19,7 @@ package com.google.zxing.client.android;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import com.google.zxing.BlackPointEstimationMethod;
|
import com.google.zxing.BlackPointEstimationMethod;
|
||||||
import com.google.zxing.MonochromeBitmapSource;
|
import com.google.zxing.MonochromeBitmapSource;
|
||||||
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
import com.google.zxing.common.BlackPointEstimator;
|
import com.google.zxing.common.BlackPointEstimator;
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ final class RGBMonochromeBitmapSource implements MonochromeBitmapSource {
|
||||||
return image.width();
|
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) {
|
if (!method.equals(lastMethod) || argument != lastArgument) {
|
||||||
int width = image.width();
|
int width = image.width();
|
||||||
int height = image.height();
|
int height = image.height();
|
||||||
|
|
|
@ -19,6 +19,7 @@ package com.google.zxing.client.android;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import com.google.zxing.BlackPointEstimationMethod;
|
import com.google.zxing.BlackPointEstimationMethod;
|
||||||
import com.google.zxing.MonochromeBitmapSource;
|
import com.google.zxing.MonochromeBitmapSource;
|
||||||
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
import com.google.zxing.common.BlackPointEstimator;
|
import com.google.zxing.common.BlackPointEstimator;
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ final class YUVMonochromeBitmapSource implements MonochromeBitmapSource {
|
||||||
return image.width();
|
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) {
|
if (!method.equals(lastMethod) || argument != lastArgument) {
|
||||||
int width = image.width();
|
int width = image.width();
|
||||||
int height = image.height();
|
int height = image.height();
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package com.google.zxing.common;
|
package com.google.zxing.common;
|
||||||
|
|
||||||
|
import com.google.zxing.ReaderException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Encapsulates logic that estimates the optimal "black point", the luminance value
|
* <p>Encapsulates logic that estimates the optimal "black point", the luminance value
|
||||||
* which is the best line between "white" and "black" in a grayscale image.</p>
|
* which is the best line between "white" and "black" in a grayscale image.</p>
|
||||||
|
@ -43,8 +45,9 @@ public final class BlackPointEstimator {
|
||||||
* than 0.0; 1.0 is a good "default"
|
* than 0.0; 1.0 is a good "default"
|
||||||
* @return index within argument of bucket corresponding to brightest values which should be
|
* @return index within argument of bucket corresponding to brightest values which should be
|
||||||
* considered "black"
|
* 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) {
|
if (Float.isNaN(biasTowardsWhite) || biasTowardsWhite <= 0.0f) {
|
||||||
throw new IllegalArgumentException("Illegal biasTowardsWhite: " + biasTowardsWhite);
|
throw new IllegalArgumentException("Illegal biasTowardsWhite: " + biasTowardsWhite);
|
||||||
|
@ -83,6 +86,15 @@ public final class BlackPointEstimator {
|
||||||
secondPeak = temp;
|
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
|
// Find a valley between them that is low and closer to the white peak
|
||||||
int bestValley = secondPeak - 1;
|
int bestValley = secondPeak - 1;
|
||||||
int bestValleyScore = -1;
|
int bestValleyScore = -1;
|
||||||
|
|
|
@ -82,20 +82,19 @@ public abstract class AbstractOneDReader implements OneDReader {
|
||||||
// the middle. So we'd scan row middle, then middle - rowStep, then middle + rowStep,
|
// the middle. So we'd scan row middle, then middle - rowStep, then middle + rowStep,
|
||||||
// then middle - 2*rowStep, etc.
|
// then middle - 2*rowStep, etc.
|
||||||
// rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily decided
|
// 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 middle = height >> 1;
|
||||||
int rowStep;
|
int rowStep = Math.max(1, height >> (tryHarder ? 7 : 4));
|
||||||
if (tryHarder) {
|
|
||||||
rowStep = 2; // Look at every other line if "trying harder"
|
|
||||||
} else {
|
|
||||||
rowStep = Math.max(1, height >> 4);
|
|
||||||
}
|
|
||||||
int maxLines;
|
int maxLines;
|
||||||
if (tryHarder || barcodesToSkip > 0) {
|
if (tryHarder || barcodesToSkip > 0) {
|
||||||
maxLines = height; // Look at the whole image; looking for more than one barcode
|
maxLines = height; // Look at the whole image; looking for more than one barcode
|
||||||
} else {
|
} else {
|
||||||
maxLines = 7;
|
maxLines = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result lastResult = null;
|
||||||
|
|
||||||
for (int x = 0; x < maxLines; x++) {
|
for (int x = 0; x < maxLines; x++) {
|
||||||
|
|
||||||
int rowStepsAboveOrBelow = (x + 1) >> 1;
|
int rowStepsAboveOrBelow = (x + 1) >> 1;
|
||||||
|
@ -105,36 +104,42 @@ public abstract class AbstractOneDReader implements OneDReader {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber);
|
image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber);
|
||||||
|
} catch (ReaderException re) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
image.getBlackRow(rowNumber, row, 0, width);
|
image.getBlackRow(rowNumber, row, 0, width);
|
||||||
|
|
||||||
try {
|
for (int attempt = 0; attempt < 2; attempt++) {
|
||||||
Result result = decodeRow(rowNumber, row, hints);
|
if (attempt == 1) { // trying again?
|
||||||
if (barcodesToSkip > 0) { // See if we should skip and keep looking
|
if (tryHarder) { // only if "trying harder"
|
||||||
barcodesToSkip--;
|
row.reverse(); // reverse the row and continue
|
||||||
} else {
|
} else {
|
||||||
return result;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (ReaderException re) {
|
|
||||||
if (tryHarder) {
|
|
||||||
row.reverse(); // try scanning the row backwards
|
|
||||||
try {
|
try {
|
||||||
Result result = decodeRow(rowNumber, row, hints);
|
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
|
if (barcodesToSkip > 0) { // See if we should skip and keep looking
|
||||||
barcodesToSkip--;
|
barcodesToSkip--;
|
||||||
|
lastResult = result; // Remember what we just saw
|
||||||
} else {
|
} else {
|
||||||
|
if (attempt == 1) {
|
||||||
// Found it, but upside-down:
|
// Found it, but upside-down:
|
||||||
result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180));
|
result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} catch (ReaderException re2) {
|
}
|
||||||
|
} catch (ReaderException re) {
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ReaderException("No barcode found");
|
throw new ReaderException("No barcode found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ package com.google.zxing.client.j2me;
|
||||||
|
|
||||||
import com.google.zxing.BlackPointEstimationMethod;
|
import com.google.zxing.BlackPointEstimationMethod;
|
||||||
import com.google.zxing.MonochromeBitmapSource;
|
import com.google.zxing.MonochromeBitmapSource;
|
||||||
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
import com.google.zxing.common.BlackPointEstimator;
|
import com.google.zxing.common.BlackPointEstimator;
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ public final class LCDUIImageMonochromeBitmapSource implements MonochromeBitmapS
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) {
|
public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
|
||||||
if (!method.equals(lastMethod) || argument != lastArgument) {
|
if (!method.equals(lastMethod) || argument != lastArgument) {
|
||||||
int[] histogram = new int[LUMINANCE_BUCKETS];
|
int[] histogram = new int[LUMINANCE_BUCKETS];
|
||||||
float biasTowardsWhite = 1.0f;
|
float biasTowardsWhite = 1.0f;
|
||||||
|
|
|
@ -18,6 +18,7 @@ package com.google.zxing.client.j2se;
|
||||||
|
|
||||||
import com.google.zxing.BlackPointEstimationMethod;
|
import com.google.zxing.BlackPointEstimationMethod;
|
||||||
import com.google.zxing.MonochromeBitmapSource;
|
import com.google.zxing.MonochromeBitmapSource;
|
||||||
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
import com.google.zxing.common.BlackPointEstimator;
|
import com.google.zxing.common.BlackPointEstimator;
|
||||||
|
|
||||||
|
@ -51,6 +52,10 @@ public final class BufferedImageMonochromeBitmapSource implements MonochromeBitm
|
||||||
lastArgument = 0;
|
lastArgument = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BufferedImage getImage() {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isBlack(int x, int y) {
|
public boolean isBlack(int x, int y) {
|
||||||
return computeRGBLuminance(image.getRGB(x, y)) < blackPoint;
|
return computeRGBLuminance(image.getRGB(x, y)) < blackPoint;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +83,7 @@ public final class BufferedImageMonochromeBitmapSource implements MonochromeBitm
|
||||||
return image.getWidth();
|
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) {
|
if (!method.equals(lastMethod) || argument != lastArgument) {
|
||||||
int width = image.getWidth();
|
int width = image.getWidth();
|
||||||
int height = image.getHeight();
|
int height = image.getHeight();
|
||||||
|
@ -120,8 +125,9 @@ public final class BufferedImageMonochromeBitmapSource implements MonochromeBitm
|
||||||
throw new IllegalStateException("Rotate not supported");
|
throw new IllegalStateException("Rotate not supported");
|
||||||
}
|
}
|
||||||
// 90 degrees counterclockwise:
|
// 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);
|
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());
|
BufferedImage rotatedImage = new BufferedImage(image.getHeight(), image.getWidth(), image.getType());
|
||||||
op.filter(image, rotatedImage);
|
op.filter(image, rotatedImage);
|
||||||
return new BufferedImageMonochromeBitmapSource(rotatedImage);
|
return new BufferedImageMonochromeBitmapSource(rotatedImage);
|
||||||
|
|
Loading…
Reference in a new issue