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

TestProject.zip
다운로드

▶ SharpenType.cs

namespace TestProject
{
    /// <summary>
    /// 선명 타입
    /// </summary>
    public enum SharpenType
    {
        /// <summary>
        /// 선명 7:1
        /// </summary>
        Sharpen7To1,

        /// <summary>
        /// 선명 9:1
        /// </summary>
        Sharpen9To1,

        /// <summary>
        /// 선명 12:1
        /// </summary>
        Sharpen12To1,

        /// <summary>
        /// 선명 24:1
        /// </summary>
        Sharpen24To1,

        /// <summary>
        /// 선명 48:1
        /// </summary>
        Sharpen48To1,

        /// <summary>
        /// 선명 5:4
        /// </summary>
        Sharpen5To4,

        /// <summary>
        /// 선명 10:8
        /// </summary>
        Sharpen10To8,

        /// <summary>
        /// 선명 11:8
        /// </summary>
        Sharpen11To8,

        /// <summary>
        /// 선명 821
        /// </summary>
        Sharpen821
    }
}

 

728x90

 

▶ Matrix.cs

namespace TestProject
{
    /// <summary>
    /// 매트릭스
    /// </summary>
    public static class Matrix
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 선명 7:1 - Sharpen7To1

        /// <summary>
        /// 선명 7:1
        /// </summary>
        public static double[,] Sharpen7To1
        {
            get
            {
                return new double[,]
                {
                    { 1,  1,  1 },
                    { 1, -7,  1 },
                    { 1,  1,  1 }
                };
            }
        }

        #endregion
        #region 선명 9:1 - Sharpen9To1

        /// <summary>
        /// 선명 9:1
        /// </summary>
        public static double[,] Sharpen9To1
        {
            get
            {
                return new double[,]
                {
                    { -1, -1, -1 },
                    { -1,  9, -1 },
                    { -1, -1, -1 }
                };
            }
        }

        #endregion
        #region 선명 12:1 - Sharpen12To1

        /// <summary>
        /// 선명 12:1
        /// </summary>
        public static double[,] Sharpen12To1
        {
            get
            {
                return new double[,]
                {
                    { -1, -1, -1 },
                    { -1, 12, -1 },
                    { -1, -1, -1 }
                };
            }
        }

        #endregion
        #region 선명 24:1 - Sharpen24To1

        /// <summary>
        /// 선명 24:1
        /// </summary>
        public static double[,] Sharpen24To1
        {
            get
            {
                return new double[,]
                {
                    { -1, -1, -1, -1, -1 },
                    { -1, -1, -1, -1, -1 },
                    { -1, -1, 24, -1, -1 },
                    { -1, -1, -1, -1, -1 },
                    { -1, -1, -1, -1, -1 }
                };
            }
        }

        #endregion
        #region 선명 48:1 - Sharpen48To1

        /// <summary>
        /// 선명 48:1
        /// </summary>
        public static double[,] Sharpen48To1
        {
            get
            {
                return new double[,]
                {
                    { -1, -1, -1, -1, -1, -1, -1 },
                    { -1, -1, -1, -1, -1, -1, -1 },
                    { -1, -1, -1, -1, -1, -1, -1 },
                    { -1, -1, -1, 48, -1, -1, -1 },
                    { -1, -1, -1, -1, -1, -1, -1 },
                    { -1, -1, -1, -1, -1, -1, -1 },
                    { -1, -1, -1, -1, -1, -1, -1 }
                };
            }
        }

        #endregion
        #region 선명 5:4 - Sharpen5To4

        /// <summary>
        /// 선명 5:4
        /// </summary>
        public static double[,] Sharpen5To4
        {
            get
            {
                return new double[,]
                {
                    {  0, -1,  0 },
                    { -1,  5, -1 },
                    {  0, -1,  0 }
                };
            }
        }

        #endregion
        #region 선명 10:8 - Sharpen10To8

        /// <summary>
        /// 선명 10:8
        /// </summary>
        public static double[,] Sharpen10To8
        {
            get
            {
                return new double[,]
                {
                    {  0, -2,  0 },
                    { -2, 10, -2 },
                    {  0, -2,  0 }
                };
            }
        }

        #endregion
        #region 선명 11:8 - Sharpen11To8

        /// <summary>
        /// 선명 11:8
        /// </summary>
        public static double[,] Sharpen11To8
        {
            get
            {
                return new double[,]
                {
                    {  0, -2,  0 },
                    { -2, 11, -2 },
                    {  0, -2,  0 }
                };
            }
        }

        #endregion
        #region 선명 821 - Sharpen821

