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); }
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); }
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)); }
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)); }); }
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); }
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])); }
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; } } } }
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); }
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); }
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); }
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."); } } }
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); }
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); }