示例#1
0
        static bool IsWithinGapLimits(SkeletonMinutia end1, SkeletonMinutia end2)
        {
            int distanceSq = (end1.Position - end2.Position).LengthSq;

            if (distanceSq <= Integers.Sq(Parameters.MaxRuptureSize))
            {
                return(true);
            }
            if (distanceSq > Integers.Sq(Parameters.MaxGapSize))
            {
                return(false);
            }
            double gapDirection = DoubleAngle.Atan(end1.Position, end2.Position);
            double direction1   = DoubleAngle.Atan(end1.Position, AngleSampleForGapRemoval(end1));

            if (DoubleAngle.Distance(direction1, DoubleAngle.Opposite(gapDirection)) > Parameters.MaxGapAngle)
            {
                return(false);
            }
            double direction2 = DoubleAngle.Atan(end2.Position, AngleSampleForGapRemoval(end2));

            if (DoubleAngle.Distance(direction2, gapDirection) > Parameters.MaxGapAngle)
            {
                return(false);
            }
            return(true);
        }
        static List <int> ShapeCoverage(EdgeShape edge)
        {
            int minLengthBin    = (edge.Length - Parameters.MaxDistanceError) / Parameters.MaxDistanceError;
            int maxLengthBin    = (edge.Length + Parameters.MaxDistanceError) / Parameters.MaxDistanceError;
            int angleBins       = (int)Math.Ceiling(2 * Math.PI / Parameters.MaxAngleError);
            int minReferenceBin = (int)(DoubleAngle.Difference(edge.ReferenceAngle, Parameters.MaxAngleError) / Parameters.MaxAngleError);
            int maxReferenceBin = (int)(DoubleAngle.Add(edge.ReferenceAngle, Parameters.MaxAngleError) / Parameters.MaxAngleError);
            int endReferenceBin = (maxReferenceBin + 1) % angleBins;
            int minNeighborBin  = (int)(DoubleAngle.Difference(edge.NeighborAngle, Parameters.MaxAngleError) / Parameters.MaxAngleError);
            int maxNeighborBin  = (int)(DoubleAngle.Add(edge.NeighborAngle, Parameters.MaxAngleError) / Parameters.MaxAngleError);
            int endNeighborBin  = (maxNeighborBin + 1) % angleBins;
            var coverage        = new List <int>();

            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)
                    {
                        coverage.Add((referenceBin << 24) + (neighborBin << 16) + lengthBin);
                    }
                }
            }
            return(coverage);
        }
示例#3
0
        static DoubleMatrix SmoothRidges(DoubleMatrix input, DoubleMatrix orientation, BooleanMatrix mask, BlockMap blocks, double angle, IntPoint[][] lines)
        {
            var output = new DoubleMatrix(input.Size);

            foreach (var block in blocks.Primary.Blocks.Iterate())
            {
                if (mask[block])
                {
                    var line = lines[DoubleAngle.Quantize(DoubleAngle.Add(orientation[block], angle), lines.Length)];
                    foreach (var linePoint in line)
                    {
                        var target = blocks.Primary.Block(block);
                        var source = target.Move(linePoint).Intersect(new IntRect(blocks.Pixels));
                        target = source.Move(-linePoint);
                        for (int y = target.Top; y < target.Bottom; ++y)
                        {
                            for (int x = target.Left; x < target.Right; ++x)
                            {
                                output.Add(x, y, input[x + linePoint.X, y + linePoint.Y]);
                            }
                        }
                    }
                    var blockArea = blocks.Primary.Block(block);
                    for (int y = blockArea.Top; y < blockArea.Bottom; ++y)
                    {
                        for (int x = blockArea.Left; x < blockArea.Right; ++x)
                        {
                            output.Multiply(x, y, 1.0 / line.Length);
                        }
                    }
                }
            }
            return(output);
        }
示例#4
0
        public EdgeShape(ImmutableMinutia reference, ImmutableMinutia neighbor)
        {
            IntPoint vector   = neighbor.Position - reference.Position;
            double   quadrant = 0;
            int      x        = vector.X;
            int      y        = vector.Y;

            if (y < 0)
            {
                x        = -x;
                y        = -y;
                quadrant = Math.PI;
            }
            if (x < 0)
            {
                int tmp = -x;
                x         = y;
                y         = tmp;
                quadrant += DoubleAngle.HalfPi;
            }
            int shift  = 32 - (int)Integers.LeadingZeros(((uint)x | (uint)y) >> PolarCacheBits);
            int offset = (y >> shift) * PolarCacheRadius + (x >> shift);

            Length = PolarDistanceCache[offset] << shift;
            double angle = PolarAngleCache[offset] + quadrant;

            ReferenceAngle = DoubleAngle.Difference(reference.Direction, angle);
            NeighborAngle  = DoubleAngle.Difference(neighbor.Direction, DoubleAngle.Opposite(angle));
        }
