示例#1
0
        static BooleanMatrix FilterRelativeContrast(DoubleMatrix contrast, BlockMap blocks)
        {
            var sortedContrast = new List <double>();

            foreach (var block in contrast.Size.Iterate())
            {
                sortedContrast.Add(contrast[block]);
            }
            sortedContrast.Sort();
            sortedContrast.Reverse();
            int    pixelsPerBlock   = blocks.Pixels.Area / blocks.Primary.Blocks.Area;
            int    sampleCount      = Math.Min(sortedContrast.Count, Parameters.RelativeContrastSample / pixelsPerBlock);
            int    consideredBlocks = Math.Max(Doubles.RoundToInt(sampleCount * Parameters.RelativeContrastPercentile), 1);
            double averageContrast  = 0;

            for (int i = 0; i < consideredBlocks; ++i)
            {
                averageContrast += sortedContrast[i];
            }
            averageContrast /= consideredBlocks;
            var limit  = averageContrast * Parameters.MinRelativeContrast;
            var result = new BooleanMatrix(blocks.Primary.Blocks);

            foreach (var block in blocks.Primary.Blocks.Iterate())
            {
                if (contrast[block] < limit)
                {
                    result[block] = true;
                }
            }
            // https://sourceafis.machinezoo.com/transparency/relative-contrast-mask
            FingerprintTransparency.Current.Log("relative-contrast-mask", result);
            return(result);
        }
 static byte[,] ComputeOrientationMap(double[,] image, bool[,] mask, BlockMap blocks)
 {
     PointF[,] accumulated = ComputePixelwiseOrientation(image, mask, blocks);
     PointF[,] byBlock     = AverageBlockOrientations(accumulated, blocks, mask);
     PointF[,] smooth      = SmoothOutOrientationMap(byBlock, mask);
     return(ConvertOrientationVectorsToAngles(smooth, mask));
 }
        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);
        }
示例#4
0
        public static MutableTemplate Extract(DoubleMatrix raw, double dpi)
        {
            var template = new MutableTemplate();

            // https://sourceafis.machinezoo.com/transparency/decoded-image
            FingerprintTransparency.Current.Log("decoded-image", raw);
            if (Math.Abs(dpi - 500) > Parameters.DpiTolerance)
            {
                raw = ScaleImage(raw, dpi);
            }
            // https://sourceafis.machinezoo.com/transparency/scaled-image
            FingerprintTransparency.Current.Log("scaled-image", raw);
            template.Size = raw.Size;
            var blocks = new BlockMap(raw.Width, raw.Height, Parameters.BlockSize);

            // https://sourceafis.machinezoo.com/transparency/blocks
            FingerprintTransparency.Current.Log("blocks", blocks);
            var histogram       = Histogram(blocks, raw);
            var smoothHistogram = SmoothHistogram(blocks, histogram);
            var mask            = Mask(blocks, histogram);
            var equalized       = Equalize(blocks, raw, smoothHistogram, mask);
            var orientation     = OrientationMap(equalized, mask, blocks);
            var smoothedLines   = OrientedLines(Parameters.ParallelSmoothingResolution, Parameters.ParallelSmoothingRadius, Parameters.ParallelSmoothingStep);
            var smoothed        = SmoothRidges(equalized, orientation, mask, blocks, 0, smoothedLines);

            // https://sourceafis.machinezoo.com/transparency/parallel-smoothing
            FingerprintTransparency.Current.Log("parallel-smoothing", smoothed);
            var orthogonalLines = OrientedLines(Parameters.OrthogonalSmoothingResolution, Parameters.OrthogonalSmoothingRadius, Parameters.OrthogonalSmoothingStep);
            var orthogonal      = SmoothRidges(smoothed, orientation, mask, blocks, Math.PI, orthogonalLines);

            // https://sourceafis.machinezoo.com/transparency/orthogonal-smoothing
            FingerprintTransparency.Current.Log("orthogonal-smoothing", orthogonal);
            var binary    = Binarize(smoothed, orthogonal, mask, blocks);
            var pixelMask = FillBlocks(mask, blocks);

            CleanupBinarized(binary, pixelMask);
            // https://sourceafis.machinezoo.com/transparency/pixel-mask
            FingerprintTransparency.Current.Log("pixel-mask", pixelMask);
            var inverted  = Invert(binary, pixelMask);
            var innerMask = InnerMask(pixelMask);
            var ridges    = new Skeleton(binary, SkeletonType.Ridges);
            var valleys   = new Skeleton(inverted, SkeletonType.Valleys);

            template.Minutiae = new List <MutableMinutia>();
            CollectMinutiae(template.Minutiae, ridges, MinutiaType.Ending);
            CollectMinutiae(template.Minutiae, valleys, MinutiaType.Bifurcation);
            // https://sourceafis.machinezoo.com/transparency/skeleton-minutiae
            FingerprintTransparency.Current.Log("skeleton-minutiae", template);
            MaskMinutiae(template.Minutiae, innerMask);
            // https://sourceafis.machinezoo.com/transparency/inner-minutiae
            FingerprintTransparency.Current.Log("inner-minutiae", template);
            RemoveMinutiaClouds(template.Minutiae);
            // https://sourceafis.machinezoo.com/transparency/removed-minutia-clouds
            FingerprintTransparency.Current.Log("removed-minutia-clouds", template);
            template.Minutiae = LimitTemplateSize(template.Minutiae);
            // https://sourceafis.machinezoo.com/transparency/top-minutiae
            FingerprintTransparency.Current.Log("top-minutiae", template);
            return(template);
        }
