Click here to Skip to main content
15,892,839 members
Articles / Programming Languages / C#

Split a Single-Pixel-Width Connected Line Graph Into Line Segments by The Hit-and-Miss Transformation

Rate me:
Please Sign up or sign in to vote.
4.89/5 (13 votes)
16 Aug 20078 min read 58.9K   976   58  
Split a single-pixel-width connected line graph into line segments by the Hit-and-Miss transformation.
using System;
using System.Collections.Generic;
using System.Text;

namespace LineSegmentSplitter
{
    class HitAndMissTransformation
    {
        public static bool[,] AndTrue2D(bool[,] srcBoolMatrix, bool[,] kernel)
        {
            // kernel information
            int hk = kernel.GetLength(1);
            int wk = kernel.GetLength(0);
            int halfHk = (hk - 1) / 2;
            int halfWk = (wk - 1) / 2;

            // matrix info
            int height = srcBoolMatrix.GetLength(1);
            int width = srcBoolMatrix.GetLength(0);

            bool[,] expandSrcBoolMatrix = BoundFillingBackgroundIntensityExpand(srcBoolMatrix, kernel);

            // prepare dst bool matrix
            int expandHeight = expandSrcBoolMatrix.GetLength(1);
            int expandWidth = expandSrcBoolMatrix.GetLength(0);
            bool[,] expandDstBoolMatrix = new bool[expandWidth, expandHeight];

            int xStart = halfWk;
            int xEnd = width + halfWk;
            int yStart = halfHk;
            int yEnd = height + halfHk;

            for (int x = xStart; x < xEnd; x++)
            {
                for (int y = yStart; y < yEnd; y++)
                {
                    bool isHit = true;
                    // inside kernel
                    for (int kx = -1 * halfWk; kx <= halfWk; kx++)
                    {
                        for (int ky = -1 * halfHk; ky <= halfHk; ky++)
                        {
                            // kernel, expandSrcBoolMatrix, and expandDstBoolMatrix are bool[,]
                            if (kernel[kx + halfWk, ky + halfHk])
                            // kernel element is true
                            {
                                if (!expandSrcBoolMatrix[x + kx, y + ky])
                                // image element is false
                                {
                                    isHit = false;
                                    break;
                                }
                            }
                        }
                    }
                    expandDstBoolMatrix[x, y] = isHit;
                }
            }

            bool[,] dstBoolMatrix = BoundFillingBackgroundIntensityShrink(expandDstBoolMatrix, kernel);
            return dstBoolMatrix;
        } // AndTrue2D()

        public static bool[,] AndTrueFalse2D(bool[,] srcBoolMatrix, bool[,] kernel)
        {
            // kernel information
            int hk = kernel.GetLength(1);
            int wk = kernel.GetLength(0);
            int halfHk = (hk - 1) / 2;
            int halfWk = (wk - 1) / 2;

            // matrix info
            int height = srcBoolMatrix.GetLength(1);
            int width = srcBoolMatrix.GetLength(0);

            bool[,] expandSrcBoolMatrix = BoundFillingBackgroundIntensityExpand(srcBoolMatrix, kernel);

            // prepare dst bool matrix
            int expandHeight = expandSrcBoolMatrix.GetLength(1);
            int expandWidth = expandSrcBoolMatrix.GetLength(0);
            bool[,] expandDstBoolMatrix = new bool[expandWidth, expandHeight];

            int xStart = halfWk;
            int xEnd = width + halfWk;
            int yStart = halfHk;
            int yEnd = height + halfHk;

            for (int x = xStart; x < xEnd; x++)
            {
                for (int y = yStart; y < yEnd; y++)
                {
                    bool isHit = true;
                    // inside kernel
                    for (int kx = -1 * halfWk; kx <= halfWk; kx++)
                    {
                        for (int ky = -1 * halfHk; ky <= halfHk; ky++)
                        {
                            // kernel is a bool[,]
                            // expandSrcBoolMatrix, and expandDstBoolMatrix are bool[,]
                            if ((kernel[kx + halfWk, ky + halfHk] && !expandSrcBoolMatrix[x + kx, y + ky])
                                || (!kernel[kx + halfWk, ky + halfHk] && expandSrcBoolMatrix[x + kx, y + ky]))
                            {
                                isHit = false;
                                break;
                            }
                        }
                    }
                    expandDstBoolMatrix[x, y] = isHit;
                }
            }

            bool[,] dstBoolMatrix = BoundFillingBackgroundIntensityShrink(expandDstBoolMatrix, kernel);
            return dstBoolMatrix;
        } // AndTrueFalse2D()

