import com.google.zxing.DecodeHintType;\r
import com.google.zxing.MonochromeBitmapSource;\r
import com.google.zxing.ReaderException;\r
+import com.google.zxing.ResultPoint;\r
import com.google.zxing.common.BitArray;\r
import com.google.zxing.common.Collections;\r
import com.google.zxing.common.Comparator;\r
-import com.google.zxing.common.GenericResultPoint;\r
\r
import java.util.Hashtable;\r
import java.util.Vector;\r
*\r
* <p>This class is not thread-safe and should not be reused.</p>\r
*\r
- * @author srowen@google.com (Sean Owen)\r
+ * @author Sean Owen\r
*/\r
-final class FinderPatternFinder {\r
+public class FinderPatternFinder {\r
\r
private static final int CENTER_QUORUM = 2;\r
- private static final int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center\r
- private static final int MAX_MODULES = 57; // support up to version 10 for mobile clients\r
+ protected static final int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center\r
+ protected static final int MAX_MODULES = 57; // support up to version 10 for mobile clients\r
private static final int INTEGER_MATH_SHIFT = 8;\r
\r
private final MonochromeBitmapSource image;\r
private final Vector possibleCenters;\r
private boolean hasSkipped;\r
+ private final int[] crossCheckStateCount;\r
\r
/**\r
* <p>Creates a finder that will search the image for three finder patterns.</p>\r
*\r
* @param image image to search\r
*/\r
- FinderPatternFinder(MonochromeBitmapSource image) {\r
+ public FinderPatternFinder(MonochromeBitmapSource image) {\r
this.image = image;\r
this.possibleCenters = new Vector();\r
+ this.crossCheckStateCount = new int[5];\r
+ }\r
+\r
+ protected MonochromeBitmapSource getImage() {\r
+ return image;\r
+ }\r
+\r
+ protected Vector getPossibleCenters() {\r
+ return possibleCenters;\r
}\r
\r
FinderPatternInfo find(Hashtable hints) throws ReaderException {\r
// image, and then account for the center being 3 modules in size. This gives the smallest\r
// number of pixels the center could be, so skip this often. When trying harder, look for all\r
// QR versions regardless of how dense they are.\r
- int iSkip = (int) (maxI / (MAX_MODULES * 4.0f) * 3);\r
+ int iSkip = (3 * maxI) / (4 * MAX_MODULES);\r
if (iSkip < MIN_SKIP || tryHarder) {\r
iSkip = MIN_SKIP;\r
}\r
\r
boolean done = false;\r
int[] stateCount = new int[5];\r
+ BitArray blackRow = new BitArray(maxJ);\r
for (int i = iSkip - 1; i < maxI && !done; i += iSkip) {\r
// Get a row of black/white values\r
- BitArray blackRow = image.getBlackRow(i, null, 0, maxJ);\r
+ blackRow = image.getBlackRow(i, blackRow, 0, maxJ);\r
stateCount[0] = 0;\r
stateCount[1] = 0;\r
stateCount[2] = 0;\r
// expensive and didn't improve performance.\r
iSkip = 2;\r
if (hasSkipped) {\r
- done = haveMulitplyConfirmedCenters();\r
+ done = haveMultiplyConfirmedCenters();\r
} else {\r
int rowSkip = findRowSkip();\r
if (rowSkip > stateCount[2]) {\r
iSkip = stateCount[0];\r
if (hasSkipped) {\r
// Found a third one\r
- done = haveMulitplyConfirmedCenters();\r
+ done = haveMultiplyConfirmedCenters();\r
}\r
}\r
}\r
}\r
\r
FinderPattern[] patternInfo = selectBestPatterns();\r
- GenericResultPoint.orderBestPatterns(patternInfo);\r
+ ResultPoint.orderBestPatterns(patternInfo);\r
\r
return new FinderPatternInfo(patternInfo);\r
}\r
* @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios\r
* used by finder patterns to be considered a match\r
*/\r
- private static boolean foundPatternCross(int[] stateCount) {\r
+ protected static boolean foundPatternCross(int[] stateCount) {\r
int totalModuleSize = 0;\r
for (int i = 0; i < 5; i++) {\r
int count = stateCount[i];\r
Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance;\r
}\r
\r
+ private int[] getCrossCheckStateCount() {\r
+ crossCheckStateCount[0] = 0;\r
+ crossCheckStateCount[1] = 0;\r
+ crossCheckStateCount[2] = 0;\r
+ crossCheckStateCount[3] = 0;\r
+ crossCheckStateCount[4] = 0;\r
+ return crossCheckStateCount;\r
+ }\r
+\r
/**\r
* <p>After a horizontal scan finds a potential finder pattern, this method\r
* "cross-checks" by scanning down vertically through the center of the possible\r
MonochromeBitmapSource image = this.image;\r
\r
int maxI = image.getHeight();\r
- int[] stateCount = new int[5];\r
+ int[] stateCount = getCrossCheckStateCount();\r
\r
// Start counting up from center\r
int i = startI;\r
MonochromeBitmapSource image = this.image;\r
\r
int maxJ = image.getWidth();\r
- int[] stateCount = new int[5];\r
+ int[] stateCount = getCrossCheckStateCount();\r
\r
int j = startJ;\r
while (j >= 0 && image.isBlack(j, centerI)) {\r
* @param j end of possible finder pattern in row\r
* @return true if a finder pattern candidate was found this time\r
*/\r
- private boolean handlePossibleCenter(int[] stateCount,\r
+ protected boolean handlePossibleCenter(int[] stateCount,\r
int i,\r
int j) {\r
int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];\r
// How far down can we skip before resuming looking for the next\r
// pattern? In the worst case, only the difference between the\r
// difference in the x / y coordinates of the two centers.\r
- // This is the case where you find top left first. Draw it out.\r
+ // This is the case where you find top left last.\r
hasSkipped = true;\r
return (int) (Math.abs(firstConfirmedCenter.getX() - center.getX()) -\r
- Math.abs(firstConfirmedCenter.getY() - center.getY()));\r
+ Math.abs(firstConfirmedCenter.getY() - center.getY())) / 2;\r
}\r
}\r
}\r
* at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the\r
* candidates is "pretty similar"\r
*/\r
- private boolean haveMulitplyConfirmedCenters() {\r
+ private boolean haveMultiplyConfirmedCenters() {\r
int confirmedCount = 0;\r
float totalModuleSize = 0.0f;\r
int max = possibleCenters.size();\r
// and that we need to keep looking. We detect this by asking if the estimated module sizes\r
// vary too much. We arbitrarily say that when the total deviation from average exceeds\r
// 15% of the total module size estimates, it's too much.\r
- float average = totalModuleSize / max;\r
+ float average = totalModuleSize / (float) max;\r
float totalDeviation = 0.0f;\r
for (int i = 0; i < max; i++) {\r
FinderPattern pattern = (FinderPattern) possibleCenters.elementAt(i);\r
totalDeviation += Math.abs(pattern.getEstimatedModuleSize() - average);\r
}\r
- return totalDeviation <= 0.15f * totalModuleSize;\r
+ return totalDeviation <= 0.05f * totalModuleSize;\r
}\r
\r
/**\r
\r
if (size < 3) {\r
// Couldn't find enough finder patterns\r
- throw new ReaderException("Could not find three finder patterns");\r
+ throw ReaderException.getInstance();\r
}\r
\r
if (size > 3) {\r