示例#5
0
        static DoubleMatrix OrientationMap(DoubleMatrix image, BooleanMatrix mask, BlockMap blocks)
        {
            var accumulated = PixelwiseOrientation(image, mask, blocks);
            var byBlock     = BlockOrientations(accumulated, blocks, mask);
            var smooth      = SmoothOrientation(byBlock, mask);

            return(OrientationAngles(smooth, mask));
        }
示例#6
0
        public FingerprintTemplate(byte[,] image, int dpi = 500)
        {
            const int blockSize = 15;

            if (dpi != 500)
            {
                image = ScaleImage(image, dpi);
            }


            image = InvertInput(image);
            var blocks = new BlockMap(new Point(image.GetLength(1), image.GetLength(0)), blockSize);


            var histogram       = ComputeHistogram(blocks, image);
            var smoothHistogram = ComputeSmoothedHistogram(blocks, histogram);
            var mask            = ComputeMask(blocks, histogram);

            double[,] equalized = Equalize(blocks, image, smoothHistogram, mask);

            byte[,] orientation = ComputeOrientationMap(equalized, mask, blocks);


            double[,] smoothed   = SmoothByOrientation(equalized, orientation, mask, blocks, 0, ConstructOrientedLines(step: 1.59));
            double[,] orthogonal = SmoothByOrientation(smoothed, orientation, mask, blocks, Angle.PIB,
                                                       ConstructOrientedLines(resolution: 11, radius: 4, step: 1.11));

            var binary = Binarize(smoothed, orthogonal, mask, blocks);

            CleanupBinarized(binary);
            BitmapUtils.ShowImage(binary);



            var pixelMask = FillBlocks(mask, blocks);
            var innerMask = ComputeInnerMask(pixelMask);

            var inverted = Invert(binary, pixelMask);

            FingerprintSkeleton ridges  = new FingerprintSkeleton(binary);
            FingerprintSkeleton valleys = new FingerprintSkeleton(inverted);

            CollectMinutiae(ridges, FingerprintMinutiaType.Ending);
            CollectMinutiae(valleys, FingerprintMinutiaType.Bifurcation);
            ApplyMask(innerMask);
            RemoveMinutiaClouds();
            LimitTemplateSize();
            ShuffleMinutiae();

            BuildEdgeTable();
        }
        static bool[,] ComputeMask(BlockMap blocks, int[, ,] histogram)
        {
            byte[,] contrast = ComputeClippedContrast(blocks, histogram);
            var mask = ComputeAbsoluteContrast(contrast);

            MergeMask(mask, ComputeRelativeContrast(contrast, blocks));
            MergeMask(mask, ApplyVotingFilter(mask, radius: 9, majority: 0.86, borderDist: 7));
            MergeMask(mask, FilterBlockErrors(mask));
            mask = InvertMask(mask);
            MergeMask(mask, FilterBlockErrors(mask));
            MergeMask(mask, FilterBlockErrors(mask));
            MergeMask(mask, ApplyVotingFilter(mask, radius: 7, borderDist: 4));
            return(mask);
        }
 static bool[,] FillBlocks(bool[,] mask, BlockMap blocks)
 {
     bool[,] pixelized = blocks.PixelCount.Allocate <bool>();
     foreach (var block in blocks.AllBlocks)
     {
         if (block.Get(mask))
         {
             foreach (var pixel in blocks.BlockAreas[block])
             {
                 pixel.Set(pixelized, true);
             }
         }
     }
     return(pixelized);
 }
