[C#/WINFORM] Bitmap 클래스 : 컴파스 가장자리 탐지 필터(Compass Edge Detection Filter) 사용하기
C#/WinForm 2021. 1. 4. 19:56728x90
반응형
728x170
▶ CompassEdgeDetectionType.cs
namespace TestProject
{
/// <summary>
/// 컴파스 가장자리 탐지 타입
/// </summary>
public enum CompassEdgeDetectionType
{
/// <summary>
/// Prewitt 3X3X4
/// </summary>
Prewitt3X3X4,
/// <summary>
/// Prewitt 3X3X8
/// </summary>
Prewitt3X3X8,
/// <summary>
/// Prewitt 5X5X4
/// </summary>
Prewitt5X5X4,
/// <summary>
/// Sobel 3X3X4
/// </summary>
Sobel3X3X4,
/// <summary>
/// Sobel 3X3X8
/// </summary>
Sobel3X3X8,
/// <summary>
/// Sobel 5X5X4
/// </summary>
Sobel5X5X4,
/// <summary>
/// Scharr 3X3X4
/// </summary>
Scharr3X3X4,
/// <summary>
/// Scharr 3X3X8
/// </summary>
Scharr3X3X8,
/// <summary>
/// Scharr 5X5X4
/// </summary>
Scharr5X5X4,
/// <summary>
/// Kirsch 3X3X4
/// </summary>
Kirsch3X3X4,
/// <summary>
/// Kirsch 3X3X8
/// </summary>
Kirsch3X3X8,
/// <summary>
/// Isotropic 3X3X4
/// </summary>
Isotropic3X3X4,
/// <summary>
/// Isotropic 3X3X8
/// </summary>
Isotropic3X3X8
}
}
728x90
▶ BitmapHelper.cs
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace TestProject
{
/// <summary>
/// 비트맵 헬퍼
/// </summary>
public static class BitmapHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region Prewitt 3X3X4 - Prewitt3X3X4
/// <summary>
/// Prewitt 3X3X4
/// </summary>
public static double[,,] Prewitt3X3X4
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, 0, 1 },
{ -1, 0, 1 },
{ -1, 0, 1 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 90);
return kernelArray;
}
}
#endregion
#region Prewitt 3X3X8 - Prewitt3X3X8
/// <summary>
/// Prewitt 3X3X8
/// </summary>
public static double[,,] Prewitt3X3X8
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, 0, 1 },
{ -1, 0, 1 },
{ -1, 0, 1 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 45);
return kernelArray;
}
}
#endregion
#region Prewitt 5X5X4 - Prewitt5X5X4
/// <summary>
/// Prewitt 5X5X4
/// </summary>
public static double[,,] Prewitt5X5X4
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -2, -1, 0, 1, 2 },
{ -2, -1, 0, 1, 2 },
{ -2, -1, 0, 1, 2 },
{ -2, -1, 0, 1, 2 },
{ -2, -1, 0, 1, 2 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 90);
return kernelArray;
}
}
#endregion
#region Kirsch 3X3X4 - Kirsch3X3X4
/// <summary>
/// Kirsch 3X3X4
/// </summary>
public static double[,,] Kirsch3X3X4
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -3, -3, 5 },
{ -3, 0, 5 },
{ -3, -3, 5 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 90);
return kernelArray;
}
}
#endregion
#region Kirsch 3X3X8 - Kirsch3X3X8
/// <summary>
/// Kirsch 3X3X8
/// </summary>
public static double[,,] Kirsch3X3X8
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -3, -3, 5 },
{ -3, 0, 5 },
{ -3, -3, 5 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 45);
return kernelArray;
}
}
#endregion
#region Sobel 3X3X4 - Sobel3X3X4
/// <summary>
/// Sobel 3X3X4
/// </summary>
public static double[,,] Sobel3X3X4
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, 0, 1 },
{ -2, 0, 2 },
{ -1, 0, 1 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 90);
return kernelArray;
}
}
#endregion
#region Sobel 3X3X8 - Sobel3X3X8
/// <summary>
/// Sobel3X3X8
/// </summary>
public static double[,,] Sobel3X3X8
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, 0, 1 },
{ -2, 0, 2 },
{ -1, 0, 1 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 45);
return kernelArray;
}
}
#endregion
#region Sobel 5X5X4 - Sobel5X5X4
/// <summary>
/// Sobel 5X5X4
/// </summary>
public static double[,,] Sobel5X5X4
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -5, -4, 0, 4, 5 },
{ -8, -10, 0, 10, 8 },
{ -10, -20, 0, 20, 10 },
{ -8, -10, 0, 10, 8 },
{ -5, -4, 0, 4, 5 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 90);
return kernelArray;
}
}
#endregion
#region Scharr 3X3X4 - Scharr3X3X4
/// <summary>
/// Scharr 3X3X4
/// </summary>
public static double[,,] Scharr3X3X4
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, 0, 1 },
{ -3, 0, 3 },
{ -1, 0, 1 }
};
double[, ,] kernelArray = RotateArray(baseKernelArray, 90);
return kernelArray;
}
}
#endregion
#region Scharr 3X3X8 - Scharr3X3X8
/// <summary>
/// Scharr 3X3X8
/// </summary>
public static double[,,] Scharr3X3X8
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, 0, 1 },
{ -3, 0, 3 },
{ -1, 0, 1 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 45);
return kernelArray;
}
}
#endregion
#region Scharr 5X5X4 - Scharr5X5X4
/// <summary>
/// Scharr 5X5X4
/// </summary>
public static double[, ,] Scharr5X5X4
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, -1, 0, 1, 1 },
{ -2, -2, 0, 2, 2 },
{ -3, -6, 0, 6, 3 },
{ -2, -2, 0, 2, 2 },
{ -1, -1, 0, 1, 1 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 90);
return kernelArray;
}
}
#endregion
#region Isotropic 3X3X4 - Isotropic3X3X4
/// <summary>
/// Isotropic 3X3X4
/// </summary>
public static double[,,] Isotropic3X3X4
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, 0, 1 },
{ -Math.Sqrt(2), 0, Math.Sqrt(2) },
{ -1, 0, 1 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 90);
return kernelArray;
}
}
#endregion
#region Isotropic 3X3X8 - Isotropic3X3X8
/// <summary>
/// Isotropic 3X3X8
/// </summary>
public static double[,,] Isotropic3X3X8
{
get
{
double[,] baseKernelArray = new double[,]
{
{ -1, 0, 1 },
{ -Math.Sqrt(2), 0, Math.Sqrt(2) },
{ -1, 0, 1 }
};
double[,,] kernelArray = RotateArray(baseKernelArray, 45);
return kernelArray;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// 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 컴파스 가장자리 탐지 필터 적용하기 - ApplyCompassEdgeDetectionFilter(sourceBitmap, compassEdgeDetectionType)
/// <summary>
/// 컴파스 가장자리 탐지 필터 적용하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="compassEdgeDetectionType">컴파스 가장자리 탐지 타입</param>
/// <returns>비트맵</returns>
public static Bitmap ApplyCompassEdgeDetectionFilter(Bitmap sourceBitmap, CompassEdgeDetectionType compassEdgeDetectionType)
{
Bitmap targetBitmap = null;
switch(compassEdgeDetectionType)
{
case CompassEdgeDetectionType.Sobel3X3X4 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Sobel3X3X4, 1.0 / 4.0);
break;
case CompassEdgeDetectionType.Sobel3X3X8 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Sobel3X3X8, 1.0/ 4.0);
break;
case CompassEdgeDetectionType.Sobel5X5X4 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Sobel5X5X4, 1.0/ 84.0);
break;
case CompassEdgeDetectionType.Prewitt3X3X4 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Prewitt3X3X4, 1.0 / 3.0);
break;
case CompassEdgeDetectionType.Prewitt3X3X8 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Prewitt3X3X8, 1.0/ 3.0);
break;
case CompassEdgeDetectionType.Prewitt5X5X4 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Prewitt5X5X4, 1.0 / 15.0);
break;
case CompassEdgeDetectionType.Scharr3X3X4 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Scharr3X3X4, 1.0 / 4.0);
break;
case CompassEdgeDetectionType.Scharr3X3X8 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Scharr3X3X8, 1.0 / 4.0);
break;
case CompassEdgeDetectionType .Scharr5X5X4 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Scharr5X5X4, 1.0 / 21.0);
break;
case CompassEdgeDetectionType.Kirsch3X3X4 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Kirsch3X3X4, 1.0 / 15.0);
break;
case CompassEdgeDetectionType.Kirsch3X3X8 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Kirsch3X3X8, 1.0 / 15.0);
break;
case CompassEdgeDetectionType.Isotropic3X3X4 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Isotropic3X3X4, 1.0 / 3.4);
break;
case CompassEdgeDetectionType.Isotropic3X3X8 :
targetBitmap = ApplyConvolutionFilter(sourceBitmap, Isotropic3X3X8, 1.0 / 3.4);
break;
}
return targetBitmap;
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 배열 회전하기 - RotateArray(sourceArray, angle)
/// <summary>
/// 배열 회전하기
/// </summary>
/// <param name="sourceArray">소스 배열</param>
/// <param name="angle">각도</param>
/// <returns>배열</returns>
private static double[,,] RotateArray(double[,] sourceArray, double angle)
{
double[,,] targetArray = new double[(int )(360 / angle), sourceArray.GetLength(0), sourceArray.GetLength(1)];
int xOffset = sourceArray.GetLength(1) / 2;
int yOffset = sourceArray.GetLength(0) / 2;
for(int y = 0; y < sourceArray.GetLength(0); y++)
{
for (int x = 0; x < sourceArray.GetLength(1); x++)
{
for(int compass = 0; compass < targetArray.GetLength(0); compass++)
{
double radian = compass * angle * Math.PI / 180.0;
int targetX = (int)(Math.Round((x - xOffset) * Math.Cos(radian) - (y - yOffset) * Math.Sin(radian)) + xOffset);
int targetY = (int)(Math.Round((x - xOffset) * Math.Sin(radian) + (y - yOffset) * Math.Cos(radian)) + yOffset);
targetArray[compass, targetY, targetX] = sourceArray[y, x];
}
}
}
return targetArray;
}
#endregion
#region 회선 필터 적용하기 - ApplyConvolutionFilter(sourceBitmap, filterArray, factor, bias)
/// <summary>
/// 회선 필터 적용하기
/// </summary>
/// <param name="sourceBitmap">소스 비트맵</param>
/// <param name="filterArray">필터 배열</param>
/// <param name="factor">팩터</param>
/// <param name="bias">바이어스</param>
/// <returns>비트맵</returns>
private static Bitmap ApplyConvolutionFilter(Bitmap sourceBitmap, double[,,] filterArray, double factor = 1, int bias = 0)
{
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);
double blue = 0.0;
double green = 0.0;
double red = 0.0;
double blueCompass = 0.0;
double greenCompass = 0.0;
double redCompass = 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 compass = 0; compass < filterArray.GetLength(0); compass++)
{
blueCompass = 0.0;
greenCompass = 0.0;
redCompass = 0.0;
for(int filterY = -filterOffset; filterY <= filterOffset; filterY++)
{
for(int filterX = -filterOffset; filterX <= filterOffset; filterX++)
{
sourceOffset = targetOffset + (filterX * 4) + (filterY * sourceBitmapData.Stride);
blueCompass += (double)(sourceArray[sourceOffset ]) * filterArray[compass, filterY + filterOffset, filterX + filterOffset];
greenCompass += (double)(sourceArray[sourceOffset + 1]) * filterArray[compass, filterY + filterOffset, filterX + filterOffset];
redCompass += (double)(sourceArray[sourceOffset + 2]) * filterArray[compass, filterY + filterOffset, filterX + filterOffset];
}
}
blue = (blueCompass > blue ? blueCompass : blue );
green = (greenCompass > green ? greenCompass : green);
red = (redCompass > red ? redCompass : red );
}
blue = factor * blue + bias;
green = factor * green + bias;
red = factor * red + bias;
if(blue > 255)
{
blue = 255;
}
else if(blue < 0)
{
blue = 0;
}
if(green > 255)
{
green = 255;
}
else if(green < 0)
{
green = 0;
}
if(red > 255)
{
red = 255;
}
else if(red < 0)
{
red = 0;
}
targetArray[targetOffset ] = (byte)(blue);
targetArray[targetOffset + 1] = (byte)(green);
targetArray[targetOffset + 2] = (byte)(red);
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
}
}
300x250
▶ 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.ApplyCompassEdgeDetectionFilter
(
sourceBitmap,
CompassEdgeDetectionType.Isotropic3X3X4
);
this.pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
this.pictureBox.Image = targetBitmap;
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[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 |
[C#/WINFORM] Bitmap 클래스 : 비트맵 자르기(Shear) (0) | 2021.01.08 |
[C#/WINFORM] Bitmap 클래스 : 스테인 글라스 필터(Stained Glass Filter) 사용하기 (0) | 2021.01.04 |
[C#/WINFORM] Bitmap 클래스 : 경계 추출 필터(Boundary Extraction Filter) 사용하기 (0) | 2021.01.03 |
[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 |
댓글을 달아 주세요