        public static bool[,] AndTrueFalseDontCare2D(bool[,] srcBoolMatrix, double[,] kernel)
        {
            // kernel information
            int hk = kernel.GetLength(1);
            int wk = kernel.GetLength(0);
            int halfHk = (hk - 1) / 2;
            int halfWk = (wk - 1) / 2;

            // matrix info
            int height = srcBoolMatrix.GetLength(1);
            int width = srcBoolMatrix.GetLength(0);

            bool[,] expandSrcBoolMatrix = BoundFillingBackgroundIntensityExpand(srcBoolMatrix, kernel);

            // prepare dst bool matrix
            int expandHeight = expandSrcBoolMatrix.GetLength(1);
            int expandWidth = expandSrcBoolMatrix.GetLength(0);
            bool[,] expandDstBoolMatrix = new bool[expandWidth, expandHeight];

            int xStart = halfWk;
            int xEnd = width + halfWk;
            int yStart = halfHk;
            int yEnd = height + halfHk;

            for (int x = xStart; x < xEnd; x++)
            {
                for (int y = yStart; y < yEnd; y++)
                {
                    bool isHit = true;
                    // inside kernel
                    for (int kx = -1 * halfWk; kx <= halfWk; kx++)
                    {
                        for (int ky = -1 * halfHk; ky <= halfHk; ky++)
                        {
                            // kernel is a double[,]
                            // expandSrcBoolMatrix, and expandDstBoolMatrix are bool[,]
                            if ((kernel[kx + halfWk, ky + halfHk] == 1 && !expandSrcBoolMatrix[x + kx, y + ky])
                                || (kernel[kx + halfWk, ky + halfHk] == 0 && expandSrcBoolMatrix[x + kx, y + ky]))
                            {
                                isHit = false;
                                break;
                            }
                        }
                    }
                    expandDstBoolMatrix[x, y] = isHit;
                }
            }

            bool[,] dstBoolMatrix = BoundFillingBackgroundIntensityShrink(expandDstBoolMatrix, kernel);
            return dstBoolMatrix;
        } // AndTrueFalseDontCare2D()


        public static bool[,] BoundFillingBackgroundIntensityExpand(bool[,] srcBoolMatrix, int hk, int wk)
        {
            int height = srcBoolMatrix.GetLength(1);
            int width = srcBoolMatrix.GetLength(0);


            // half kernal width and height
            int halfWk = (wk - 1) / 2;
            int halfHk = (hk - 1) / 2;

            // expanded matrix height & width
            int heightA2 = height + 2 * halfHk;
            int widthA2 = width + 2 * halfWk;
            bool[,] expand = new bool[widthA2, heightA2];

            int Wm1aHWK = width - 1 + halfWk;
            int HHKm1 = halfHk - 1;
            // upper row
            for (int xe = halfWk, x = 0; xe <= Wm1aHWK; xe++, x++)
                for (int ye = 0, y = halfHk; ye <= HHKm1; ye++, y--)
                    expand[xe, ye] = false;
            // bottom row
            int Hm1a2HHk = height - 1 + 2 * halfHk;
            for (int xe = halfWk, x = 0; xe <= Wm1aHWK; xe++, x++)
                for (int ye = height + halfHk, y = height - 2; ye <= Hm1a2HHk; ye++, y--)
                    expand[xe, ye] = false;
            // left column
            int HWKm1 = halfWk - 1;
            int Hm1aHHK = height - 1 + halfHk;
            for (int xe = 0, x = halfWk; xe <= HWKm1; xe++, x--)
                for (int ye = halfHk, y = 0; ye <= Hm1aHHK; ye++, y++)
                    expand[xe, ye] = false;
            // right column
            int Wm1a2HWK = width - 1 + 2 * halfWk;
            for (int xe = width + halfWk, x = width - 2; xe <= Wm1a2HWK; xe++, x--)
                for (int ye = halfHk, y = 0; ye <= Hm1aHHK; ye++, y++)
                    expand[xe, ye] = false;
            // center
            for (int xe = halfWk, x = 0; xe <= Wm1aHWK; xe++, x++)
                for (int ye = halfHk, y = 0; ye <= Hm1aHHK; ye++, y++)
                    expand[xe, ye] = srcBoolMatrix[x, y];
            // left-top corner
            for (int xc = 0, xe = 2 * halfWk; xc <= HWKm1; xc++, xe--)
                for (int y = 0; y <= HHKm1; y++)
                    expand[xc, y] = false;
            // right-top corner
            for (int xc = width + halfWk, xe = width + halfWk - 2; xc <= Wm1a2HWK; xc++, xe--)
                for (int y = 0; y <= HHKm1; y++)
                    expand[xc, y] = false;
            // left-bottom corner
            for (int xc = 0, xe = 2 * halfWk; xc <= HWKm1; xc++, xe--)
                for (int y = height + halfHk; y <= Hm1a2HHk; y++)
                    expand[xc, y] = false;
            // right-bottom corner
            for (int xc = width + halfWk, xe = width + halfWk - 2; xc <= Wm1a2HWK; xc++, xe--)
                for (int y = height + halfHk; y <= Hm1a2HHk; y++)
                    expand[xc, y] = false;
            return expand;
        }