示例#9
0
        static BooleanMatrix FillBlocks(BooleanMatrix mask, BlockMap blocks)
        {
            var pixelized = new BooleanMatrix(blocks.Pixels);

            foreach (var block in blocks.Primary.Blocks.Iterate())
            {
                if (mask[block])
                {
                    foreach (var pixel in blocks.Primary.Block(block).Iterate())
                    {
                        pixelized[pixel] = true;
                    }
                }
            }
            return(pixelized);
        }
示例#10
0
        static BooleanMatrix Mask(BlockMap blocks, HistogramCube histogram)
        {
            var contrast = ClipContrast(blocks, histogram);
            var mask     = FilterAbsoluteContrast(contrast);

            mask.Merge(FilterRelativeContrast(contrast, blocks));
            // https://sourceafis.machinezoo.com/transparency/combined-mask
            FingerprintTransparency.Current.Log("combined-mask", mask);
            mask.Merge(FilterBlockErrors(mask));
            mask.Invert();
            mask.Merge(FilterBlockErrors(mask));
            mask.Merge(FilterBlockErrors(mask));
            mask.Merge(Vote(mask, null, Parameters.MaskVoteRadius, Parameters.MaskVoteMajority, Parameters.MaskVoteBorderDistance));
            // https://sourceafis.machinezoo.com/transparency/filtered-mask
            FingerprintTransparency.Current.Log("filtered-mask", mask);
            return(mask);
        }
        static int[, ,] ComputeHistogram(BlockMap blocks, byte[,] image)
        {
            var histogram = new int[blocks.BlockCount.Y, blocks.BlockCount.X, 256];

            foreach (var block in blocks.AllBlocks)
            {
                var area = blocks.BlockAreas[block];
                for (int y = area.Bottom; y < area.Top; ++y)
                {
                    for (int x = area.Left; x < area.Right; ++x)
                    {
                        ++histogram[block.Y, block.X, image[y, x]];
                    }
                }
            }
            return(histogram);
        }
        static bool[,] ComputeRelativeContrast(byte[,] contrast, BlockMap blocks)
        {
            const int    sampleSize     = 168568;
            const double sampleFraction = 0.49;
            const double relativeLimit  = 0.34;

            List <byte> sortedContrast = new List <byte>();

            foreach (byte contrastItem in contrast)
            {
                sortedContrast.Add(contrastItem);
            }
            sortedContrast.Sort();
            sortedContrast.Reverse();

            int pixelsPerBlock   = blocks.PixelCount.Area / blocks.AllBlocks.TotalArea;
            int sampleCount      = Math.Min(sortedContrast.Count, sampleSize / pixelsPerBlock);
            int consideredBlocks = Math.Max(Convert.ToInt32(sampleCount * sampleFraction), 1);

            int averageContrast = 0;

            for (int i = 0; i < consideredBlocks; ++i)
            {
                averageContrast += sortedContrast[i];
            }
            averageContrast /= consideredBlocks;
            byte limit = Convert.ToByte(averageContrast * relativeLimit);

            var result = blocks.BlockCount.Allocate <bool>();

            for (int y = 0; y < blocks.BlockCount.Y; ++y)
            {
                for (int x = 0; x < blocks.BlockCount.X; ++x)
                {
                    if (contrast[y, x] < limit)
                    {
                        result[y, x] = true;
                    }
                }
            }
            return(result);
        }
        static byte[,] ComputeClippedContrast(BlockMap blocks, int[, ,] histogram)
        {
            const double clipFraction = 0.08;

            byte[,] result = new byte[blocks.BlockCount.Y, blocks.BlockCount.X];
            foreach (var block in blocks.AllBlocks)
            {
                int area = 0;
                for (int i = 0; i < 256; ++i)
                {
                    area += histogram[block.Y, block.X, i];
                }
                int clipLimit = Convert.ToInt32(area * clipFraction);

                int accumulator = 0;
                int lowerBound  = 255;
                for (int i = 0; i < 256; ++i)
                {
                    accumulator += histogram[block.Y, block.X, i];
                    if (accumulator > clipLimit)
                    {
                        lowerBound = i;
                        break;
                    }
                }

                accumulator = 0;
                int upperBound = 0;
                for (int i = 255; i >= 0; --i)
                {
                    accumulator += histogram[block.Y, block.X, i];
                    if (accumulator > clipLimit)
                    {
                        upperBound = i;
                        break;
                    }
                }

                result[block.Y, block.X] = (byte)(upperBound - lowerBound);
            }
            return(result);
        }
