static PointF[,] SmoothOutOrientationMap(PointF[,] orientation, bool[,] mask) { const int radius = 1; var size = Point.SizeOf(mask); PointF[,] smoothed = size.Allocate <PointF>(); for (int y = 0; y < size.Y; ++y) { for (int x = 0; x < size.X; ++x) { if (mask[y, x]) { Rectangle neighbors = Rectangle.Between( new Point(Math.Max(0, x - radius), Math.Max(0, y - radius)), new Point(Math.Min(size.X, x + radius + 1), Math.Min(size.Y, y + radius + 1))); PointF sum = new PointF(); for (int ny = neighbors.Bottom; ny < neighbors.Top; ++ny) { for (int nx = neighbors.Left; nx < neighbors.Right; ++nx) { if (mask[ny, nx]) { sum += orientation[ny, nx]; } } } smoothed[y, x] = sum; } } } return(smoothed); }
static bool[,] ComputeInnerMask(bool[,] outer) { const int minBorderDistance = 14; var size = Point.SizeOf(outer); var inner = size.Allocate <bool>(); for (int y = 1; y < size.Y - 1; ++y) { for (int x = 1; x < size.X - 1; ++x) { inner[y, x] = outer[y, x]; } } if (minBorderDistance >= 1) { inner = ShrinkMask(inner, 1); } int total = 1; for (int step = 1; total + step <= minBorderDistance; step *= 2) { inner = ShrinkMask(inner, step); total += step; } if (total < minBorderDistance) { inner = ShrinkMask(inner, minBorderDistance - total); } return(inner); }
static bool[,] Binarize(double[,] input, double[,] baseline, bool[,] mask, BlockMap blocks) { var size = Point.SizeOf(input); var binarized = size.Allocate <bool>(); for (int blockY = 0; blockY < blocks.AllBlocks.Height; ++blockY) { for (int blockX = 0; blockX < blocks.AllBlocks.Width; ++blockX) { if (mask[blockY, blockX]) { Rectangle rect = blocks.BlockAreas[blockY, blockX]; for (int y = rect.Bottom; y < rect.Top; ++y) { for (int x = rect.Left; x < rect.Right; ++x) { if (input[y, x] - baseline[y, x] > 0) { binarized[y, x] = true; } } } } } } return(binarized); }
static void MergeMask(bool[,] mask, bool[,] merged) { var size = Point.SizeOf(mask); for (int y = 0; y < size.Y; ++y) { for (int x = 0; x < size.X; ++x) { mask[y, x] |= merged[y, x]; } } }
static bool[,] Invert(bool[,] binary, bool[,] mask) { var size = Point.SizeOf(binary); var inverted = size.Allocate <bool>(); for (int y = 0; y < size.Y; ++y) { for (int x = 0; x < size.X; ++x) { inverted[y, x] = !binary[y, x] && mask[y, x]; } } return(inverted); }
static bool[,] InvertMask(bool[,] mask) { var size = Point.SizeOf(mask); var inverted = size.Allocate <bool>(); for (int y = 0; y < size.Y; ++y) { for (int x = 0; x < size.X; ++x) { inverted[y, x] = !mask[y, x]; } } return(inverted); }
static bool[,] ShrinkMask(bool[,] mask, int amount) { var size = Point.SizeOf(mask); var shrunk = size.Allocate <bool>(); for (int y = amount; y < size.Y - amount; ++y) { for (int x = amount; x < size.X - amount; ++x) { shrunk[y, x] = mask[y - amount, x] && mask[y + amount, x] && mask[y, x - amount] && mask[y, x + amount]; } } return(shrunk); }
static void CleanupBinarized(bool[,] binary) { var size = Point.SizeOf(binary); var islands = FilterBinarized(InvertMask(binary)); var holes = FilterBinarized(binary); for (int y = 0; y < size.Y; ++y) { for (int x = 0; x < size.X; ++x) { binary[y, x] = binary[y, x] && !islands[y, x] || holes[y, x]; } } RemoveCrosses(binary); }
static byte[,] ConvertOrientationVectorsToAngles(PointF[,] vectors, bool[,] mask) { var size = Point.SizeOf(mask); byte[,] angles = size.Allocate <byte>(); for (int y = 0; y < size.Y; ++y) { for (int x = 0; x < size.X; ++x) { if (mask[y, x]) { angles[y, x] = Angle.ToByte(Angle.Atan(vectors[y, x])); } } } return(angles); }
static bool[,] ComputeAbsoluteContrast(byte[,] contrast) { const int limit = 17; var size = Point.SizeOf(contrast); bool[,] result = size.Allocate <bool>(); for (int y = 0; y < size.Y; ++y) { for (int x = 0; x < size.X; ++x) { if (contrast[y, x] < limit) { result[y, x] = true; } } } return(result); }
void BuildEdgeTable() { const int maxDistance = 490; const int maxNeighbors = 9; EdgeTable = new NeighborEdge[Minutiae.Count][]; var edges = new List <NeighborEdge>(); var allSqDistances = new int[Minutiae.Count]; for (int reference = 0; reference < EdgeTable.Length; ++reference) { Point referencePosition = Minutiae[reference].Position; int sqMaxDistance = MathEx.Sq(maxDistance); if (Minutiae.Count - 1 > maxNeighbors) { for (int neighbor = 0; neighbor < Minutiae.Count; ++neighbor) { allSqDistances[neighbor] = (referencePosition - Minutiae[neighbor].Position).SqLength; } Array.Sort(allSqDistances); sqMaxDistance = allSqDistances[maxNeighbors]; } for (int neighbor = 0; neighbor < Minutiae.Count; ++neighbor) { if (neighbor != reference && (referencePosition - Minutiae[neighbor].Position).SqLength <= sqMaxDistance) { NeighborEdge record = new NeighborEdge(); record.Edge = new EdgeShape(this, reference, neighbor); record.Neighbor = neighbor; edges.Add(record); } } edges.Sort(NeighborEdgeComparer.Instance); if (edges.Count > maxNeighbors) { edges.RemoveRange(maxNeighbors, edges.Count - maxNeighbors); } EdgeTable[reference] = edges.ToArray(); edges.Clear(); } }
static int[, ,] ComputeSmoothedHistogram(BlockMap blocks, int[, ,] input) { var blocksAround = new Point[] { new Point(0, 0), new Point(-1, 0), new Point(0, -1), new Point(-1, -1) }; var output = new int[blocks.CornerCount.Y, blocks.CornerCount.X, 256]; foreach (var corner in blocks.AllCorners) { foreach (Point relative in blocksAround) { var block = corner + relative; if (blocks.AllBlocks.Contains(block)) { for (int i = 0; i < 256; ++i) { output[corner.Y, corner.X, i] += input[block.Y, block.X, i]; } } } } return(output); }
Point[][] ConstructOrientedLines(int resolution = 32, int radius = 7, double step = 1.5) { Point[][] result = new Point[resolution][]; for (int orientationIndex = 0; orientationIndex < resolution; ++orientationIndex) { List <Point> line = new List <Point>(); line.Add(new Point()); PointF direction = Angle.ToVector(Angle.ByBucketCenter(orientationIndex, 2 * resolution)); for (double r = radius; r >= 0.5; r /= step) { Point point = (r * direction).Round(); if (!line.Contains(point)) { line.Add(point); line.Add(-point); } } line.Sort(MathEx.CompareYX); result[orientationIndex] = line.ToArray(); } return(result); }
static void RemoveCrosses(bool[,] input) { var size = Point.SizeOf(input); bool any = true; while (any) { any = false; for (int y = 0; y < size.Y - 1; ++y) { for (int x = 0; x < size.X - 1; ++x) { if (input[y, x] && input[y + 1, x + 1] && !input[y + 1, x] && !input[y, x + 1] || input[y + 1, x] && input[y, x + 1] && !input[y, x] && !input[y + 1, x + 1]) { input[y, x] = false; input[y + 1, x] = false; input[y, x + 1] = false; input[y + 1, x + 1] = false; any = true; } } } } }
static byte[,] ScaleImage(byte[,] input, int newX, int newY) { var oldSize = Point.SizeOf(input); var output = new byte[newY, newX]; double scaleX = newX / (double)oldSize.X; double scaleY = newY / (double)oldSize.Y; double descaleX = 1 / scaleX; double descaleY = 1 / scaleY; for (int y = 0; y < newY; ++y) { double y1 = y * descaleY; double y2 = y1 + descaleY; int y1i = (int)y1; int y2i = (int)Math.Ceiling(y2); for (int x = 0; x < newX; ++x) { double x1 = x * descaleX; double x2 = x1 + descaleX; int x1i = (int)x1; int x2i = (int)Math.Ceiling(x2); double sum = 0; for (int oy = y1i; oy < y2i; ++oy) { var ry = Math.Min(oy + 1, y2) - Math.Max(oy, y1); for (int ox = x1i; ox < x2i; ++ox) { var rx = Math.Min(ox + 1, x2) - Math.Max(ox, x1); sum += rx * ry * input[oy, ox]; } } output[y, x] = Convert.ToByte(sum * (scaleX * scaleY)); } } return(output); }
static bool[,] ApplyVotingFilter(bool[,] input, int radius = 1, double majority = 0.51, int borderDist = 0) { var size = Point.SizeOf(input); Rectangle rect = new Rectangle(new Point(borderDist, borderDist), new Point(size.X - 2 * borderDist, size.Y - 2 * borderDist)); var output = size.Allocate <bool>(); for (int y = rect.RangeY.Begin; y < rect.RangeY.End; ++y) { for (int x = rect.Left; x < rect.Right; ++x) { Rectangle neighborhood = Rectangle.Between( new Point(Math.Max(x - radius, 0), Math.Max(y - radius, 0)), new Point(Math.Min(x + radius + 1, size.X), Math.Min(y + radius + 1, size.Y))); int ones = 0; for (int ny = neighborhood.Bottom; ny < neighborhood.Top; ++ny) { for (int nx = neighborhood.Left; nx < neighborhood.Right; ++nx) { if (input[ny, nx]) { ++ones; } } } double voteWeight = 1.0 / neighborhood.TotalArea; if (ones * voteWeight >= majority) { output[y, x] = true; } } } return(output); }
static byte[,] ScaleImage(byte[,] input, int dpi) { var size = Point.SizeOf(input); return(ScaleImage(input, Convert.ToInt32(500.0 / dpi * size.X), Convert.ToInt32(500.0 / dpi * size.Y))); }