Click here to Skip to main content
15,881,757 members
Articles / Web Development / HTML

A Framework in C# for Fingerprint Verification

2 Jan 2019CPOL11 min read 1.6M   143.5K   672  
In this article, we introduce a framework in C# for fingerprint verification, we briefly explain how to perform fingerprint verification experiments and how to integrate your algorithms to the framework.
/*
 * Created by: Octavio Loyola González (octavioloyola@gmail.com) and Miguel Angel Medina Pérez (miguel.medina.perez@gmail.com)
 * Created: 
 * Comments by: Miguel Angel Medina Pérez (miguel.medina.perez@gmail.com)
 */

using System;
using System.Drawing;
using ImageProcessingTools;
using PatternRecognition.FingerprintRecognition.Core;

namespace PatternRecognition.FingerprintRecognition.FeatureExtractors
{
    /// <summary>
    ///     An implementation of the <see cref="SkeletonImage"/> extractor proposed by Ratha et al. in 1995.
    /// </summary>
    /// <remarks>
    ///     <para>
    ///         This is an implementation of the <see cref="SkeletonImage"/> extractor proposed by Ratha et al. [1] in 1995.
    ///     </para>
    ///     <para>
    ///         Take into account that this algorithm is created to work with fingerprint images at 500 dpi. Proper modifications have to be made for different image resolutions.
    ///     </para>
    ///     <para>
    ///         References:
    ///     </para>
    ///     <para>
    ///         <list type="number">
    ///             <item>
    ///                Ratha N.K., Chen S.Y. and Jain A.K., "Adaptive flow orientation-based feature extraction in fingerprint images," Pattern Recognition, vol. 28, no. 11, pp. 1657–1672, 1995.
    ///             </item>             
    ///         </list>
    ///     </para>
    /// </remarks>
    public class Ratha1995SkeImgExtractor : FeatureExtractor<SkeletonImage>
    {
        #region public

        /// <summary>
        ///     Extract a skeleton image from the specified bitmap image.
        /// </summary>
        /// <param name="image">The source bitmap image to extract features from.</param>
        /// <returns>The features extracted from the specified bitmap image.</returns>
        public override SkeletonImage ExtractFeatures(Bitmap image)
        {
            Ratha1995OrImgExtractor ratha1995OrImgExtractor = new Ratha1995OrImgExtractor();
            OrientationImage orientationImage = ratha1995OrImgExtractor.ExtractFeatures(image);
            ImageMatrix skeletonImage = ExtractSkeletonImage(image, orientationImage);

            byte[] img = new byte[skeletonImage.Width * skeletonImage.Height];
            for (int i = 0; i < skeletonImage.Height; i++)
                for (int j = 0; j < skeletonImage.Width; j++)
                    img[skeletonImage.Width * i + j] = (byte) skeletonImage[i, j];

            return new SkeletonImage(img, skeletonImage.Width, skeletonImage.Height);
        }

        /// <summary>
        ///     Extract a skeleton image from the specified bitmap image.
        /// </summary>
        /// <param name="image">The source bitmap image to extract features from.</param>
        /// <returns>The extracted skeleton image represented by a matrix.</returns>
        public ImageMatrix ExtractSkeletonImage(Bitmap image, OrientationImage orientationImage)
        {
            ImageMatrix matrix = new ImageMatrix(image);

            GaussianBlur gb = new GaussianBlur();
            matrix = gb.Apply(matrix);

            matrix = GetBinaryImage(matrix, orientationImage);
            ApplyThinning(matrix, orientationImage);
            RemoveSpikes(matrix, orientationImage);
            FixBifurcations(matrix, orientationImage);
            RemoveSmallSegments(matrix, orientationImage);

            return matrix;
        }

        #endregion
        
        #region private
        
        private ImageMatrix GetBinaryImage(ImageMatrix matrix, OrientationImage orientationImage)
        {
            int[] filter = new int[] { 1, 2, 5, 7, 5, 2, 1 };
            ImageMatrix newImg = new ImageMatrix(matrix.Width, matrix.Height);
            for (int i = 0; i < matrix.Width; i++)
                for (int j = 0; j < matrix.Height; j++)
                {
                    newImg[j, i] = 255;
                }
            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++)
                            {
                                int[] projection = GetProjection(orientationImage, row, col, xi, yi, matrix);
                               
                                int[] smoothed = new int[orientationImage.WindowSize + 1];
                                const int n = 7;
                                for (int j = 0; j < projection.Length; j++)
                                {
                                    int idx = 0;
                                    int sum = 0, count = 0;
                                    for (int 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;
                                }

                                int 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))
                                {
                                    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;
        }