示例#14
0
        static HistogramCube Histogram(BlockMap blocks, DoubleMatrix image)
        {
            var histogram = new HistogramCube(blocks.Primary.Blocks, Parameters.HistogramDepth);

            foreach (var block in blocks.Primary.Blocks.Iterate())
            {
                var area = blocks.Primary.Block(block);
                for (int y = area.Top; y < area.Bottom; ++y)
                {
                    for (int x = area.Left; x < area.Right; ++x)
                    {
                        int depth = (int)(image[x, y] * histogram.Bins);
                        histogram.Increment(block, histogram.Constrain(depth));
                    }
                }
            }
            // https://sourceafis.machinezoo.com/transparency/histogram
            FingerprintTransparency.Current.Log("histogram", histogram);
            return(histogram);
        }
        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);
        }
 static PointF[,] AverageBlockOrientations(PointF[,] orientation, BlockMap blocks, bool[,] mask)
 {
     PointF[,] sums = new PointF[blocks.BlockCount.Y, blocks.BlockCount.X];
     foreach (var block in blocks.AllBlocks)
     {
         if (block.Get(mask))
         {
             PointF    sum  = new PointF();
             Rectangle area = blocks.BlockAreas[block];
             for (int y = area.Bottom; y < area.Top; ++y)
             {
                 for (int x = area.Left; x < area.Right; ++x)
                 {
                     sum += orientation[y, x];
                 }
             }
             sums[block.Y, block.X] = sum;
         }
     }
     return(sums);
 }
        static PointF[,] ComputePixelwiseOrientation(double[,] input, bool[,] mask, BlockMap blocks)
        {
            List <List <ConsideredOrientation> > neighbors = GetTestedOrientations();

            PointF[,] orientation = new PointF[input.GetLength(0), input.GetLength(1)];
            for (int blockY = 0; blockY < blocks.BlockCount.Y; ++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 (ConsideredOrientation neighbor in neighbors[y % neighbors.Count])
                        {
                            int radius = Math.Max(Math.Abs(neighbor.CheckLocation.X), Math.Abs(neighbor.CheckLocation.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)
                                {
                                    double before   = input[y - neighbor.CheckLocation.Y, x - neighbor.CheckLocation.X];
                                    double at       = input[y, x];
                                    double after    = input[y + neighbor.CheckLocation.Y, x + neighbor.CheckLocation.X];
                                    double strength = at - Math.Max(before, after);
                                    if (strength > 0)
                                    {
                                        orientation[y, x] = orientation[y, x] + strength * neighbor.OrientationVector;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return(orientation);
        }
示例#18
0
        static DoublePointMatrix BlockOrientations(DoublePointMatrix orientation, BlockMap blocks, BooleanMatrix mask)
        {
            var sums = new DoublePointMatrix(blocks.Primary.Blocks);

            foreach (var block in blocks.Primary.Blocks.Iterate())
            {
                if (mask[block])
                {
                    var area = blocks.Primary.Block(block);
                    for (int y = area.Top; y < area.Bottom; ++y)
                    {
                        for (int x = area.Left; x < area.Right; ++x)
                        {
                            sums.Add(block, orientation[x, y]);
                        }
                    }
                }
            }
            // https://sourceafis.machinezoo.com/transparency/block-orientation
            FingerprintTransparency.Current.Log("block-orientation", sums);
            return(sums);
        }
示例#19
0
        static HistogramCube SmoothHistogram(BlockMap blocks, HistogramCube input)
        {
            var blocksAround = new IntPoint[] { new IntPoint(0, 0), new IntPoint(-1, 0), new IntPoint(0, -1), new IntPoint(-1, -1) };
            var output       = new HistogramCube(blocks.Secondary.Blocks, input.Bins);

            foreach (var corner in blocks.Secondary.Blocks.Iterate())
            {
                foreach (var relative in blocksAround)
                {
                    var block = corner + relative;
                    if (blocks.Primary.Blocks.Contains(block))
                    {
                        for (int i = 0; i < input.Bins; ++i)
                        {
                            output.Add(corner, i, input[block, i]);
                        }
                    }
                }
            }
            // https://sourceafis.machinezoo.com/transparency/smoothed-histogram
            FingerprintTransparency.Current.Log("smoothed-histogram", output);
            return(output);
        }
示例#20
0
        static DoubleMatrix ClipContrast(BlockMap blocks, HistogramCube histogram)
        {
            var result = new DoubleMatrix(blocks.Primary.Blocks);

            foreach (var block in blocks.Primary.Blocks.Iterate())
            {
                int volume      = histogram.Sum(block);
                int clipLimit   = Doubles.RoundToInt(volume * Parameters.ClippedContrast);
                int accumulator = 0;
                int lowerBound  = histogram.Bins - 1;
                for (int i = 0; i < histogram.Bins; ++i)
                {
                    accumulator += histogram[block, i];
                    if (accumulator > clipLimit)
                    {
                        lowerBound = i;
                        break;
                    }
                }
                accumulator = 0;
                int upperBound = 0;
                for (int i = histogram.Bins - 1; i >= 0; --i)
                {
                    accumulator += histogram[block, i];
                    if (accumulator > clipLimit)
                    {
                        upperBound = i;
                        break;
                    }
                }
                result[block] = (upperBound - lowerBound) * (1.0 / (histogram.Bins - 1));
            }
            // https://sourceafis.machinezoo.com/transparency/contrast
            FingerprintTransparency.Current.Log("contrast", result);
            return(result);
        }
 static double[,] SmoothByOrientation(double[,] input, byte[,] orientation, bool[,] mask, BlockMap blocks, byte angle, Point[][] lines)
 {
     double[,] output = new double[input.GetLength(0), input.GetLength(1)];
     foreach (var block in blocks.AllBlocks)
     {
         if (block.Get(mask))
         {
             Point[] line = lines[Angle.Quantize(Angle.Add(orientation[block.Y, block.X], angle), lines.Length)];
             foreach (Point linePoint in line)
             {
                 Rectangle target = blocks.BlockAreas[block];
                 Rectangle source = target.GetShifted(linePoint);
                 source.Clip(new Rectangle(blocks.PixelCount));
                 target = source.GetShifted(-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];
                     }
                 }
             }
             Rectangle 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] *= 1.0 / line.Length;
                 }
             }
         }
     }
     return(output);
 }
        static double[,] Equalize(BlockMap blocks, byte[,] image, int[, ,] histogram, bool[,] blockMask)
        {
            const double maxScaling = 3.99;
            const double minScaling = 0.25;

            const double rangeMin  = -1;
            const double rangeMax  = 1;
            const double rangeSize = rangeMax - rangeMin;

            const double widthMax = rangeSize / 256 * maxScaling;
            const double widthMin = rangeSize / 256 * minScaling;

            var limitedMin   = new double[256];
            var limitedMax   = new double[256];
            var toFloatTable = new double[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);
                toFloatTable[i] = i / 255;
            }

            var cornerMapping = new double[blocks.CornerCount.Y, blocks.CornerCount.X, 256];

            foreach (var corner in blocks.AllCorners)
            {
                if (corner.Get(blockMask, false) ||
                    new Point(corner.X - 1, corner.Y).Get(blockMask, false) ||
                    new Point(corner.X, corner.Y - 1).Get(blockMask, false) ||
                    new Point(corner.X - 1, corner.Y - 1).Get(blockMask, false))
                {
                    int area = 0;
                    for (int i = 0; i < 256; ++i)
                    {
                        area += histogram[corner.Y, corner.X, i];
                    }
                    double widthWeigth = rangeSize / area;

                    double top = rangeMin;
                    for (int i = 0; i < 256; ++i)
                    {
                        double width     = histogram[corner.Y, corner.X, i] * widthWeigth;
                        double equalized = top + toFloatTable[i] * width;
                        top += width;

                        double limited = equalized;
                        if (limited < limitedMin[i])
                        {
                            limited = limitedMin[i];
                        }
                        if (limited > limitedMax[i])
                        {
                            limited = limitedMax[i];
                        }
                        cornerMapping[corner.Y, corner.X, i] = limited;
                    }
                }
            }

            var result = new double[blocks.PixelCount.Y, blocks.PixelCount.X];

            foreach (var block in blocks.AllBlocks)
            {
                if (block.Get(blockMask))
                {
                    var area = blocks.BlockAreas[block];
                    for (int y = area.Bottom; y < area.Top; ++y)
                    {
                        for (int x = area.Left; x < area.Right; ++x)
                        {
                            byte pixel = image[y, x];

                            double bottomLeft  = cornerMapping[block.Y, block.X, pixel];
                            double bottomRight = cornerMapping[block.Y, block.X + 1, pixel];
                            double topLeft     = cornerMapping[block.Y + 1, block.X, pixel];
                            double topRight    = cornerMapping[block.Y + 1, block.X + 1, pixel];

                            var fraction = area.GetFraction(new Point(x, y));
                            result[y, x] = MathEx.Interpolate(topLeft, topRight, bottomLeft, bottomRight, fraction);
                        }
                    }
                }
            }
            return(result);
        }
