Bitmap 클래스 객체와 배열의 변환
■
그림의 내용을 배열에 담고 있을 때, 이 그림을 담은 Bitmap 객체를 만들거나,
혹은 그 반대의 동작을 하는 함수들을 담은 클래스입니다.
SetPixel()이나 GetPixel()을 사용하면 구현할 수 있으나 실용적으로 이용하기에는 너무 느리므로 다음의 클래스 함수가 유용합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
class TBitmap
{
//=========================================================================
// gray 2D array => bitmap
//=========================================================================
public static Bitmap BitmapOfGrayArr(int[,] inten2D, PixelFormat pxlformat)
{
int xsize = inten2D.GetLength(0);
int ysize = inten2D.GetLength(1);
Bitmap bitmap = null;
if (pxlformat == PixelFormat.Format24bppRgb)
{
bitmap = new Bitmap(xsize, ysize, PixelFormat.Format24bppRgb);
BitmapData bmpdata = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmpdata.Stride;
int nbytes = stride * bitmap.Height;
byte[] rgb1D = new byte[nbytes];
// 배열에 그림 내용 채우기
int idxBlue = 0;
for (int ix = 0; ix < xsize; ix++)
{
for (int iy = 0; iy < ysize; iy++)
{
idxBlue = iy * stride + 3 * ix;
rgb1D[idxBlue + 0] = Convert.ToByte(inten2D[ix, iy]);
rgb1D[idxBlue + 1] = Convert.ToByte(inten2D[ix, iy]);
rgb1D[idxBlue + 2] = Convert.ToByte(inten2D[ix, iy]);
}
}
// 배열에 있는 그림을 bitmap에 복사
System.Runtime.InteropServices.Marshal.Copy(rgb1D, 0, bmpdata.Scan0, nbytes);
bitmap.UnlockBits(bmpdata);
}
else if (pxlformat == PixelFormat.Format8bppIndexed)
{
bitmap = new Bitmap(xsize, ysize, PixelFormat.Format8bppIndexed);
BitmapData bmpdata = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
int stride = bmpdata.Stride;
int nbytes = stride * bitmap.Height;
byte[] rgb1D = new byte[nbytes];
// 배열에 그림 내용 채우기
ColorPalette pal = bitmap.Palette;
for (int i = 0; i < 256; i++)
pal.Entries[i] = Color.FromArgb(255, i, i, i);
bitmap.Palette = pal;
int idxPxl = 0;
for (int ix = 0; ix < xsize; ix++)
{
for (int iy = 0; iy < ysize; iy++)
{
idxPxl = iy * stride + ix;
rgb1D[idxPxl + 0] = Convert.ToByte(inten2D[ix, iy]);
}
}
// 배열에 있는 그림을 bitmap에 복사
System.Runtime.InteropServices.Marshal.Copy(rgb1D, 0, bmpdata.Scan0, nbytes);
bitmap.UnlockBits(bmpdata);
}
//~~~~ 검증
//for (int iy = 0; iy < ysize; iy++)
//{
// for (int ix = 0; ix < xsize; ix++)
// {
// if (bitmap.GetPixel(ix, iy).R != inten2D[ix, iy])
// {
// Console.WriteLine("{0}, {1}, {2}", bitmap.GetPixel(ix, iy).R,
// bitmap.GetPixel(ix, iy).G,
// bitmap.GetPixel(ix, iy).B);
// }
// }
//}
return bitmap;
}
//=========================================================================
// rgb 2D array => bitmap (Format24bppRgb 포맷만)
//=========================================================================
public static Bitmap BitmapOfRGBArr(int[,] red, int[,] green, int[,] blue)
{
int xsize = red.GetLength(0);
int ysize = red.GetLength(1);
Bitmap bitmap = null;
bitmap = new Bitmap(xsize, ysize, PixelFormat.Format24bppRgb);
BitmapData bmpdata = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmpdata.Stride;
int nbytes = stride * bitmap.Height;
byte[] rgb1D = new byte[nbytes];
// 배열에 그림 내용 채우기
int idxBlue = 0;
for (int ix = 0; ix < xsize; ix++)
{
for (int iy = 0; iy < ysize; iy++)
{
idxBlue = iy * stride + 3 * ix;
rgb1D[idxBlue + 0] = Convert.ToByte(blue[ix, iy]);
rgb1D[idxBlue + 1] = Convert.ToByte(green[ix, iy]);
rgb1D[idxBlue + 2] = Convert.ToByte(red[ix, iy]);
}
}
// 배열에 있는 그림을 bitmap에 복사
System.Runtime.InteropServices.Marshal.Copy(rgb1D, 0, bmpdata.Scan0, nbytes);
bitmap.UnlockBits(bmpdata);
//~~~~ 검증
//for (int iy = 0; iy < ysize; iy++)
//{
// for (int ix = 0; ix < xsize; ix++)
// {
// if ((bitmap.GetPixel(ix, iy).R != red[ix, iy]) ||
// (bitmap.GetPixel(ix, iy).G != green[ix, iy]) ||
// (bitmap.GetPixel(ix, iy).B != blue[ix, iy]))
// {
// Console.WriteLine("{0}, {1}, {2}", bitmap.GetPixel(ix, iy).R,
// bitmap.GetPixel(ix, iy).G,
// bitmap.GetPixel(ix, iy).B);
// }
// }
//}
return bitmap;
}
//=========================================================================
// bitmap => gray 2D array
//=========================================================================
public static byte[,] GrayArrOfBitmap(Bitmap bitmap)
{
int xsize = bitmap.Width;
int ysize = bitmap.Height;
byte[,] inten2D = new byte[xsize, ysize];
if (bitmap.PixelFormat == PixelFormat.Format24bppRgb)
{
// 이미지의 좌측 상단에서 시작하여 가로방향으로 먼저 스캔.
// b,g,r, b,g,r, b,g,r, .... 순서로 저장
// x 방향 끝에는 옵셋이 들어 있으므로 stride를 사용해서 인덱싱 해야 함
BitmapData bmpdata = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmpdata.Stride;
int nbytes = stride * bitmap.Height;
byte[] rgb1D = new byte[nbytes];
System.Runtime.InteropServices.Marshal.Copy(bmpdata.Scan0, rgb1D, 0, nbytes);
bitmap.UnlockBits(bmpdata);
// 2차원 배열에 옮기기
int idxBlue = 0;
for (int ix = 0; ix < xsize; ix++)
{
for (int iy = 0; iy < ysize; iy++)
{
idxBlue = iy * stride + 3 * ix;
byte b = rgb1D[idxBlue + 0];
byte g = rgb1D[idxBlue + 1];
byte r = rgb1D[idxBlue + 2];
inten2D[ix, iy] = Convert.ToByte(0.299 * r + 0.587 * g + 0.114 * b);
}
}
}
else if (bitmap.PixelFormat == PixelFormat.Format8bppIndexed)
{
// 이미지의 좌측 상단에서 시작하여 가로방향으로 먼저 스캔.
// 1. Pallette에 인덱싱 정보 들어있고
// 2. inten, inten, inten,... 순서로 저장
// x 방향 끝에는 옵셋이 들어 있으므로 stride를 사용해서 인덱싱 해야 함
BitmapData bmpdata = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
int stride = bmpdata.Stride;
int nbytes = stride * bitmap.Height;
byte[] rgb1D = new byte[nbytes];
System.Runtime.InteropServices.Marshal.Copy(bmpdata.Scan0, rgb1D, 0, nbytes);
bitmap.UnlockBits(bmpdata);
// 2차원 배열에 옮기기
ColorPalette pal = bitmap.Palette;
int idxPxl = 0;
for (int ix = 0; ix < xsize; ix++)
{
for (int iy = 0; iy < ysize; iy++)
{
idxPxl = iy * stride + ix;
byte r = pal.Entries[rgb1D[idxPxl + 0]].R;
byte g = pal.Entries[rgb1D[idxPxl + 0]].G;
byte b = pal.Entries[rgb1D[idxPxl + 0]].B;
inten2D[ix, iy] = Convert.ToByte(0.299 * r + 0.587 * g + 0.114 * b);
}
}
}
//~~~~ 검증
//for (int iy = 0; iy < ysize; iy++)
//{
// for (int ix = 0; ix < xsize; ix++)
// {
// if (bitmap.GetPixel(ix, iy).R != inten2D[ix, iy])
// {
// Console.WriteLine("{0}, {1}, {2}", bitmap.GetPixel(ix, iy).R,
// bitmap.GetPixel(ix, iy).G,
// bitmap.GetPixel(ix, iy).B);
// }
// }
//}
return inten2D;
}
//=========================================================================
// bitmap => rgb 2D array. Format24bppRgb 포맷만
//=========================================================================
public static void RGBArrOfBitmap(Bitmap bitmap, out byte[,] red, out byte[,] green, out byte[,] blue)
{
int xsize = bitmap.Width;
int ysize = bitmap.Height;
red = new byte[xsize, ysize];
green = new byte[xsize, ysize];
blue = new byte[xsize, ysize];
if (bitmap.PixelFormat == PixelFormat.Format24bppRgb)
{
// 이미지의 좌측 상단에서 시작하여 가로방향으로 먼저 스캔.
// b,g,r, b,g,r, b,g,r, .... 순서로 저장
// x 방향 끝에는 옵셋이 들어 있으므로 stride를 사용해서 인덱싱 해야 함
BitmapData bmpdata = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmpdata.Stride;
int nbytes = stride * bitmap.Height;
byte[] rgb1D = new byte[nbytes];
System.Runtime.InteropServices.Marshal.Copy(bmpdata.Scan0, rgb1D, 0, nbytes);
bitmap.UnlockBits(bmpdata);
// 2차원 배열에 옮기기
int idxBlue = 0;
for (int ix = 0; ix < xsize; ix++)
{
for (int iy = 0; iy < ysize; iy++)
{
idxBlue = iy * stride + 3 * ix;
blue[ix, iy] = rgb1D[idxBlue + 0];
green[ix, iy] = rgb1D[idxBlue + 1];
red[ix, iy] = rgb1D[idxBlue + 2];
}
}
}
else
{
}
//~~~~ 검증
//for (int iy = 0; iy < ysize; iy++)
//{
// for (int ix = 0; ix < xsize; ix++)
// {
// if ((bitmap.GetPixel(ix, iy).R != red[ix, iy]) ||
// (bitmap.GetPixel(ix, iy).G != green[ix, iy]) ||
// (bitmap.GetPixel(ix, iy).B != blue[ix, iy]))
// {
// Console.WriteLine("{0}, {1}, {2}", bitmap.GetPixel(ix, iy).R,
// bitmap.GetPixel(ix, iy).G,
// bitmap.GetPixel(ix, iy).B);
// }
// }
//}
}
}