        private int[] GetProjection(OrientationImage oi, int row, int col, int x, int y, ImageMatrix matrix)
        {
            double angle = oi.AngleInRadians(row, col);
            double orthogonalAngle = oi.AngleInRadians(row, col) + Math.PI / 2;
            
            int maxLength = oi.WindowSize / 2;
            int[] projection = new int[2 * maxLength + 1];
            int[] outlayerCount = new int[2 * maxLength + 1];
            bool outlayerFound = false;
            int totalSum = 0;
            int validPointsCount = 0;
            for (int li = -maxLength, i = 0; li <= maxLength; li++, i++)
            {
                int xi = Convert.ToInt32(x - li * Math.Cos(orthogonalAngle));
                int yi = Convert.ToInt32(y - li * Math.Sin(orthogonalAngle));

                int ySum = 0;
                for (int lj = -maxLength; lj <= maxLength; lj++)
                {
                    int xj = Convert.ToInt32(xi - lj * Math.Cos(angle));
                    int yj = Convert.ToInt32(yi - lj * Math.Sin(angle));
                    if (xj >= 0 && yj >= 0 && xj < matrix.Width && yj < matrix.Height)
                    {
                        ySum += matrix[yj, xj];
                        validPointsCount++;
                    }
                    else
                    {
                        outlayerCount[i]++;
                        outlayerFound = true;
                    }
                }
                projection[i] = ySum;
                totalSum += ySum;
            }

            if (outlayerFound)
            {
                int avg = totalSum / validPointsCount;
                for (int i = 0; i < projection.Length; i++)
                    projection[i] += avg * outlayerCount[i];
            }

            return projection;
        }

        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;
                        }
            }
        }

        private void RemoveSpikes(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))
                    {
                        double[] cos = new double[3];
                        double[] sin = new double[3];

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

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

                        double orthogonalAngle2 = orthogonalAngle - Math.PI / 12;
                        cos[2] = Math.Cos(orthogonalAngle2);
                        sin[2] = Math.Sin(orthogonalAngle2);

                        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++)
                            {
                                int xj = xi;
                                int yj = yi;
                                bool spikeFound = true;
                                while (spikeFound)
                                {
                                    spikeFound = false;
                                    if (xj > 0 && xj < matrix.Width - 1 && yj > 0 && yj < matrix.Height - 1)
                                    {
                                        int tl = matrix[yj - 1, xj - 1];
                                        int tc = matrix[yj - 1, xj]; 
                                        int tr = matrix[yj - 1, xj + 1]; 

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

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

                                        if (CouldBeSpike(tl, tc, tr, le, ce, ri, bl, bc, br))
                                            for (int i = 0; i < sin.Length && !spikeFound; i++)
                                            {
                                                int xk = Convert.ToInt32(Math.Round(xj - cos[i]));
                                                int 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;
                                                    }
                                                }
                                            }
                                    }
                                }
                            }
                    }
        }

        private void FixBifurcations(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 (IsCorner(tl, tc, tr, le, ce, ri, bl, bc, br))
                                        {
                                            matrix[yi, xi] = 255;
                                            changed = true;
                                        }
                                    }
                                    else
                                        matrix[yi, xi] = 255;
                        }
            }
        }

        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 bool IsVR(int tl, int tc, int tr, int le, int ce, int ri, int bl, int bc, int br)
        {
            if (tl == 0 && tc == 255 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 0 && bc == 255 && br == 255
                )
                return true;
            if (tl == 0 && tc == 255 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 0 && bc == 0 && br == 0
                )
                return true;
            if (tl == 255 && tc == 255 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 0 && bc == 0 && br == 255
                )
                return true;
            if (tl == 0 && tc == 255 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 0 && bc == 0 && br == 255
                )
                return true;
            if (tl == 0 && tc == 0 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 0 && bc == 255 && br == 255
                )
                return true;
            if (tl == 0 && tc == 0 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 0 && bc == 0 && br == 255
                )
                return true;

            return false;
        }

        private bool IsVL(int tl, int tc, int tr, int le, int ce, int ri, int bl, int bc, int br)
        {
            if (tl == 255 && tc == 255 && tr == 0 &&
                            le == 255 && ce == 0 && ri == 0 &&
                            bl == 255 && bc == 255 && br == 0
                            )
                return true;
            if (tl == 0 && tc == 0 && tr == 0 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 255 && br == 0
                )
                return true;
            if (tl == 255 && tc == 0 && tr == 0 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 255 && br == 255
                )
                return true;
            if (tl == 255 && tc == 0 && tr == 0 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 255 && br == 0
                )
                return true;
            if (tl == 255 && tc == 255 && tr == 0 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 0 && br == 0
                )
                return true;
            if (tl == 255 && tc == 0 && tr == 0 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 0 && br == 0
                )
                return true;

            return false;
        }

        private bool IsHB(int tl, int tc, int tr, int le, int ce, int ri, int bl, int bc, int br)
        {
            if (tl == 0 && tc == 0 && tr == 0 &&
                            le == 255 && ce == 0 && ri == 255 &&
                            bl == 255 && bc == 255 && br == 255
                            )
                return true;
            if (tl == 0 && tc == 0 && tr == 0 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 0 && bc == 255 && br == 255
                )
                return true;
            if (tl == 0 && tc == 0 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
                return true;
            if (tl == 0 && tc == 0 && tr == 0 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
                return true;
            if (tl == 0 && tc == 0 && tr == 0 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 255 && br == 255
                )
                return true;
            if (tl == 0 && tc == 0 && tr == 0 &&
                le == 0 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 255 && br == 255
                )
                return true;
            return false;
        }

        private bool IsHT(int tl, int tc, int tr, int le, int ce, int ri, int bl, int bc, int br)
        {
            if (tl == 255 && tc == 255 && tr == 255 &&
                            le == 255 && ce == 0 && ri == 255 &&
                            bl == 0 && bc == 0 && br == 0
                            )
                return true;
            if (tl == 255 && tc == 255 && tr == 0 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 0 && bc == 0 && br == 0
                )
                return true;
            if (tl == 255 && tc == 255 && tr == 255 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 0 && br == 0
                )
                return true;
            if (tl == 255 && tc == 255 && tr == 255 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 0 && bc == 0 && br == 0
                )
                return true;
            if (tl == 255 && tc == 255 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                bl == 0 && bc == 0 && br == 0
                )
                return true;
            if (tl == 255 && tc == 255 && tr == 255 &&
                le == 0 && ce == 0 && ri == 0 &&
                bl == 0 && bc == 0 && br == 0
                )
                return true;
            return false;
        }

        private bool CouldBeSpike(int tl, int tc, int tr, int le, int ce, int ri, int bl, int bc, int br)
        {
            if (tl == 255 && tc == 255 && tr == 255 &&
                le == 255 && ce == 0 && ri == 255 &&
                             bc == 0
                )
                return true;
            if (tl == 255 && tc == 255 && tr == 255 &&
                le == 255 && ce == 0 &&
                bl == 255 && br == 0
                )
                return true;
            if (tl == 255 && tc == 255 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 255
                )
                return true;
            if (tl == 255 && tr == 0 &&
                le == 255 && ce == 0 &&
                bl == 255 && bc == 255 && br == 255
                )
                return true;
            if (tc == 0 &&
                le == 255 && ce == 0 && ri == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
                return true;
            if (tl == 0 && tr == 255 &&
                             ce == 0 && ri == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
                return true;
            if (tc == 255 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                            bc == 255 && br == 255
                )
                return true;
            if (tl == 255 && tc == 255 && tr == 255 &&
                             ce == 0 && ri == 255 &&
                bl == 0 && br == 255
                )
                return true;

            return false;
        }

        private bool IsCorner(int tl, int tc, int tr, int le, int ce, int ri, int bl, int bc, int br)
        {
            if (tl == 255 && tc == 255 && //tr == 255 &&
                le == 255 && ce == 0 && ri == 0 &&
                /*bl == 255 &&*/ bc == 0 /*&& br == 255*/
                )
                return true;

            if (/*tl == 255 &&*/ tc == 0 && //tr == 255 &&
                le == 255 && ce == 0 && ri == 0 &&
                bl == 255 && bc == 255 //&& br == 255
                )
                return true;

            if (/*tl == 255 &&*/ tc == 0 && //tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                /*bl == 255 &&*/ bc == 255 && br == 255
                )
                return true;

            if (/*tl == 255 &&*/ tc == 255 && tr == 255 &&
                le == 0 && ce == 0 && ri == 255 &&
                /*bl == 255 &&*/ bc == 0 //&& br == 255
                )
                return true;

            return false;
        }

        private bool IsEnd(ImageMatrix matrix, int x, int y, out int x1, out int y1)
        {
            x1 = -1;
            y1 = -1;

            int tl = (x > 0 && y > 0) ? matrix[y - 1, x - 1] : 255;
            int tc = (y > 0) ? matrix[y - 1, x] : 255;
            int tr = (x < matrix.Width - 1 && y > 0) ? matrix[y - 1, x + 1] : 255;
            int cl = (x > 0) ? matrix[y, x - 1] : 255;
            int ce = matrix[y, x];
            int cr = (x < matrix.Width - 1) ? matrix[y, x + 1] : 255;
            int bl = (x > 0 && y < matrix.Height - 1) ? matrix[y + 1, x - 1] : 255;
            int bc = (y < matrix.Height - 1) ? matrix[y + 1, x] : 255;
            int br = (x < matrix.Width - 1 && y < matrix.Height - 1) ? matrix[y + 1, x + 1] : 255;

            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x;
                y1 = y;
                return true;
            }
            if (tl == 0 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x - 1;
                y1 = y - 1;
                return true;
            }
            if (tl == 255 && tc == 0 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x;
                y1 = y - 1;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 0 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x + 1;
                y1 = y - 1;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 0 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x + 1;
                y1 = y;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 0
                )
            {
                x1 = x + 1;
                y1 = y + 1;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 0 && br == 255
                )
            {
                x1 = x;
                y1 = y + 1;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 0 && bc == 255 && br == 255
                )
            {
                x1 = x - 1;
                y1 = y + 1;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 0 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x - 1;
                y1 = y;
                return true;
            }
            return false;
        }

        private bool IsContinous(ImageMatrix matrix, int x0, int y0, int x, int y, out int x1, out int y1)
        {
            x1 = -1;
            y1 = -1;
            bool isBlack = false;
            if (matrix[y0, x0] == 0)
            {
                matrix[y0, x0] = 255;
                isBlack = true;
            }

            int tl = (x > 0 && y > 0) ? matrix[y - 1, x - 1] : 255;
            int tc = (y > 0) ? matrix[y - 1, x] : 255;
            int tr = (x < matrix.Width - 1 && y > 0) ? matrix[y - 1, x + 1] : 255;
            int cl = (x > 0) ? matrix[y, x - 1] : 255;
            int ce = matrix[y, x];
            int cr = (x < matrix.Width - 1) ? matrix[y, x + 1] : 255;
            int bl = (x > 0 && y < matrix.Height - 1) ? matrix[y + 1, x - 1] : 255;
            int bc = (y < matrix.Height - 1) ? matrix[y + 1, x] : 255;
            int br = (x < matrix.Width - 1 && y < matrix.Height - 1) ? matrix[y + 1, x + 1] : 255;

            if (tl == 0 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x - 1;
                y1 = y - 1;
                if (isBlack)
                    matrix[y0, x0] = 0;
                return true;
            }
            if (tl == 255 && tc == 0 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x;
                y1 = y - 1;
                if (isBlack)
                    matrix[y0, x0] = 0;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 0 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x + 1;
                y1 = y - 1;
                if (isBlack)
                    matrix[y0, x0] = 0;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 0 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x + 1;
                y1 = y;
                if (isBlack)
                    matrix[y0, x0] = 0;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 0
                )
            {
                x1 = x + 1;
                y1 = y + 1;
                if (isBlack)
                    matrix[y0, x0] = 0;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 0 && br == 255
                )
            {
                x1 = x;
                y1 = y + 1;
                if (isBlack)
                    matrix[y0, x0] = 0;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 255 && ce == 0 && cr == 255 &&
                bl == 0 && bc == 255 && br == 255
                )
            {
                x1 = x - 1;
                y1 = y + 1;
                if (isBlack)
                    matrix[y0, x0] = 0;
                return true;
            }
            if (tl == 255 && tc == 255 && tr == 255 &&
                cl == 0 && ce == 0 && cr == 255 &&
                bl == 255 && bc == 255 && br == 255
                )
            {
                x1 = x - 1;
                y1 = y;
                if (isBlack)
                    matrix[y0, x0] = 0;
                return true;
            }
            return false;
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Tecnológico de Monterrey
Mexico Mexico
I received my B.S. and M.S. degrees from the University of Ciego de Ávila, Cuba, in 2007 and I received my PhD. degree in 2014 from the National Institute of Astrophysics, Optics and Electronics (INAOE), Mexico.

I have developed software to solve pattern recognition problems. A successful example is the algorithm DMC which is the most accurate (according to EER) among those which compare both fingerprints and palmprints in the international competition FVC-onGoing.

I have been involved in several research projects about pattern recognition and I have published tens of papers in referenced journals such as "Pattern Recognition," "Knowledge-Based Systems," "Information Sciences", and "IEEE Transactions on Information Forensics and Security."

Written By
Cuba Cuba
Milton García-Borroto is graduated from Las Villas Central University, Cuba, in 2000. He received the M.S. degree in 2007 from the National Institute of Astrophisics, Optics and Electronics, Mexico, where he continues his studies toward a Ph.D. degree. His research interests are pattern recognition and biometry.

Relevant papers:
1. M. García-Borroto, J. F. Martinez Trinidad, J. A. Carrasco Ochoa, M. A. Medina-Pérez, and J. Ruiz-Shulcloper. LCMine: An efficient algorithm for mining discriminative regularities and its application in supervised classification. Pattern Recognition vol. 43, pp. 3025-3034, 2010.
2. M. García-Borroto, J. F. Martinez Trinidad, J. A. Carrasco Ochoa. A New Emerging Pattern Mining Algorithm and Its Application in Supervised Classification. M.J. Zaki et al. (Eds.): PAKDD 2010, Part I, Lecture Notes in Artificial Intelligence, vol. 6118, pp. 150–157, 2010.
3. M. A. Medina-Pérez, A. Gutiérrez-Rodríguez, and M. García-Borroto, "Improving Fingerprint Matching Using an Orientation-Based Minutia Descriptor," Lecture Notes in Computer Science, vol. 5856, pp. 121-128, 2009.
4. M. García-Borroto, Y. Villuendas-Rey, J. A. Carrasco-Ochoa, and J. F. Martínez-Trinidad, "Finding Small Consistent Subset for the Nearest Neighbor Classifier Based on Support Graphs," Lecture Notes in Computer Science, vol. 5856, pp. 465-472, 2009.
5. M. García-Borroto, Y. Villuendas-Rey, J. A. Carrasco-Ochoa, and J. F. Martínez-Trinidad, "Using Maximum Similarity Graphs to Edit Nearest Neighbor Classifiers," Lecture Notes in Computer Science, vol. 5856, pp. 489-496, 2009.
6. M. A. Medina-Pérez, M. García-Borroto, and J. Ruiz-Shulcloper, "Object Selection Based on Subclass Error Correcting for ALVOT," Lecture Notes in Computer Science, vol. 4756, pp. 496-505, 2007.

Andres Eduardo Gutierrez Rodriguez is graduated from Las Villas Central University, Cuba, in 2006. He received the M.S. degree in 2009 from the University of Ciego de Ávila, Cuba. His research interests are pattern recognition and biometry.

Relevant papers:

-M. A. Medina-Pérez, A. Gutiérrez-Rodríguez, and M. García-Borroto, "Improving Fingerprint Matching Using an Orientation-Based Minutia Descriptor," Lecture Notes in Computer Science, vol. 5856, pp. 121-128, 2009.
-A. E. Gutierrez-Rodriguez, M. A. Medina-Perez, J. F. Martinez-Trinidad, J. A. Carrasco-Ochoa, and M. Garcia-Borroto, "New Dissimilarity Measures for Ultraviolet Spectra Identification," Lecture Notes in Computer Science, vol. 6256, pp. 220-229, 2010.

Written By
Program Manager
Spain Spain
Octavio Loyola-González received his PhD degree in Computer Science from the National Institute for Astrophysics, Optics, and Electronics, Mexico. He has won several awards from different institutions due to his research work on applied projects; consequently, he is a Member of the National System of Researchers in Mexico (Rank1). He worked as a distinguished professor and researcher at Tecnologico de Monterrey, Campus Puebla, for undergraduate and graduate programs of Computer Sciences. Currently, he is responsible for running Machine Learning & Artificial Intelligence practice inside Stratesys., where he is involved in the development and implementation using analytics and data mining. He has outstanding experience in the fields of big data & pattern recognition, cloud computing, IoT, and analytical tools to apply them in sectors where he has worked for as Banking & Insurance, Retail, Oil&Gas, Agriculture, Cybersecurity, Biotechnology, and Dactyloscopy. From these applied projects, Dr. Loyola-González has published several books and papers in well-known journals, and he has several ongoing patents as manager and researcher in Stratesys.

Comments and Discussions