示例#23
0
        static DoubleMatrix Equalize(BlockMap blocks, DoubleMatrix image, HistogramCube histogram, BooleanMatrix blockMask)
        {
            const double rangeMin    = -1;
            const double rangeMax    = 1;
            const double rangeSize   = rangeMax - rangeMin;
            double       widthMax    = rangeSize / histogram.Bins * Parameters.MaxEqualizationScaling;
            double       widthMin    = rangeSize / histogram.Bins * Parameters.MinEqualizationScaling;
            var          limitedMin  = new double[histogram.Bins];
            var          limitedMax  = new double[histogram.Bins];
            var          dequantized = new double[histogram.Bins];

            for (int i = 0; i < histogram.Bins; ++i)
            {
                limitedMin[i]  = Math.Max(i * widthMin + rangeMin, rangeMax - (histogram.Bins - 1 - i) * widthMax);
                limitedMax[i]  = Math.Min(i * widthMax + rangeMin, rangeMax - (histogram.Bins - 1 - i) * widthMin);
                dequantized[i] = i / (double)(histogram.Bins - 1);
            }
            var mappings = new Dictionary <IntPoint, double[]>();

            foreach (var corner in blocks.Secondary.Blocks.Iterate())
            {
                double[] mapping = new double[histogram.Bins];
                mappings[corner] = mapping;
                if (blockMask.Get(corner, false) ||
                    blockMask.Get(corner.X - 1, corner.Y, false) ||
                    blockMask.Get(corner.X, corner.Y - 1, false) ||
                    blockMask.Get(corner.X - 1, corner.Y - 1, false))
                {
                    double step = rangeSize / histogram.Sum(corner);
                    double top  = rangeMin;
                    for (int i = 0; i < histogram.Bins; ++i)
                    {
                        double band      = histogram[corner, i] * step;
                        double equalized = top + dequantized[i] * band;
                        top += band;
                        if (equalized < limitedMin[i])
                        {
                            equalized = limitedMin[i];
                        }
                        if (equalized > limitedMax[i])
                        {
                            equalized = limitedMax[i];
                        }
                        mapping[i] = equalized;
                    }
                }
            }
            var result = new DoubleMatrix(blocks.Pixels);

            foreach (var block in blocks.Primary.Blocks.Iterate())
            {
                var area = blocks.Primary.Block(block);
                if (blockMask[block])
                {
                    var topleft     = mappings[block];
                    var topright    = mappings[new IntPoint(block.X + 1, block.Y)];
                    var bottomleft  = mappings[new IntPoint(block.X, block.Y + 1)];
                    var bottomright = mappings[new IntPoint(block.X + 1, block.Y + 1)];
                    for (int y = area.Top; y < area.Bottom; ++y)
                    {
                        for (int x = area.Left; x < area.Right; ++x)
                        {
                            int    depth = histogram.Constrain((int)(image[x, y] * histogram.Bins));
                            double rx    = (x - area.X + 0.5) / area.Width;
                            double ry    = (y - area.Y + 0.5) / area.Height;
                            result[x, y] = Doubles.Interpolate(bottomleft[depth], bottomright[depth], topleft[depth], topright[depth], rx, ry);
                        }
                    }
                }
                else
                {
                    for (int y = area.Top; y < area.Bottom; ++y)
                    {
                        for (int x = area.Left; x < area.Right; ++x)
                        {
                            result[x, y] = -1;
                        }
                    }
                }
            }
            // https://sourceafis.machinezoo.com/transparency/equalized-image
            FingerprintTransparency.Current.Log("equalized-image", result);
            return(result);
        }
