첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ 캐니 오퍼레이터 회선 적용하기

----------------------------------------------------------------------------------------------------

using System;

 

#region 캐니 오퍼레이터 회선 적용하기 - ConvolveCannyOperator(sourceArray)

 

/// <summary>

/// 캐니 오퍼레이터 회선 적용하기

/// </summary>

/// <param name="sourceArray">소스 배열</param>

/// <returns>캐니 오퍼레이터 회선 적용 배열</returns>

public int[,] ConvolveCannyOperator(int[,] sourceArray)

{

    int sourceWidth  = sourceArray.GetUpperBound(1) + 1;

    int sourceHeight = sourceArray.GetUpperBound(0) + 1;

 

    double[,] gaussianMaskArray =

    {

        { 1.0/273.0,  4.0/273.0,  7.0/273.0,  4.0/273.0, 1.0/273.0 },

        { 4.0/273.0, 16.0/273.0, 16.0/273.0, 16.0/273.0, 4.0/273.0 },

        { 7.0/273.0, 26.0/273.0, 41.0/273.0, 26.0/273.0, 7.0/273.0 },

        { 4.0/273.0, 16.0/273.0, 16.0/273.0, 16.0/273.0, 4.0/273.0 },

        { 1.0/273.0,  4.0/273.0,  7.0/273.0,  4.0/273.0, 1.0/273.0 }

    };

 

    double[,] sobelXMaskArray =

    {

        { -1.0, 0.0, 1.0 },

        { -2.0, 0.0, 2.0 },

        { -1.0, 0.0, 1.0 }

    };

 

    double[,] sobelYMaskArray =

    {

        { -1.0, -2.0, -1.0 },

        {  0.0,  0.0,  0.0 },

        {  1.0,  2.0,  1.0 }

    };

 

    int[,]    gaussianArray  = ConvolveEdge(sourceArray, gaussianMaskArray);

    int[,]    sobelXArray    = ConvolveEdgeNoBias(gaussianArray, sobelXMaskArray);

    int[,]    sobelYArray    = ConvolveEdgeNoBias(gaussianArray, sobelYMaskArray);

    double[,] angleArray     = new double[sourceHeight, sourceWidth];

    double[,] magnitudeArray = new double[sourceHeight, sourceWidth];

 

    for(int y = 0; y < sourceHeight; y++)

    {

        for(int x = 0; x < sourceWidth; x++)

        {

            angleArray[y, x] = Math.Atan2(sobelYArray[y, x], sobelXArray[y, x]);

 

            magnitudeArray[y, x] = Math.Sqrt(sobelXArray[y, x] * sobelXArray[y, x] +

                sobelYArray[y, x] * sobelYArray[y, x]);

        }

    }

 

    int[,] NonMaxArray = ConvolveCannyOperationNonMaximum(angleArray, magnitudeArray, sourceWidth, sourceHeight, 3, 3);

 

    int[,] thresholdArray = ConvolveCannyOperatorThreshold(NonMaxArray, sourceWidth, sourceHeight, 3, 3, 30, 200);

 

    return thresholdArray;

}

 

#endregion

 

#region 캐니 오퍼레이터 비-최대 회선 적용하기 - ConvolveCannyOperationNonMaximum(angleArray, magnitudeArray,

    sourceWidth, sourceHeight, maskWidth, maskHeight)

 

/// <summary>

/// 캐니 오퍼레이터 비-최대 회선 적용하기

/// </summary>

/// <param name="angleArray">각도 배열</param>

/// <param name="magnitudeArray">강도 배열</param>

/// <param name="sourceWidth">소스 너비</param>

/// <param name="sourceHeight">소스 높이</param>

/// <param name="maskWidth">마스크 너비</param>

/// <param name="maskHeight">마스크 높이</param>

/// <returns>캐니 오퍼레이터 비-최대 회선 적용 배열</returns>

private int[,] ConvolveCannyOperationNonMaximum(double[,] angleArray, double[,] magnitudeArray, int sourceWidth,

    int sourceHeight, int maskWidth, int maskHeight)

{

    int[,]   resultArray          = new int[sourceHeight,sourceWidth];

    int      xPadding             = maskWidth  / 2;

    int      yPadding             = maskHeight / 2;

    double[] targetAngleArray     = new double[maskHeight * maskWidth];

    double[] targetMagnitudeArray = new double[maskHeight * maskWidth];

 

    for(int y = 0; y < sourceHeight - 2 * yPadding; y++)

    {

        for(int x = 0; x < sourceWidth - 2 * xPadding; x++)

        {

            int index = 0;

 

            for(int r = 0; r < maskHeight; r++)

            {

                for(int c = 0; c < maskWidth; c++)

                {

                    targetAngleArray[index] = angleArray[y + r, x + c];

 

                    targetMagnitudeArray[index++] = magnitudeArray[y + r, x + c];

                }

            }

 

            resultArray[y + yPadding, x + xPadding] = SuppressNonMaximum(targetAngleArray, targetMagnitudeArray, index);

        }

    }

 

    for(int y = 0; y < yPadding; y++)

    {

        for(int x = xPadding; x < sourceWidth - xPadding; x++)

        {

            resultArray[y, x] = resultArray[yPadding, x];

 

            resultArray[sourceHeight - 1 - y, x] = resultArray[sourceHeight - 1 - yPadding, x];

        }

    }

 

    for(int x = 0; x < xPadding; x++)

    {

        for(int y = 0; y < sourceHeight; y++)

        {

            resultArray[y, x] = resultArray[y, xPadding];

 

            resultArray[y, sourceWidth - 1 - x] = resultArray[y, sourceWidth - 1 - xPadding];

        }

    }

 

    return resultArray;

}

 

