Blog | Tag | Local | Guest | Login | Write |  RSS
bitmap에 해당되는 글 2건


 이번시간에는 Raw로 된 Image 파일을 Bitmap으로 바꾸는 방법에 대하여 포스팅을 하겠습니다.
 사실 이 내용은 제가 직접 구현했다기 보다는,, 잘 알고 있는 위대한 동생님꼐서 ㅋ
 저번 프로젝트를 하면서 알려주신 방법입니다. 

 그.아이 의 말에 의하면 여러가지 방법이 있다고 하는데, (API를 쓴다 Bitmap으로 변환한다 등등등등)
 이번에 소개해 드릴 방법은 순수(?)하게 .Net Framework에서 제공하는 기능만을 가지고 구현 하는 방법
 이라고 하더군요 쿨럭 ㄷㄷㄷ, ㅋ

   (  붙여넣기를 했더니 예쁘지 않아서 캡쳐해왔습니다-_-;;)

   코드가 어렵지않아서 그냥 코드만 보셔도 사실 무방할 것이라고 생각됩니다.
  설명 들어갑니다 ^^*

 함수의 헤더는 이런 형식을 띄고 있습니다. 

          public Bitmap RawToBitmap(int Width,int Height,Byte[][] RawData)

 기본적으로 비트멥을 생성하기 위해 필요하다고 생각되는 가로와 세로정보, 그리고 rawData를
 파라미터로 받아 오고 있습니다. 필요하다면 픽셀포멧도 파라미터로 넣는것도 괜찮다고 생각합니다만 ㅋ
 일단 구현 내용은 8bit의 흑백영상이기에 pass해 봅니다.

         Bitmap BitmapImage = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);

 비트맵을 생성하고 있습니다. 생성자에는 파라미터로 받은 가로,세로 정보와 함께 픽셀정보를 넣어줍니다.
 아까 설명한 대로 지금 사용하고 있는 raw이미지는 8bit의 흑백영상이기에 PixelFormat.Format8bppIndexed을
 사용하였지만, 필요에 따라 바꾸셔도 무방한 파라미터라고 보실 수 있습니다. 

 PixelFormat은 픽셀정보를 담은 구조체로 더 자세한 정보는 msdn에서 찾아보시기 바랍니다 ^^
 http://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat(VS.85).aspx

           BitmapData BitmapImageData = BitmapImage.LockBits(new Rectangle(0, 0, Width, Height)
                                                , ImageLockMode.WriteOnly,, PixelFormat.Format8bppIndexed);

 방금 생성한 Bitmap 객체에 RawData를 읽어오기 앞서, 외부에서 이 Bitmap 메모리에 접근하지 않도록 하기위해 
 이 메모리를 Lock하는 과정입니다. 
 LockBits라는 함수를 사용하면 메모리를 독점할 수 있으며, BitmapData를 return하는데 
 이 return된 BitmapData를 사용하여 Bitmap객체의 메모리에 접근하여 사용할 수 있다고 합니다.

 BitmapData의 자세한 정보역시 msdn을 참고하여 알아봅시다.
 http://msdn.microsoft.com/ko-kr/library/system.drawing.imaging.bitmapdata(en-us,VS.85).aspx

           unsafe {}  
 unsafe 키워드를 사용합니다.
 이 코드공간 안에서는 C#에서 잘 사용하지 않는 포인터를 사용 할 수 있으며,
 자세한 내용은 다음에 포스팅 하도록 하겠습니다.

            byte* Pointer = (byte*)BitmapImageData.Scan0.ToPointer();

 BitmapImageData 객체를 이용하여 Bitmap객체의 메모리에 접근하기 위해  Scan0속성을 포인터로  받아옵니다.
 이 함수는 객체의 포인터를 리턴하며, 이 포인터를 이용하여 rawData의 내용을 BItmap 객체의 메모리에 기록하면 됩니다.
 뒤에 나오는 for문 코드는 rawData를 Bitmap객체의 메모리에 기록하는 내용입니다.

            BitmapImage.UnlockBits(BitmapImageData);