示例#24
0
        static DoublePointMatrix PixelwiseOrientation(DoubleMatrix input, BooleanMatrix mask, BlockMap blocks)
        {
            var neighbors   = PlanOrientations();
            var orientation = new DoublePointMatrix(input.Size);

            for (int blockY = 0; blockY < blocks.Primary.Blocks.Y; ++blockY)
            {
                var maskRange = MaskRange(mask, blockY);
                if (maskRange.Length > 0)
                {
                    var validXRange = new IntRange(
                        blocks.Primary.Block(maskRange.Start, blockY).Left,
                        blocks.Primary.Block(maskRange.End - 1, blockY).Right);
                    for (int y = blocks.Primary.Block(0, blockY).Top; y < blocks.Primary.Block(0, blockY).Bottom; ++y)
                    {
                        foreach (var neighbor in neighbors[y % neighbors.Length])
                        {
                            int radius = Math.Max(Math.Abs(neighbor.Offset.X), Math.Abs(neighbor.Offset.Y));
                            if (y - radius >= 0 && y + radius < input.Height)
                            {
                                var xRange = new IntRange(Math.Max(radius, validXRange.Start), Math.Min(input.Width - radius, validXRange.End));
                                for (int x = xRange.Start; x < xRange.End; ++x)
                                {
                                    double before   = input[x - neighbor.Offset.X, y - neighbor.Offset.Y];
                                    double at       = input[x, y];
                                    double after    = input[x + neighbor.Offset.X, y + neighbor.Offset.Y];
                                    double strength = at - Math.Max(before, after);
                                    if (strength > 0)
                                    {
                                        orientation.Add(x, y, strength * neighbor.Orientation);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            // https://sourceafis.machinezoo.com/transparency/pixelwise-orientation
            FingerprintTransparency.Current.Log("pixelwise-orientation", orientation);
            return(orientation);
        }
示例#25
0
        static BooleanMatrix Binarize(DoubleMatrix input, DoubleMatrix baseline, BooleanMatrix mask, BlockMap blocks)
        {
            var size      = input.Size;
            var binarized = new BooleanMatrix(size);

            foreach (var block in blocks.Primary.Blocks.Iterate())
            {
                if (mask[block])
                {
                    var rect = blocks.Primary.Block(block);
                    for (int y = rect.Top; y < rect.Bottom; ++y)
                    {
                        for (int x = rect.Left; x < rect.Right; ++x)
                        {
                            if (input[x, y] - baseline[x, y] > 0)
                            {
                                binarized[x, y] = true;
                            }
                        }
                    }
                }
            }
            // https://sourceafis.machinezoo.com/transparency/binarized-image
            FingerprintTransparency.Current.Log("binarized-image", binarized);
            return(binarized);
        }
示例#26
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);
        }