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