public void Remove(BinaryMap input) { BinaryMap sw2ne = new BinaryMap(input.Size); BinaryMap se2nw = new BinaryMap(input.Size); BinaryMap positions = new BinaryMap(input.Size); BinaryMap squares = new BinaryMap(input.Size); while (true) { sw2ne.Copy(input, new RectangleC(0, 0, input.Width - 1, input.Height - 1), new Point()); sw2ne.And(input, new RectangleC(1, 1, input.Width - 1, input.Height - 1), new Point()); sw2ne.AndNot(input, new RectangleC(0, 1, input.Width - 1, input.Height - 1), new Point()); sw2ne.AndNot(input, new RectangleC(1, 0, input.Width - 1, input.Height - 1), new Point()); se2nw.Copy(input, new RectangleC(0, 1, input.Width - 1, input.Height - 1), new Point()); se2nw.And(input, new RectangleC(1, 0, input.Width - 1, input.Height - 1), new Point()); se2nw.AndNot(input, new RectangleC(0, 0, input.Width - 1, input.Height - 1), new Point()); se2nw.AndNot(input, new RectangleC(1, 1, input.Width - 1, input.Height - 1), new Point()); positions.Copy(sw2ne); positions.Or(se2nw); if (positions.IsEmpty()) { break; } squares.Copy(positions); squares.Or(positions, new RectangleC(0, 0, positions.Width - 1, positions.Height - 1), new Point(1, 0)); squares.Or(positions, new RectangleC(0, 0, positions.Width - 1, positions.Height - 1), new Point(0, 1)); squares.Or(positions, new RectangleC(0, 0, positions.Width - 1, positions.Height - 1), new Point(1, 1)); input.AndNot(squares); } Logger.Log(input); }
void UpdateView() { if (IsVisible && Skeleton != null) { SourceAFIS.General.Size minSize = new SkeletonShadow().GetSize(Skeleton); if (OriginalWidth >= minSize.Width && OriginalHeight >= minSize.Height) { BinaryMap shadow = new BinaryMap(OriginalWidth, OriginalHeight); new SkeletonShadow().Draw(Skeleton, shadow); SetValue(ShadowProperty, shadow); BinaryMap blur = new BinaryMap(shadow); blur.Or(shadow, new RectangleC(0, 0, OriginalWidth - 1, OriginalHeight), new APoint(1, 0)); blur.Or(shadow, new RectangleC(1, 0, OriginalWidth - 1, OriginalHeight), new APoint(0, 0)); blur.Or(shadow, new RectangleC(0, 0, OriginalWidth, OriginalHeight - 1), new APoint(0, 1)); blur.Or(shadow, new RectangleC(0, 1, OriginalWidth, OriginalHeight - 1), new APoint(0, 0)); SetValue(ShadowBlurProperty, blur); var points = from minutia in Skeleton.Minutiae where minutia.Valid select new WPoint(minutia.Position.X - 3, OriginalHeight - 1 - minutia.Position.Y - 3); SetValue(PositionsProperty, points); } else { SetValue(ShadowProperty, null); SetValue(PositionsProperty, null); } } else { SetValue(ShadowProperty, null); SetValue(ShadowBlurProperty, null); SetValue(PositionsProperty, null); } }
public BinaryMap Binarize(float[,] input, float[,] baseline, BinaryMap mask, BlockMap blocks) { BinaryMap binarized = new BinaryMap(input.GetLength(1), input.GetLength(0)); Parallel.For(0, blocks.AllBlocks.Height, delegate(int blockY) { for (int blockX = 0; blockX < blocks.AllBlocks.Width; ++blockX) { if (mask.GetBit(blockX, blockY)) { RectangleC 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.SetBitOne(x, y); } } } } } }); Logger.Log(binarized); return(binarized); }
public float[,] Smooth(float[,] input, byte[,] orientation, BinaryMap mask, BlockMap blocks) { Point[][] lines = Lines.Construct(); float[,] output = new float[input.GetLength(0), input.GetLength(1)]; Parallel.ForEach(blocks.AllBlocks, delegate(Point block) { if (mask.GetBit(block)) { Point[] line = lines[Angle.Quantize(Angle.Add(orientation[block.Y, block.X], AngleOffset), lines.Length)]; foreach (Point linePoint in line) { RectangleC target = blocks.BlockAreas[block]; RectangleC source = target.GetShifted(linePoint); source.Clip(new RectangleC(blocks.PixelCount)); target = source.GetShifted(Calc.Negate(linePoint)); for (int y = target.Bottom; y < target.Top; ++y) for (int x = target.Left; x < target.Right; ++x) output[y, x] += input[y + linePoint.Y, x + linePoint.X]; } RectangleC blockArea = blocks.BlockAreas[block]; for (int y = blockArea.Bottom; y < blockArea.Top; ++y) for (int x = blockArea.Left; x < blockArea.Right; ++x) output[y, x] *= 1f / line.Length; } }); Logger.Log(output); return output; }
BinaryMap Subtract(BinaryMap outer, BinaryMap inner) { BinaryMap buffer = new BinaryMap(outer); buffer.AndNot(inner); return(buffer); }
Range GetMaskLineRange(BinaryMap mask, int y) { int first = -1; int last = -1; for (int x = 0; x < mask.Width; ++x) { if (mask.GetBit(x, y)) { last = x; if (first < 0) { first = x; } } } if (first >= 0) { return(new Range(first, last + 1)); } else { return(new Range()); } }
public BinaryMap Draw(SkeletonBuilder skeleton) { BinaryMap binary = new BinaryMap(GetSize(skeleton)); Draw(skeleton, binary); return(binary); }
public BinaryMap Compute(BinaryMap outer) { BinaryMap inner = new BinaryMap(outer.Size); inner.Copy(outer, new RectangleC(1, 1, outer.Width - 2, outer.Height - 2), new Point(1, 1)); BinaryMap temporary = new BinaryMap(outer.Size); if (MinBorderDistance >= 1) { ShrinkBy(temporary, inner, 1); } int total = 1; for (int step = 1; total + step <= MinBorderDistance; step *= 2) { ShrinkBy(temporary, inner, step); total += step; } if (total < MinBorderDistance) { ShrinkBy(temporary, inner, MinBorderDistance - total); } Logger.Log(inner); return(inner); }
PointF[,] Smooth(PointF[,] orientation, BinaryMap mask) { PointF[,] smoothed = new PointF[mask.Height, mask.Width]; Parallel.For(0, mask.Height, delegate(int y) { for (int x = 0; x < mask.Width; ++x) { if (mask.GetBit(x, y)) { RectangleC neighbors = new RectangleC( new Point(Math.Max(0, x - SmoothingRadius), Math.Max(0, y - SmoothingRadius)), new Point(Math.Min(mask.Width, x + SmoothingRadius + 1), Math.Min(mask.Height, y + SmoothingRadius + 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.GetBit(nx, ny)) { sum = Calc.Add(sum, orientation[ny, nx]); } } } smoothed[y, x] = sum; } } }); return(smoothed); }
public byte[,] Detect(float[,] image, BinaryMap mask, BlockMap blocks) { PointF[,] accumulated = AccumulateOrientations(image, mask, blocks); PointF[,] byBlock = SumBlocks(accumulated, blocks, mask); PointF[,] smooth = Smooth(byBlock, mask); byte[,] angles = ToAngles(smooth, mask); Logger.Log(angles); return(angles); }
public void Filter(TemplateBuilder template, BinaryMap mask) { template.Minutiae.RemoveAll(minutia => { var arrow = Calc.Round(-DirectedExtension * Angle.ToVector(minutia.Direction)); return(!mask.GetBitSafe((Point)minutia.Position + new Size(arrow), false)); }); Logger.Log(template); }
void ShrinkBy(BinaryMap temporary, BinaryMap inner, int amount) { temporary.Clear(); temporary.Copy(inner, new RectangleC(amount, 0, inner.Width - amount, inner.Height), new Point(0, 0)); temporary.And(inner, new RectangleC(0, 0, inner.Width - amount, inner.Height), new Point(amount, 0)); temporary.And(inner, new RectangleC(0, amount, inner.Width, inner.Height - amount), new Point(0, 0)); temporary.And(inner, new RectangleC(0, 0, inner.Width, inner.Height - amount), new Point(0, amount)); inner.Copy(temporary); }
public void Trace(BinaryMap binary, SkeletonBuilder skeleton) { List <Point> minutiaPoints = FindMinutiae(binary); Dictionary <Point, List <Point> > linking = LinkNeighboringMinutiae(minutiaPoints); Dictionary <Point, SkeletonBuilder.Minutia> minutiaMap = ComputeMinutiaCenters(linking, skeleton); TraceRidges(binary, minutiaMap); FixLinkingGaps(skeleton); Logger.Log(skeleton); }
public TemplateBuilder Extract(byte[,] invertedImage, int dpi) { TemplateBuilder template = null; DpiAdjuster.Adjust(this, dpi, delegate() { byte[,] image = ImageInverter.GetInverted(invertedImage); BlockMap blocks = new BlockMap(new Size(image.GetLength(1), image.GetLength(0)), BlockSize); Logger.Log("BlockMap", blocks); short[, ,] histogram = Histogram.Analyze(blocks, image); short[, ,] smoothHistogram = Histogram.SmoothAroundCorners(blocks, histogram); BinaryMap mask = Mask.ComputeMask(blocks, histogram); float[,] equalized = Equalizer.Equalize(blocks, image, smoothHistogram, mask); byte[,] orientation = Orientation.Detect(equalized, mask, blocks); float[,] smoothed = RidgeSmoother.Smooth(equalized, orientation, mask, blocks); float[,] orthogonal = OrthogonalSmoother.Smooth(smoothed, orientation, mask, blocks); BinaryMap binary = Binarizer.Binarize(smoothed, orthogonal, mask, blocks); binary.AndNot(BinarySmoother.Filter(binary.GetInverted())); binary.Or(BinarySmoother.Filter(binary)); Logger.Log("ResultadoSmoothingBinario", binary); CrossRemover.Remove(binary); BinaryMap pixelMask = mask.FillBlocks(blocks); BinaryMap innerMask = InnerMask.Compute(pixelMask); BinaryMap inverted = binary.GetInverted(); inverted.And(pixelMask); SkeletonBuilder ridges = null; SkeletonBuilder valleys = null; Parallel.Invoke( () => { ridges = ProcessSkeleton("Ridges", binary); }, () => { valleys = ProcessSkeleton("Valleys", inverted); }); template = new TemplateBuilder(); template.OriginalDpi = dpi; template.OriginalWidth = invertedImage.GetLength(1); template.OriginalHeight = invertedImage.GetLength(0); MinutiaCollector.Collect(ridges, TemplateBuilder.MinutiaType.Extremidade, template); MinutiaCollector.Collect(valleys, TemplateBuilder.MinutiaType.Bifurcação, template); MinutiaMask.Filter(template, innerMask); StandardDpiScaling.Scale(template); MinutiaCloudRemover.Filter(template); UniqueMinutiaSorter.Filter(template); MinutiaSorter.Shuffle(template); Logger.Log("FinalTemplate", template); }); return(template); }
bool IsOverlapping(Point[] line, BinaryMap shadow) { for (int i = ToleratedOverlapLength; i < line.Length - ToleratedOverlapLength; ++i) { if (shadow.GetBit(line[i])) { return(true); } } return(false); }
void UpdateBorder() { if (IsVisible && Mask != null) { BinaryMap mask = Inverted ? Mask.GetInverted() : Mask; SetValue(BorderProperty, Subtract(Expand(Expand(mask)), mask)); } else { SetValue(BorderProperty, null); } }
static bool IsFalseEnding(BinaryMap binary, Point ending) { foreach (Point relativeNeighbor in Neighborhood.CornerNeighbors) { Point neighbor = Calc.Add(ending, relativeNeighbor); if (binary.GetBit(neighbor)) { return(Calc.CountBits(binary.GetNeighborhood(neighbor)) > 2); } } return(false); }
void AddRidge(SkeletonBuilder skeleton, BinaryMap shadow, Gap gap, Point[] line) { SkeletonBuilder.Ridge ridge = new SkeletonBuilder.Ridge(); foreach (Point point in line) { ridge.Points.Add(point); } ridge.Start = gap.End1; ridge.End = gap.End2; foreach (Point point in line) { shadow.SetBitOne(point); } }
float[, ,] ComputeEqualization(BlockMap blocks, short[, ,] histogram, BinaryMap blockMask) { float widthMax = RangeSize / 256f * MaxScaling; float widthMin = RangeSize / 256f * MinScaling; float[] limitedMin = new float[256]; float[] limitedMax = new float[256]; for (int i = 0; i < 256; ++i) { limitedMin[i] = Math.Max(i * widthMin + RangeMin, RangeMax - (255 - i) * widthMax); limitedMax[i] = Math.Min(i * widthMax + RangeMin, RangeMax - (255 - i) * widthMin); } float[, ,] equalization = new float[blocks.CornerCount.Height, blocks.CornerCount.Width, 256]; Parallel.ForEach(blocks.AllCorners, delegate(Point corner) { if (blockMask.GetBitSafe(corner.X, corner.Y, false) || blockMask.GetBitSafe(corner.X - 1, corner.Y, false) || blockMask.GetBitSafe(corner.X, corner.Y - 1, false) || blockMask.GetBitSafe(corner.X - 1, corner.Y - 1, false)) { int area = 0; for (int i = 0; i < 256; ++i) { area += histogram[corner.Y, corner.X, i]; } float widthWeigth = RangeSize / area; float top = RangeMin; for (int i = 0; i < 256; ++i) { float width = histogram[corner.Y, corner.X, i] * widthWeigth; float equalized = top + ToFloatTable[i] * width; top += width; float limited = equalized; if (limited < limitedMin[i]) { limited = limitedMin[i]; } if (limited > limitedMax[i]) { limited = limitedMax[i]; } equalization[corner.Y, corner.X, i] = limited; } } }); return(equalization); }
BinaryMap Expand(BinaryMap map) { BinaryMap buffer = new BinaryMap(map); buffer.Or(map, new RectangleC(0, 0, map.Width - 1, map.Height), new APoint(1, 0)); buffer.Or(map, new RectangleC(1, 0, map.Width - 1, map.Height), new APoint(0, 0)); buffer.Or(map, new RectangleC(0, 0, map.Width, map.Height - 1), new APoint(0, 1)); buffer.Or(map, new RectangleC(0, 1, map.Width, map.Height - 1), new APoint(0, 0)); buffer.Or(map, new RectangleC(0, 0, map.Width - 1, map.Height - 1), new APoint(1, 1)); buffer.Or(map, new RectangleC(1, 1, map.Width - 1, map.Height - 1), new APoint(0, 0)); buffer.Or(map, new RectangleC(0, 1, map.Width - 1, map.Height - 1), new APoint(1, 0)); buffer.Or(map, new RectangleC(1, 0, map.Width - 1, map.Height - 1), new APoint(0, 1)); return(buffer); }
byte[,] ToAngles(PointF[,] vectors, BinaryMap mask) { byte[,] angles = new byte[mask.Height, mask.Width]; Parallel.For(0, mask.Height, delegate(int y) { for (int x = 0; x < mask.Width; ++x) { if (mask.GetBit(x, y)) { angles[y, x] = Angle.ToByte(Angle.Atan(vectors[y, x])); } } }); return(angles); }
List <Point> FindMinutiae(BinaryMap binary) { List <Point> result = new List <Point>(); for (int y = 0; y < binary.Height; ++y) { for (int x = 0; x < binary.Width; ++x) { if (binary.GetBit(x, y) && IsMinutia[binary.GetNeighborhood(x, y)]) { result.Add(new Point(x, y)); } } } return(result); }
public BinaryMap DetectLowContrast(byte[,] contrast) { BinaryMap result = new BinaryMap(contrast.GetLength(1), contrast.GetLength(0)); for (int y = 0; y < result.Height; ++y) { for (int x = 0; x < result.Width; ++x) { if (contrast[y, x] < Limit) { result.SetBitOne(x, y); } } } Logger.Log(result); return(result); }
public void Draw(SkeletonBuilder skeleton, BinaryMap binary) { foreach (SkeletonBuilder.Minutia minutia in skeleton.Minutiae) { binary.SetBitOne(minutia.Position); foreach (SkeletonBuilder.Ridge ridge in minutia.Ridges) { if (ridge.Start.Position.Y <= ridge.End.Position.Y) { foreach (Point point in ridge.Points) { binary.SetBitOne(point); } } } } }
public BinaryMap ComputeMask(BlockMap blocks, short[, ,] histogram) { byte[,] contrast = Contrast.Compute(blocks, histogram); BinaryMap mask = new BinaryMap(AbsoluteContrast.DetectLowContrast(contrast)); mask.Or(RelativeContrast.DetectLowContrast(contrast, blocks)); mask.Or(LowContrastMajority.Filter(mask)); mask.Or(BlockErrorFilter.Filter(mask)); mask.Invert(); mask.Or(BlockErrorFilter.Filter(mask)); mask.Or(BlockErrorFilter.Filter(mask)); mask.Or(InnerMaskFilter.Filter(mask)); Logger.Log(mask); return(mask); }
SkeletonBuilder ProcessSkeleton(string name, BinaryMap binary) { SkeletonBuilder skeleton = null; DetailLogger.RunInContext(name, delegate() { Logger.Log("Binarized", binary); BinaryMap thinned = Thinner.Thin(binary); skeleton = new SkeletonBuilder(); RidgeTracer.Trace(thinned, skeleton); DotRemover.Filter(skeleton); PoreRemover.Filter(skeleton); GapRemover.Filter(skeleton); TailRemover.Filter(skeleton); FragmentRemover.Filter(skeleton); BranchMinutiaRemover.Filter(skeleton); }); return(skeleton); }
void TraceRidges(BinaryMap binary, Dictionary <Point, SkeletonBuilder.Minutia> minutiaePoints) { Dictionary <Point, SkeletonBuilder.Ridge> leads = new Dictionary <Point, SkeletonBuilder.Ridge>(); foreach (Point minutiaPoint in minutiaePoints.Keys) { foreach (Point startRelative in Neighborhood.CornerNeighbors) { Point start = Calc.Add(minutiaPoint, startRelative); if (binary.GetBitSafe(start, false) && !minutiaePoints.ContainsKey(start) && !leads.ContainsKey(start)) { SkeletonBuilder.Ridge ridge = new SkeletonBuilder.Ridge(); ridge.Points.Add(minutiaPoint); ridge.Points.Add(start); Point previous = minutiaPoint; Point current = start; do { Point next = new Point(); foreach (Point nextRelative in Neighborhood.CornerNeighbors) { next = Calc.Add(current, nextRelative); if (binary.GetBitSafe(next, false) && next != previous) { break; } } AssertException.Check(next != new Point()); previous = current; current = next; ridge.Points.Add(current); } while (!minutiaePoints.ContainsKey(current)); Point end = current; ridge.Start = minutiaePoints[minutiaPoint]; ridge.End = minutiaePoints[end]; leads[ridge.Points[1]] = ridge; leads[ridge.Reversed.Points[1]] = ridge; } } } }
SkeletonBuilder ProcessSkeleton(string name, BinaryMap binary) { SkeletonBuilder skeleton = null; DetailLogger.RunInContext(name, delegate() { Logger.Log("Binarized", binary); BinaryMap thinned = Thinner.Thin(binary); skeleton = new SkeletonBuilder(); RidgeTracer.Trace(thinned, skeleton); ////Testing Start //var outFileDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "outputSkeletonRidgeTracer-" + name + DateTime.UtcNow.Millisecond + ".bin"); //var file = new FileStream(outFileDir, FileMode.CreateNew); //var binWrite = new BinaryWriter(file); //binWrite.Write(skeleton.Minutiae.Count()); //Console.WriteLine(skeleton.Minutiae.Count()); //foreach (var minutia in skeleton.Minutiae) //{ // binWrite.Write(minutia.Valid); // Console.WriteLine(minutia.Valid); // binWrite.Write(minutia.Position.X); // Console.WriteLine(minutia.Position.X); // binWrite.Write(minutia.Position.Y); // Console.WriteLine(minutia.Position.Y); // binWrite.Write(minutia.Ridges.Count); // Console.WriteLine(minutia.Ridges.Count); //} //binWrite.Close(); //file.Close(); ////Testing Finish DotRemover.Filter(skeleton); PoreRemover.Filter(skeleton); GapRemover.Filter(skeleton); TailRemover.Filter(skeleton); FragmentRemover.Filter(skeleton); BranchMinutiaRemover.Filter(skeleton); }); Count++; return(skeleton); }
PointF[,] SumBlocks(PointF[,] orientation, BlockMap blocks, BinaryMap mask) { PointF[,] sums = new PointF[blocks.BlockCount.Height, blocks.BlockCount.Width]; Parallel.ForEach(blocks.AllBlocks, delegate(Point block) { if (mask.GetBit(block)) { PointF sum = new PointF(); RectangleC area = blocks.BlockAreas[block]; for (int y = area.Bottom; y < area.Top; ++y) { for (int x = area.Left; x < area.Right; ++x) { sum = Calc.Add(sum, orientation[y, x]); } } sums[block.Y, block.X] = sum; } }); return(sums); }
PointF[,] AccumulateOrientations(float[,] input, BinaryMap mask, BlockMap blocks) { List <List <NeighborInfo> > neighbors = PrepareNeighbors(); PointF[,] orientation = new PointF[input.GetLength(0), input.GetLength(1)]; Parallel.For(0, mask.Height, delegate(int blockY) { Range validMaskRange = GetMaskLineRange(mask, blockY); if (validMaskRange.Length > 0) { Range validXRange = new Range(blocks.BlockAreas[blockY, validMaskRange.Begin].Left, blocks.BlockAreas[blockY, validMaskRange.End - 1].Right); for (int y = blocks.BlockAreas[blockY, 0].Bottom; y < blocks.BlockAreas[blockY, 0].Top; ++y) { foreach (NeighborInfo neighbor in neighbors[y % neighbors.Count]) { int radius = Math.Max(Math.Abs(neighbor.Position.X), Math.Abs(neighbor.Position.Y)); if (y - radius >= 0 && y + radius < input.GetLength(0)) { Range xRange = new Range(Math.Max(radius, validXRange.Begin), Math.Min(input.GetLength(1) - radius, validXRange.End)); for (int x = xRange.Begin; x < xRange.End; ++x) { float before = input[y - neighbor.Position.Y, x - neighbor.Position.X]; float at = input[y, x]; float after = input[y + neighbor.Position.Y, x + neighbor.Position.X]; float strength = at - Math.Max(before, after); if (strength > 0) { orientation[y, x] = Calc.Add(orientation[y, x], Calc.Multiply(strength, neighbor.Orientation)); } } } } } } }); Logger.Log("Raw", orientation); return(orientation); }