#endregion

 

#region 비-최대 억제하기 - SuppressNonMaximum(targetAngleArray, targetMagnitudeArray, targetLength)

 

/// <summary>

/// 비-최대 억제하기

/// </summary>

/// <param name="targetAngleArray">타겟 각도 배열</param>

/// <param name="targetMagnitudeArray">타겟 강도 배열</param>

/// <param name="targetLength">타겟 길이</param>

/// <returns>처리 결과</returns>

private int SuppressNonMaximum(double[] targetAngleArray, double[] targetMagnitudeArray, int targetLength)

{

    int    middle = targetLength / 2;

    double iAngle1;

    double iAngle2;

    double iAngle3;

    double iAngle4;

    double cAngle;

    double range = Math.PI / 8.0;

 

    for(int i = 0; i < middle; i++)

    {

        if(targetMagnitudeArray[middle] > targetMagnitudeArray[i] &&

            targetMagnitudeArray[middle] > targetMagnitudeArray[targetLength - 1 - i])

        {

            iAngle1 = Math.PI / 4.0 * (i + 1);

            iAngle2 = Math.PI / 4.0 * (i + 1) + Math.PI;

            iAngle3 = Math.PI / 4.0 * i - 3.0 * Math.PI / 4.0 ;

            iAngle4 = Math.PI / 4.0 * i - 3.0 * Math.PI / 4.0 - Math.PI;

            cAngle  = targetAngleArray[middle];

 

            if((cAngle - range) < iAngle1 && iAngle1 < (cAngle + range))

            {

                return (int)targetMagnitudeArray[middle];

            }

            else if((cAngle - range) < iAngle2 && iAngle2 < (cAngle + range))

            {

                return (int)targetMagnitudeArray[middle];

            }

            else if((cAngle - range) < iAngle3 && iAngle3 < (cAngle + range))

            {

                return (int)targetMagnitudeArray[middle];

            }

            else if((cAngle - range) < iAngle4 && iAngle4 < (cAngle + range))

            {

                return (int)targetMagnitudeArray[middle];

            }

        }

    }

 

    return 0;

}

 

#endregion

 

#region 캐니 오퍼레이터 한계값 회선 적용하기 - ConvolveCannyOperatorThreshold(angleArray, sourceWidth, sourceHeight,

    maskWidth, maskHeight, lower, upper)

 

/// <summary>

/// 캐니 오퍼레이터 한계값 회선 적용하기

/// </summary>

/// <param name="angleArray">각도 배열</param>

/// <param name="sourceWidth">소스 너비</param>

/// <param name="sourceHeight">소스 높이</param>

/// <param name="maskWidth">마스크 너비</param>

/// <param name="maskHeight">마스크 높이</param>

/// <param name="lower">하한</param>

/// <param name="upper">상한</param>

/// <returns>캐니 오퍼레이터 한계값 회선 적용 배열</returns>

private int[,] ConvolveCannyOperatorThreshold(int[,] angleArray, int sourceWidth, int sourceHeight, int maskWidth,

    int maskHeight, int lower, int upper)

{

    int[,] resultArray = new int[sourceHeight, sourceWidth];

    int    xPadding    = maskWidth / 2;

    int    yPadding    = maskHeight / 2;

    int[]  targetArray = new int[maskHeight * maskWidth];

 

    for(int y = 0; y < sourceHeight - 2 * yPadding; y++)

    {

        for(int x = 0; x < sourceWidth - 2 * xPadding; x++)

        {

            int index = 0;

 

            for(int r = 0; r < maskHeight; r++)

            {

                for(int c = 0; c < maskWidth; c++)

                {

                    targetArray[index++] = angleArray[y + r, x + c];

                }

            }

 

            resultArray[y + yPadding, x + xPadding] = LimitThreshold(targetArray, index, lower, upper);

        }

    }

 

    for(int y = 0; y < yPadding; y++)

    {

        for(int x = xPadding; x < sourceWidth - xPadding; x++)

        {

            resultArray[y, x] = resultArray[yPadding, x];

 

            resultArray[sourceHeight - 1 - y, x] = resultArray[sourceHeight - 1 - yPadding, x];

        }

    }

 

    for(int x = 0; x < xPadding; x++)

    {

        for(int y = 0; y < sourceHeight; y++)

        {

            resultArray[y, x] = resultArray[y, xPadding];

 

            resultArray[y, sourceWidth - 1 - x] = resultArray[y, sourceWidth - 1 - xPadding];

        }

    }

 

    return resultArray;

}

 

#endregion

 

#region 한계값 제한하기 - LimitThreshold(targetArray, targetLength, lower, upper)

 

/// <summary>

/// 한계값 제한하기

/// </summary>

/// <param name="targetArray">타겟 배열</param>

/// <param name="targetLength">타겟 길이</param>

/// <param name="lower">하한</param>

/// <param name="upper">상한</param>

/// <returns>처리 결과</returns>

private int LimitThreshold(int[] targetArray, int targetLength, int lower, int upper)

{

    int middle = targetLength / 2;

 

    if(targetArray[middle] > upper)

    {

        return 255;

    }

    else if(targetArray[middle] < lower)

    {

        return 0;

    }

    else

    {

        for(int i = 0; i < targetLength; i++)

        {

            if(targetArray[i] >= targetArray[middle])

            {

                return 255;

            }

        }

    }

 

    return 0;

}

 

#endregion

----------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker

댓글을 달아 주세요