Add column caching to MonochromeBitmapSources and use it to improve Data Matrix speed
authorsrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Wed, 22 Oct 2008 08:43:56 +0000 (08:43 +0000)
committersrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Wed, 22 Oct 2008 08:43:56 +0000 (08:43 +0000)
git-svn-id: http://zxing.googlecode.com/svn/trunk@631 59b500cc-1b3d-0410-9834-0bbf25fbcc57

android/src/com/google/zxing/client/android/YUVMonochromeBitmapSource.java
bug/src/com/google/zxing/client/bug/AWTImageMonochromeBitmapSource.java
core/src/com/google/zxing/MonochromeBitmapSource.java
core/src/com/google/zxing/common/BaseMonochromeBitmapSource.java
core/src/com/google/zxing/datamatrix/detector/Detector.java
javame/src/com/google/zxing/client/j2me/LCDUIImageMonochromeBitmapSource.java
javase/src/com/google/zxing/client/j2se/BufferedImageMonochromeBitmapSource.java

index 9c0ff14..15021b8 100755 (executable)
@@ -72,6 +72,10 @@ final class YUVMonochromeBitmapSource extends BaseMonochromeBitmapSource {
 
   }
 
+  public void cacheColumnForLuminance(int x) {
+
+  }
+
   /**
    * Create a greyscale Android Bitmap from the YUV data based on the crop rectangle.
    *
index 6752cb3..d1db8eb 100644 (file)
@@ -74,4 +74,8 @@ public final class AWTImageMonochromeBitmapSource extends BaseMonochromeBitmapSo
     // do nothing; we are already forced to cache all pixels
   }
 
+  public void cacheColumnForLuminance(int x) {
+    // do nothing
+  }
+
 }
index 8dda19e..6d3655a 100644 (file)
@@ -48,6 +48,11 @@ public interface MonochromeBitmapSource {
    */
   BitArray getBlackRow(int y, BitArray row, int startX, int getWidth);
 
+  /**
+   * Entirely analogous to {@link #getBlackRow(int, BitArray, int, int)} but gets a column.
+   */
+  BitArray getBlackColumn(int x, BitArray column, int startY, int getHeight);
+
   /**
    * @return height of underlying image
    */
