728x90
반응형
728x170
▶ MorphologyType.cs
namespace TestProject
{
/// <summary>
/// 모폴로지 타입
/// </summary>
public enum MorphologyType
{
/// <summary>
/// 침식
/// </summary>
Erosion,
/// <summary>
/// 팽창
/// </summary>
Dilation
}
}
728x90
▶ BoundaryExtractionFilterType.cs
namespace TestProject
{
/// <summary>
/// 경계 추출 필터 타입
/// </summary>
public enum BoundaryExtractionFilterType
{
/// <summary>
/// 경계 추출
/// </summary>
BoundaryExtraction,
/// <summary>
/// 경계 선명
/// </summary>
BoundarySharpen,
/// <summary>
/// 경계 추적
/// </summary>
BoundaryTrace
}
}
300x250
▶ BitmapHelper.cs
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 경계 추출 필터 적용하기 - ApplyBoundaryExtractionFilter(sourceBitmap, structureElementArray, filterType, applyBlue, applyGreen, applyRed)
/// <summary>
/// 경계 추출 필터 적용하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="structureElementArray">구조 요소 배열</param>
/// <param name="filterType">경계 추출 필터 타입</param>
/// <param name="applyBlue">청색 채널 적용 여부</param>
/// <param name="applyGreen">녹색 채널 적용 여부</param>
/// <param name="applyRed">적색 채널 적용 여부</param>
/// <returns>비트맵</returns>
public static Bitmap ApplyBoundaryExtractionFilter
(
Bitmap sourceBitmap,
bool[,] structureElementArray,
BoundaryExtractionFilterType filterType,
bool applyBlue = true,
bool applyGreen = true,
bool applyRed = true
)
{
Bitmap targetBitmap = null;
if(filterType == BoundaryExtractionFilterType.BoundaryExtraction)
{
targetBitmap = GetBoundaryExtractionBitmap
(
sourceBitmap,
structureElementArray,
applyBlue,
applyGreen,
applyRed
);
}
else if(filterType == BoundaryExtractionFilterType.BoundarySharpen)
{
targetBitmap = GetBoundarySharpenBitmap
(
sourceBitmap,
structureElementArray,
applyBlue,
applyGreen,
applyRed
);
}
else if(filterType == BoundaryExtractionFilterType.BoundaryTrace)
{
targetBitmap = GetBoundaryTraceBitmap
(
sourceBitmap,
structureElementArray,
applyBlue,
applyGreen,
applyRed
);
}
return targetBitmap;
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 모폴로지 연산 적용하기 - ApplyMorphologyOperation(sourceBitmap, structuringElementArray, morphologyType, applyBlue, applyGreen, applyRed)
/// <summary>
/// 모폴로지 연산 적용하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="structuringElementArray">구조 요소 배열</param>
/// <param name="morphologyType">모폴로지 타입</param>
/// <param name="applyBlue">청색 채널 적용 여부</param>
/// <param name="applyGreen">녹색 채널 적용 여부</param>
/// <param name="applyRed">적색 채널 적용 여부</param>
/// <returns>비트맵</returns>
private static Bitmap ApplyMorphologyOperation
(
Bitmap sourceBitmap,
bool[,] structuringElementArray,
MorphologyType morphologyType,
bool applyBlue = true,
bool applyGreen = true,
bool applyRed = true
)
{
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);
int filterOffset = (structuringElementArray.GetLength(0) - 1) / 2;
int sourceOffset = 0;
int targetOffset = 0;
byte blueErode = 0;
byte greenErode = 0;
byte redErode = 0;
byte blueDilate = 0;
byte greenDilate = 0;
byte redDilate = 0;
for(int offsetY = 0; offsetY < sourceBitmap.Height - filterOffset; offsetY++)
{
for(int offsetX = 0; offsetX < sourceBitmap.Width - filterOffset; offsetX++)
{
targetOffset = offsetY * sourceBitmapData.Stride + offsetX * 4;
blueErode = 255;
greenErode = 255;
redErode = 255;
blueDilate = 0;
greenDilate = 0;
redDilate = 0;
for(int filterY = -filterOffset; filterY <= filterOffset; filterY++)
{
for(int filterX = -filterOffset; filterX <= filterOffset; filterX++)
{
if(structuringElementArray[filterY + filterOffset, filterX + filterOffset] == true)
{
sourceOffset = targetOffset + (filterX * 4) + (filterY * sourceBitmapData.Stride);
sourceOffset = (sourceOffset < 0 ? 0 : (sourceOffset >= sourceArray.Length + 2 ? sourceArray.Length - 3 : sourceOffset));
blueDilate = (sourceArray[sourceOffset ] > blueDilate ? sourceArray[sourceOffset ] : blueDilate );
greenDilate = (sourceArray[sourceOffset + 1] > greenDilate ? sourceArray[sourceOffset + 1] : greenDilate);
redDilate = (sourceArray[sourceOffset + 2] > redDilate ? sourceArray[sourceOffset + 2] : redDilate );
blueErode = (sourceArray[sourceOffset ] < blueErode ? sourceArray[sourceOffset ] : blueErode );
greenErode = (sourceArray[sourceOffset + 1] < greenErode ? sourceArray[sourceOffset + 1] : greenErode);
redErode = (sourceArray[sourceOffset + 2] < redErode ? sourceArray[sourceOffset + 2] : redErode );
}
}
}
blueErode = (applyBlue ? blueErode : sourceArray[targetOffset]);
blueDilate = (applyBlue ? blueDilate : sourceArray[targetOffset]);
greenErode = (applyGreen ? greenErode : sourceArray[targetOffset + 1]);
greenDilate = (applyGreen ? greenDilate : sourceArray[targetOffset + 1]);
redErode = (applyRed ? redErode : sourceArray[targetOffset + 2]);
redDilate = (applyRed ? redDilate : sourceArray[targetOffset + 2]);
if(morphologyType == MorphologyType.Erosion)
{
targetArray[targetOffset ] = blueErode;
targetArray[targetOffset + 1] = greenErode;
targetArray[targetOffset + 2] = redErode;
}
else if(morphologyType == MorphologyType.Dilation)
{
targetArray[targetOffset ] = blueDilate;
targetArray[targetOffset + 1] = greenDilate;
targetArray[targetOffset + 2] = redDilate;
}
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
#region 색상 빼기 - SubtractColor(color1, color2)
/// <summary>
/// 색상 빼기
/// </summary>
/// <param name="color1">색상 1</param>
/// <param name="color2">색상 2</param>
/// <returns>색상</returns>
private static byte SubtractColor(byte color1, byte color2)
{
int target = (int)color1 - (int)color2;
return (byte)(target < 0 ? 0 : target);
}
#endregion
#region 이미지 빼기 - SubtractImage(sourceBitmap, subtractBitmap)
/// <summary>
/// 이미지 빼기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="subtractBitmap">차감 비트맵</param>
/// <returns>비트맵</returns>
private static Bitmap SubtractImage(Bitmap sourceBitmap, Bitmap subtractBitmap)
{
BitmapData sourceBitmapData = sourceBitmap.LockBits
(
new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb
);
byte[] targetByteArray = new byte[sourceBitmapData.Stride * sourceBitmapData.Height];
Marshal.Copy(sourceBitmapData.Scan0, targetByteArray, 0, targetByteArray.Length);
sourceBitmap.UnlockBits(sourceBitmapData);
BitmapData subtractBitmapData = subtractBitmap.LockBits
(
new Rectangle(0, 0, subtractBitmap.Width, subtractBitmap.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb
);
byte[] subtractByteArray = new byte[subtractBitmapData.Stride * subtractBitmapData.Height];
Marshal.Copy(subtractBitmapData.Scan0, subtractByteArray, 0, subtractByteArray.Length);
subtractBitmap.UnlockBits(subtractBitmapData);
for(int k = 0; k + 4 < targetByteArray.Length && k + 4 < subtractByteArray.Length; k += 4)
{
targetByteArray[k ] = SubtractColor(targetByteArray[k ], subtractByteArray[k ]);
targetByteArray[k + 1] = SubtractColor(targetByteArray[k + 1], subtractByteArray[k + 1]);
targetByteArray[k + 2] = SubtractColor(targetByteArray[k + 2], subtractByteArray[k + 2]);
targetByteArray[k + 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
#region 경계 추출 비트맵 구하기 - GetBoundaryExtractionBitmap(sourceBitmap, structuringElementArray, applyBlue, applyGreen, applyRed)
/// <summary>
/// 경계 추출 비트맵 구하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="structuringElementArray">구조 요소 배열</param>
/// <param name="applyBlue">청색 채널 적용 여부</param>
/// <param name="applyGreen">녹색 채널 적용 여부</param>
/// <param name="applyRed">적색 채널 적용 여부</param>
/// <returns>비트맵</returns>
private static Bitmap GetBoundaryExtractionBitmap
(
Bitmap sourceBitmap,
bool[,] structuringElementArray,
bool applyBlue = true,
bool applyGreen = true,
bool applyRed = true
)
{
Bitmap resultBitmap = ApplyMorphologyOperation
(
sourceBitmap,
structuringElementArray,
MorphologyType.Dilation,
applyBlue,
applyGreen,
applyRed
);
resultBitmap = SubtractImage(resultBitmap, sourceBitmap);
return resultBitmap;
}
#endregion
#region 경계 선명 비트맵 구하기 - GetBoundarySharpenBitmap(sourceBitmap, structuringElementArray, applyBlue, applyGreen, applyRed)
/// <summary>
/// 경계 선명 비트맵 구하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="structuringElementArray">구조 요소 배열</param>
/// <param name="applyBlue">청색 채널 적용 여부</param>
/// <param name="applyGreen">녹색 채널 적용 여부</param>
/// <param name="applyRed">적색 채널 적용 여부</param>
/// <returns>비트맵</returns>
private static Bitmap GetBoundarySharpenBitmap
(
Bitmap sourceBitmap,
bool[,] structuringElementArray,
bool applyBlue = true,
bool applyGreen = true,
bool applyRed = true
)
{
Bitmap targetBitmap = GetBoundaryExtractionBitmap
(
sourceBitmap,
structuringElementArray,
applyBlue,
applyGreen,
applyRed
);
targetBitmap = AddImage
(
ApplyMorphologyOperation
(
sourceBitmap,
structuringElementArray,
MorphologyType.Dilation,
applyBlue,
applyGreen,
applyRed
),
targetBitmap
);
return targetBitmap;
}
#endregion
#region 색상 더하기 - AddColor(color1, color2)
/// <summary>
/// 색상 더하기
/// </summary>
/// <param name="color1">색상 1</param>
/// <param name="color2">색상 2</param>
/// <returns>색상</returns>
private static byte AddColor(byte color1, byte color2)
{
int target = color1 + color2;
return (byte)(target < 0 ? 0 : (target > 255 ? 255 : target));
}
#endregion
#region 이미지 더하기 - AddImage(sourceBitmap, addBitmap)
/// <summary>
/// 이미지 더하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="addBitmap">가감 비트맵</param>
/// <returns>비트맵</returns>
private static Bitmap AddImage(Bitmap sourceBitmap, Bitmap addBitmap)
{
BitmapData sourceBitmapData = sourceBitmap.LockBits
(
new Rectangle (0, 0, sourceBitmap.Width, sourceBitmap.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb
);
byte[] targetByteArray = new byte[sourceBitmapData.Stride * sourceBitmapData.Height];
Marshal.Copy(sourceBitmapData.Scan0, targetByteArray, 0, targetByteArray.Length);
sourceBitmap.UnlockBits(sourceBitmapData);
BitmapData addBitmapData = addBitmap.LockBits
(
new Rectangle(0, 0, addBitmap.Width, addBitmap.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb
);
byte[] addByteArray = new byte[addBitmapData.Stride * addBitmapData.Height];
Marshal.Copy(addBitmapData.Scan0, addByteArray, 0, addByteArray.Length);
addBitmap.UnlockBits(addBitmapData);
for(int k = 0; k + 4 < targetByteArray.Length && k + 4 < addByteArray.Length; k += 4)
{
targetByteArray[k ] = AddColor(targetByteArray[k ], addByteArray[k ]);
targetByteArray[k + 1] = AddColor(targetByteArray[k + 1], addByteArray[k + 1]);
targetByteArray[k + 2] = AddColor(targetByteArray[k + 2], addByteArray[k + 2]);
targetByteArray[k + 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
#region 경계 추적 비트맵 구하기 - GetBoundaryTraceBitmap(sourceBitmap, structuringElementArray, applyBlue, applyGreen, applyRed)
/// <summary>
/// 경계 추적 비트맵 구하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="structuringElementArray">구조 요소 배열</param>
/// <param name="applyBlue">청색 채널 적용 여부</param>
/// <param name="applyGreen">녹색 채널 적용 여부</param>
/// <param name="applyRed">적색 채널 적용 여부</param>
/// <returns>비트맵</returns>
private static Bitmap GetBoundaryTraceBitmap
(
Bitmap sourceBitmap,
bool[,] structuringElementArray,
bool applyBlue = true,
bool applyGreen = true,
bool applyRed = true
)
{
Bitmap targetBitmap = GetBoundaryExtractionBitmap
(
sourceBitmap,
structuringElementArray,
applyBlue,
applyGreen,
applyRed
);
targetBitmap = SubtractImage(sourceBitmap, targetBitmap);
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.ApplyBoundaryExtractionFilter
(
sourceBitmap,
new bool[3, 3]
{
{ true, true, true },
{ true, true, true },
{ true, true, true }
},
BoundaryExtractionFilterType.BoundaryExtraction,
true,
true,
false
);
this.pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
this.pictureBox.Image = targetBitmap;
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] Bitmap 클래스 : 불선명 필터(Blur Filter) 사용하기 (0) | 2021.01.08 |
---|---|
[C#/WINFORM] Bitmap 클래스 : 비트맵 회전하기 (0) | 2021.01.08 |
[C#/WINFORM] Bitmap 클래스 : 비트맵 자르기(Shear) (0) | 2021.01.08 |
[C#/WINFORM] Bitmap 클래스 : 컴파스 가장자리 탐지 필터(Compass Edge Detection Filter) 사용하기 (0) | 2021.01.04 |
[C#/WINFORM] Bitmap 클래스 : 스테인 글라스 필터(Stained Glass Filter) 사용하기 (0) | 2021.01.04 |
[C#/WINFORM] Bitmap 클래스 : 카툰 필터(Cartoon Filter) 사용하기 (0) | 2021.01.03 |
[C#/WINFORM] Bitmap 클래스 : 오일 페인트 필터(Oil Paint Filter) 사용하기 (0) | 2021.01.03 |
[C#/WINFORM] Bitmap 클래스 : 이미지 추상 색상 필터 사용하기 (0) | 2021.01.03 |
[C#/WINFORM] Bitmap 클래스 : 바이트 배열 구하기 (0) | 2021.01.03 |
[C#/WINFORM] Bitmap 클래스 : 정사각형 크기 비트맵에 복사하기 (0) | 2021.01.03 |
댓글을 달아 주세요