private double[] GetOrientations(int radio, Minutia mtia, OrientationImage dirImg) { double[] currOrientations = new double[radio / 3]; int n = radio / 3; double incAng = 2 * Math.PI * 3.0 / radio; for (int i = 0; i < n; i++) { double myAng = mtia.Angle + i * incAng; if (myAng > 2 * Math.PI) { myAng -= (double)(2 * Math.PI); } Point pnt = SetPosToSPoint(myAng, radio, new Point(mtia.X, mtia.Y)); int row, col; dirImg.GetBlockCoordFromPixel(pnt.X, pnt.Y, out row, out col); if ((col < 0) || (row < 0) || (row >= dirImg.Height) || (col >= dirImg.Width) || (dirImg.IsNullBlock(row, col))) { currOrientations[i] = double.NaN; } else { currOrientations[i] = Math.Min(Angle.DifferencePi(mtia.Angle, dirImg.AngleInRadians(row, col)), Angle.DifferencePi(mtia.Angle, dirImg.AngleInRadians(row, col) + Math.PI)); } } return(currOrientations); }
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 static double[] GetOrientations(int radio, Minutia mtia, OrientationImage dirImg) { var currOrientations = new double[radio / 3]; var n = radio / 3; var incAng = 2 * Math.PI * 3.0 / radio; for (var i = 0; i < n; i++) { var myAng = mtia.Angle + i * incAng; if (myAng > 2 * Math.PI) { myAng -= 2 * Math.PI; } var pnt = SetPosToSPoint(myAng, radio, new Point(mtia.X, mtia.Y)); dirImg.GetBlockCoordFromPixel(pnt.X, pnt.Y, out var row, out var col); if (col < 0 || row < 0 || row >= dirImg.Height || col >= dirImg.Width || dirImg.IsNullBlock(row, col)) { currOrientations[i] = double.NaN; } else { currOrientations[i] = Math.Min(Angle.DifferencePi(mtia.Angle, dirImg.AngleInRadians(row, col)), Angle.DifferencePi(mtia.Angle, dirImg.AngleInRadians(row, col) + Math.PI)); } } return(currOrientations); }
internal Qi2005Features(List <Minutia> minutiae, OrientationImage dImg) { Minutiae = new List <GOwMtia>(minutiae.Count); foreach (Minutia mtia in minutiae) { Minutiae.Add(new GOwMtia(mtia, dImg)); } }
public QiFeatures(IReadOnlyCollection <Minutia> minutiae, OrientationImage dImg) { Minutiae = new List <QiMinutia>(minutiae.Count); foreach (var mtia in minutiae) { Minutiae.Add(new QiMinutia(mtia, dImg)); } }
/// <summary> /// Extract a minutia list 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 List <Minutia> ExtractFeatures(Bitmap image) { Ratha1995OrImgExtractor orImgExtractor = new Ratha1995OrImgExtractor(); OrientationImage orientationImage = orImgExtractor.ExtractFeatures(image); ImageMatrix matrix = skeImgExtractor.ExtractSkeletonImage(image, orientationImage); return(GetMinutiaes(matrix, orientationImage)); }
internal Tico2003Features(List <Minutia> minutiae, OrientationImage dImg) { Minutiae = new List <OBMtiaDescriptor>(minutiae.Count); for (short i = 0; i < minutiae.Count; i++) { OBMtiaDescriptor mtiaDescriptor = new OBMtiaDescriptor(minutiae[i], dImg); Minutiae.Add(mtiaDescriptor); } }
internal TicoFeatures(IReadOnlyList <Minutia> minutiae, OrientationImage dImg) { Minutiae = new List <MinutiaDescriptor>(minutiae.Count); for (short i = 0; i < minutiae.Count; i++) { var mtiaDescriptor = new MinutiaDescriptor(minutiae[i], dImg); Minutiae.Add(mtiaDescriptor); } }
internal bool IsInBound(Point pnt, OrientationImage dImg) { if (pnt.X > 0 && pnt.X < dImg.Width * dImg.WindowSize && pnt.Y > 0 && pnt.Y < dImg.Height * dImg.WindowSize) { return(true); } return(false); }
internal GOwMtia(Minutia mnt, OrientationImage dImg) { Minutia = mnt; Segments = new Segment[6]; for (int i = 0; i < Segments.Length; i++) { Segments[i] = new Segment(i * (2 * Math.PI / 6) + mnt.Angle, mnt, dImg); } }
private static void RemoveBadBlocks(OrientationImage oi) { var neighborsMatrix = new int[oi.Height, oi.Width]; for (var row0 = 0; row0 < oi.Height; row0++) { for (var col0 = 0; col0 < oi.Width; col0++) { if (oi[row0, col0] != OrientationImage.Null) { var lowRow = Math.Max(0, row0 - 1); var lowCol = Math.Max(0, col0 - 1); var highRow = Math.Min(row0 + 1, oi.Height - 1); var highCol = Math.Min(col0 + 1, oi.Width - 1); for (var row1 = lowRow; row1 <= highRow; row1++) { for (var col1 = lowCol; col1 <= highCol; col1++) { if (oi[row1, col1] != OrientationImage.Null) { neighborsMatrix[row0, col0]++; } } } } } } for (var row0 = 0; row0 < oi.Height; row0++) { for (var col0 = 0; col0 < oi.Width; col0++) { if (oi[row0, col0] != OrientationImage.Null) { var shouldRemove = true; var lowRow = Math.Max(0, row0 - 1); var lowCol = Math.Max(0, col0 - 1); var highRow = Math.Min(row0 + 1, oi.Height - 1); var highCol = Math.Min(col0 + 1, oi.Width - 1); for (var row1 = lowRow; row1 <= highRow && shouldRemove; row1++) { for (var col1 = lowCol; col1 <= highCol && shouldRemove; col1++) { if (neighborsMatrix[row1, col1] == 9) { shouldRemove = false; } } } if (shouldRemove) { oi[row0, col0] = OrientationImage.Null; } } } } }
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); }
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; } } } } } } } }
// overrides void Start() { _hrClient = GetComponent <HRClient>(); _log = GetComponent <Log>(); _restingImages = GetComponent <RestingImages>(); _focusDetector = FindObjectOfType <FocusDetector>(); _focusDetector.Focused += onAttentionGrabberFocused; _image = GetComponentInChildren <OrientationImage>(); }
private static OrientationImage SmoothOrImg(OrientationImage img) { var smoothed = new OrientationImage(img.Width, img.Height, img.WindowSize); const byte wSize = 3; for (var row = 0; row < img.Height; row++) { for (var col = 0; col < img.Width; col++) { if (!img.IsNullBlock(row, col)) { int count; double ySum; var xSum = ySum = count = 0; double angle; for (var y = row - wSize / 2; y <= row + wSize / 2; y++) { for (var x = col - wSize / 2; x <= col + wSize / 2; x++) { if (y >= 0 && y < img.Height && x >= 0 && x < img.Width && !img.IsNullBlock(y, x)) { angle = img.AngleInRadians(y, x); xSum += Math.Cos(2 * angle); ySum += Math.Sin(2 * angle); count++; } } } if (count == 0 || Math.Abs(xSum) < double.Epsilon && Math.Abs(ySum) < double.Epsilon) { smoothed[row, col] = OrientationImage.Null; } else { var xAvg = xSum / count; var yAvg = ySum / count; angle = Angle.ToDegrees(Angle.ComputeAngle(xAvg, yAvg)) / 2; smoothed[row, col] = Convert.ToByte(Math.Round(angle)); } } else { smoothed[row, col] = OrientationImage.Null; } } } return(smoothed); }
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); }
public static ImageMatrix ExtractSkeletonImage(Bitmap image, OrientationImage orientationImage) { var matrix = new ImageMatrix(image); var 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); }
internal Segment(double ang, Minutia mnt, OrientationImage dImg) { bool endOfPoints = false; int i = 1; List <double> points = new List <double>(); while (!endOfPoints) { Point pnt = SetPosToSPoint(ang, i * interval, new Point(mnt.X, mnt.Y)); if (IsInBound(pnt, dImg)) { int row, col; dImg.GetBlockCoordFromPixel(pnt.X, pnt.Y, out row, out col); if ((col < 0) || (row < 0) || (row >= dImg.Height) || (col >= dImg.Width) || (dImg.IsNullBlock(row, col))) { points.Add(double.NaN); } else { points.Add(Math.Min(Angle.DifferencePi(mnt.Angle, dImg.AngleInRadians(row, col)), Angle.DifferencePi(mnt.Angle, dImg.AngleInRadians(row, col) + Math.PI))); } i++; } else { endOfPoints = true; } } bool isLastNan = false; int j = points.Count - 1; while (!isLastNan && j >= 0) { if (double.IsNaN(points[j])) { points.RemoveAt(j); j--; } else { isLastNan = true; } } directions = points.ToArray(); }
/// <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)); }
internal MinutiaDescriptor(Minutia mnt, OrientationImage dImg) { Minutia = mnt; //difRadio = (int) Math.Truncate((Resolution/25.4)*ridgePeriod*2); EmptyFeaturesCount = 0; Orientations = new double[72]; for (int i = 0, j = 0; i < 4; i++) { var curr = GetOrientations(InitRadio + i * DifRadio, Minutia, dImg); for (var k = 0; k < curr.Length; k++) { Orientations[j++] = curr[k]; if (double.IsNaN(curr[k])) { EmptyFeaturesCount++; } } } }
/// <summary> /// Extract features of type <see cref="Tico2003Features"/> from the specified minutia list and orientation image. /// </summary> /// <param name="mtiae"> /// The minutia list to extract the features from. /// </param> /// <param name="orImg"> /// The skeleton image to extract the features from. /// </param> /// <returns> /// Features of type <see cref="Tico2003Features"/> extracted from the specified minutiae and skeleton image. /// </returns> public Tico2003Features ExtractFeatures(List <Minutia> mtiae, OrientationImage orImg) { return(new Tico2003Features(mtiae, orImg)); }
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); }
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; } } } } } } } } } } } }
/// <summary> /// Extract features of type <see cref="Qi2005Features"/> from the specified minutia list and orientation image. /// </summary> /// <param name="mtiae"> /// The minutia list to extract the features from. /// </param> /// <param name="orImg"> /// The skeleton image to extract the features from. /// </param> /// <returns> /// Features of type <see cref="Qi2005Features"/> extracted from the specified minutiae and skeleton image. /// </returns> public Qi2005Features ExtractFeatures(List <Minutia> mtiae, OrientationImage orImg) { return(new Qi2005Features(mtiae, orImg)); }
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; } } } }