예제 #1
0
        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);
        }
예제 #2
0
 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);
 }
예제 #3
0
        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()}");
        }
예제 #4
0
        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);
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
        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()}");
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
 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);
        }
예제 #10
0
        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");
        }
예제 #11
0
        /// <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));
        }
예제 #12
0
        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);
        }
예제 #13
0
        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);
        }
예제 #14
0
        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);
        }
예제 #15
0
        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);
        }
예제 #16
0
        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");
        }
예제 #17
0
        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");
        }
예제 #18
0
        /// <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);
        }
예제 #19
0
        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);
        }
예제 #20
0
        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);
        }
예제 #21
0
        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);
        }
예제 #22
0
        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);
        }
예제 #23
0
        /// <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);
        }
예제 #24
0
        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);
        }
예제 #25
0
 public static BinaryImage DownSizeToHalf(BinaryImage binaryImage)
 {
     return(Shrinker.ShrinkByHalf(binaryImage));
 }
예제 #26
0
 public static BinaryImage CropAroundFigures(BinaryImage binaryImage)
 {
     return(Cropper.CropAroundFigures(binaryImage));
 }
예제 #27
0
 public static BinaryImage Thinning(BinaryImage binaryImage)
 {
     return(Thinner.Thinning(binaryImage));
 }
예제 #28
0
        public static BinaryImage GetSignatureIn(BinaryImage binaryImage, int samplingRate = 180)
        {
            var signature = SignatureReader.GetSignature(binaryImage, samplingRate);

            return(SignaturePlotter.Plot(signature));
        }
예제 #29
0
 public static bool VerifyIfSignatureMatchesToTemplate(BinaryImage signatureImage, BinaryImage templateImage)
 {
     return(SignatureMatcher.IsMatch(signatureImage, templateImage));
 }