/// <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. /// And then we cross-cross-cross check with another diagonal scan.</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 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); if (centerJ == null) { return(false); } float?centerI = crossCheckVertical(i, (int)centerJ.Value, stateCount[2], stateCountTotal); if (centerI != null) { // Re-cross check centerJ = crossCheckHorizontal((int)centerJ.Value, (int)centerI.Value, stateCount[2], stateCountTotal); if (centerJ != null && crossCheckDiagonal((int)centerI, (int)centerJ)) { float estimatedModuleSize = stateCountTotal / 7.0f; bool found = false; for (int index = 0; index < possibleCenters.Count; index++) { var center = possibleCenters[index]; // Look for about the same center and module size: if (center.aboutEquals(estimatedModuleSize, centerI.Value, centerJ.Value)) { possibleCenters.RemoveAt(index); possibleCenters.Insert(index, center.combineEstimate(centerI.Value, centerJ.Value, estimatedModuleSize)); found = true; break; } } if (!found) { var point = new FinderPattern(centerJ.Value, centerI.Value, estimatedModuleSize); possibleCenters.Add(point); if (resultPointCallback != null) { resultPointCallback(point); } } return(true); } } return(false); }
/// <summary> /// Processes the finder pattern info. /// </summary> /// <param name="info">The info.</param> /// <returns></returns> 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) { return(null); } int dimension; if (!computeDimension(topLeft, topRight, bottomLeft, moduleSize, out dimension)) { return(null); } Internal.Version provisionalVersion = Internal.Version.getProvisionalVersionForDimension(dimension); if (provisionalVersion == null) { return(null); } 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) { alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); if (alignmentPattern == null) { continue; } break; } // 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); if (bits == null) { return(null); } ResultPoint[] points; if (alignmentPattern == null) { points = new ResultPoint[] { bottomLeft, topLeft, topRight }; } else { points = new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern }; } return(new DetectorResult(bits, points)); }
/// <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> 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; float square = 0.0f; foreach (var center in possibleCenters) { float size = center.EstimatedModuleSize; totalModuleSize += size; square += size * size; } float average = totalModuleSize / 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 (var possibleCenter in possibleCenters) { totalModuleSize += possibleCenter.EstimatedModuleSize; } float average = totalModuleSize / possibleCenters.Count; possibleCenters.Sort(new CenterComparator(average)); //possibleCenters.subList(3, possibleCenters.Count).clear(); possibleCenters = possibleCenters.GetRange(0, 3); } return(new[] { possibleCenters[0], possibleCenters[1], possibleCenters[2] }); }