기록이 완료되면 다시 외부에서 Bitmap메모리에 접근할 수 있도록 UnLockBits함수를 사용해 다시 해제 해줍니다. 

            SetGrayscalePalette(BitmapImage);

 마지막으로 SetGrayscalePalette 함수를 사용하는데 이는  8bit Image를 위해 필요한 색상 표로
 24 bit image를 사용하시는 분들을 필요 없는 내용이며, rawData에 맞도록 변형하여 사용하시면 되는 부분입니다.
 내용은 다음과 같습니다. 

 


미관상 코드를 캡쳐해서 붙여놓았는데,
혹 필요하시다면 다음에서 복사해서 가시기 바랍니다. ^^*


 마지막으로, 
 저에게 이러한 멋진방법을 알려주신 레퍼런스는 이며,
 http://whatisthat.co.kr/54
 혹 질문이 있으신 분은 요기 말고 저기에 해주시기 바랍니다 ㅋㅋㅋ
 아주 친절한 답변이 있을거에요~~

 그럼 어디서 훔쳐온듯한 찝찝한 기분의 포스팅을 마치도록 하겠습니다. ㅋ



 



 비트맵영상에서의 단위 픽셀을 표현하는 방법에 따라 정밀도가 다르다.
 여기서 픽셀을 표현하는 방법은 파일의 종류에 따라 다르게 되는데
 보통 하나의 픽셀을 몇비트로 표현하는가? 에 대한 정보를 가지고 있고 이에 따라 다양한 컬러모드가 존재한다. 
 물론 한 픽셀의 정보를 많은 비트를 사용할 수록 정밀도가 높아지지만,, 그만큼 그림 파일 하나의 메모리는 커지게된다.
 하지만 메모리를 아끼기위해 한 픽셀의 정보를 최소비트만을 이용하자면,, 그만큼 정밀도는 떨어질 것이다. 
 적당한 조절이 필요하다는 말씀!!

 이번포스팅에서는 픽셀과 컬러 모드에대한 몇가지 예를 들어볼 생각이다.

1. 픽셀(Pixcel)

픽셀(Pixel)은 Picture element의 줄임말이다.
 
즉, 옆의 그림을 참고하면 그림을 확대하고 확대 또확대 확대하다보면
더 이상 확대되지않고 모자이크처럼
정사각형의 하나의 색상단위를 볼 수 있는데,,
다음과 같이 더 이상 세분할 수 없느 이미지의 기본 요소가 되는 것을 픽셀이라고 지칭한다.
화소라는 표현을 사용하기도 한다.

이 픽셀들은 정사각형 모양으로 각각
컬러 정보와 위치 정보를 담고
여러 개가 모여서 하나의 이미지를
만들어 내는 것이다.

장점 ; 일반적인 사진, 그림에서 섬세한의 이미지에 적합하다.
단점 ; 각픽셀에 대하 정보를 가지고 있으므로 그림이 커질수록 더 많은 픽셀이 필요하고 그만큼 디스크의 차지공간은 넓어진다.
         또, 그림을 다음과 같이 확대를 계속하다보면 모자이크처럼 큰점으로 나타나 처음의 섬세함을 찾을 수가 없다.


2. 컬러모드


 1) 트루컬러(true) 모드
 -> 단위 픽셀이 24비트를 가진다. 즉, R,G,B 각각 8비트로 3개라 24비트이다. 
     이를 통해서 2의 24승만큼의 컬러를 표현할 수 있게되는데,, 이를 십진수로 표현하면
     대략 16777216(1670만) 컬러가 되므로,, 최고의 컬러수로 영상을 저장, 가장 정밀도가 높은 컬러모드라고 할 수 있다.
     물론, 디스크의 용량이 충분하다면, 최고의 정밀도를 위해서 트루컬러모드를 추천한다.

 2) 인덱스 모드