示例#5
0
 static void MaskMinutiae(List <MutableMinutia> minutiae, BooleanMatrix mask)
 {
     minutiae.RemoveAll(minutia =>
     {
         var arrow = (-Parameters.MaskDisplacement * DoubleAngle.ToVector(minutia.Direction)).Round();
         return(!mask.Get(minutia.Position + arrow, false));
     });
 }
示例#6
0
        static DoubleMatrix OrientationAngles(DoublePointMatrix vectors, BooleanMatrix mask)
        {
            var size   = mask.Size;
            var angles = new DoubleMatrix(size);

            foreach (var block in size.Iterate())
            {
                if (mask[block])
                {
                    angles[block] = DoubleAngle.Atan(vectors[block]);
                }
            }
            return(angles);
        }
示例#7
0
        public double Direction()
        {
            int first = Parameters.RidgeDirectionSkip;
            int last  = Parameters.RidgeDirectionSkip + Parameters.RidgeDirectionSample - 1;

            if (last >= Points.Count)
            {
                int shift = last - Points.Count + 1;
                last  -= shift;
                first -= shift;
            }
            if (first < 0)
            {
                first = 0;
            }
            return(DoubleAngle.Atan(Points[first], Points[last]));
        }
示例#8
0
 static EdgeShape()
 {
     for (int y = 0; y < PolarCacheRadius; ++y)
     {
         for (int x = 0; x < PolarCacheRadius; ++x)
         {
             PolarDistanceCache[y * PolarCacheRadius + x] = Doubles.RoundToInt(Math.Sqrt(Doubles.Sq(x) + Doubles.Sq(y)));
             if (y > 0 || x > 0)
             {
                 PolarAngleCache[y * PolarCacheRadius + x] = DoubleAngle.Atan(x, y);
             }
             else
             {
                 PolarAngleCache[y * PolarCacheRadius + x] = 0;
             }
         }
     }
 }
示例#9
0
        static ConsideredOrientation[][] PlanOrientations()
        {
            var random = new OrientationRandom();
            var splits = new ConsideredOrientation[Parameters.OrientationSplit][];

            for (int i = 0; i < Parameters.OrientationSplit; ++i)
            {
                var orientations = splits[i] = new ConsideredOrientation[Parameters.OrientationsChecked];
                for (int j = 0; j < Parameters.OrientationsChecked; ++j)
                {
                    var sample = orientations[j] = new ConsideredOrientation();
                    while (true)
                    {
                        double angle    = random.Next() * Math.PI;
                        double distance = Doubles.InterpolateExponential(Parameters.MinOrientationRadius, Parameters.MaxOrientationRadius, random.Next());
                        sample.Offset = (distance * DoubleAngle.ToVector(angle)).Round();
                        if (sample.Offset == IntPoint.Zero)
                        {
                            continue;
                        }
                        if (sample.Offset.Y < 0)
                        {
                            continue;
                        }
                        bool duplicate = false;
                        for (int jj = 0; jj < j; ++jj)
                        {
                            if (orientations[jj].Offset == sample.Offset)
                            {
                                duplicate = true;
                            }
                        }
                        if (duplicate)
                        {
                            continue;
                        }
                        break;
                    }
                    sample.Orientation = DoubleAngle.ToVector(DoubleAngle.Add(DoubleAngle.ToOrientation(DoubleAngle.Atan((DoublePoint)sample.Offset)), Math.PI));
                }
            }
            return(splits);
        }
