C#/Winform

C# 이미지 픽셀의 RGB 값을 읽고 쓰는 방법

우준세 2024. 1. 18. 17:57
728x90
반응형

 

 

이번 포스팅은 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에 대한 자세한 내용은 제가 포스팅한 글을 확인하시면 이해가 빠르실 것 같네요

 

[C#] Marshal.Copy 이해

 

[C#] Marshal.Copy 이해

지난번 포스팅에서 Bitmap.Clone과 new Bitmap의 차이를 보여드리며 이미지 복사하는 방법에 대해 알아봤습니다. 이번 포스팅은 Bitmap을 사용하면서 이미지를 복사하는 다른 방법인 Marshal.Copy() 메서드

wjunsea.tistory.com

 

복사한 바이트 배열을 순회하면서 각 픽셀의 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를 읽고 쓰는 방법에 대한 내용을 정리하였습니다.

간단한 픽셀 작업부터 큰 이미지를 처리하는 방법까지 살펴봤습니다.

 

틀린 점이나 질문이 있으시면 댓글로 남겨주세요!

 

감사합니다 :) 

 

728x90
반응형