MultiFinderPatternFinder.java (zxing-zxing-3.4.0) | : | MultiFinderPatternFinder.java (zxing-zxing-3.4.1) | ||
---|---|---|---|---|
skipping to change at line 49 | skipping to change at line 49 | |||
* <p>This class is thread-safe but not reentrant. Each thread must allocate its own object. | * <p>This class is thread-safe but not reentrant. Each thread must allocate its own object. | |||
* | * | |||
* <p>In contrast to {@link FinderPatternFinder}, this class will return an arra y of all possible | * <p>In contrast to {@link FinderPatternFinder}, this class will return an arra y of all possible | |||
* QR code locations in the image.</p> | * QR code locations in the image.</p> | |||
* | * | |||
* <p>Use the TRY_HARDER hint to ask for a more thorough detection.</p> | * <p>Use the TRY_HARDER hint to ask for a more thorough detection.</p> | |||
* | * | |||
* @author Sean Owen | * @author Sean Owen | |||
* @author Hannes Erven | * @author Hannes Erven | |||
*/ | */ | |||
final class MultiFinderPatternFinder extends FinderPatternFinder { | public final class MultiFinderPatternFinder extends FinderPatternFinder { | |||
private static final FinderPatternInfo[] EMPTY_RESULT_ARRAY = new FinderPatter nInfo[0]; | private static final FinderPatternInfo[] EMPTY_RESULT_ARRAY = new FinderPatter nInfo[0]; | |||
private static final FinderPattern[] EMPTY_FP_ARRAY = new FinderPattern[0]; | private static final FinderPattern[] EMPTY_FP_ARRAY = new FinderPattern[0]; | |||
private static final FinderPattern[][] EMPTY_FP_2D_ARRAY = new FinderPattern[0 ][]; | private static final FinderPattern[][] EMPTY_FP_2D_ARRAY = new FinderPattern[0 ][]; | |||
// TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for | // TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for | |||
// since it limits the number of regions to decode | // since it limits the number of regions to decode | |||
// max. legal count of modules per QR code edge (177) | // max. legal count of modules per QR code edge (177) | |||
private static final float MAX_MODULE_COUNT_PER_EDGE = 180; | private static final float MAX_MODULE_COUNT_PER_EDGE = 180; | |||
skipping to change at line 88 | skipping to change at line 88 | |||
* A comparator that orders FinderPatterns by their estimated module size. | * A comparator that orders FinderPatterns by their estimated module size. | |||
*/ | */ | |||
private static final class ModuleSizeComparator implements Comparator<FinderPa ttern>, Serializable { | private static final class ModuleSizeComparator implements Comparator<FinderPa ttern>, Serializable { | |||
@Override | @Override | |||
public int compare(FinderPattern center1, FinderPattern center2) { | public int compare(FinderPattern center1, FinderPattern center2) { | |||
float value = center2.getEstimatedModuleSize() - center1.getEstimatedModul eSize(); | float value = center2.getEstimatedModuleSize() - center1.getEstimatedModul eSize(); | |||
return value < 0.0 ? -1 : value > 0.0 ? 1 : 0; | return value < 0.0 ? -1 : value > 0.0 ? 1 : 0; | |||
} | } | |||
} | } | |||
MultiFinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallb ack) { | public MultiFinderPatternFinder(BitMatrix image, ResultPointCallback resultPoi ntCallback) { | |||
super(image, resultPointCallback); | super(image, resultPointCallback); | |||
} | } | |||
/** | /** | |||
* @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are | * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are | |||
* those that have been detected at least 2 times, and whose module | * those that have been detected at least 2 times, and whose module | |||
* size differs from the average among those patterns the least | * size differs from the average among those patterns the least | |||
* @throws NotFoundException if 3 such finder patterns do not exist | * @throws NotFoundException if 3 such finder patterns do not exist | |||
*/ | */ | |||
private FinderPattern[][] selectMultipleBestPatterns() throws NotFoundExceptio n { | private FinderPattern[][] selectMultipleBestPatterns() throws NotFoundExceptio n { | |||
skipping to change at line 128 | skipping to change at line 128 | |||
* Now lets start: build a list of tuples of three finder locations that | * Now lets start: build a list of tuples of three finder locations that | |||
* - feature similar module sizes | * - feature similar module sizes | |||
* - are placed in a distance so the estimated module count is within the Q R specification | * - are placed in a distance so the estimated module count is within the Q R specification | |||
* - have similar distance between upper left/right and left top/bottom fin der patterns | * - have similar distance between upper left/right and left top/bottom fin der patterns | |||
* - form a triangle with 90° angle (checked by comparing top right/bottom left distance | * - form a triangle with 90° angle (checked by comparing top right/bottom left distance | |||
* with pythagoras) | * with pythagoras) | |||
* | * | |||
* Note: we allow each point to be used for more than one code region: this might seem | * Note: we allow each point to be used for more than one code region: this might seem | |||
* counterintuitive at first, but the performance penalty is not that big. A t this point, | * counterintuitive at first, but the performance penalty is not that big. A t this point, | |||
* we cannot make a good quality decision whether the three finders actually represent | * we cannot make a good quality decision whether the three finders actually represent | |||
* a QR code, or are just by chance layouted so it looks like there might be a QR code there. | * a QR code, or are just by chance laid out so it looks like there might be a QR code there. | |||
* So, if the layout seems right, lets have the decoder try to decode. | * So, if the layout seems right, lets have the decoder try to decode. | |||
*/ | */ | |||
List<FinderPattern[]> results = new ArrayList<>(); // holder for the result s | List<FinderPattern[]> results = new ArrayList<>(); // holder for the result s | |||
for (int i1 = 0; i1 < (size - 2); i1++) { | for (int i1 = 0; i1 < (size - 2); i1++) { | |||
FinderPattern p1 = possibleCenters.get(i1); | FinderPattern p1 = possibleCenters.get(i1); | |||
if (p1 == null) { | if (p1 == null) { | |||
continue; | continue; | |||
} | } | |||
skipping to change at line 237 | skipping to change at line 237 | |||
// number of pixels the center could be, so skip this often. When trying har der, look for all | // number of pixels the center could be, so skip this often. When trying har der, look for all | |||
// QR versions regardless of how dense they are. | // QR versions regardless of how dense they are. | |||
int iSkip = (3 * maxI) / (4 * MAX_MODULES); | int iSkip = (3 * maxI) / (4 * MAX_MODULES); | |||
if (iSkip < MIN_SKIP || tryHarder) { | if (iSkip < MIN_SKIP || tryHarder) { | |||
iSkip = MIN_SKIP; | iSkip = MIN_SKIP; | |||
} | } | |||
int[] stateCount = new int[5]; | int[] stateCount = new int[5]; | |||
for (int i = iSkip - 1; i < maxI; i += iSkip) { | for (int i = iSkip - 1; i < maxI; i += iSkip) { | |||
// Get a row of black/white values | // Get a row of black/white values | |||
clearCounts(stateCount); | doClearCounts(stateCount); | |||
int currentState = 0; | int currentState = 0; | |||
for (int j = 0; j < maxJ; j++) { | for (int j = 0; j < maxJ; j++) { | |||
if (image.get(j, i)) { | if (image.get(j, i)) { | |||
// Black pixel | // Black pixel | |||
if ((currentState & 1) == 1) { // Counting white pixels | if ((currentState & 1) == 1) { // Counting white pixels | |||
currentState++; | currentState++; | |||
} | } | |||
stateCount[currentState]++; | stateCount[currentState]++; | |||
} else { // White pixel | } else { // White pixel | |||
if ((currentState & 1) == 0) { // Counting black pixels | if ((currentState & 1) == 0) { // Counting black pixels | |||
if (currentState == 4) { // A winner? | if (currentState == 4) { // A winner? | |||
if (foundPatternCross(stateCount) && handlePossibleCenter(stateCou nt, i, j)) { // Yes | if (foundPatternCross(stateCount) && handlePossibleCenter(stateCou nt, i, j)) { // Yes | |||
// Clear state to start looking again | // Clear state to start looking again | |||
currentState = 0; | currentState = 0; | |||
clearCounts(stateCount); | doClearCounts(stateCount); | |||
} else { // No, shift counts back by two | } else { // No, shift counts back by two | |||
shiftCounts2(stateCount); | doShiftCounts2(stateCount); | |||
currentState = 3; | currentState = 3; | |||
} | } | |||
} else { | } else { | |||
stateCount[++currentState]++; | stateCount[++currentState]++; | |||
} | } | |||
} else { // Counting white pixels | } else { // Counting white pixels | |||
stateCount[currentState]++; | stateCount[currentState]++; | |||
} | } | |||
} | } | |||
} // for j=... | } // for j=... | |||
End of changes. 6 change blocks. | ||||
6 lines changed or deleted | 6 lines changed or added |