IEnumerable<MinutiaPair> GetRoots()
        {
            const int minEdgeLength = 58;
            const int maxEdgeLookups = 1633;

            int counter = 0;
            var filters = new Predicate<EdgeShape>[]
            {
                shape => shape.Length >= minEdgeLength,
                shape => shape.Length < minEdgeLength
            };
            foreach (var shapeFilter in filters)
            {
                for (int step = 1; step < Candidate.Minutiae.Count; ++step)
                    for (int pass = 0; pass < step + 1; ++pass)
                        for (int candidateReference = pass; candidateReference < Candidate.Minutiae.Count; candidateReference += step + 1)
                        {
                            int candidateNeighbor = (candidateReference + step) % Candidate.Minutiae.Count;
                            var candidateEdge = new EdgeShape(Candidate, candidateReference, candidateNeighbor);
                            if (shapeFilter(candidateEdge))
                            {
                                List<IndexedEdge> matches;
                                if (EdgeHash.TryGetValue(HashShape(candidateEdge), out matches))
                                {
                                    foreach (var match in matches)
                                    {
                                        if (MatchingShapes(match.Shape, candidateEdge))
                                        {
                                            var pair = new MinutiaPair()
                                            {
                                                Probe = match.Reference,
                                                Candidate = candidateReference
                                            };
                                            yield return pair;
                                            ++counter;
                                            if (counter >= maxEdgeLookups)
                                                yield break;
                                        }
                                    }
                                }
                            }
                        }
            }
        }
 static int HashShape(EdgeShape edge)
 {
     return((edge.ReferenceAngle / MaxAngleError << 24) + (edge.NeighborAngle / MaxAngleError << 16) + edge.Length / MaxDistanceError);
 }
        double ComputeScore()
        {
            const int minSupportingEdges = 1;
            const double distanceErrorFlatness = 0.69;
            const double angleErrorFlatness = 0.27;

            const double pairCountFactor = 0.032;
            const double pairFractionFactor = 8.98;
            const double correctTypeFactor = 0.629;
            const double supportedCountFactor = 0.193;
            const double edgeCountFactor = 0.265;
            const double distanceAccuracyFactor = 9.9;
            const double angleAccuracyFactor = 2.79;

            double score = pairCountFactor * PairCount;
            score += pairFractionFactor * (PairCount / (double)Template.Minutiae.Count + PairCount / (double)Candidate.Minutiae.Count) / 2;

            for (int i = 0; i < PairCount; ++i)
            {
                PairInfo pair = PairList[i];
                if (pair.SupportingEdges >= minSupportingEdges)
                    score += supportedCountFactor;
                score += edgeCountFactor * (pair.SupportingEdges + 1);
                if (Template.Minutiae[pair.Pair.Probe].Type == Candidate.Minutiae[pair.Pair.Candidate].Type)
                    score += correctTypeFactor;
            }

            var innerDistanceRadius = Convert.ToInt32(distanceErrorFlatness * FingerprintMatcher.MaxDistanceError);
            var innerAngleRadius = Convert.ToInt32(angleErrorFlatness * FingerprintMatcher.MaxAngleError);

            var distanceErrorSum = 0;
            var angleErrorSum = 0;

            for (int i = 1; i < PairCount; ++i)
            {
                PairInfo pair = PairList[i];
                var probeEdge = new EdgeShape(Template, pair.Reference.Probe, pair.Pair.Probe);
                var candidateEdge = new EdgeShape(Candidate, pair.Reference.Candidate, pair.Pair.Candidate);
                distanceErrorSum += Math.Abs(probeEdge.Length - candidateEdge.Length);
                angleErrorSum += Math.Max(innerDistanceRadius, Angle.Distance(probeEdge.ReferenceAngle, candidateEdge.ReferenceAngle));
                angleErrorSum += Math.Max(innerAngleRadius, Angle.Distance(probeEdge.NeighborAngle, candidateEdge.NeighborAngle));
            }

            if (PairCount >= 2)
            {
                var maxDistanceError = FingerprintMatcher.MaxDistanceError * (PairCount - 1);
                score += distanceAccuracyFactor * (maxDistanceError - distanceErrorSum) / maxDistanceError;
                var maxAngleError = FingerprintMatcher.MaxAngleError * (PairCount - 1) * 2;
                score += angleAccuracyFactor * (maxAngleError - angleErrorSum) / maxAngleError;
            }

            return score;
        }
 static bool MatchingShapes(EdgeShape probe, EdgeShape candidate)
 {
     int lengthDelta = probe.Length - candidate.Length;
     if (lengthDelta >= -MaxDistanceError && lengthDelta <= MaxDistanceError)
     {
         byte complementaryAngleError = Angle.Complementary(MaxAngleError);
         byte referenceDelta = Angle.Difference(probe.ReferenceAngle, candidate.ReferenceAngle);
         if (referenceDelta <= MaxAngleError || referenceDelta >= complementaryAngleError)
         {
             byte neighborDelta = Angle.Difference(probe.NeighborAngle, candidate.NeighborAngle);
             if (neighborDelta <= MaxAngleError || neighborDelta >= complementaryAngleError)
                 return true;
         }
     }
     return false;
 }
 static int HashShape(EdgeShape edge)
 {
     return (edge.ReferenceAngle / MaxAngleError << 24) + (edge.NeighborAngle / MaxAngleError << 16) + edge.Length / MaxDistanceError;
 }
 static IEnumerable<int> GetShapeCoverage(EdgeShape edge)
 {
     int minLengthBin = (edge.Length - MaxDistanceError) / MaxDistanceError;
     int maxLengthBin = (edge.Length + MaxDistanceError) / MaxDistanceError;
     int angleBins = MathEx.DivRoundUp(256, MaxAngleError);
     int minReferenceBin = Angle.Difference(edge.ReferenceAngle, MaxAngleError) / MaxAngleError;
     int maxReferenceBin = Angle.Add(edge.ReferenceAngle, MaxAngleError) / MaxAngleError;
     int endReferenceBin = (maxReferenceBin + 1) % angleBins;
     int minNeighborBin = Angle.Difference(edge.NeighborAngle, MaxAngleError) / MaxAngleError;
     int maxNeighborBin = Angle.Add(edge.NeighborAngle, MaxAngleError) / MaxAngleError;
     int endNeighborBin = (maxNeighborBin + 1) % angleBins;
     for (int lengthBin = minLengthBin; lengthBin <= maxLengthBin; ++lengthBin)
         for (int referenceBin = minReferenceBin; referenceBin != endReferenceBin; referenceBin = (referenceBin + 1) % angleBins)
             for (int neighborBin = minNeighborBin; neighborBin != endNeighborBin; neighborBin = (neighborBin + 1) % angleBins)
                 yield return (referenceBin << 24) + (neighborBin << 16) + lengthBin;
 }