-> 요즘 디스크의 격이 싸졌다고는 하지만, 디스크의 용량에는 결국 한계가 있다. 
    그래서 영상정보를 줄여서 저장할 필요성을 느끼게 되는데,,, 그런 의미에서 나온 모드가 인덱스 모드이다.
    다음의 모드는 픽셀당 24비트를 8비트나 16비트로 줄여서 저장하기 위한 시도이다.
    사실 세상에는 많은 색의 표현이 있지만 실제로 우리가 구분이 가능한 색은 많지 않기 때문에 
    다음과 같은 방식으로 저장하여도 트루컬러와 크게 차이를 느끼지 못한다.

    그렇다면 어떻게 색상정보를 줄이는가? 하면 
    24bit의 트루컬러의 이미지중에 8비트라면 8비트만큼의 가장 많이 사용하는 색상정보를 컬러테이블에 저장
    16비트라면 16비트 만큼의 가장 많이 사용하는 색상정보를 컬러 테이블에 저장한다.
    (    예를들어 8 bit는  0~255 까지의 수를 표현할 수 있으므로 총 256가지의 컬러
                16비트는 0~65535까지의 수를 표현할 수 있으므로 총 65536가지의 컬러를  표현할 수 있다.    )


 인덱스  R
 255  212 132  22 
 ...  ... ...  ... 
 1  112 150  255 
 0  23 52  69 

(8bit 팔레트 : 가장 많이 사용된 255가지의 색상정보를 인덱스로 가지고 있다.)

 0  195
 122  255  56
 88  46 200 

(9*9의 8bit 팔레트를 사용하는 bitmap 이미지의 구조)
(255는 위의 인덱스를 쫒아가 RGB값이 각각 211,132,22인 값을 지니게 된다.)
(즉, 트루컬러를 사용했으면 각각의 픽셀당 24bit를 쓰지만,, 이와같은 방법을 사용하면 8bit로 디스크의 샤용이 확 준다.)
(16bit 팔레트를 사용한다면 더 좋은 정밀도를 가질 수 있다.)

단색

16색

8bit



1비트는 0과 1 두수를 표현할 수 있으므로 두가지 컬러를 나타낼수 있다는 말입니다.
8비트는 0~255 까지의 수를 표현할 수 있으므로 총 256가지의 컬러를 나타낼수 있고,

24bit

16bit

32bit

 16비트는 0~65535까지의 수를 표현할 수 있으므로 총 65536가지의 컬러를 나타낼수 있고,
24비트는 0~16777215까지의 수를 표현할 수 있으므로 총 16777216(1670만)컬러를 나타낼수 있죠.
32비트는..^^?
윈도우의 디스플레이등록정보를 보시면 해상도를 설정하는 부분이 있습니다.
그부분의 '색 품질'란에 보시면 16비트, 32비트라고 되어있습니다.
여기서 32비트중 24비트(1670만컬러)는 색을 표현하는데 쓰고,
나머지 8비트는 투명도를 표현하는데 사용됩니다.


 참고 )
1. 16bit는 가라로 만들었음;; 화면해상도를 16bit로 한 뒤 캡쳐 ㄷㄷㄷ
2. 32bit는 무엇?? ㄷㄷㄷ
  : 32bit중 24 bit는 트루컬러처럼 RGB를 사용하고 남은 8bit를 투명도를 표현하는데 사용.
3. 어쨋든 캡쳐는 24bit로 하였으므로,,, 16bit캡쳐본은 오히려 메모리낭비;; 32bit는 24bit와 같음 ㄷㄷㄷ


 

다음은 C++에서 제공하는 팔레트를 저장할 수 있는 구조체이다.

 typedef struct tagRGBQUAD
{
           BYTE          rgbBlue;                  // B 성분 (파란색)
           BYTE          rgbGreen;                // G 성분 (녹색)
           BYTE          rgbRed;                   // R 성분 (빨간색)
           BYTE          rgbReserved1;          // 예약된 변수
} RGBQUAD;



 
 3) 흑백 모드
-> 흑백모드는 RGB의 모든 값이 서로 동일할 때 나타난다.
     RGB가 모두 0이되면 흑백이 되고 255가 되면 가장 밝은 백색이 된다.
     이는 8bit의 특별한 팔레트를 가지고 있는 것이다.  즉, 흑백정보에서는 저장된 인덱스의 값이 바로 밝기정보가 된다.

   R
 255 255  255  255 
 ...  ... ...  ... 
 1 1 1 1
 0

(흑백영상의 팔레트)