/// <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);
        }
예제 #2
0
        /// <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]
            });
        }