Exemple #7
0
        public void Compute(MatcherThread thread)
        {
            MinutiaCount               = thread.Count;
            MinutiaScore               = Parameters.MinutiaScore * MinutiaCount;
            MinutiaFractionInProbe     = thread.Count / (double)thread.Probe.Minutiae.Length;
            MinutiaFractionInCandidate = thread.Count / (double)thread.Candidate.Minutiae.Length;
            MinutiaFraction            = 0.5 * (MinutiaFractionInProbe + MinutiaFractionInCandidate);
            MinutiaFractionScore       = Parameters.MinutiaFractionScore * MinutiaFraction;
            SupportingEdgeSum          = 0;
            SupportedMinutiaCount      = 0;
            MinutiaTypeHits            = 0;
            for (int i = 0; i < thread.Count; ++i)
            {
                var pair = thread.Tree[i];
                SupportingEdgeSum += pair.SupportingEdges;
                if (pair.SupportingEdges >= Parameters.MinSupportingEdges)
                {
                    ++SupportedMinutiaCount;
                }
                if (thread.Probe.Minutiae[pair.Probe].Type == thread.Candidate.Minutiae[pair.Candidate].Type)
                {
                    ++MinutiaTypeHits;
                }
            }
            EdgeCount             = thread.Count + SupportingEdgeSum;
            EdgeScore             = Parameters.EdgeScore * EdgeCount;
            SupportedMinutiaScore = Parameters.SupportedMinutiaScore * SupportedMinutiaCount;
            MinutiaTypeScore      = Parameters.MinutiaTypeScore * MinutiaTypeHits;
            int    innerDistanceRadius = Doubles.RoundToInt(Parameters.DistanceErrorFlatness * Parameters.MaxDistanceError);
            double innerAngleRadius    = Parameters.AngleErrorFlatness * Parameters.MaxAngleError;

            DistanceErrorSum = 0;
            AngleErrorSum    = 0;
            for (int i = 1; i < thread.Count; ++i)
            {
                var pair          = thread.Tree[i];
                var probeEdge     = new EdgeShape(thread.Probe.Minutiae[pair.ProbeRef], thread.Probe.Minutiae[pair.Probe]);
                var candidateEdge = new EdgeShape(thread.Candidate.Minutiae[pair.CandidateRef], thread.Candidate.Minutiae[pair.Candidate]);
                DistanceErrorSum += Math.Max(innerDistanceRadius, Math.Abs(probeEdge.Length - candidateEdge.Length));
                AngleErrorSum    += Math.Max(innerAngleRadius, DoubleAngle.Distance(probeEdge.ReferenceAngle, candidateEdge.ReferenceAngle));
                AngleErrorSum    += Math.Max(innerAngleRadius, DoubleAngle.Distance(probeEdge.NeighborAngle, candidateEdge.NeighborAngle));
            }
            DistanceAccuracyScore = 0;
            AngleAccuracyScore    = 0;
            int distanceErrorPotential = Parameters.MaxDistanceError * Math.Max(0, thread.Count - 1);

            DistanceAccuracySum   = distanceErrorPotential - DistanceErrorSum;
            DistanceAccuracyScore = Parameters.DistanceAccuracyScore * (distanceErrorPotential > 0 ? DistanceAccuracySum / (double)distanceErrorPotential : 0);
            double angleErrorPotential = Parameters.MaxAngleError * Math.Max(0, thread.Count - 1) * 2;

            AngleAccuracySum   = angleErrorPotential - AngleErrorSum;
            AngleAccuracyScore = Parameters.AngleAccuracyScore * (angleErrorPotential > 0 ? AngleAccuracySum / angleErrorPotential : 0);
            TotalScore         = MinutiaScore
                                 + MinutiaFractionScore
                                 + SupportedMinutiaScore
                                 + EdgeScore
                                 + MinutiaTypeScore
                                 + DistanceAccuracyScore
                                 + AngleAccuracyScore;
            ShapedScore = Shape(TotalScore);
        }