/// <returns> true iff we have found at least 3 finder patterns that have been detected /// at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the /// candidates is "pretty similar" /// </returns> private bool haveMultiplyConfirmedCenters() { int confirmedCount = 0; float totalModuleSize = 0.0f; int max = possibleCenters.Count; for (int i = 0; i < max; i++) { FinderPattern pattern = (FinderPattern)possibleCenters[i]; if (pattern.Count >= CENTER_QUORUM) { confirmedCount++; totalModuleSize += pattern.EstimatedModuleSize; } } if (confirmedCount < 3) { return(false); } // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" // and that we need to keep looking. We detect this by asking if the estimated module sizes // vary too much. We arbitrarily say that when the total deviation from average exceeds // 5% of the total module size estimates, it's too much. //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float average = totalModuleSize / (float)max; float totalDeviation = 0.0f; for (int i = 0; i < max; i++) { FinderPattern pattern = (FinderPattern)possibleCenters[i]; totalDeviation += System.Math.Abs(pattern.EstimatedModuleSize - average); } return(totalDeviation <= 0.05f * totalModuleSize); }
/// <returns> the 3 best <seealso cref="FinderPattern"/>s from our list of candidates. The "best" are /// those that have been detected at least <seealso cref="#CENTER_QUORUM"/> times, and whose module /// size differs from the average among those patterns the least </returns> /// <exception cref="NotFoundException"> if 3 such finder patterns do not exist </exception> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: private FinderPattern[] selectBestPatterns() throws com.google.zxing.NotFoundException private FinderPattern[] selectBestPatterns() { int startSize = possibleCenters.Count; if (startSize < 3) { // Couldn't find enough finder patterns throw NotFoundException.NotFoundInstance; } // Filter outlier possibilities whose module size is too different if (startSize > 3) { // But we can only afford to do so if we have at least 4 possibilities to choose from float totalModuleSize = 0.0f; float square = 0.0f; foreach (FinderPattern center in possibleCenters) { float size = center.EstimatedModuleSize; totalModuleSize += size; square += size * size; } float average = totalModuleSize / (float)startSize; float stdDev = (float)Math.Sqrt(square / startSize - average * average); possibleCenters.Sort(new FurthestFromAverageComparator(average)); float limit = Math.Max(0.2f * average, stdDev); for (int i = 0; i < possibleCenters.Count && possibleCenters.Count > 3; i++) { FinderPattern pattern = possibleCenters[i]; if (Math.Abs(pattern.EstimatedModuleSize - average) > limit) { possibleCenters.RemoveAt(i); i--; } } } if (possibleCenters.Count > 3) { // Throw away all but those first size candidate points we found. float totalModuleSize = 0.0f; foreach (FinderPattern possibleCenter in possibleCenters) { totalModuleSize += possibleCenter.EstimatedModuleSize; } float average = totalModuleSize / (float)possibleCenters.Count; possibleCenters.Sort(new CenterComparator(average)); //possibleCenters.subList(3, possibleCenters.Count).clear(); possibleCenters.RemoveRange(3, possibleCenters.Count - 3); } return(new FinderPattern[] { possibleCenters[0], possibleCenters[1], possibleCenters[2] }); }
/// <returns> number of rows we could safely skip during scanning, based on the first /// two finder patterns that have been located. In some cases their position will /// allow us to infer that the third pattern must lie below a certain point farther /// down in the image. /// </returns> private int findRowSkip() { int max = possibleCenters.Count; if (max <= 1) { return(0); } FinderPattern firstConfirmedCenter = null; for (int i = 0; i < max; i++) { FinderPattern center = (FinderPattern)possibleCenters[i]; if (center.Count >= CENTER_QUORUM) { if (firstConfirmedCenter == null) { firstConfirmedCenter = center; } else { // We have two confirmed centers // How far down can we skip before resuming looking for the next // pattern? In the worst case, only the difference between the // difference in the x / y coordinates of the two centers. // This is the case where you find top left last. hasSkipped = true; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" return((int)(System.Math.Abs(firstConfirmedCenter.X - center.X) - System.Math.Abs(firstConfirmedCenter.Y - center.Y)) / 2); } } } return(0); }
/// <returns> number of rows we could safely skip during scanning, based on the first /// two finder patterns that have been located. In some cases their position will /// allow us to infer that the third pattern must lie below a certain point farther /// down in the image. </returns> private int findRowSkip() { int max = possibleCenters.Count; if (max <= 1) { return(0); } FinderPattern firstConfirmedCenter = null; foreach (FinderPattern center in possibleCenters) { if (center.Count >= CENTER_QUORUM) { if (firstConfirmedCenter == null) { firstConfirmedCenter = center; } else { // We have two confirmed centers // How far down can we skip before resuming looking for the next // pattern? In the worst case, only the difference between the // difference in the x / y coordinates of the two centers. // This is the case where you find top left last. hasSkipped = true; return((int)(Math.Abs(firstConfirmedCenter.X - center.X) - Math.Abs(firstConfirmedCenter.Y - center.Y)) / 2); } } } return(0); }
/** * @return true iff we have found at least 3 finder patterns that have been detected * at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the * candidates is "pretty similar" */ private bool haveMulitplyConfirmedCenters() { int confirmedCount = 0; float totalModuleSize = 0.0f; int max = possibleCenters.Count; for (int i = 0; i < max; i++) { FinderPattern pattern = (FinderPattern)possibleCenters[i]; if (pattern.getCount() >= CENTER_QUORUM) { confirmedCount++; totalModuleSize += pattern.getEstimatedModuleSize(); } } if (confirmedCount < 3) { return(false); } // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" // and that we need to keep looking. We detect this by asking if the estimated module sizes // vary too much. We arbitrarily say that when the total deviation from average exceeds // 15% of the total module size estimates, it's too much. float average = totalModuleSize / max; float totalDeviation = 0.0f; for (int i = 0; i < max; i++) { FinderPattern pattern = (FinderPattern)possibleCenters[i]; totalDeviation += Math.Abs(pattern.getEstimatedModuleSize() - average); } return(totalDeviation <= 0.15f * totalModuleSize); }
/// <summary> <p>This is called when a horizontal scan finds a possible alignment pattern. It will /// cross check with a vertical scan, and if successful, will, ah, cross-cross-check /// with another horizontal scan. This is needed primarily to locate the real horizontal /// center of the pattern in cases of extreme skew.</p> /// /// <p>If that succeeds the finder pattern location is added to a list that tracks /// the number of times each location has been nearly-matched as a finder pattern. /// Each additional find is more evidence that the location is in fact a finder /// pattern center /// /// </summary> /// <param name="stateCount">reading state module counts from horizontal scan /// </param> /// <param name="i">row where finder pattern may be found /// </param> /// <param name="j">end of possible finder pattern in row /// </param> /// <returns> true if a finder pattern candidate was found this time /// </returns> protected internal virtual bool handlePossibleCenter(int[] stateCount, int i, int j) { int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; float centerJ = centerFromEnd(stateCount, j); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float centerI = crossCheckVertical(i, (int)centerJ, stateCount[2], stateCountTotal); if (!System.Single.IsNaN(centerI)) { // Re-cross check //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" centerJ = crossCheckHorizontal((int)centerJ, (int)centerI, stateCount[2], stateCountTotal); if (!System.Single.IsNaN(centerJ)) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float estimatedModuleSize = (float)stateCountTotal / 7.0f; bool found = false; int max = possibleCenters.Count; for (int index = 0; index < max; index++) { FinderPattern center = (FinderPattern)possibleCenters[index]; // Look for about the same center and module size: if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { center.incrementCount(); found = true; break; } } if (!found) { ResultPoint point = new FinderPattern(centerJ, centerI, estimatedModuleSize); possibleCenters.Add(point); if (resultPointCallback != null) { resultPointCallback.foundPossibleResultPoint(point); } } return(true); } } return(false); }
/// <returns> the 3 best {@link FinderPattern}s from our list of candidates. The "best" are /// those that have been detected at least {@link #CENTER_QUORUM} times, and whose module /// size differs from the average among those patterns the least /// </returns> /// <throws> ReaderException if 3 such finder patterns do not exist </throws> private FinderPattern[] selectBestPatterns() { int startSize = possibleCenters.Count; if (startSize < 3) { // Couldn't find enough finder patterns return(null); } // Filter outlier possibilities whose module size is too different if (startSize > 3) { // But we can only afford to do so if we have at least 4 possibilities to choose from float totalModuleSize = 0.0f; for (int i = 0; i < startSize; i++) { totalModuleSize += ((FinderPattern)possibleCenters[i]).EstimatedModuleSize; } //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float average = totalModuleSize / (float)startSize; for (int i = 0; i < possibleCenters.Count && possibleCenters.Count > 3; i++) { FinderPattern pattern = (FinderPattern)possibleCenters[i]; if (System.Math.Abs(pattern.EstimatedModuleSize - average) > 0.2f * average) { possibleCenters.RemoveAt(i); i--; } } } if (possibleCenters.Count > 3) { // Throw away all but those first size candidate points we found. Collections.insertionSort(possibleCenters, new CenterComparator()); SupportClass.SetCapacity(possibleCenters, 3); } return(new FinderPattern[] { (FinderPattern)possibleCenters[0], (FinderPattern)possibleCenters[1], (FinderPattern)possibleCenters[2] }); }
/// <summary> /// <p>This is called when a horizontal scan finds a possible alignment pattern. It will /// cross check with a vertical scan, and if successful, will, ah, cross-cross-check /// with another horizontal scan. This is needed primarily to locate the real horizontal /// center of the pattern in cases of extreme skew.</p> /// /// <p>If that succeeds the finder pattern location is added to a list that tracks /// the number of times each location has been nearly-matched as a finder pattern. /// Each additional find is more evidence that the location is in fact a finder /// pattern center /// </summary> /// <param name="stateCount"> reading state module counts from horizontal scan </param> /// <param name="i"> row where finder pattern may be found </param> /// <param name="j"> end of possible finder pattern in row </param> /// <returns> true if a finder pattern candidate was found this time </returns> protected internal bool handlePossibleCenter(int[] stateCount, int i, int j) { int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; float centerJ = centerFromEnd(stateCount, j); float centerI = crossCheckVertical(i, (int)centerJ, stateCount[2], stateCountTotal); if (!float.IsNaN(centerI)) { // Re-cross check centerJ = crossCheckHorizontal((int)centerJ, (int)centerI, stateCount[2], stateCountTotal); if (!float.IsNaN(centerJ)) { float estimatedModuleSize = (float)stateCountTotal / 7.0f; bool found = false; for (int index = 0; index < possibleCenters.Count; index++) { FinderPattern center = possibleCenters[index]; // Look for about the same center and module size: if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { possibleCenters[index] = center.combineEstimate(centerI, centerJ, estimatedModuleSize); found = true; break; } } if (!found) { FinderPattern point = new FinderPattern(centerJ, centerI, estimatedModuleSize); possibleCenters.Add(point); if (resultPointCallback != null) { resultPointCallback.foundPossibleResultPoint(point); } } return(true); } } return(false); }
/** * <p>This is called when a horizontal scan finds a possible alignment pattern. It will * cross check with a vertical scan, and if successful, will, ah, cross-cross-check * with another horizontal scan. This is needed primarily to locate the real horizontal * center of the pattern in cases of extreme skew.</p> * * <p>If that succeeds the finder pattern location is added to a list that tracks * the number of times each location has been nearly-matched as a finder pattern. * Each additional find is more evidence that the location is in fact a finder * pattern center * * @param stateCount reading state module counts from horizontal scan * @param i row where finder pattern may be found * @param j end of possible finder pattern in row * @return true if a finder pattern candidate was found this time */ private bool handlePossibleCenter(int[] stateCount, int i, int j) { int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; float centerJ = centerFromEnd(stateCount, j); float centerI = crossCheckVertical(i, (int)centerJ, stateCount[2], stateCountTotal); if (!Single.IsNaN(centerI)) { // Re-cross check centerJ = crossCheckHorizontal((int)centerJ, (int)centerI, stateCount[2], stateCountTotal); if (!Single.IsNaN(centerJ)) { float estimatedModuleSize = (float)stateCountTotal / 7.0f; bool found = false; int max = possibleCenters.Count; for (int index = 0; index < max; index++) { FinderPattern center = (FinderPattern)possibleCenters[index]; // Look for about the same center and module size: if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { center.incrementCount(); found = true; break; } } if (!found) { possibleCenters.Add(new FinderPattern(centerJ, centerI, estimatedModuleSize)); } return(true); } } return(false); }
protected internal virtual DetectorResult processFinderPatternInfo(FinderPatternInfo info) { FinderPattern topLeft = info.TopLeft; FinderPattern topRight = info.TopRight; FinderPattern bottomLeft = info.BottomLeft; float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1.0f) { throw ReaderException.Instance; } int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); int modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7; AlignmentPattern alignmentPattern = null; // Anything above version 1 has an alignment pattern if (provisionalVersion.AlignmentPatternCenters.Length > 0) { // Guess where a "bottom right" finder pattern would have been float bottomRightX = topRight.X - topLeft.X + bottomLeft.X; float bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y; // Estimate that alignment pattern is closer by 3 modules // from "bottom right" to known top left location //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" int estAlignmentX = (int)(topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X)); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" int estAlignmentY = (int)(topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y)); // Kind of arbitrary -- expand search radius before giving up for (int i = 4; i <= 16; i <<= 1) { try { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); break; } catch (ReaderException re) { // try next round } } // If we didn't find alignment pattern... well try anyway without it } PerspectiveTransform transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); BitMatrix bits = sampleGrid(image, transform, dimension); ResultPoint[] points; if (alignmentPattern == null) { points = new ResultPoint[] { bottomLeft, topLeft, topRight }; } else { points = new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern }; } return(new DetectorResult(bits, points)); }
/// <summary> <p>This is called when a horizontal scan finds a possible alignment pattern. It will /// cross check with a vertical scan, and if successful, will, ah, cross-cross-check /// with another horizontal scan. This is needed primarily to locate the real horizontal /// center of the pattern in cases of extreme skew.</p> /// /// <p>If that succeeds the finder pattern location is added to a list that tracks /// the number of times each location has been nearly-matched as a finder pattern. /// Each additional find is more evidence that the location is in fact a finder /// pattern center /// /// </summary> /// <param name="stateCount">reading state module counts from horizontal scan /// </param> /// <param name="i">row where finder pattern may be found /// </param> /// <param name="j">end of possible finder pattern in row /// </param> /// <returns> true if a finder pattern candidate was found this time /// </returns> protected internal virtual bool handlePossibleCenter(int[] stateCount, int i, int j) { int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; float centerJ = centerFromEnd(stateCount, j); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float centerI = crossCheckVertical(i, (int) centerJ, stateCount[2], stateCountTotal); if (!System.Single.IsNaN(centerI)) { // Re-cross check //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2], stateCountTotal); if (!System.Single.IsNaN(centerJ)) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float estimatedModuleSize = (float) stateCountTotal / 7.0f; bool found = false; int max = possibleCenters.Count; for (int index = 0; index < max; index++) { FinderPattern center = (FinderPattern) possibleCenters[index]; // Look for about the same center and module size: if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { center.incrementCount(); found = true; break; } } if (!found) { ResultPoint point = new FinderPattern(centerJ, centerI, estimatedModuleSize); possibleCenters.Add(point); if (resultPointCallback != null) { resultPointCallback.foundPossibleResultPoint(point); } } return true; } } return false; }
public FinderPatternInfo(FinderPattern[] patternCenters) { this.bottomLeft = patternCenters[0]; this.topLeft = patternCenters[1]; this.topRight = patternCenters[2]; }
/** * <p>Detects a QR Code in an image, simply.</p> * * @param hints optional hints to detector * @return {@link DetectorResult} encapsulating results of detecting a QR Code * @throws ReaderException if no QR Code can be found */ public DetectorResult detect(System.Collections.Hashtable hints) { MonochromeBitmapSource image = this.image; if (!BlackPointEstimationMethod.TWO_D_SAMPLING.Equals(image.getLastEstimationMethod())) { image.estimateBlackPoint(BlackPointEstimationMethod.TWO_D_SAMPLING, 0); } FinderPatternFinder finder = new FinderPatternFinder(image); FinderPatternInfo info = finder.find(hints); FinderPattern topLeft = info.getTopLeft(); FinderPattern topRight = info.getTopRight(); FinderPattern bottomLeft = info.getBottomLeft(); float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1.0f) { throw new ReaderException(); } int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); int modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7; AlignmentPattern alignmentPattern = null; // Anything above version 1 has an alignment pattern if (provisionalVersion.getAlignmentPatternCenters().Length > 0) { // Guess where a "bottom right" finder pattern would have been float bottomRightX = topRight.getX() - topLeft.getX() + bottomLeft.getX(); float bottomRightY = topRight.getY() - topLeft.getY() + bottomLeft.getY(); // Estimate that alignment pattern is closer by 3 modules // from "bottom right" to known top left location float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; int estAlignmentX = (int)(topLeft.getX() + correctionToTopLeft * (bottomRightX - topLeft.getX())); int estAlignmentY = (int)(topLeft.getY() + correctionToTopLeft * (bottomRightY - topLeft.getY())); // Kind of arbitrary -- expand search radius before giving up for (int i = 4; i <= 16; i <<= 1) { try { alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); break; } catch (ReaderException re) { // try next round } } if (alignmentPattern == null) { throw new ReaderException(); } } BitMatrix bits = sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, dimension); ResultPoint[] points; if (alignmentPattern == null) { points = new ResultPoint[] { bottomLeft, topLeft, topRight }; } else { points = new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern }; } return(new DetectorResult(bits, points)); }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: protected final com.google.zxing.common.DetectorResult processFinderPatternInfo(FinderPatternInfo info) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException protected internal DetectorResult processFinderPatternInfo(FinderPatternInfo info) { FinderPattern topLeft = info.TopLeft; FinderPattern topRight = info.TopRight; FinderPattern bottomLeft = info.BottomLeft; float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1.0f) { throw NotFoundException.NotFoundInstance; } int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); int modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7; AlignmentPattern alignmentPattern = null; // Anything above version 1 has an alignment pattern if (provisionalVersion.AlignmentPatternCenters.Length > 0) { // Guess where a "bottom right" finder pattern would have been float bottomRightX = topRight.X - topLeft.X + bottomLeft.X; float bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y; // Estimate that alignment pattern is closer by 3 modules // from "bottom right" to known top left location float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; int estAlignmentX = (int)(topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X)); int estAlignmentY = (int)(topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y)); // Kind of arbitrary -- expand search radius before giving up for (int i = 4; i <= 16; i <<= 1) { try { alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); break; } catch (NotFoundException re) { // try next round } } // If we didn't find alignment pattern... well try anyway without it } PerspectiveTransform transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); BitMatrix bits = sampleGrid(image, transform, dimension); ResultPoint[] points; if (alignmentPattern == null) { points = new ResultPoint[] { bottomLeft, topLeft, topRight }; } else { points = new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern }; } return(new DetectorResult(bits, points)); }