public void GetsTheCoordinatesOfAllPixelsOnALineDefinedByAStartingPointAndAngle0( string testcaseName, int angle, MatrixPosition[] expectedResult) { //// [ (0,0) (0,1) (0,2) (0,3) (0,4) (0,5) (0,6) (0,7) (0,8) (0,9) ] //// [ (1,0) (1,1) (1,2) (1,3) (1,4) (1,5) (1,6) (1,7) (1,8) (1,9) ] //// [ (2,0) (2,1) (2,2) (2,3) (2,4) (2,5) (2,6) (2,7) (2,8) (2,9) ] //// [ (3,0) (3,1) (3,2) (3,3) (3,4) (3,5) (3,6) (3,7) (3,8) (3,9) ] //// [ (4,0) (4,1) (4,2) (4,3) (4,4) (4,5) (4,6) (4,7) (4,8) (4,9) ] //// [ (5,0) (5,1) (5,2) (5,3) (5,4) X (5,6) (5,7) (5,8) (5,9) ] x = Starting Point (m,n) //// [ (6,0) (6,1) (6,2) (6,3) (6,4) (6,5) (6,6) (6,7) (6,8) (6,9) ] //// [ (7,0) (7,1) (7,2) (7,3) (7,4) (7,5) (7,6) (7,7) (7,8) (7,9) ] //// [ (8,0) (8,1) (8,2) (8,3) (8,4) (8,5) (8,6) (8,7) (8,8) (8,9) ] //// [ (9,0) (9,1) (9,2) (9,3) (9,4) (9,5) (9,6) (9,7) (9,8) (9,9) ] var inputImage = new BinaryImage(10, 10); var startingPoint = new MatrixPosition(5, 5); var result = SignatureReader.GetSamplingLineForAngle( inputImage, startingPoint, angle); var resultingPositions = result.SamplingPoints.Select(x => x.Position).ToArray(); resultingPositions.Should().ContainInOrder(expectedResult, testcaseName); resultingPositions.Should().HaveCount(expectedResult.Length); }
private static bool IsPositionWithinImage(BinaryImage image, MatrixPosition position) { return(position.M >= 0 && position.N >= 0 && position.M < image.Size.Height && position.N < image.Size.Width); }
public void ShrinksImagesToHalfItsSize() { var sampleImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 0 }, { 0, 0, 0, 0, 0, 0 }, }); var expected = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 }, }); var result = Shrinker.ShrinkByHalf(sampleImage); result.Should().Be(expected, $"result:\r\n{result.ToMatrixString()}\r\n should be as expected:\r\n{expected.ToMatrixString()}"); }
public void InterpretsMatrixCoordinatesCorrectly() { var sampleImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 1, 0 }, { 1, 0, 1 }, { 1, 0, 0 } }); // first row int m = 0; sampleImage[m, 0].Should().Be(BinaryImage.White); sampleImage[m, 1].Should().Be(BinaryImage.Black); sampleImage[m, 2].Should().Be(BinaryImage.White); // second row: m=1 m = 1; sampleImage[m, 0].Should().Be(BinaryImage.Black); sampleImage[m, 1].Should().Be(BinaryImage.White); sampleImage[m, 2].Should().Be(BinaryImage.Black); // third row: m=2 m = 2; sampleImage[m, 0].Should().Be(BinaryImage.Black); sampleImage[m, 1].Should().Be(BinaryImage.White); sampleImage[m, 2].Should().Be(BinaryImage.White); }
/// <summary> /// Returns the coordinates of the pixels that lie on the sampling line, which is defined by the /// <paramref name="startingPosition"/> and its <paramref name="angle"/> to the edge of the /// <paramref name="image"/>. The <paramref name="startingPosition"/> will not be returned in the /// result set. /// </summary> /// <remarks> /// <example> /// Here's an example using the angle of 45 degrees. /// <![CDATA[ /// ^ /// | E E = edge of the image /// | \ \ = sampling line /// | \ c = center /// | \ /// | \ /// | \ /// | c /// | /// . /// . /// . ---------------------------> /// ]]> /// </example> /// </remarks> internal static SamplingLine GetSamplingLineForAngle( BinaryImage image, MatrixPosition startingPosition, int angle) { const int MaxIterationLimit = 50000; var samplingLine = new SamplingLine(); MatrixPosition nextPosition; double phi = (angle + 180d) * Math.PI / 180d; int r = 1; do { var deltaN = (int)Math.Round(r * Math.Cos(phi), 0, MidpointRounding.ToZero); var deltaM = (int)Math.Round(r * Math.Sin(phi), 0, MidpointRounding.ToZero); nextPosition = new MatrixPosition(startingPosition.M + deltaM, startingPosition.N + deltaN); if (nextPosition != startingPosition // ReSharper disable once SimplifyLinqExpressionUseAll && !samplingLine.ContainsPosition(nextPosition) && IsPositionWithinImage(image, nextPosition)) { var pointOfInterest = new SamplingPoint(nextPosition, r); samplingLine.Add(pointOfInterest); } r++; } while (IsPositionWithinImage(image, nextPosition) && r < MaxIterationLimit); return(samplingLine); }
public void AppliesThinningOnImage() { var structuringElement = new StructuringElement( new[, ] { { 0, 0, -1 }, { 1, 1, -1 }, { -1, -1, -1 } }); var inputImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0 }, { 1, 1, 1 }, { 1, 1, 1 } }); var expected = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 1 } }); var structuringElements = new[] { structuringElement }; var result = Thinner.Thinning(inputImage, structuringElements); result.Should().Be( expected, $"result:\r\n{result.ToMatrixString()}\r\n should be as expected:\r\n{expected.ToMatrixString()}"); }
/// <summary> /// Shrinks the <paramref name="image"/> by half its size and returns the new image as result. /// </summary> internal static BinaryImage ShrinkByHalf(BinaryImage image) { var downSizedImage = new BinaryImage(image.Size.Width / 2, image.Size.Height / 2); var matrixSize = new Size(2, 2); Parallel.For( 0, downSizedImage.Size.Height, downSizedM => { int originalM = downSizedM * 2; for (int downSizedN = 0; downSizedN < downSizedImage.Size.Width; downSizedN++) { int originalN = downSizedN * 2; var positionInImage = new MatrixPosition(originalM, originalN); var neighbourMatrixFromPosition = image.GetNeighborMatrixFromPosition(positionInImage, matrixSize); float averageValue = neighbourMatrixFromPosition.GetAverageValue(); downSizedImage[downSizedM, downSizedN] = averageValue >= 0.75f ? BinaryImage.Black : BinaryImage.White; } }); return(downSizedImage); }
private static IEnumerable <int> FindAllBlackPixelsOnSamplingLine( BinaryImage image, SamplingLine samplingLine) { return(from samplingPoints in samplingLine.SamplingPoints where image[samplingPoints.Position] == BinaryImage.Black select samplingPoints.Radius); }
public void GetsNeighbourMatrixFromPosition( BinaryImage binaryImage, MatrixPosition positionInImage, Size sizeOfNeighbourMatrix, BinaryMatrix expectedResult) { var result = binaryImage.GetNeighborMatrixFromPosition(positionInImage, sizeOfNeighbourMatrix); result.Should().Be(expectedResult); }
public void VerifySignatureWith360SamplingPointsOfNumber1MatchesFittingTemplate() { var signature01Image = BinaryImage.FromImage(TestDataResources.calculatedSign360_01); var template01Image = BinaryImage.FromImage(TestDataResources.signatureTemplate360_01); var template02Image = BinaryImage.FromImage(TestDataResources.signatureTemplate360_02); bool firstResult = SignatureMatcher.IsMatch(signature01Image, template01Image); bool secondResult = SignatureMatcher.IsMatch(signature01Image, template02Image); firstResult.Should().BeTrue("signature of number 1 should match template of number 1"); secondResult.Should().BeFalse("signature of number 1 must not match template of number 2"); }
/// <summary> /// Gets the center of the object in <paramref name="image"/>. /// </summary> internal static MatrixPosition GetCenterOfObjectIn(BinaryImage image) { int leftMostPoint = image.FindLeftMostPixelIn(); int rightMostPoint = image.FindRightMostPixelIn(); int centerNPoint = (leftMostPoint + rightMostPoint) / 2; int topMostPoint = image.FindTopMostPixelPosition(); int bottomLinePoint = image.FindBottomLinePixelIn(); int centerMPoint = (topMostPoint + bottomLinePoint) / 2; return(new MatrixPosition(centerMPoint, centerNPoint)); }
public void CanConvertImagesToBinaryImageAndBack() { var signature01Image = BinaryImage.FromImage(TestDataResources.calculatedSign360_01); signature01Image.IsEmpty().Should().BeFalse("signature must not be empty"); var converted = signature01Image.ToBitmap(); var convertedBackSignature01Image = BinaryImage.FromImage(converted); convertedBackSignature01Image.IsEmpty().Should().BeFalse("signature must not be empty"); signature01Image.Should().Be(convertedBackSignature01Image); }
public void CanConvertSignatureTemplateImagesToBinaryImageAndBack() { var templateImage = BinaryImage.FromImage(TestDataResources.signatureTemplate360_00); templateImage.IsEmpty().Should().BeFalse("signature template must not be empty"); var converted = templateImage.ToBitmap(); var convertedBackImage = BinaryImage.FromImage(converted); convertedBackImage.IsEmpty().Should().BeFalse("signature template must not be empty"); templateImage.Should().Be(convertedBackImage); }
public void ClonesImages() { var firstImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0 }, { 1, 1, 0 }, { 0, 0, 1 } }); var secondImage = firstImage.Clone(); firstImage.Should().Be(secondImage); }
public void WritesImageToMatrixString() { const string Expected = "010\r\n110\r\n001"; var sampleImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 1, 0 }, { 1, 1, 0 }, { 0, 0, 1 } }); string result = sampleImage.ToMatrixString(); result.Should().Be(Expected); }
public void CanReadSignatureTemplates() { var binaryImage = BinaryImage.FromImage(TestDataResources.sampleSignTemplate); string test = binaryImage.ToMatrixString(); test.Should().Be( "1111100" + Environment.NewLine + "1111000" + Environment.NewLine + "1111000" + Environment.NewLine + "1111000" + Environment.NewLine + "1110000" + Environment.NewLine + "1110000" + Environment.NewLine + "1100000" + Environment.NewLine + "1100000" + Environment.NewLine + "1000000"); }
public void GetNeighborMatrixFromPosition() { var sampleImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 0 }, { 0, 0, 0, 0, 0, 0 }, }); sampleImage.GetNeighborMatrixFromPosition(0, 0, 2).ToString().Should().Be("00\r\n01"); sampleImage.GetNeighborMatrixFromPosition(1, 0, 2).ToString().Should().Be("01\r\n01"); sampleImage.GetNeighborMatrixFromPosition(0, 1, 2).ToString().Should().Be("00\r\n11"); sampleImage.GetNeighborMatrixFromPosition(1, 1, 2).ToString().Should().Be("11\r\n11"); }
/// <summary> /// Gets the signature of an object in <paramref name="image"/> by using a variable number of sampling lines. /// </summary> /// <returns> /// The coordinates of the signature points in an ordered list. /// The key of the dictionary represents the index of the sampling point. /// The value represents the radius from the center of all pixels found. /// </returns> internal static ShapeSignature GetSignature(BinaryImage image, int numberOfSamplingLines) { CheckNumberOfSamplingLinesIsInRange(numberOfSamplingLines); var signature = new ShapeSignature(numberOfSamplingLines); int samplingIndex = 0; var samplingLines = GetSamplingLines(image, numberOfSamplingLines); foreach (var samplingLine in samplingLines) { int[] pointsInAngle = FindAllBlackPixelsOnSamplingLine(image, samplingLine).ToArray(); signature.Add(samplingIndex, pointsInAngle); samplingIndex++; } return(signature); }
internal static Bitmap Plot(BinaryImage sourceImage, IEnumerable <SamplingLine> samplingLines) { const int BitsPerByte = 8; var sourceImageBmp = sourceImage.ToBitmap(); var rectangle = new Rectangle(0, 0, sourceImageBmp.Width, sourceImageBmp.Height); var bitmapData = sourceImageBmp.LockBits( rectangle, ImageLockMode.WriteOnly, sourceImageBmp.PixelFormat); var bytesPerPixel = Image.GetPixelFormatSize(sourceImageBmp.PixelFormat) / BitsPerByte; unsafe { var ptrFirstPixel = (byte *)bitmapData.Scan0; foreach (var samplingLine in samplingLines) { foreach (var samplingPoint in samplingLine.SamplingPoints) { int m = samplingPoint.Position.M; int n = samplingPoint.Position.N; var byteX = n * bytesPerPixel; var ptrCurrentLine = ptrFirstPixel + (m * bitmapData.Stride); if (sourceImage[m, n] == BinaryImage.Black) { ptrCurrentLine[byteX] = Hit.B; // blue ptrCurrentLine[byteX + 1] = Hit.G; // green ptrCurrentLine[byteX + 2] = Hit.R; // red } else { ptrCurrentLine[byteX] = Miss.B; // blue ptrCurrentLine[byteX + 1] = Miss.G; // green ptrCurrentLine[byteX + 2] = Miss.R; // red } } } } sourceImageBmp.UnlockBits(bitmapData); return(sourceImageBmp); }
internal static BinaryImage Plot(ShapeSignature signature) { int[][] signaturePoints = signature.Get(); int largestRadius = FindLargestRadiusIn(signature); var image = new BinaryImage(signature.NumberOfSamplingPoints, largestRadius + 3); for (int i = 0; i < signature.NumberOfSamplingPoints; i++) { int[] pointInAngle = signaturePoints[i]; for (int j = 0; j < pointInAngle.Length; j++) { int radius = pointInAngle[j]; image[radius, i] = BinaryImage.Black; } } return(image); }
public void ComparesTwoImages() { var firstImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } }); var secondImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } }); firstImage.Should().Be(secondImage); }
internal static IReadOnlyCollection <SamplingLine> GetSamplingLines(BinaryImage image, int numberOfSamplingLines) { CheckNumberOfSamplingLinesIsInRange(numberOfSamplingLines); double angleIncrement = 360d / numberOfSamplingLines; var samplingLines = new SamplingLine[numberOfSamplingLines]; var center = GetCenterOfObjectIn(image); for (int samplingIndex = 0; samplingIndex < numberOfSamplingLines; samplingIndex++) { // value of the angle, at which the sampling from the center will be taken. int angle = (int)Math.Round(samplingIndex * angleIncrement, 0, MidpointRounding.ToZero); var samplingLine = GetSamplingLineForAngle(image, center, angle); samplingLines[samplingIndex] = samplingLine; } return(samplingLines); }
/// <summary> /// Applies a smooth filter on <paramref name="binaryImage"/> to remove noise and create /// more distinguishable lines. /// </summary> public static BinaryImage Smoothing(BinaryImage binaryImage) { // Defines the size of the matrix used to remove the noises in a black and white image. // NOTE: the size should be at least 3 and an odd number const int MatrixSize = 7; // Needed for edge cases of the image border. const int MatrixRadius = MatrixSize / 2; var img = binaryImage.Clone(); Parallel.For( MatrixRadius, img.Size.Height - MatrixRadius, m => { for (int n = MatrixRadius; n < img.Size.Width - MatrixRadius; n++) { // 1 1 0 // 1 x 0 -> x is the average of all values around. // 0 0 0 var matrixColors = new BinaryMatrix(new Size(MatrixSize, MatrixSize)); for (var matrixM = 0; matrixM < MatrixSize; matrixM++) { for (var matrixN = 0; matrixN < MatrixSize; matrixN++) { int imageM = m - MatrixRadius + matrixM; int imageN = n - MatrixRadius + matrixN; matrixColors[matrixM, matrixN] = img[imageM, imageN]; } } float average = matrixColors.GetAverageValue(); img[m, n] = average >= 0.5f ? BinaryImage.Black : BinaryImage.White; } }); return(img); }
public void CropsLargeImages() { var sampleImage = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 1, 0, 0 }, { 0, 0, 0, 1, 1, 1, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }); var expected = BinaryImage.FromByteArray( new byte[, ] { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 1, 0, 0 }, { 0, 0, 0, 1, 1, 1, 0, 0 }, { 0, 0, 1, 1, 1, 1, 0, 0 }, { 0, 0, 0, 1, 1, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }); var result = Cropper.CropAroundFigures(sampleImage); result.Should().Be(expected); }
public static BinaryImage DownSizeToHalf(BinaryImage binaryImage) { return(Shrinker.ShrinkByHalf(binaryImage)); }
public static BinaryImage CropAroundFigures(BinaryImage binaryImage) { return(Cropper.CropAroundFigures(binaryImage)); }
public static BinaryImage Thinning(BinaryImage binaryImage) { return(Thinner.Thinning(binaryImage)); }
public static BinaryImage GetSignatureIn(BinaryImage binaryImage, int samplingRate = 180) { var signature = SignatureReader.GetSignature(binaryImage, samplingRate); return(SignaturePlotter.Plot(signature)); }
public static bool VerifyIfSignatureMatchesToTemplate(BinaryImage signatureImage, BinaryImage templateImage) { return(SignatureMatcher.IsMatch(signatureImage, templateImage)); }