앱개발
wpf - Opencv Blur
제갈티
2025. 6. 16. 22:09
<!-- WPF 윈도우의 루트 요소 정의 -->
<!-- x:Class: 이 XAML과 연결될 C# 코드-비하인드 클래스 지정 -->
<!-- xmlns: XML 네임스페이스 선언 - WPF 컨트롤들을 사용하기 위한 필수 선언 -->
<!-- Title: 윈도우 제목 표시줄에 나타날 텍스트 -->
<!-- Height/Width: 윈도우의 초기 크기 (픽셀 단위) -->
<Window x:Class="wpf_opencv_blur.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Image Blur App" Height="768" Width="1024">
<!-- Grid: WPF의 가장 유연한 레이아웃 컨테이너 -->
<!-- 행과 열을 정의하여 자식 요소들을 배치할 수 있음 -->
<Grid>
<!-- Grid의 행(Row) 정의 섹션 -->
<Grid.RowDefinitions>
<!-- 첫 번째 행: Height="Auto" - 내용물의 크기에 맞춰 자동 조절 -->
<!-- 버튼들이 들어갈 공간으로, 버튼 높이만큼만 차지 -->
<RowDefinition Height="Auto"/>
<!-- 두 번째 행: Height="*" - 남은 공간을 모두 차지 -->
<!-- 별표(*)는 비례 크기를 의미하며, 첫 번째 행을 제외한 모든 공간 사용 -->
<!-- 이미지 표시 영역으로 사용됨 -->
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- StackPanel: 자식 요소들을 한 방향으로 순차적으로 배열하는 컨테이너 -->
<!-- Grid.Row="0": 첫 번째 행(인덱스 0)에 배치 -->
<!-- Orientation="Horizontal": 자식 요소들을 수평(가로)으로 배열 -->
<!-- Margin="10": 사방으로 10픽셀의 여백 설정 -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10">
<!-- 이미지 로딩 버튼 -->
<!-- x:Name: C# 코드에서 이 버튼을 참조할 때 사용할 변수명 -->
<!-- Content: 버튼에 표시될 텍스트 -->
<!-- Width/Height: 버튼의 고정 크기 (픽셀 단위) -->
<!-- Margin="5": 사방으로 5픽셀 여백 (버튼 간 간격 조절) -->
<!-- Click: 버튼 클릭 시 호출될 C# 메서드명 지정 -->
<Button x:Name="LoadImageButton" Content="Load Image"
Width="100" Height="30" Margin="5" Click="LoadImageButton_Click"/>
<!-- 블러링 처리 버튼 -->
<!-- LoadImageButton과 동일한 스타일과 크기로 일관성 유지 -->
<Button x:Name="BlurButton" Content="Blurring"
Width="100" Height="30" Margin="5" Click="BlurButton_Click"/>
</StackPanel>
<!-- 이미지 표시용 컨트롤 -->
<!-- Grid.Row="1": 두 번째 행(인덱스 1)에 배치 -->
<!-- Stretch="Uniform": 이미지의 가로세로 비율을 유지하면서 컨트롤 크기에 맞춤 -->
<!-- 다른 Stretch 옵션들: -->
<!-- - None: 원본 크기 유지 -->
<!-- - Fill: 비율 무시하고 컨트롤 크기에 완전히 맞춤 -->
<!-- - UniformToFill: 비율 유지하면서 컨트롤을 완전히 채움 (잘림 가능) -->
<!-- Margin="10": 이미지 주변에 10픽셀 여백으로 깔끔한 외관 -->
<Image x:Name="ImageDisplay" Grid.Row="1"
Stretch="Uniform" Margin="10,10,-247,-1153"/>
</Grid>
</Window>
- MainWindow.xaml
// System 네임스페이스: .NET Framework의 기본 시스템 타입들을 포함
// 주요 클래스: Exception, EventArgs, ArgumentException 등
// 이 프로젝트에서 사용: Exception 처리, EventArgs 매개변수
using System;
// System.Runtime.InteropServices 네임스페이스: 관리 코드와 비관리 코드 간의 상호 운용성 제공
// 주요 클래스: Marshal - 메모리 관리 및 포인터 조작을 위한 정적 메서드들 포함
// 이 프로젝트에서 사용: Marshal.Copy() - OpenCV Mat의 네이티브 메모리 데이터를 관리 배열로 복사
using System.Runtime.InteropServices;
// System.Windows.Media 네임스페이스: WPF의 미디어 관련 기능 제공
// 주요 클래스: PixelFormat, PixelFormats - 이미지의 픽셀 형식 정의
// 이 프로젝트에서 사용: PixelFormats.Bgr24, PixelFormats.Gray8 등 이미지 형식 지정
using System.Windows.Media;
// System.Windows.Media.Imaging 네임스페이스: WPF의 이미지 처리 및 비트맵 관련 기능
// 주요 클래스: BitmapSource - WPF에서 이미지를 표시하기 위한 기본 클래스
// 이 프로젝트에서 사용: BitmapSource.Create() - Mat 데이터로부터 WPF 표시용 비트맵 생성
using System.Windows.Media.Imaging;
// Microsoft.Win32 네임스페이스: Windows 운영체제와의 상호작용을 위한 클래스들
// 주요 클래스: OpenFileDialog - 파일 선택 대화상자 제공
// 이 프로젝트에서 사용: 이미지 파일 선택을 위한 파일 대화상자 표시
using Microsoft.Win32;
// OpenCvSharp 네임스페이스: OpenCV 라이브러리의 C# 래퍼
// 주요 클래스: Mat (이미지 데이터 컨테이너), Cv2 (OpenCV 함수들), ImreadModes, Size 등
// 이 프로젝트에서 사용:
// - Mat: 이미지 데이터 저장 및 조작
// - Cv2.GaussianBlur(): 가우시안 블러 필터 적용
// - ImreadModes.Color: 컬러 이미지로 읽기 지정
// - Size: 블러 커널 크기 지정
using OpenCvSharp;
namespace wpf_opencv_blur
{
public partial class MainWindow : System.Windows.Window
{
private Mat originalImage;
public MainWindow()
{
InitializeComponent();
}
private void LoadImageButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Filter = "Image files (*.jpg;*.jpeg;*.png;*.bmp)|*.jpg;*.jpeg;*.png;*.bmp",
Title = "이미지 파일을 선택하세요"
};
if (openFileDialog.ShowDialog() == true)
{
try
{
// 기존 이미지 해제
originalImage?.Dispose();
// 새 이미지 로드
originalImage = new Mat(openFileDialog.FileName, ImreadModes.Color);
DisplayImage(originalImage);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"이미지 로딩 중 오류가 발생했습니다: {ex.Message}");
}
}
}
private void BlurButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (originalImage == null || originalImage.Empty())
{
System.Windows.MessageBox.Show("먼저 이미지를 로드해주세요.");
return;
}
try
{
Mat blurredImage = new Mat();
// 가우시안 블러 적용
Cv2.GaussianBlur(originalImage, blurredImage, new OpenCvSharp.Size(15, 15), 3);
// 블러링된 이미지 표시
DisplayImage(blurredImage);
// 메모리 해제
blurredImage.Dispose();
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"블러링 처리 중 오류가 발생했습니다: {ex.Message}");
}
}
private void DisplayImage(Mat image)
{
if (image != null && !image.Empty())
{
BitmapSource bitmapSource = MatToBitmapSource(image);
if (bitmapSource != null)
{
ImageDisplay.Source = bitmapSource;
}
}
}
private BitmapSource MatToBitmapSource(Mat mat)
{
if (mat.Empty())
return null;
try
{
// Mat의 데이터를 byte 배열로 변환
byte[] imageData = new byte[mat.Rows * mat.Cols * mat.Channels()];
Marshal.Copy(mat.Data, imageData, 0, imageData.Length);
// PixelFormat 결정
PixelFormat pixelFormat;
switch (mat.Channels())
{
case 1:
pixelFormat = PixelFormats.Gray8;
break;
case 3:
pixelFormat = PixelFormats.Bgr24;
break;
case 4:
pixelFormat = PixelFormats.Bgra32;
break;
default:
throw new ArgumentException("지원되지 않는 채널 수입니다.");
}
// BitmapSource 생성
int stride = mat.Cols * mat.Channels();
BitmapSource bitmapSource = BitmapSource.Create(
mat.Cols, mat.Rows,
96, 96,
pixelFormat,
null,
imageData,
stride
);
return bitmapSource;
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"이미지 변환 중 오류: {ex.Message}");
return null;
}
}
/// <summary>
/// 윈도우가 닫힐 때 호출되는 메서드를 재정의합니다.
/// 이 메서드는 윈도우가 완전히 닫히기 전에 필요한 정리 작업을 수행합니다.
/// </summary>
/// <param name="e">윈도우 닫기 이벤트와 관련된 이벤트 데이터</param>
protected override void OnClosed(EventArgs e)
{
// null 조건부 연산자(?.)를 사용하여 originalImage가 null이 아닌 경우에만 Dispose() 호출
// OpenCV의 Mat 객체는 네이티브 메모리를 사용하므로 명시적으로 해제해야 함
// Dispose()를 호출하지 않으면 메모리 누수(memory leak)가 발생할 수 있음
originalImage?.Dispose();
// 부모 클래스(System.Windows.Window)의 OnClosed 메서드를 호출
// 이는 WPF 윈도우의 기본 정리 작업을 수행하기 위해 반드시 필요함
// 예: 이벤트 핸들러 해제, 윈도우 리소스 정리 등
base.OnClosed(e);
}
}
}