        /// <summary>
        /// 선명 821
        /// </summary>
        public static double[,] Sharpen821
        {
            get
            {
                return new double[,]
                {
                    { -1, -1, -1, -1, -1 },
                    { -1,  2,  2,  2, -1 },
                    { -1,  2,  8,  2,  1 },
                    { -1,  2,  2,  2, -1 },
                    { -1, -1, -1, -1, -1 }
                };
            }
        }

        #endregion
    }
}

 

300x250

 

▶ BitmapHelper.cs

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

namespace TestProject
{
    /// <summary>
    /// 비트맵 헬퍼
    /// </summary>
    public static class BitmapHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// 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 선명 가장자리 탐지 필터 적용하기 - SharpenEdgeDetect(sourceBitmap, sharpenType, bias, grayscale, mono, medianFilterSize)

        /// <summary>
        /// 선명 가장자리 탐지 필터 적용하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="sharpenType">선명 타입</param>
        /// <param name="bias">바이어스</param>
        /// <param name="grayscale">회색조 여부</param>
        /// <param name="mono">모노 여부</param>
        /// <param name="medianFilterSize">중앙값 필터 크기</param>
        /// <returns>비트맵</returns>
        public static Bitmap ApplySharpenEdgeDetectionFilter
        (
            Bitmap      sourceBitmap,
            SharpenType sharpenType,
            int         bias             = 0,
            bool        grayscale        = false,
            bool        mono             = false,
            int         medianFilterSize = 0
        )
        {
            Bitmap targetBitmap = null;

            if(medianFilterSize == 0)
            {
                targetBitmap = sourceBitmap;
            }
            else
            {
                targetBitmap = ApplyMedianFilter(sourceBitmap, medianFilterSize);
            }

            switch(sharpenType)
            {
                case SharpenType.Sharpen7To1 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen7To1, 1.0, bias, grayscale, mono);

                    break;

                case SharpenType.Sharpen9To1 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen9To1, 1.0, bias, grayscale, mono);

                    break;