        public static bool[,] BoundFillingBackgroundIntensityExpand(bool[,] srcBoolMatrix, bool[,] kernel)
        {
            int hk = kernel.GetLength(1);
            int wk = kernel.GetLength(0);
            return BoundFillingBackgroundIntensityExpand(srcBoolMatrix, hk, wk);           
        } // BoundFillingBackgroundIntensityExpand()


        public static bool[,] BoundFillingBackgroundIntensityExpand(bool[,] srcBoolMatrix, double[,] kernel)
        {
            int hk = kernel.GetLength(1);
            int wk = kernel.GetLength(0);
            return BoundFillingBackgroundIntensityExpand(srcBoolMatrix, hk, wk);
        } // BoundFillingBackgroundIntensityExpand()

        public static bool[,] BoundFillingBackgroundIntensityShrink(bool[,] expandSrcBoolMatrix, int hk, int wk)
        {
            // kernel information
            int halfHk = (hk - 1) / 2;
            int halfWk = (wk - 1) / 2;

            // matrix info
            int height = expandSrcBoolMatrix.GetLength(1);
            int width = expandSrcBoolMatrix.GetLength(0);

            // shink matrix info
            int heightM2 = height - 2 * halfHk;
            int widthM2 = width - 2 * halfWk;
            bool[,] shrink = new bool[widthM2, heightM2];
            int WmHWKm1 = width - halfWk - 1;
            int HmHHKm1 = height - halfHk - 1;

            // copy centre part
            for (int xs = 0, x = halfWk; x <= WmHWKm1; x++, xs++)
                for (int ys = 0, y = halfHk; y <= HmHHKm1; y++, ys++)
                    shrink[xs, ys] = expandSrcBoolMatrix[x, y];

            return shrink;
        }

        public static bool[,] BoundFillingBackgroundIntensityShrink(bool[,] expandSrcBoolMatrix, bool[,] kernel)
        {
            // kernel information
            int hk = kernel.GetLength(1);
            int wk = kernel.GetLength(0);
            return BoundFillingBackgroundIntensityShrink(expandSrcBoolMatrix, hk, wk);
        } // BoundFillingBackgroundIntensityShrink()

        public static bool[,] BoundFillingBackgroundIntensityShrink(bool[,] expandSrcBoolMatrix, double[,] kernel)
        {
            // kernel information
            int hk = kernel.GetLength(1);
            int wk = kernel.GetLength(0);
            return BoundFillingBackgroundIntensityShrink(expandSrcBoolMatrix, hk, wk);
        } // BoundFillingBackgroundIntensityShrink()

        
    }
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Team Leader
United Kingdom United Kingdom
Ping is the Director of Technology Development of AI Speech Ltd. His main interests includes artificial intellegent, speech technologies, image processing technologies, and software engineering methodologies.

Comments and Discussions