private void RemoveSmallSegments(ImageMatrix matrix, OrientationImage orientationImage)
        {
            for (int row = 0; row < orientationImage.Height; row++)
            {
                for (int col = 0; col < orientationImage.Width; col++)
                {
                    if (!orientationImage.IsNullBlock(row, col))
                    {
                        int x, y;
                        orientationImage.GetPixelCoordFromBlock(row, col, out x, out y);

                        int maxLength = orientationImage.WindowSize / 2;
                        for (int xi = x - maxLength; xi < x + maxLength; xi++)
                        {
                            for (int yi = y - maxLength; yi < y + maxLength; yi++)
                            {
                                const int pThreshold = 10;
                                int[]     xArr       = new int[pThreshold + 1];
                                int[]     yArr       = new int[pThreshold + 1];

                                int x0, y0;
                                if (IsEnd(matrix, xi, yi, out x0, out y0))
                                {
                                    xArr[0] = xi;
                                    yArr[0] = yi;

                                    xArr[1] = x0;
                                    yArr[1] = y0;

                                    bool endFound         = false;
                                    bool bifurcationFound = false;
                                    int  pCount           = 1;
                                    for (int i = 1; i < pThreshold && !endFound && !bifurcationFound; i++)
                                    {
                                        if (IsEnd(matrix, xArr[i], yArr[i], out xArr[i + 1], out yArr[i + 1]))
                                        {
                                            endFound = true;
                                        }
                                        else if (!IsContinous(matrix, xArr[i - 1], yArr[i - 1], xArr[i], yArr[i],
                                                              out xArr[i + 1], out yArr[i + 1]))
                                        {
                                            bifurcationFound = true;
                                        }

                                        pCount++;
                                    }
                                    if (endFound || (bifurcationFound && pCount <= pThreshold))
                                    {
                                        for (int i = 0; i < pCount; i++)
                                        {
                                            matrix[yArr[i], xArr[i]] = 255;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        private void ApplyThinning(ImageMatrix matrix, OrientationImage orientationImage)
        {
            bool changed = true;

            while (changed)
            {
                changed = false;
                for (int row = 0; row < orientationImage.Height; row++)
                {
                    for (int col = 0; col < orientationImage.Width; col++)
                    {
                        if (!orientationImage.IsNullBlock(row, col))
                        {
                            int x, y;
                            orientationImage.GetPixelCoordFromBlock(row, col, out x, out y);

                            int maxLength = orientationImage.WindowSize / 2;
                            for (int xi = x - maxLength; xi < x + maxLength; xi++)
                            {
                                for (int yi = y - maxLength; yi < y + maxLength; yi++)
                                {
                                    if (xi > 0 && xi < matrix.Width - 1 && yi > 0 && yi < matrix.Height - 1)
                                    {
                                        int tl = matrix[yi - 1, xi - 1];
                                        int tc = matrix[yi - 1, xi];
                                        int tr = matrix[yi - 1, xi + 1];

                                        int le = matrix[yi, xi - 1];
                                        int ce = matrix[yi, xi];
                                        int ri = matrix[yi, xi + 1];

                                        int bl = matrix[yi + 1, xi - 1];
                                        int bc = matrix[yi + 1, xi];
                                        int br = matrix[yi + 1, xi + 1];

                                        if (IsVL(tl, tc, tr, le, ce, ri, bl, bc, br) ||
                                            IsVR(tl, tc, tr, le, ce, ri, bl, bc, br) ||
                                            IsHT(tl, tc, tr, le, ce, ri, bl, bc, br) ||
                                            IsHB(tl, tc, tr, le, ce, ri, bl, bc, br))
                                        {
                                            matrix[yi, xi] = 255;
                                            changed        = true;
                                        }
                                    }
                                    else
                                    {
                                        matrix[yi, xi] = 255;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        public static OrientationImage ExtractFeatures(Bitmap image)
        {
            var matrix = new ImageMatrix(image);

            var gx = (new SobelVerticalFilter()).Apply(matrix);
            var gy = (new SobelHorizontalFilter()).Apply(matrix);

            var width  = Convert.ToByte(image.Width / BlockSize);
            var height = Convert.ToByte(image.Height / BlockSize);
            var oi     = new OrientationImage(width, height, BlockSize);

            for (var row = 0; row < height; row++)
            {
                for (var col = 0; col < width; col++)
                {
                    oi.GetPixelCoordFromBlock(row, col, out var x, out var y);
                    var x0 = Math.Max(x - BlockSize / 2, 0);
                    var x1 = Math.Min(image.Width - 1, x + BlockSize / 2);
                    var y0 = Math.Max(y - BlockSize / 2, 0);
                    var y1 = Math.Min(image.Height - 1, y + BlockSize / 2);

                    int gxy = 0, gxx = 0, gyy = 0;
                    for (var yi = y0; yi <= y1; yi++)
                    {
                        for (var xi = x0; xi <= x1; xi++)
                        {
                            gxy += gx[yi, xi] * gy[yi, xi];
                            gxx += gx[yi, xi] * gx[yi, xi];
                            gyy += gy[yi, xi] * gy[yi, xi];
                        }
                    }

                    if (gxx - gyy == 0 && gxy == 0)
                    {
                        oi[row, col] = OrientationImage.Null;
                    }
                    else
                    {
                        var angle = Angle.ToDegrees(Angle.ComputeAngle(gxx - gyy, 2 * gxy));
                        angle = angle / 2 + 90;
                        if (angle > 180)
                        {
                            angle = angle - 180;
                        }
                        oi[row, col] = Convert.ToByte(Math.Round(angle));
                    }
                }
            }

            RemoveBadBlocksVariance(oi, matrix);
            RemoveBadBlocks(oi);
            var smoothed = SmoothOrImg(oi);

            return(smoothed);
        }
예제 #4
0
        private static void ApplyThinning(ImageMatrix matrix, OrientationImage orientationImage)
        {
            var changed = true;

            while (changed)
            {
                changed = false;
                for (var row = 0; row < orientationImage.Height; row++)
                {
                    for (var col = 0; col < orientationImage.Width; col++)
                    {
                        if (!orientationImage.IsNullBlock(row, col))
                        {
                            orientationImage.GetPixelCoordFromBlock(row, col, out int x, out int y);

                            var maxLength = orientationImage.WindowSize / 2;
                            for (var xi = x - maxLength; xi < x + maxLength; xi++)
                            {
                                for (var yi = y - maxLength; yi < y + maxLength; yi++)
                                {
                                    if (xi > 0 && xi < matrix.Width - 1 && yi > 0 && yi < matrix.Height - 1)
                                    {
                                        var tl = matrix[yi - 1, xi - 1];
                                        var tc = matrix[yi - 1, xi];
                                        var tr = matrix[yi - 1, xi + 1];

                                        var le = matrix[yi, xi - 1];
                                        var ce = matrix[yi, xi];
                                        var ri = matrix[yi, xi + 1];

                                        var bl = matrix[yi + 1, xi - 1];
                                        var bc = matrix[yi + 1, xi];
                                        var br = matrix[yi + 1, xi + 1];

                                        if (IsVl(tl, tc, tr, le, ce, ri, bl, bc, br) ||
                                            IsVr(tl, tc, tr, le, ce, ri, bl, bc, br) ||
                                            IsHt(tl, tc, tr, le, ce, ri, bl, bc, br) ||
                                            IsHb(tl, tc, tr, le, ce, ri, bl, bc, br))
                                        {
                                            matrix[yi, xi] = 255;
                                            changed        = true;
                                        }
                                    }
                                    else
                                    {
                                        matrix[yi, xi] = 255;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #5
0
        private static ImageMatrix GetBinaryImage(ImageMatrix matrix, OrientationImage orientationImage)
        {
            int[] filter = { 1, 2, 5, 7, 5, 2, 1 };
            var   newImg = new ImageMatrix(matrix.Width, matrix.Height);

            for (var i = 0; i < matrix.Width; i++)
            {
                for (var j = 0; j < matrix.Height; j++)
                {
                    newImg[j, i] = 255;
                }
            }
            for (var row = 0; row < orientationImage.Height; row++)
            {
                for (var col = 0; col < orientationImage.Width; col++)
                {
                    if (!orientationImage.IsNullBlock(row, col))
                    {
                        orientationImage.GetPixelCoordFromBlock(row, col, out int x, out int y);

                        var maxLength = orientationImage.WindowSize / 2;
                        for (var xi = x - maxLength; xi < x + maxLength; xi++)
                        {
                            for (var yi = y - maxLength; yi < y + maxLength; yi++)
                            {
                                var projection = GetProjection(orientationImage, row, col, xi, yi, matrix);

                                var       smoothed = new int[orientationImage.WindowSize + 1];
                                const int n        = 7;
                                for (var j = 0; j < projection.Length; j++)
                                {
                                    var idx = 0;
                                    int sum = 0, count = 0;
                                    for (var k = j - n / 2; k <= j + n / 2; k++, idx++)
                                    {
                                        if (k >= 0 && k < projection.Length)
                                        {
                                            sum += projection[k] * filter[idx];
                                            count++;
                                        }
                                    }
                                    smoothed[j] = sum / count;
                                }

                                var center = smoothed.Length / 2;
                                int left;
                                for (left = center - 1; smoothed[left] == smoothed[center] && left > 0; left--)
                                {
                                    ;
                                }

                                int rigth;
                                for (rigth = center + 1;
                                     smoothed[rigth] == smoothed[center] && rigth < smoothed.Length - 1;
                                     rigth++)
                                {
                                    ;
                                }

                                if (xi >= 0 && xi < matrix.Width && yi >= 0 && yi < matrix.Height)
                                {
                                    newImg[yi, xi] = 255;
                                }

                                if (xi <= 0 || xi >= matrix.Width - 1 || yi <= 0 || yi >= matrix.Height - 1 ||
                                    left == 255 && rigth == smoothed.Length - 1)
                                {
                                    continue;
                                }
                                if (smoothed[center] < smoothed[left] && smoothed[center] < smoothed[rigth])
                                {
                                    newImg[yi, xi] = 0;
                                }
                                else if (rigth - left == 2 &&
                                         (smoothed[left] < smoothed[left - 1] &&
                                          smoothed[left] < smoothed[center] ||
                                          smoothed[rigth] < smoothed[rigth + 1] &&
                                          smoothed[rigth] < smoothed[center] ||
                                          smoothed[center] < smoothed[left - 1] &&
                                          smoothed[center] < smoothed[rigth + 1] ||
                                          smoothed[center] < smoothed[left - 1] &&
                                          smoothed[center] < smoothed[rigth] ||
                                          smoothed[center] < smoothed[left] &&
                                          smoothed[center] < smoothed[rigth + 1]))
                                {
                                    newImg[yi, xi] = 0;
                                }
                            }
                        }
                    }
                }
            }
            return(newImg);
        }
예제 #6
0
        private static void RemoveSpikes(ImageMatrix matrix, OrientationImage orientationImage)
        {
            for (var row = 0; row < orientationImage.Height; row++)
            {
                for (var col = 0; col < orientationImage.Width; col++)
                {
                    if (!orientationImage.IsNullBlock(row, col))
                    {
                        var cos = new double[3];
                        var sin = new double[3];

                        var orthogonalAngle = orientationImage.AngleInRadians(row, col) + Math.PI / 2;
                        cos[0] = Math.Cos(orthogonalAngle);
                        sin[0] = Math.Sin(orthogonalAngle);

                        var orthogonalAngle1 = orthogonalAngle + Math.PI / 12;
                        cos[1] = Math.Cos(orthogonalAngle1);
                        sin[1] = Math.Sin(orthogonalAngle1);

                        var orthogonalAngle2 = orthogonalAngle - Math.PI / 12;
                        cos[2] = Math.Cos(orthogonalAngle2);
                        sin[2] = Math.Sin(orthogonalAngle2);
                        orientationImage.GetPixelCoordFromBlock(row, col, out int x, out int y);

                        var maxLength = orientationImage.WindowSize / 2;
                        for (var xi = x - maxLength; xi < x + maxLength; xi++)
                        {
                            for (var yi = y - maxLength; yi < y + maxLength; yi++)
                            {
                                var xj         = xi;
                                var yj         = yi;
                                var spikeFound = true;
                                while (spikeFound)
                                {
                                    spikeFound = false;
                                    if (xj > 0 && xj < matrix.Width - 1 && yj > 0 && yj < matrix.Height - 1)
                                    {
                                        var tl = matrix[yj - 1, xj - 1];
                                        var tc = matrix[yj - 1, xj];
                                        var tr = matrix[yj - 1, xj + 1];

                                        var le = matrix[yj, xj - 1];
                                        var ce = matrix[yj, xj];
                                        var ri = matrix[yj, xj + 1];

                                        var bl = matrix[yj + 1, xj - 1];
                                        var bc = matrix[yj + 1, xj];
                                        var br = matrix[yj + 1, xj + 1];

                                        if (CouldBeSpike(tl, tc, tr, le, ce, ri, bl, bc, br))
                                        {
                                            for (var i = 0; i < sin.Length && !spikeFound; i++)
                                            {
                                                var xk = Convert.ToInt32(Math.Round(xj - cos[i]));
                                                var yk = Convert.ToInt32(Math.Round(yj - sin[i]));
                                                if (matrix[yk, xk] == 0)
                                                {
                                                    matrix[yj, xj] = 255;
                                                    xj             = xk;
                                                    yj             = yk;
                                                    spikeFound     = true;
                                                }
                                                else
                                                {
                                                    xk = Convert.ToInt32(Math.Round(xj + cos[i]));
                                                    yk = Convert.ToInt32(Math.Round(yj + sin[i]));
                                                    if (matrix[yk, xk] == 0)
                                                    {
                                                        matrix[yj, xj] = 255;
                                                        xj             = xk;
                                                        yj             = yk;
                                                        spikeFound     = true;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #7
0
        private static List <Minutia> GetMinutiaes(ImageMatrix matrix, OrientationImage orientationImage)
        {
            var minutiaes = new List <Minutia>();

            for (var row = 0; row < orientationImage.Height; row++)
            {
                for (var col = 0; col < orientationImage.Width; col++)
                {
                    if (!orientationImage.IsNullBlock(row, col))
                    {
                        orientationImage.GetPixelCoordFromBlock(row, col, out var x, out var y);

                        var maxLength = orientationImage.WindowSize / 2;

                        for (var xi = x - maxLength; xi < x + maxLength; xi++)
                        {
                            for (var yi = y - maxLength; yi < y + maxLength; yi++)
                            {
                                if (xi > 0 && xi < matrix.Width - 1 && yi > 0 && yi < matrix.Height - 1)
                                {
                                    if (matrix[yi, xi] == 0)
                                    {
                                        var values = new List <int>
                                        {
                                            matrix[yi, xi + 1] == 255 ? 0 : 1,
                                            matrix[yi - 1, xi + 1] == 255 ? 0 : 1,
                                            matrix[yi - 1, xi] == 255 ? 0 : 1,
                                            matrix[yi - 1, xi - 1] == 255 ? 0 : 1,
                                            matrix[yi, xi - 1] == 255 ? 0 : 1,
                                            matrix[yi + 1, xi - 1] == 255 ? 0 : 1,
                                            matrix[yi + 1, xi] == 255 ? 0 : 1,
                                            matrix[yi + 1, xi + 1] == 255 ? 0 : 1
                                        };

                                        var cn = 0;
                                        for (var i = 0; i < values.Count; i++)
                                        {
                                            var idx = i;
                                            if (i == 7)
                                            {
                                                idx = -1;
                                            }
                                            cn += Math.Abs(values[i] - values[idx + 1]);
                                        }
                                        cn = (int)(cn * 0.5);


                                        double angleminu;
                                        // end minutiae
                                        if (cn == 1)
                                        {
                                            angleminu = GetMinutiaeAngle(matrix, xi, yi, MinutiaType.End);
                                            if (Math.Abs(angleminu - (-1)) > double.Epsilon)
                                            {
                                                minutiaes.Add(new Minutia
                                                {
                                                    Angle       = (float)angleminu,
                                                    X           = (short)xi,
                                                    Y           = (short)yi,
                                                    MinutiaType = MinutiaType.End
                                                }
                                                              );
                                            }
                                        }
                                        //bifurcation minutiae
                                        if (cn == 3)
                                        {
                                            angleminu = GetMinutiaeAngle(matrix, xi, yi, MinutiaType.Bifurcation);
                                            if (!double.IsNaN(angleminu) && Math.Abs(angleminu - (-1)) > double.Epsilon)
                                            {
                                                minutiaes.Add(new Minutia
                                                {
                                                    Angle       = (float)angleminu,
                                                    X           = (short)xi,
                                                    Y           = (short)yi,
                                                    MinutiaType = MinutiaType.Bifurcation
                                                }
                                                              );
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            var noInTheBorder = new List <Minutia>();

            for (var i = 0; i < minutiaes.Count; i++)
            {
                // boundary Effects (foreground areas)
                orientationImage.GetBlockCoordFromPixel(minutiaes[i].X, minutiaes[i].Y, out var row, out var col);
                if (row >= 1 && col >= 1 && col < orientationImage.Width - 1 && row < orientationImage.Height - 1)
                {
                    if (!
                        (orientationImage.IsNullBlock(row - 1, col) ||
                         orientationImage.IsNullBlock(row + 1, col) ||
                         orientationImage.IsNullBlock(row, col - 1) ||
                         orientationImage.IsNullBlock(row, col + 1) //||
                        )
                        )
                    {
                        noInTheBorder.Add(minutiaes[i]);
                    }
                }
            }

            var toErase = new bool[noInTheBorder.Count];

            for (var i = 0; i < noInTheBorder.Count; i++)
            {
                var mA = noInTheBorder[i];
                for (var j = 0; j < noInTheBorder.Count; j++)
                {
                    if (i != j)
                    {
                        var mB = noInTheBorder[j];
                        // different to orientation image
                        orientationImage.GetBlockCoordFromPixel(mA.X, mA.Y, out var row, out var col);
                        var angleOi = orientationImage.AngleInRadians(row, col);
                        if (mA.MinutiaType == MinutiaType.End &&
                            Math.Min(Angle.DifferencePi(mA.Angle, angleOi),
                                     Angle.DifferencePi(mA.Angle, angleOi + Math.PI)) > Math.PI / 6)
                        {
                            toErase[i] = true;
                        }

                        //  near minutiaes elimination
                        if (mA.MinutiaType == mB.MinutiaType &&
                            MtiaEuclideanDistance.Compare(mA, mB) < 5)
                        {
                            toErase[i] = toErase[j] = true;
                        }

                        //  Ridge break elimination (Ratha)
                        if (mA.MinutiaType == MinutiaType.End &&
                            mB.MinutiaType == MinutiaType.End &&
                            Math.Abs(mA.Angle - mB.Angle) < double.Epsilon &&
                            MtiaEuclideanDistance.Compare(mA, mB) < 10)
                        {
                            toErase[i] = toErase[j] = true;
                        }

                        // Ridge break elimination (tavo - migue)
                        if (mA.MinutiaType == MinutiaType.End &&
                            mB.MinutiaType == MinutiaType.End &&
                            Angle.DifferencePi(mA.Angle, mB.Angle) < Math.PI / 12 &&
                            MtiaEuclideanDistance.Compare(mA, mB) < 10)
                        {
                            toErase[i] = toErase[j] = true;
                        }

                        // spike elimination
                        if (mA.MinutiaType == MinutiaType.End &&
                            mB.MinutiaType == MinutiaType.Bifurcation &&
                            MtiaEuclideanDistance.Compare(mA, mB) < 15)
                        {
                            if (RemoveSpikeOnMinutiae(matrix, mA, mB))
                            {
                                toErase[i] = true;
                            }
                        }
                    }
                }
            }

            var result = new List <Minutia>();

            for (var i = 0; i < noInTheBorder.Count; i++)
            {
                if (!toErase[i])
                {
                    result.Add(noInTheBorder[i]);
                }
            }

            return(result);
        }
        private static void RemoveBadBlocksVariance(OrientationImage oi, ImageMatrix matrix)
        {
            var    maxLength      = oi.WindowSize / 2;
            var    varianceMatrix = new int[oi.Height, oi.Width];
            double max            = 0;
            var    min            = double.MaxValue;

            for (var row = 0; row < oi.Height; row++)
            {
                for (var col = 0; col < oi.Width; col++)
                {
                    oi.GetPixelCoordFromBlock(row, col, out var x, out var y);

                    // Computing Average
                    var sum   = 0;
                    var count = 0;
                    for (var xi = x - maxLength; xi < x + maxLength; xi++)
                    {
                        for (var yi = y - maxLength; yi < y + maxLength; yi++)
                        {
                            if (xi >= 0 && xi < matrix.Width && yi >= 0 && yi < matrix.Height)
                            {
                                sum += matrix[yi, xi];
                                count++;
                            }
                        }
                    }
                    var avg = 1.0 * sum / count;

                    // Computing Variance
                    double sqrSum = 0;
                    for (var xi = x - maxLength; xi < x + maxLength; xi++)
                    {
                        for (var yi = y - maxLength; yi < y + maxLength; yi++)
                        {
                            if (xi >= 0 && xi < matrix.Width && yi >= 0 && yi < matrix.Height)
                            {
                                var diff = matrix[yi, xi] - avg;
                                sqrSum += diff * diff;
                            }
                        }
                    }
                    varianceMatrix[row, col] = Convert.ToInt32(Math.Round(sqrSum / (count - 1)));

                    // Computing de max variance
                    if (varianceMatrix[row, col] > max)
                    {
                        max = varianceMatrix[row, col];
                    }
                    if (varianceMatrix[row, col] < min)
                    {
                        min = varianceMatrix[row, col];
                    }
                }
            }

            for (var row = 0; row < oi.Height; row++)
            {
                for (var col = 0; col < oi.Width; col++)
                {
                    varianceMatrix[row, col] =
                        Convert.ToInt32(Math.Round(254.0 * (varianceMatrix[row, col] - min) / (max - min)));
                }
            }

            const int t = 15;

            for (var row = 0; row < oi.Height; row++)
            {
                for (var col = 0; col < oi.Width; col++)
                {
                    if (!oi.IsNullBlock(row, col) && varianceMatrix[row, col] <= t)
                    {
                        oi[row, col] = OrientationImage.Null;
                    }
                }
            }
        }