Changed the 2D histogram calculation to sample four rows spread across the image...
authordswitkin <dswitkin@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Fri, 22 May 2009 20:59:15 +0000 (20:59 +0000)
committerdswitkin <dswitkin@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Fri, 22 May 2009 20:59:15 +0000 (20:59 +0000)
git-svn-id: http://zxing.googlecode.com/svn/trunk@950 59b500cc-1b3d-0410-9834-0bbf25fbcc57

core/src/com/google/zxing/common/BaseMonochromeBitmapSource.java
core/src/com/google/zxing/common/BlackPointEstimator.java
core/test/src/com/google/zxing/datamatrix/DataMatrixBlackBox2TestCase.java
core/test/src/com/google/zxing/qrcode/QRCodeBlackBox1TestCase.java
core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java
core/test/src/com/google/zxing/qrcode/QRCodeBlackBox3TestCase.java
core/test/src/com/google/zxing/qrcode/QRCodeBlackBox4TestCase.java

index 2e16a73..06f0513 100644 (file)
@@ -59,15 +59,15 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
 
     // Reuse the same int array each time
     initLuminances();
-    luminances = getLuminanceRow(y, luminances);
+    int[] localLuminances = getLuminanceRow(y, luminances);
 
     // If the current decoder calculated the blackPoint based on one row, assume we're trying to
     // decode a 1D barcode, and apply some sharpening.
     if (lastMethod.equals(BlackPointEstimationMethod.ROW_SAMPLING)) {
-      int left = luminances[startX];
-      int center = luminances[startX + 1];
+      int left = localLuminances[startX];
+      int center = localLuminances[startX + 1];
       for (int x = 1; x < getWidth - 1; x++) {
-        int right = luminances[startX + x + 1];
+        int right = localLuminances[startX + x + 1];
         // Simple -1 4 -1 box filter with a weight of 2
         int luminance = ((center << 2) - left - right) >> 1;
         if (luminance < blackPoint) {
@@ -78,7 +78,7 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
       }
     } else {
       for (int x = 0; x < getWidth; x++) {
-        if (luminances[startX + x] < blackPoint) {
+        if (localLuminances[startX + x] < blackPoint) {
           row.set(x);
         }
       }
@@ -95,11 +95,11 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
 
     // Reuse the same int array each time
     initLuminances();
-    luminances = getLuminanceColumn(x, luminances);
+    int[] localLuminances = getLuminanceColumn(x, luminances);
 
     // We don't handle "row sampling" specially here
     for (int y = 0; y < getHeight; y++) {
-      if (luminances[startY + y] < blackPoint) {
+      if (localLuminances[startY + y] < blackPoint) {
         column.set(y);
       }
     }
index 9fdc04b..0520d10 100644 (file)
@@ -25,8 +25,7 @@ import com.google.zxing.ReaderException;
  * which is the best line between "white" and "black" in a grayscale image.</p>\r
  *\r
  * <p>For an interesting discussion of this issue, see\r
- * <a href="http://webdiis.unizar.es/~neira/12082/thresholding.pdf">http://webdiis.unizar.es/~neira/12082/thresholding.pdf</a>.\r
- * </p>\r
+ * <a href="http://webdiis.unizar.es/~neira/12082/thresholding.pdf">this paper</a>.</p>\r
  *\r
  * NOTE: This class is not threadsafe.\r
  *\r
@@ -74,21 +73,26 @@ public final class BlackPointEstimator {
     initArrays(width);\r
 \r
     if (method.equals(BlackPointEstimationMethod.TWO_D_SAMPLING)) {\r
-      int minDimension = width < height ? width : height;\r
-      int startX = (width - minDimension) >> 1;\r
-      int startY = (height - minDimension) >> 1;\r
-      for (int n = 0; n < minDimension; n++) {\r
-        int luminance = source.getLuminance(startX + n, startY + n);\r
-        histogram[luminance >> LUMINANCE_SHIFT]++;\r
+      // We used to sample a diagonal in the 2D case, but it missed a lot of pixels, and it required\r
+      // n calls to getLuminance(). We had a net improvement of 63 blackbox tests decoded by\r
+      // sampling several rows from the middle of the image, using getLuminanceRow(). We read more\r
+      // pixels total, but with fewer function calls, and more continguous memory.\r
+      for (int y = 1; y < 5; y++) {\r
+        int row = height * y / 5;\r
+        int[] localLuminances = source.getLuminanceRow(row, luminances);\r
+        int right = width * 4 / 5;\r
+        for (int x = width / 5; x < right; x++) {\r
+          histogram[localLuminances[x] >> LUMINANCE_SHIFT]++;\r
+        }\r
       }\r
     } else if (method.equals(BlackPointEstimationMethod.ROW_SAMPLING)) {\r
       if (argument < 0 || argument >= height) {\r
         throw new IllegalArgumentException("Row is not within the image: " + argument);\r
       }\r
 \r
-      luminances = source.getLuminanceRow(argument, luminances);\r
+      int[] localLuminances = source.getLuminanceRow(argument, luminances);\r
       for (int x = 0; x < width; x++) {\r
-        histogram[luminances[x] >> LUMINANCE_SHIFT]++;\r
+        histogram[localLuminances[x] >> LUMINANCE_SHIFT]++;\r
       }\r
     } else {\r
       throw new IllegalArgumentException("Unknown method");\r
index bb13f1c..710bbe7 100644 (file)
@@ -27,7 +27,7 @@ public final class DataMatrixBlackBox2TestCase extends AbstractBlackBoxTestCase
   public DataMatrixBlackBox2TestCase() {
     // TODO use MultiFormatReader here once Data Matrix decoder is done
     super("test/data/blackbox/datamatrix-2", new DataMatrixReader(), BarcodeFormat.DATAMATRIX);
-    addTest(3, 3, 0.0f);
+    addTest(2, 2, 0.0f);
     addTest(1, 1, 90.0f);
     addTest(4, 4, 180.0f);
     addTest(3, 3, 270.0f);
index d54168e..f6b83ea 100644 (file)
@@ -27,9 +27,9 @@ public final class QRCodeBlackBox1TestCase extends AbstractBlackBoxTestCase {
 
   public QRCodeBlackBox1TestCase() {
     super("test/data/blackbox/qrcode-1", new MultiFormatReader(), BarcodeFormat.QR_CODE);
-    addTest(18, 18, 0.0f);
-    addTest(14, 14, 90.0f);
-    addTest(18, 18, 180.0f);
+    addTest(19, 19, 0.0f);
+    addTest(15, 15, 90.0f);
+    addTest(16, 16, 180.0f);
     addTest(13, 14, 270.0f);
   }
 
index 2ba64ae..085cbf3 100644 (file)
@@ -27,10 +27,10 @@ public final class QRCodeBlackBox2TestCase extends AbstractBlackBoxTestCase {
 
   public QRCodeBlackBox2TestCase() {
     super("test/data/blackbox/qrcode-2", new MultiFormatReader(), BarcodeFormat.QR_CODE);
-    addTest(22, 22, 0.0f);
-    addTest(18, 18, 90.0f);
+    addTest(24, 24, 0.0f);
+    addTest(21, 21, 90.0f);
     addTest(22, 22, 180.0f);
-    addTest(17, 17, 270.0f);
+    addTest(17, 18, 270.0f);
   }
 
 }
\ No newline at end of file
index a8b9125..9440d40 100644 (file)
@@ -27,10 +27,10 @@ public final class QRCodeBlackBox3TestCase extends AbstractBlackBoxTestCase {
 
   public QRCodeBlackBox3TestCase() {
     super("test/data/blackbox/qrcode-3", new MultiFormatReader(), BarcodeFormat.QR_CODE);
-    addTest(29, 29, 0.0f);
-    addTest(26, 26, 90.0f);
-    addTest(30, 30, 180.0f);
-    addTest(29, 29, 270.0f);
+    addTest(33, 33, 0.0f);
+    addTest(33, 33, 90.0f);
+    addTest(32, 32, 180.0f);
+    addTest(34, 34, 270.0f);
   }
 
 }
\ No newline at end of file
index 02168f9..c614aa8 100644 (file)
@@ -29,10 +29,10 @@ public final class QRCodeBlackBox4TestCase extends AbstractBlackBoxTestCase {
 
   public QRCodeBlackBox4TestCase() {
     super("test/data/blackbox/qrcode-4", new MultiFormatReader(), BarcodeFormat.QR_CODE);
-    addTest(33, 33, 0.0f);
-    addTest(33, 33, 90.0f);
-    addTest(32, 32, 180.0f);
-    addTest(32, 32, 270.0f);
+    addTest(34, 34, 0.0f);
+    addTest(36, 36, 90.0f);
+    addTest(35, 35, 180.0f);
+    addTest(34, 34, 270.0f);
   }
 
 }
\ No newline at end of file