示例#10
0
        static bool MatchingShapes(EdgeShape probe, EdgeShape candidate)
        {
            int lengthDelta = probe.Length - candidate.Length;

            if (lengthDelta >= -Parameters.MaxDistanceError && lengthDelta <= Parameters.MaxDistanceError)
            {
                double complementaryAngleError = DoubleAngle.Complementary(Parameters.MaxAngleError);
                double referenceDelta          = DoubleAngle.Difference(probe.ReferenceAngle, candidate.ReferenceAngle);
                if (referenceDelta <= Parameters.MaxAngleError || referenceDelta >= complementaryAngleError)
                {
                    double neighborDelta = DoubleAngle.Difference(probe.NeighborAngle, candidate.NeighborAngle);
                    if (neighborDelta <= Parameters.MaxAngleError || neighborDelta >= complementaryAngleError)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
示例#11
0
        List <MinutiaPair> MatchPairs(NeighborEdge[] probeStar, NeighborEdge[] candidateStar)
        {
            double complementaryAngleError = DoubleAngle.Complementary(Parameters.MaxAngleError);
            var    results = new List <MinutiaPair>();
            int    start   = 0;
            int    end     = 0;

            for (int candidateIndex = 0; candidateIndex < candidateStar.Length; ++candidateIndex)
            {
                var candidateEdge = candidateStar[candidateIndex];
                while (start < probeStar.Length && probeStar[start].Length < candidateEdge.Length - Parameters.MaxDistanceError)
                {
                    ++start;
                }
                if (end < start)
                {
                    end = start;
                }
                while (end < probeStar.Length && probeStar[end].Length <= candidateEdge.Length + Parameters.MaxDistanceError)
                {
                    ++end;
                }
                for (int probeIndex = start; probeIndex < end; ++probeIndex)
                {
                    var    probeEdge     = probeStar[probeIndex];
                    double referenceDiff = DoubleAngle.Difference(probeEdge.ReferenceAngle, candidateEdge.ReferenceAngle);
                    if (referenceDiff <= Parameters.MaxAngleError || referenceDiff >= complementaryAngleError)
                    {
                        double neighborDiff = DoubleAngle.Difference(probeEdge.NeighborAngle, candidateEdge.NeighborAngle);
                        if (neighborDiff <= Parameters.MaxAngleError || neighborDiff >= complementaryAngleError)
                        {
                            var pair = Allocate();
                            pair.Probe     = probeEdge.Neighbor;
                            pair.Candidate = candidateEdge.Neighbor;
                            pair.Distance  = candidateEdge.Length;
                            results.Add(pair);
                        }
                    }
                }
            }
            return(results);
        }
示例#12
0
 public void Validate()
 {
     /*
      * Width and height are informative only. Don't validate them. Ditto for version string.
      */
     if (PositionsX == null)
     {
         throw new NullReferenceException("Null array of X positions.");
     }
     if (PositionsY == null)
     {
         throw new NullReferenceException("Null array of Y positions.");
     }
     if (Directions == null)
     {
         throw new NullReferenceException("Null array of minutia directions.");
     }
     if (Types == null)
     {
         throw new NullReferenceException("Null minutia type string.");
     }
     if (PositionsX.Length != Types.Length || PositionsY.Length != Types.Length || Directions.Length != Types.Length)
     {
         throw new ArgumentException("Inconsistent lengths of minutia property arrays.");
     }
     for (int i = 0; i < Types.Length; ++i)
     {
         if (Math.Abs(PositionsX[i]) > 10_000 || Math.Abs(PositionsY[i]) > 10_000)
         {
             throw new ArgumentException("Minutia position out of range.");
         }
         if (!DoubleAngle.Normalized(Directions[i]))
         {
             throw new ArgumentException("Denormalized minutia direction.");
         }
         if (Types[i] != 'E' && Types[i] != 'B')
         {
             throw new ArgumentException("Unknown minutia type.");
         }
     }
 }
示例#13
0
        static IntPoint[][] OrientedLines(int resolution, int radius, double step)
        {
            var result = new IntPoint[resolution][];

            for (int orientationIndex = 0; orientationIndex < resolution; ++orientationIndex)
            {
                var line = new List <IntPoint>();
                line.Add(IntPoint.Zero);
                var direction = DoubleAngle.ToVector(DoubleAngle.FromOrientation(DoubleAngle.BucketCenter(orientationIndex, resolution)));
                for (double r = radius; r >= 0.5; r /= step)
                {
                    var sample = (r * direction).Round();
                    if (!line.Contains(sample))
                    {
                        line.Add(sample);
                        line.Add(-sample);
                    }
                }
                result[orientationIndex] = line.ToArray();
            }
            return(result);
        }
示例#14
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);
        }