@@ -76,6 +81,11 @@ public interface MonochromeBitmapSource {
    */
   void cacheRowForLuminance(int y);
 
+  /**
+   * Entirely analogous to {@link #cacheRowForLuminance(int)} but caches a column.
+   */
+  void cacheColumnForLuminance(int x);
+
   /**
    * <p>Estimates black point according to the given method, which is optionally parameterized by
    * a single int argument. For {@link BlackPointEstimationMethod#ROW_SAMPLING}, this
index b9de750..dd6e5f1 100644 (file)
@@ -76,6 +76,23 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
     return row;
   }
 
+  public BitArray getBlackColumn(int x, BitArray column, int startY, int getHeight) {
+    if (column == null || column.getSize() < getHeight) {
+      column = new BitArray(getHeight);
+    } else {
+      column.clear();
+    }
+
+    cacheColumnForLuminance(x);
+    // We don't handle "row sampling" specially here
+    for (int y = 0; y < getHeight; y++) {
+      if (getLuminance(x, startY + y) < blackPoint) {
+        column.set(y);
+      }
+    }
+    return column;
+  }
+
   public void estimateBlackPoint(BlackPointEstimationMethod method, int argument) throws ReaderException {
     if (!method.equals(lastMethod) || argument != lastArgument) {
       int width = getWidth();
@@ -131,4 +148,6 @@ public abstract class BaseMonochromeBitmapSource implements MonochromeBitmapSour
 
   public abstract void cacheRowForLuminance(int y);
 
+  public abstract void cacheColumnForLuminance(int x);
+
 }
index a7549e3..28c727e 100644 (file)
@@ -20,6 +20,7 @@ import com.google.zxing.MonochromeBitmapSource;
 import com.google.zxing.ReaderException;
 import com.google.zxing.ResultPoint;
 import com.google.zxing.BlackPointEstimationMethod;
+import com.google.zxing.common.BitArray;
 import com.google.zxing.common.BitMatrix;
 import com.google.zxing.common.Collections;
 import com.google.zxing.common.Comparator;
@@ -262,17 +263,19 @@ public final class Detector {
 
     int center = (minDim + maxDim) / 2;
 
+    BitArray rowOrColumn = horizontal ? image.getBlackRow(fixedDimension, null, 0, image.getWidth())
+                                      : image.getBlackColumn(fixedDimension, null, 0, image.getHeight());
+
     // Scan left/up first
     int start = center;
     while (start >= minDim) {
-      if (horizontal ? image.isBlack(start, fixedDimension) : image.isBlack(fixedDimension, start)) {
+      if (rowOrColumn.get(start)) {
         start--;
       } else {
         int whiteRunStart = start;
         do {
           start--;
-        } while (start >= minDim &&
-                 !(horizontal ? image.isBlack(start, fixedDimension) : image.isBlack(fixedDimension, start)));
+        } while (start >= minDim && !rowOrColumn.get(start));
         int whiteRunSize = whiteRunStart - start;
         if (start < minDim || whiteRunSize > maxWhiteRun) {
           start = whiteRunStart + 1; // back up
@@ -284,14 +287,13 @@ public final class Detector {
     // Then try right/down
     int end = center;
     while (end < maxDim) {
-      if (horizontal ? image.isBlack(end, fixedDimension) : image.isBlack(fixedDimension, end)) {
+      if (rowOrColumn.get(end)) {
         end++;
       } else {
         int whiteRunStart = end;
         do {
           end++;
-        } while (end < maxDim &&
-                 !(horizontal ? image.isBlack(end, fixedDimension) : image.isBlack(fixedDimension, end)));
+        } while (end < maxDim && !rowOrColumn.get(end));
         int whiteRunSize = end - whiteRunStart;
         if (end >= maxDim || whiteRunSize > maxWhiteRun) {
           end = whiteRunStart - 1;
index 04d0ca3..3ee5fe0 100644 (file)
@@ -32,16 +32,20 @@ public final class LCDUIImageMonochromeBitmapSource extends BaseMonochromeBitmap
   private final int width;
   // For why this isn't final, see below
   private int[] rgbRow;
+  private int[] rgbColumn;
   private final int[] pixelHolder;
   private int cachedRow;
+  private int cachedColumn;
 
   public LCDUIImageMonochromeBitmapSource(Image image) {
     this.image = image;
     height = image.getHeight();
     width = image.getWidth();
     rgbRow = new int[width];
+    rgbColumn = new int[height];
     pixelHolder = new int[1];
     cachedRow = -1;
+    cachedColumn = -1;
   }
 
   public int getHeight() {
@@ -61,6 +65,8 @@ public final class LCDUIImageMonochromeBitmapSource extends BaseMonochromeBitmap
     int pixel;
     if (cachedRow == y && rgbRow.length == width) {
       pixel = rgbRow[x];
+    } else if (cachedColumn == x && rgbColumn.length == height) {
+      pixel = rgbColumn[y];
     } else {
       image.getRGB(pixelHolder, 0, width, x, y, 1, 1);
       pixel = pixelHolder[0];
@@ -94,4 +100,14 @@ public final class LCDUIImageMonochromeBitmapSource extends BaseMonochromeBitmap
     }
   }
 
+  public void cacheColumnForLuminance(int x) {
+    if (x != cachedColumn) {
+      if (rgbColumn.length != height) {
+        rgbColumn = new int[height];
+      }
+      image.getRGB(rgbColumn, 0, 1, x, 0, 1, height);
+      cachedColumn = x;
+    }
+  }
+
 }
\ No newline at end of file
index 93b0211..8e27609 100644 (file)
@@ -43,7 +43,9 @@ public final class BufferedImageMonochromeBitmapSource extends BaseMonochromeBit
   private final int width;
   private final int height;
   private int[] rgbRow;
+  private int[] rgbColumn;
   private int cachedRow;
+  private int cachedColumn;
 
   /**
    * Creates an instance that uses the entire given image as a source of pixels to decode.
@@ -78,7 +80,9 @@ public final class BufferedImageMonochromeBitmapSource extends BaseMonochromeBit
     this.width = right - left;
     this.height = bottom - top;
     rgbRow = new int[width];
+    rgbColumn = new int[height];
     cachedRow = -1;
+    cachedColumn = -1;
   }
 
   /**
@@ -136,6 +140,8 @@ public final class BufferedImageMonochromeBitmapSource extends BaseMonochromeBit
     int pixel;
     if (cachedRow == y) {
       pixel = rgbRow[x];
+    } else if (cachedColumn == x) {
+      pixel = rgbColumn[y];
     } else {
       pixel = image.getRGB(left + x, top + y);
     }
@@ -153,4 +159,11 @@ public final class BufferedImageMonochromeBitmapSource extends BaseMonochromeBit
     }
   }
 
+  public void cacheColumnForLuminance(int x) {
+    if (x != cachedColumn) {
+      image.getRGB(left + x, top, 1, height, rgbColumn, 0, 1);
+      cachedColumn = x;
+    }
+  }
+
 }