*\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
\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
FinderPatternFinder(MonochromeBitmapSource image) {\r
this.image = image;\r
this.possibleCenters = new Vector();\r
+ this.crossCheckStateCount = new int[5];\r
}\r
\r
FinderPatternInfo find(Hashtable hints) throws ReaderException {\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
if (foundPatternCross(stateCount)) { // Yes\r
boolean confirmed = handlePossibleCenter(stateCount, i, j);\r
if (confirmed) {\r
- iSkip = 1; // Go back to examining each line\r
+ // Start examining every other line. Checking each line turned out to be too\r
+ // expensive and didn't improve performance.\r
+ iSkip = 2;\r
if (hasSkipped) {\r
done = haveMulitplyConfirmedCenters();\r
} else {\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
// 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
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
- }\r
-\r
- if (size == 3) {\r
- // Found just enough -- hope these are good!\r
- return new FinderPattern[]{\r
- (FinderPattern) possibleCenters.elementAt(0),\r
- (FinderPattern) possibleCenters.elementAt(1),\r
- (FinderPattern) possibleCenters.elementAt(2)\r
- };\r
+ throw ReaderException.getInstance();\r
}\r
\r
- possibleCenters.setSize(size);\r
-\r
- // Hmm, multiple found. We need to pick the best three. Find the most\r
- // popular ones whose module size is nearest the average\r
-\r
- float averageModuleSize = 0.0f;\r
- for (int i = 0; i < size; i++) {\r
- averageModuleSize += ((FinderPattern) possibleCenters.elementAt(i)).getEstimatedModuleSize();\r
+ if (size > 3) {\r
+ // Throw away all but those first size candidate points we found.\r
+ possibleCenters.setSize(size);\r
+ // We need to pick the best three. Find the most\r
+ // popular ones whose module size is nearest the average\r
+ float averageModuleSize = 0.0f;\r
+ for (int i = 0; i < size; i++) {\r
+ averageModuleSize += ((FinderPattern) possibleCenters.elementAt(i)).getEstimatedModuleSize();\r
+ }\r
+ averageModuleSize /= (float) size;\r
+ // We don't have java.util.Collections in J2ME\r
+ Collections.insertionSort(possibleCenters, new ClosestToAverageComparator(averageModuleSize));\r
}\r
- averageModuleSize /= (float) size;\r
-\r
- // We don't have java.util.Collections in J2ME\r
- Collections.insertionSort(possibleCenters, new ClosestToAverageComparator(averageModuleSize));\r
\r
return new FinderPattern[]{\r
(FinderPattern) possibleCenters.elementAt(0),\r