                case SharpenType.Sharpen12To1 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen12To1, 1.0, bias, grayscale, mono);

                    break;

                case SharpenType.Sharpen24To1 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen24To1, 1.0, bias, grayscale, mono);

                    break;

                case SharpenType.Sharpen48To1 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen48To1, 1.0, bias, grayscale, mono);

                    break;

                case SharpenType.Sharpen5To4 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen5To4, 1.0, bias, grayscale, mono);

                    break;

                case SharpenType.Sharpen10To8 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen10To8, 1.0, bias, grayscale, mono);

                    break;

                case SharpenType.Sharpen11To8 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen11To8, 3.0 / 1.0, bias, grayscale, mono);

                    break;

                case SharpenType.Sharpen821 :

                    targetBitmap = ApplySharpenEdgeDetectionFilter(targetBitmap, Matrix.Sharpen821, 8.0 / 1.0, bias, grayscale, mono);

                    break;
            }

            return targetBitmap;
        }

        #endregion

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

        #region 중앙값 필터 적용하기 - ApplyMedianFilter(sourceBitmap, matrixSize)

        /// <summary>
        /// 중앙값 필터 적용하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="matrixSize">매트릭스 크기</param>
        /// <returns>비트맵</returns>
        private static Bitmap ApplyMedianFilter(Bitmap sourceBitmap, int matrixSize)
        {
            BitmapData sourceBitmapData = sourceBitmap.LockBits
            (
                new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
                ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb
            );

            byte[] sourceByteArray = new byte[sourceBitmapData.Stride * sourceBitmapData.Height];
            byte[] targetByteArray = new byte[sourceBitmapData.Stride * sourceBitmapData.Height];

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

            sourceBitmap.UnlockBits(sourceBitmapData);

            int filterOffset = (matrixSize - 1) / 2;

            int temporaryOffset = 0;

            int byteOffset = 0;

            List<int> neighbourPixelList = new List<int>();

            byte[] middlePixel;

            for(int offsetY = filterOffset; offsetY < sourceBitmap.Height - filterOffset; offsetY++)
            {
                for(int offsetX = filterOffset; offsetX < sourceBitmap.Width - filterOffset; offsetX++)
                {
                    byteOffset = offsetY * sourceBitmapData.Stride + offsetX * 4;

                    neighbourPixelList.Clear();

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

                            neighbourPixelList.Add(BitConverter.ToInt32(sourceByteArray, temporaryOffset));
                        }
                    }

                    neighbourPixelList.Sort();

                    middlePixel = BitConverter.GetBytes(neighbourPixelList[filterOffset]);

                    targetByteArray[byteOffset    ] = middlePixel[0];
                    targetByteArray[byteOffset + 1] = middlePixel[1];
                    targetByteArray[byteOffset + 2] = middlePixel[2];
                    targetByteArray[byteOffset + 3] = middlePixel[3];
                }
            }

            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(targetByteArray, 0, targetBitmapData.Scan0, targetByteArray.Length);

            targetBitmap.UnlockBits(targetBitmapData);

            return targetBitmap;
        }

        #endregion
        #region 선명 가장자리 탐지 필터 적용하기 - ApplySharpenEdgeDetectionFilter(sourceBitmap, filterArray, factor, bias, grayscale, mono)

        /// <summary>
        /// 선명 가장자리 탐지 필터 적용하기
        /// </summary>
        /// <param name="sourceBitmap">소스 비트맵</param>
        /// <param name="filterArray">필터 배열</param>
        /// <param name="factor">팩터</param>
        /// <param name="bias">바이어스</param>
        /// <param name="grayscale">회색조 여부</param>
        /// <param name="mono">모노 여부</param>
        /// <returns>비트맵</returns>
        private static Bitmap ApplySharpenEdgeDetectionFilter
        (
            Bitmap    sourceBitmap,
            double[,] filterArray,
            double    factor    = 1,
            int       bias      = 0,
            bool      grayscale = false,
            bool      mono      = false
        )
        {
            BitmapData sourceBitmapData = sourceBitmap.LockBits
            (
                new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
                ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb
            );

            byte[] sourceByteArray = new byte[sourceBitmapData.Stride * sourceBitmapData.Height];
            byte[] targetByteArray = new byte[sourceBitmapData.Stride * sourceBitmapData.Height];

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

            sourceBitmap.UnlockBits(sourceBitmapData);

            if(grayscale == true)
            {
                for(int pixel = 0; pixel < sourceByteArray.Length; pixel += 4)
                {
                    sourceByteArray[pixel    ] = (byte)(sourceByteArray[pixel    ] * 0.11f);
                    sourceByteArray[pixel + 1] = (byte)(sourceByteArray[pixel + 1] * 0.59f);
                    sourceByteArray[pixel + 2] = (byte)(sourceByteArray[pixel + 2] * 0.3f );
                }
            }

            double blue  = 0.0;
            double green = 0.0;
            double red   = 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 filterY = -filterOffset; filterY <= filterOffset; filterY++)
                    {
                        for(int filterX = -filterOffset; filterX <= filterOffset; filterX++)
                        {
                            sourceOffset = targetOffset + (filterX * 4) + (filterY * sourceBitmapData.Stride);

                            blue  += (double)(sourceByteArray[sourceOffset    ]) * filterArray[filterY + filterOffset, filterX + filterOffset];
                            green += (double)(sourceByteArray[sourceOffset + 1]) * filterArray[filterY + filterOffset, filterX + filterOffset];
                            red   += (double)(sourceByteArray[sourceOffset + 2]) * filterArray[filterY + filterOffset, filterX + filterOffset];
                        }
                    }

                    if(mono == true)
                    {
                        blue  = targetByteArray[targetOffset    ] - factor * blue;
                        green = targetByteArray[targetOffset + 1] - factor * green;
                        red   = targetByteArray[targetOffset + 2] - factor * red;

                        blue  = (blue > bias ? 255 : 0);
                        green = (blue > bias ? 255 : 0);
                        red   = (blue > bias ? 255 : 0);
                    }
                    else
                    {
                        blue  = targetByteArray[targetOffset    ] - factor * blue  + bias;
                        green = targetByteArray[targetOffset + 1] - factor * green + bias;
                        red   = targetByteArray[targetOffset + 2] - factor * red   + bias;

                        blue  = (blue  > 255 ? 255 : (blue  < 0 ? 0 : blue ));
                        green = (green > 255 ? 255 : (green < 0 ? 0 : green));
                        red   = (red   > 255 ? 255 : (red   < 0 ? 0 : red  ));
                    }

                    targetByteArray[targetOffset    ] = (byte)(blue);
                    targetByteArray[targetOffset + 1] = (byte)(green);
                    targetByteArray[targetOffset + 2] = (byte)(red);
                    targetByteArray[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(targetByteArray, 0, targetBitmapData.Scan0, targetByteArray.Length);

            targetBitmap.UnlockBits(targetBitmapData);

            return targetBitmap;
        }

        #endregion
    }
}

 

▶ 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.ApplySharpenEdgeDetectionFilter(sourceBitmap, SharpenType.Sharpen5To4);

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

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

댓글을 달아 주세요