첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ CompassEdgeDetectionType.cs

namespace TestProject
{
    /// <summary>
    /// 컴파스 가장자리 탐지 타입
    /// </summary>
    public enum CompassEdgeDetectionType
    {
        /// <summary>
        /// Prewitt 3X3X4
        /// </summary>
        Prewitt3X3X4,

        /// <summary>
        /// Prewitt 3X3X8
        /// </summary>
        Prewitt3X3X8,

        /// <summary>
        /// Prewitt 5X5X4
        /// </summary>
        Prewitt5X5X4,

        /// <summary>
        /// Sobel 3X3X4
        /// </summary>
        Sobel3X3X4,

        /// <summary>
        /// Sobel 3X3X8
        /// </summary>
        Sobel3X3X8,

        /// <summary>
        /// Sobel 5X5X4
        /// </summary>
        Sobel5X5X4,

        /// <summary>
        /// Scharr 3X3X4
        /// </summary>
        Scharr3X3X4,

        /// <summary>
        /// Scharr 3X3X8
        /// </summary>
        Scharr3X3X8,

        /// <summary>
        /// Scharr 5X5X4
        /// </summary>
        Scharr5X5X4,

        /// <summary>
        /// Kirsch 3X3X4
        /// </summary>
        Kirsch3X3X4,

        /// <summary>
        /// Kirsch 3X3X8
        /// </summary>
        Kirsch3X3X8,

        /// <summary>
        /// Isotropic 3X3X4
        /// </summary>
        Isotropic3X3X4,

        /// <summary>
        /// Isotropic 3X3X8
        /// </summary>
        Isotropic3X3X8
    }
}

 

728x90

 

