[C#/WINFORM] Bitmap 클래스 : 그라디언트 기반 가장자리 탐지 필터(Gradient Based Edge Detection Filter) 사용하기
C#/WinForm 2021. 1. 10. 00:06728x90
728x170
▶ EdgeFilterType.cs
namespace TestProject
{
/// <summary>
/// 가장자리 필터 타입
/// </summary>
public enum EdgeFilterType
{
/// <summary>
/// Edge Detection Mono
/// </summary>
EdgeDetectionMono,
/// <summary>
/// Edge Detection Gradient
/// </summary>
EdgeDetectionGradient,
/// <summary>
/// Sharpen
/// </summary>
Sharpen,
/// <summary>
/// Sharpen Gradient
/// </summary>
SharpenGradient
}
}
728x90
▶ DerivativeLevel.cs
namespace TestProject
{
/// <summary>
/// 미분 레벨
/// </summary>
public enum DerivativeLevel : int
{
/// <summary>
/// First
/// </summary>
First = 1,
/// <summary>
/// Second
/// </summary>
Second
}
}
300x250
▶ 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, filterType,
derivativeLevel, redFactor, greenFactor, blueFactor, threshold)
/// <summary>
/// 그라디언트 기반 가장자리 탐지 필터 적용하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="filterType">가장자리 필터 타입</param>
/// <param name="derivativeLevel">미분 레벨</param>
/// <param name="redFactor">적색 팩터</param>
/// <param name="greenFactor">녹색 팩터</param>
/// <param name="blueFactor">청색 팩터</param>
/// <param name="threshold">임계치</param>
/// <returns>비트맵</returns>
public static Bitmap ApplyGradientBasedEdgeDetectionFilter
(
Bitmap sourceBitmap,
EdgeFilterType filterType,
DerivativeLevel derivativeLevel,
float redFactor = 1.0f,
float greenFactor = 1.0f,
float blueFactor = 1.0f,
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 derivative = (int)derivativeLevel;
int byteOffset = 0;
int blueGradient = 0;
int greenGradient = 0;
int redGradient = 0;
double blue = 0;
double green = 0;
double red = 0;
bool exceedsThreshold = false;
for(int offsetY = 1; offsetY < sourceBitmap.Height - 1; offsetY++)
{
for(int offsetX = 1; offsetX < sourceBitmap.Width - 1; offsetX++)
{
byteOffset = offsetY * sourceBitmapData.Stride + offsetX * 4;
blueGradient = Math.Abs
(
sourceByteArray[byteOffset - 4] -
sourceByteArray[byteOffset + 4]
) / derivative;
blueGradient += Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + sourceBitmapData.Stride]
) / derivative;
byteOffset++;
greenGradient = Math.Abs
(
sourceByteArray[byteOffset - 4] -
sourceByteArray[byteOffset + 4]
) / derivative;
greenGradient += Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + sourceBitmapData.Stride]
) / derivative;
byteOffset++;
redGradient = Math.Abs
(
sourceByteArray[byteOffset - 4] -
sourceByteArray[byteOffset + 4]
) / derivative;
redGradient += Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + sourceBitmapData.Stride]
) / derivative;
if(blueGradient + greenGradient + redGradient > threshold)
{
exceedsThreshold = true ;
}
else
{
byteOffset -= 2;
blueGradient = Math.Abs
(
sourceByteArray[byteOffset - 4] -
sourceByteArray[byteOffset + 4]
);
byteOffset++;
greenGradient = Math.Abs
(
sourceByteArray[byteOffset - 4] -
sourceByteArray[byteOffset + 4]
);
byteOffset++;
redGradient = Math.Abs
(
sourceByteArray[byteOffset - 4] -
sourceByteArray[byteOffset + 4]
);
if(blueGradient + greenGradient + redGradient > threshold)
{
exceedsThreshold = true ;
}
else
{
byteOffset -= 2;
blueGradient = Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + sourceBitmapData.Stride]
);
byteOffset++;
greenGradient = Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + sourceBitmapData.Stride]
);
byteOffset++;
redGradient = Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + sourceBitmapData.Stride]
);
if(blueGradient + greenGradient + redGradient > threshold)
{
exceedsThreshold = true ;
}
else
{
byteOffset -= 2;
blueGradient = Math.Abs
(
sourceByteArray[byteOffset - 4 - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + 4 + sourceBitmapData.Stride]
) / derivative;
blueGradient += Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride + 4] -
sourceByteArray[byteOffset + sourceBitmapData.Stride - 4]
) / derivative;
byteOffset++;
greenGradient = Math.Abs
(
sourceByteArray[byteOffset - 4 - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + 4 + sourceBitmapData.Stride]
) / derivative;
greenGradient += Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride + 4] -
sourceByteArray[byteOffset + sourceBitmapData.Stride - 4]
) / derivative;
byteOffset++;
redGradient = Math.Abs
(
sourceByteArray[byteOffset - 4 - sourceBitmapData.Stride] -
sourceByteArray[byteOffset + 4 + sourceBitmapData.Stride]
) / derivative;
redGradient += Math.Abs
(
sourceByteArray[byteOffset - sourceBitmapData.Stride + 4] -
sourceByteArray[byteOffset + sourceBitmapData.Stride - 4]
) / derivative;
if(blueGradient + greenGradient + redGradient > threshold)
{
exceedsThreshold = true ;
}
else
{
exceedsThreshold = false ;
}
}
}
}
byteOffset -= 2;
if(exceedsThreshold)
{
if(filterType == EdgeFilterType.EdgeDetectionMono)
{
blue = green = red = 255;
}
else if(filterType == EdgeFilterType.EdgeDetectionGradient)
{
blue = blueGradient * blueFactor;
green = greenGradient * greenFactor;
red = redGradient * redFactor;
}
else if(filterType == EdgeFilterType.Sharpen)
{
blue = sourceByteArray[byteOffset ] * blueFactor;
green = sourceByteArray[byteOffset + 1] * greenFactor;
red = sourceByteArray[byteOffset + 2] * redFactor;
}
else if(filterType == EdgeFilterType.SharpenGradient)
{
blue = sourceByteArray[byteOffset ] + blueGradient * blueFactor;
green = sourceByteArray[byteOffset + 1] + greenGradient * greenFactor;
red = sourceByteArray[byteOffset + 2] + redGradient * redFactor;
}
}
else
{
if(filterType == EdgeFilterType.EdgeDetectionMono ||
filterType == EdgeFilterType.EdgeDetectionGradient)
{
blue = green = red = 0;
}
else if(filterType == EdgeFilterType.Sharpen ||
filterType == EdgeFilterType.SharpenGradient)
{
blue = sourceByteArray[byteOffset ];
green = sourceByteArray[byteOffset + 1];
red = sourceByteArray[byteOffset + 2];
}
}
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[byteOffset ] = (byte)blue;
targetByteArray[byteOffset + 1] = (byte)green;
targetByteArray[byteOffset + 2] = (byte)red;
targetByteArray[byteOffset + 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.ApplyGradientBasedEdgeDetectionFilter
(
sourceBitmap,
EdgeFilterType.EdgeDetectionGradient,
DerivativeLevel.First,
1,
1,
1,
128
);
this.pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
this.pictureBox.Image = targetBitmap;
}
#endregion
}
}
728x90
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] Bitmap 클래스 : 불선명 필터(Unsharp Filter) 사용하기 (0) | 2021.01.10 |
---|---|
[C#/WINFORM] Bitmap 클래스 : 평균 색상 필터(Average Color Filter) 사용하기 (0) | 2021.01.10 |
[C#/WINFORM] Bitmap 클래스 : 침식/팽창 필터(Erosion/Dilation Filter) 사용하기 (0) | 2021.01.10 |
[C#/WINFORM] Bitmap 클래스 : 부울 가장자리 탐지 필터(Boolean Edge Detection Filter) 사용하기 (0) | 2021.01.10 |
[C#/WINFORM] Bitmap 클래스 : 2개의 비트맵에서 차이점 찾기 (0) | 2021.01.10 |
[C#/WINFORM] Bitmap 클래스 : 카툰 필터(Cartoon Filter) 사용하기 (0) | 2021.01.09 |
[C#/WINFORM] Bitmap 클래스 : 스무딩 필터(Smoothing Filter) 사용하기 (0) | 2021.01.09 |
[C#/WINFORM] Bitmap 클래스 : 선명 가장자리 탐지 필터(Sharpen Edge Detection Filter) 사용하기 (0) | 2021.01.09 |
[C#/WINFORM] 가우시안 커널(Gaussian Kernel) 계산하기 (0) | 2021.01.09 |
[C#/WINFORM] Bitmap 클래스 : 회색조 비트맵 구하기 (0) | 2021.01.08 |