[C#/WINFORM] Bitmap 클래스 : 선명 가장자리 탐지 필터(Sharpen Edge Detection Filter) 사용하기
C#/WinForm 2021. 1. 9. 22:17728x90
728x170
▶ 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
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] Bitmap 클래스 : 부울 가장자리 탐지 필터(Boolean Edge Detection Filter) 사용하기 (0) | 2021.01.10 |
---|---|
[C#/WINFORM] Bitmap 클래스 : 2개의 비트맵에서 차이점 찾기 (0) | 2021.01.10 |
[C#/WINFORM] Bitmap 클래스 : 그라디언트 기반 가장자리 탐지 필터(Gradient Based Edge Detection Filter) 사용하기 (0) | 2021.01.10 |
[C#/WINFORM] Bitmap 클래스 : 카툰 필터(Cartoon Filter) 사용하기 (0) | 2021.01.09 |
[C#/WINFORM] Bitmap 클래스 : 스무딩 필터(Smoothing Filter) 사용하기 (0) | 2021.01.09 |
[C#/WINFORM] 가우시안 커널(Gaussian Kernel) 계산하기 (0) | 2021.01.09 |
[C#/WINFORM] Bitmap 클래스 : 회색조 비트맵 구하기 (0) | 2021.01.08 |
[C#/WINFORM] Bitmap 클래스 : 투명 비트맵 구하기 (0) | 2021.01.08 |
[C#/WINFORM] Bitmap 클래스 : 불선명 필터(Blur Filter) 사용하기 (0) | 2021.01.08 |
[C#/WINFORM] Bitmap 클래스 : 비트맵 회전하기 (0) | 2021.01.08 |