[C#/WINFORM] Bitmap 클래스 : 그라디언트 기반 가장자리 탐지 필터(Gradient Based Edge Detection Filter) 사용하기
C#/WinForm 2021. 1. 10. 21:57728x90
728x170
▶ BitmapHelper.cs
using System;
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 그라디언트 기반 가장자리 탐지 필터 적용하기 - ApplyGradientBasedEdgeDetectionFilter(sourceBitmap, threshold)
/// <summary>
/// 그라디언트 기반 가장자리 탐지 필터 적용하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="threshold">임계치</param>
/// <returns>비트맵</returns>
public static Bitmap ApplyGradientBasedEdgeDetectionFilter(Bitmap sourceBitmap, byte threshold = 0)
{
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 offset = 0;
int gradientValue = 0;
bool exceedThreshold = false;
for(int offsetY = 1; offsetY < sourceBitmap.Height - 1; offsetY++)
{
for(int offsetX = 1; offsetX < sourceBitmap.Width - 1; offsetX++)
{
offset = offsetY * sourceBitmapData.Stride + offsetX * 4;
gradientValue = 0;
exceedThreshold = true;
CheckThreshold
(
sourceByteArray,
offset - 4,
offset + 4,
ref gradientValue,
threshold,
2
);
exceedThreshold = CheckThreshold
(
sourceByteArray,
offset - sourceBitmapData.Stride,
offset + sourceBitmapData.Stride,
ref gradientValue,
threshold,
2
);
if(exceedThreshold == false)
{
gradientValue = 0;
exceedThreshold = CheckThreshold
(
sourceByteArray,
offset - 4,
offset + 4,
ref gradientValue,
threshold
);
if(exceedThreshold == false)
{
gradientValue = 0;
exceedThreshold = CheckThreshold
(
sourceByteArray,
offset - sourceBitmapData.Stride,
offset + sourceBitmapData.Stride,
ref gradientValue,
threshold
);
if(exceedThreshold == false)
{
gradientValue = 0;
CheckThreshold
(
sourceByteArray,
offset - 4 - sourceBitmapData.Stride,
offset + 4 + sourceBitmapData.Stride,
ref gradientValue,
threshold,
2
);
exceedThreshold = CheckThreshold
(
sourceByteArray,
offset - sourceBitmapData.Stride + 4,
offset - 4 + sourceBitmapData.Stride,
ref gradientValue,
threshold,
2
);
if(exceedThreshold == false)
{
gradientValue = 0;
exceedThreshold = CheckThreshold
(
sourceByteArray,
offset - 4 - sourceBitmapData.Stride,
offset + 4 + sourceBitmapData.Stride,
ref gradientValue,
threshold
);
if(exceedThreshold == false)
{
gradientValue = 0;
exceedThreshold = CheckThreshold
(
sourceByteArray,
offset - sourceBitmapData.Stride + 4,
offset + sourceBitmapData.Stride - 4,
ref gradientValue,
threshold
);
}
}
}
}
}
targetByteArray[offset ] = (byte)(exceedThreshold ? 255 : 0);
targetByteArray[offset + 1] = targetByteArray[offset];
targetByteArray[offset + 2] = targetByteArray[offset];
targetByteArray[offset + 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
//////////////////////////////////////////////////////////////////////////////// Private
#region 임계치 체크하기 - CheckThreshold(sourceByteArray, offset1, offset2, gradientValue, threshold, divideBy)
/// <summary>
/// 임계치 체크하기
/// </summary>
/// <param name="sourceByteArray">소스 바이트 배열</param>
/// <param name="offset1">오프셋 1</param>
/// <param name="offset2">오프셋 2</param>
/// <param name="gradientValue">그라디언트 값</param>
/// <param name="threshold">임계치</param>
/// <param name="divideBy">젯수</param>
/// <returns>임계치 체크 결과</returns>
private static bool CheckThreshold
(
byte[] sourceByteArray,
int offset1,
int offset2,
ref int gradientValue,
byte threshold,
int divideBy = 1
)
{
gradientValue += Math.Abs(sourceByteArray[offset1 ] - sourceByteArray[offset2 ]) / divideBy;
gradientValue += Math.Abs(sourceByteArray[offset1 + 1] - sourceByteArray[offset2 + 1]) / divideBy;
gradientValue += Math.Abs(sourceByteArray[offset1 + 2] - sourceByteArray[offset2 + 2]) / divideBy;
return (gradientValue >= threshold);
}
#endregion
}
}
728x90
▶ 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.ApplyGradientBasedEdgeDetectionFilter(sourceBitmap, 250);
this.pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
this.pictureBox.Image = targetBitmap;
}
#endregion
}
}
728x90
그리드형(광고전용)