이번 포스팅은 C#에서 이미지의 픽셀의 RGB 값을 읽고 쓰는 방법에 대해 정리하였습니다.
라이브러리를 사용하지 않고 .Net Framework의 System.Drawing과 Bitmap 클래스
그리고 LockBits, BitmapData 클래스를 사용하여 RGB 데이터를 다루는 방법을 설명하였습니다.
| GetPixel
먼저 GetPixel과 Setpixel 메서드로 특정 픽셀의 RGB 값을 읽는 방법을 알아보겠습니다.
GetPixel 메서드를 사용하면 특정 위치의 픽셀 생상을 Color 객체로 가져올 수 있습니다.
이 객체에서 R, G, B 프로퍼티를 사용해 각 생상 요소의 값을 얻을 수 있습니다.
예제) GetPixel 메서드를 사용해 특정 픽셀의 RGB 값 읽기
Bitmap bmp = new Bitmap("C:\\Users\\SW팀\\source\\repos\\WindowsFormsApp1\\WindowsFormsApp1\\Test.png");
Color pixelColor = bmp.GetPixel(50, 50); // 50, 50 위치에 있는 픽셀의 색상을 가져옵니다.
int pixelRed = pixelColor.R;
int pixelGreen = pixelColor.G;
int pixelBlue = pixelColor.B;
Console.WriteLine($"pixel Red : {pixelRed}\n");
Console.WriteLine($"pixel Green : {pixelGreen}\n");
Console.WriteLine($"pixel Blue : {pixelBlue}\n");
결과)
| SetPixel
SetPixel 메서드를 사용하면 특정 위치의 픽셀 색상을 변경할 수 있습니다.
이때 Color 클래스의 FromArgb 메서드를 사용해 새로운 색상을 생성합니다.
예제) SetPixel 메서드를 사용해 특정 픽셀의 RGB 값 쓰기
bmp.SetPixel(50, 50, Color.FromArgb(100, 150, 200)); // 50, 50 위치에 있는 픽셀의 색상을 변경합니다.
Color newColor = bmp.GetPixel(50, 50);
int newPixelRed = newColor.R;
int newPixelGreen = newColor.G;
int newPixelBlue = newColor.B;
Console.WriteLine($"Change pixel Red : {newPixelRed}\n");
Console.WriteLine($"Change pixel Green : {newPixelGreen}\n");
Console.WriteLine($"Chnage pixel Blue : {newPixelBlue}\n");
결과)
| LockBits 메서드와 BitmapData 클래스
GetPixel 및 SetPixel 메서드를 사용하면
이미지가 크거나 많은 양의 픽셀을 처리해야 하는 경우에 성능이 떨어질 수 있습니다.
이럴 때는 LockBits 메서드와 BitmapData 클래스를 사용하여 더 효율적으로 처리할 수 있습니다.
| 30M 이미지 처리 예제
약 28M 크기의 이미지를 준비했습니다.
이런 큰 이미지를 GetPixel, SetPixel으로 이미지를 처리하면 굉장히 오랜 시간이 걸립니다.
먼저 LockBits 메서드를 사용해 BitmapData 객체를 얻습니다.
객체의 Scan0 프로퍼티는 이미지 데이터의 첫 바이트를 가리키는 포인터입니다.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
그런 다음 Marshal 클래스의 Copy 메서드를 사용하여 이미지 데이터를 바이트 배열로 복사합니다.
Marshal.Copy에 대한 자세한 내용은 제가 포스팅한 글을 확인하시면 이해가 빠르실 것 같네요
복사한 바이트 배열을 순회하면서 각 픽셀의 RGB 값을 읽을 수 있습니다.
IntPtr ptr = bmpData.Scan0;
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
for (int i = 0; i < rgbValues.Length; i += 3)
{
byte blue = rgbValues[i];
byte green = rgbValues[i + 1];
byte red = rgbValues[i + 2];
}
마지막으로, 변경된 픽셀 데이터를 다시 이미지에 복사하고, UnlockBits 메서드를 호출하여
이미지에 대한 Lock을 해제합니다.
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
bmp.UnlockBits(bmpData);
결과)
30M 이미지 전체를 돌면서 바이트 배열로 처리하는 시간이 약 0.19초입니다.
GetPixel이로 구했으면 굉장히 오래 걸리는 것을 확일 할 수 있으니 테스트해 보세요!
| 마무리
이렇게 C#에서 RGB를 읽고 쓰는 방법에 대한 내용을 정리하였습니다.
간단한 픽셀 작업부터 큰 이미지를 처리하는 방법까지 살펴봤습니다.
틀린 점이나 질문이 있으시면 댓글로 남겨주세요!
감사합니다 :)
'C# > Winform' 카테고리의 다른 글
C# 열린 form 활성화 및 DataGridView 최신화 방법 (0) | 2024.01.29 |
---|---|
C# Json 파일을 읽어 PropertyGrid 컨트롤 적용하는 방법 (0) | 2024.01.12 |
C# 크로스 스레드 (Cross Thread) 이해와 해결 방법 (0) | 2024.01.11 |
C# Form Show 및 존재 여부 확인 (0) | 2024.01.09 |
C# Winform DataGridView Header Cell 높이 변경 (0) | 2023.12.20 |