▶ BitmapHelper.cs

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace TestProject
{
    /// <summary>
    /// 비트맵 헬퍼
    /// </summary>
    public static class BitmapHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region Prewitt 3X3X4 - Prewitt3X3X4

        /// <summary>
        /// Prewitt 3X3X4
        /// </summary>
        public static double[,,] Prewitt3X3X4
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -1, 0, 1 },
                    { -1, 0, 1 },
                    { -1, 0, 1 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 90);

                return kernelArray;
            }
        }

        #endregion
        #region Prewitt 3X3X8 - Prewitt3X3X8

        /// <summary>
        /// Prewitt 3X3X8
        /// </summary>
        public static double[,,] Prewitt3X3X8
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -1, 0, 1 },
                    { -1, 0, 1 },
                    { -1, 0, 1 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 45);

                return kernelArray;
            }
        }

        #endregion
        #region Prewitt 5X5X4 - Prewitt5X5X4

        /// <summary>
        /// Prewitt 5X5X4
        /// </summary>
        public static double[,,] Prewitt5X5X4
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -2, -1, 0, 1, 2 },
                    { -2, -1, 0, 1, 2 },
                    { -2, -1, 0, 1, 2 },
                    { -2, -1, 0, 1, 2 },
                    { -2, -1, 0, 1, 2 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 90);

                return kernelArray;
            }
        }

        #endregion
        #region Kirsch 3X3X4 - Kirsch3X3X4

        /// <summary>
        /// Kirsch 3X3X4
        /// </summary>
        public static double[,,] Kirsch3X3X4
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -3, -3, 5 },
                    { -3,  0, 5 },
                    { -3, -3, 5 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 90);

                return kernelArray;
            }
        }

        #endregion
        #region Kirsch 3X3X8 - Kirsch3X3X8

        /// <summary>
        /// Kirsch 3X3X8
        /// </summary>
        public static double[,,] Kirsch3X3X8
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -3, -3,  5 },
                    { -3,  0,  5 },
                    { -3, -3,  5 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 45);

                return kernelArray;
            }
        }

        #endregion
        #region Sobel 3X3X4 - Sobel3X3X4

        /// <summary>
        /// Sobel 3X3X4
        /// </summary>
        public static double[,,] Sobel3X3X4
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -1, 0, 1 },
                    { -2, 0, 2 },
                    { -1, 0, 1 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 90);

                return kernelArray;
            }
        }

        #endregion
        #region Sobel 3X3X8 - Sobel3X3X8

        /// <summary>
        /// Sobel3X3X8
        /// </summary>
        public static double[,,] Sobel3X3X8
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                   { -1, 0, 1 },
                   { -2, 0, 2 },
                   { -1, 0, 1 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 45);

                return kernelArray;
            }
        }

        #endregion
        #region Sobel 5X5X4 - Sobel5X5X4

        /// <summary>
        /// Sobel 5X5X4
        /// </summary>
        public static double[,,] Sobel5X5X4
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    {  -5,  -4, 0,  4,  5 },
                    {  -8, -10, 0, 10,  8 },
                    { -10, -20, 0, 20, 10 },
                    {  -8, -10, 0, 10,  8 },
                    {  -5,  -4, 0,  4,  5 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 90);

                return kernelArray;
            }
        }

        #endregion
        #region Scharr 3X3X4 - Scharr3X3X4

        /// <summary>
        /// Scharr 3X3X4
        /// </summary>
        public static double[,,] Scharr3X3X4
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -1, 0, 1 },
                    { -3, 0, 3 },
                    { -1, 0, 1 }
                };

                double[, ,] kernelArray = RotateArray(baseKernelArray, 90);

                return kernelArray;
            }
        }

        #endregion
        #region Scharr 3X3X8 - Scharr3X3X8

        /// <summary>
        /// Scharr 3X3X8
        /// </summary>
        public static double[,,] Scharr3X3X8
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -1, 0, 1 },
                    { -3, 0, 3 },
                    { -1, 0, 1 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 45);

                return kernelArray;
            }
        }

        #endregion
        #region Scharr 5X5X4 - Scharr5X5X4

        /// <summary>
        /// Scharr 5X5X4
        /// </summary>
        public static double[, ,] Scharr5X5X4
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    { -1, -1, 0, 1, 1 },
                    { -2, -2, 0, 2, 2 },
                    { -3, -6, 0, 6, 3 },
                    { -2, -2, 0, 2, 2 },
                    { -1, -1, 0, 1, 1 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 90);

                return kernelArray;
            }
        }

        #endregion
        #region Isotropic 3X3X4 - Isotropic3X3X4

        /// <summary>
        /// Isotropic 3X3X4
        /// </summary>
        public static double[,,] Isotropic3X3X4
        {
            get
            {
                double[,] baseKernelArray = new double[,]
                {
                    {            -1, 0,            1 },
                    { -Math.Sqrt(2), 0, Math.Sqrt(2) },
                    {            -1, 0,            1 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 90);

                return kernelArray;
            }
        }

        #endregion
        #region Isotropic 3X3X8 - Isotropic3X3X8

        /// <summary>
        /// Isotropic 3X3X8
        /// </summary>
        public static double[,,] Isotropic3X3X8
        {
            get
             {
                double[,] baseKernelArray = new double[,]
                {
                    {            -1, 0,            1 },
                    { -Math.Sqrt(2), 0, Math.Sqrt(2) },
                    {            -1, 0,            1 }
                };

                double[,,] kernelArray = RotateArray(baseKernelArray, 45);

                return kernelArray;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 비트맵 로드하기 - LoadBitmap(filePath)

        /// <summary>
        /// 비트맵 로드하기
        /// </summary>
        /// <param name="filePath">파일 경로</param>
        /// <returns>비트맵</returns>
        public static Bitmap LoadBitmap(string filePath)
        {
            using(Bitmap bitmap = new Bitmap(filePath))
            {
                return new Bitmap(bitmap);
            }
        }

        #endregion
        #region 컴파스 가장자리 탐지 필터 적용하기 - ApplyCompassEdgeDetectionFilter(sourceBitmap, compassEdgeDetectionType)

        /// <summary>
        /// 컴파스 가장자리 탐지 필터 적용하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="compassEdgeDetectionType">컴파스 가장자리 탐지 타입</param>
        /// <returns>비트맵</returns>
        public static Bitmap ApplyCompassEdgeDetectionFilter(Bitmap sourceBitmap, CompassEdgeDetectionType compassEdgeDetectionType)
        {
            Bitmap targetBitmap = null;

            switch(compassEdgeDetectionType)
            {
                case CompassEdgeDetectionType.Sobel3X3X4 :
                
                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Sobel3X3X4, 1.0 / 4.0);

                    break;

                case CompassEdgeDetectionType.Sobel3X3X8 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Sobel3X3X8, 1.0/ 4.0);

                    break;

                case CompassEdgeDetectionType.Sobel5X5X4 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Sobel5X5X4, 1.0/ 84.0);

                    break;

                case CompassEdgeDetectionType.Prewitt3X3X4 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Prewitt3X3X4, 1.0 / 3.0);

                    break;

                case CompassEdgeDetectionType.Prewitt3X3X8 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Prewitt3X3X8, 1.0/ 3.0);
                    
                    break;

                case CompassEdgeDetectionType.Prewitt5X5X4 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Prewitt5X5X4, 1.0 / 15.0);

                    break;

                case CompassEdgeDetectionType.Scharr3X3X4 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Scharr3X3X4, 1.0 / 4.0);

                    break;

                case CompassEdgeDetectionType.Scharr3X3X8 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Scharr3X3X8, 1.0 / 4.0);

                    break;

                case CompassEdgeDetectionType .Scharr5X5X4 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Scharr5X5X4, 1.0 / 21.0);

                    break;

                case CompassEdgeDetectionType.Kirsch3X3X4 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Kirsch3X3X4, 1.0 / 15.0);

                    break;

                case CompassEdgeDetectionType.Kirsch3X3X8 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Kirsch3X3X8, 1.0 / 15.0);

                    break;

                case CompassEdgeDetectionType.Isotropic3X3X4 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Isotropic3X3X4, 1.0 / 3.4);

                    break;

                case CompassEdgeDetectionType.Isotropic3X3X8 :

                    targetBitmap = ApplyConvolutionFilter(sourceBitmap, Isotropic3X3X8, 1.0 / 3.4);

                    break;
            }

            return targetBitmap;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region 배열 회전하기 - RotateArray(sourceArray, angle)

        /// <summary>
        /// 배열 회전하기
        /// </summary>
        /// <param name="sourceArray">소스 배열</param>
        /// <param name="angle">각도</param>
        /// <returns>배열</returns>
        private static double[,,] RotateArray(double[,] sourceArray, double angle)
        {
            double[,,] targetArray = new double[(int )(360 / angle), sourceArray.GetLength(0), sourceArray.GetLength(1)];

            int xOffset = sourceArray.GetLength(1) / 2;
            int yOffset = sourceArray.GetLength(0) / 2;

            for(int y = 0; y < sourceArray.GetLength(0); y++)
            {
                for (int x = 0; x < sourceArray.GetLength(1); x++)
                {
                    for(int compass = 0; compass < targetArray.GetLength(0); compass++)
                    {
                        double radian = compass * angle * Math.PI / 180.0;

                        int targetX = (int)(Math.Round((x - xOffset) * Math.Cos(radian) - (y - yOffset) * Math.Sin(radian)) + xOffset);
                        int targetY = (int)(Math.Round((x - xOffset) * Math.Sin(radian) + (y - yOffset) * Math.Cos(radian)) + yOffset);

                        targetArray[compass, targetY, targetX] = sourceArray[y, x];
                    }
                }
            }

            return targetArray;
        }

        #endregion
        #region 회선 필터 적용하기 - ApplyConvolutionFilter(sourceBitmap, filterArray, factor, bias)

        /// <summary>
        /// 회선 필터 적용하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="filterArray">필터 배열</param>
        /// <param name="factor">팩터</param>
        /// <param name="bias">바이어스</param>
        /// <returns>비트맵</returns>
        private static Bitmap ApplyConvolutionFilter(Bitmap sourceBitmap, double[,,] filterArray, double factor = 1, int bias = 0)
        {
            BitmapData sourceBitmapData = sourceBitmap.LockBits
            (
                new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
                ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb
            );

            byte[] sourceArray = new byte [sourceBitmapData.Stride * sourceBitmapData.Height];
            byte[] targetArray = new byte [sourceBitmapData.Stride * sourceBitmapData.Height];

            Marshal.Copy(sourceBitmapData.Scan0, sourceArray, 0, sourceArray.Length);

            sourceBitmap.UnlockBits(sourceBitmapData);

            double blue  = 0.0;
            double green = 0.0;
            double red   = 0.0;

            double blueCompass  = 0.0;
            double greenCompass = 0.0;
            double redCompass   = 0.0;

            int filterWidth  = filterArray.GetLength(1);
            int filterHeight = filterArray.GetLength(0);

            int filterOffset = (filterWidth-1) / 2;
            int sourceOffset = 0;
            int targetOffset = 0;

            for(int offsetY = filterOffset; offsetY < sourceBitmap.Height - filterOffset; offsetY++)
            {
                for(int offsetX = filterOffset; offsetX < sourceBitmap.Width - filterOffset; offsetX++)
                {
                    blue  = 0;
                    green = 0;
                    red   = 0;

                    targetOffset = offsetY * sourceBitmapData.Stride + offsetX * 4;

                    for(int compass = 0; compass < filterArray.GetLength(0); compass++)
                    {
                        blueCompass  = 0.0;
                        greenCompass = 0.0;
                        redCompass   = 0.0;

                        for(int filterY = -filterOffset; filterY <= filterOffset; filterY++)
                        {
                            for(int filterX = -filterOffset; filterX <= filterOffset; filterX++)
                            {
                                sourceOffset = targetOffset + (filterX * 4) + (filterY * sourceBitmapData.Stride);

                                blueCompass  += (double)(sourceArray[sourceOffset    ]) * filterArray[compass, filterY + filterOffset, filterX + filterOffset];
                                greenCompass += (double)(sourceArray[sourceOffset + 1]) * filterArray[compass, filterY + filterOffset, filterX + filterOffset];
                                redCompass   += (double)(sourceArray[sourceOffset + 2]) * filterArray[compass, filterY + filterOffset, filterX + filterOffset];
                            }
                        }

                        blue  = (blueCompass  > blue  ? blueCompass  : blue );
                        green = (greenCompass > green ? greenCompass : green);
                        red   = (redCompass   > red   ? redCompass   : red  );
                    }

                    blue  = factor * blue  + bias;
                    green = factor * green + bias;
                    red   = factor * red   + bias;

                    if(blue > 255)
                    {
                        blue = 255;
                    }
                    else if(blue < 0)
                    {
                        blue = 0;
                    }

                    if(green > 255)
                    {
                        green = 255;
                    }
                    else if(green < 0)
                    {
                        green = 0;
                    }

                    if(red > 255)
                    {
                        red = 255;
                    }
                    else if(red < 0)
                    {
                        red = 0;
                    }

                    targetArray[targetOffset    ] = (byte)(blue);
                    targetArray[targetOffset + 1] = (byte)(green);
                    targetArray[targetOffset + 2] = (byte)(red);
                    targetArray[targetOffset + 3] = 255;
                }
            }

            Bitmap targetBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);

            BitmapData targetBitmapData = targetBitmap.LockBits
            (
                new Rectangle (0, 0, targetBitmap.Width, targetBitmap.Height),
                ImageLockMode.WriteOnly,
                PixelFormat.Format32bppArgb
            );

            Marshal.Copy(targetArray, 0, targetBitmapData.Scan0, targetArray.Length);

            targetBitmap.UnlockBits(targetBitmapData);

            return targetBitmap;
        }

        #endregion
    }
}

 

300x250

 

▶ MainForm.cs

using System.Drawing;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            Bitmap sourceBitmap = BitmapHelper.LoadBitmap("IMAGE\\sample.jpg");
            Bitmap targetBitmap = BitmapHelper.ApplyCompassEdgeDetectionFilter
            (
                sourceBitmap,
                CompassEdgeDetectionType.Isotropic3X3X4
            );

            this.pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
            this.pictureBox.Image    = targetBitmap;
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요