Blog | Tag | Local | Guest | Login | Write |  RSS
Image Processing에 해당되는 글 10건
2008.11.15 :: LookUp Table 연산 1
2008.11.01 :: Saturation과 Wrap


 길고 길던 포인트의 상술ㅋ연산을 마치고
 오늘부터는 영상처리에서 많이?? 사용되는 히스토그램에 대해서 알아볼 예정입니다.
 진작진작에 게으르지않고 꼬박꼬박 포스팅해야하는데 그게 잘되질않네요;;;
 이제부터는 날짜라도 정해놓고 포스팅을 해야겠어요.. ; 탁상달력도 마련한김에 ㅋ

 자 그럼 시작해봅니다 ^^*



 히스토그램(Histogram) 이란?!

 ... 단순하게 말하자면? ... 영상의 화소가 가진 명암값에 대한 막대 그래프

이해를 돕기위한 그림



   ->   영상의 밝기(intensity)값을 수평축으로 하고 수평축의 밝기값에 대응하는 크기를 가진 픽셀수가
        영상안에 몇개나 되는지 나타내는 빈도수(frezuency)를 수직축으로 해서 만든 그래프.
입니다.

 ... 즉, 영상분석을 위한 중요한 도구 라고 할 수 있습니다. 



 위의 이해를 돕기위한 그림이 아닌 실제적인 히스토그램의 모습을 보면 다음과 같습니다.


히스토그램의 모습


흑백영상의 경우
수평축은 픽셀의 밝기값을 나타내며, 0~255의 범위를 가집니다. 
수직축의 값은 가로축, 픽셀밝기값에 해당하는 픽셀 수를 의미하며 그 크기는 영상의 크기와 밝기 분포에 따라 달라집니다.



여기서 한가지 확인할 점은

어두운 영상

밝은 영상



영상이 밝으면 히스토그램이 오른쪽에 치우쳐있는것을 확인할 수 있으며
영상이 어두워지면 히스토그램이 왼쪽으로 치우쳐있는것을 확인해 볼 수 있습니다.
(너무 당연한거라 더 설명할수가 없는거 같습니다.;; 괜히 이야기끄냈다가 본전도 못찾는 이야기 ㅠ)


 입력되는 영상의 히스토그램을 분석하면?
 ㄱ. 영상의 밝기 구성
 ㄴ. 명암의 대비 등  
       에 대한 정보를 알 수 있습니다.
 -> 이를 통하여 영상개선및 화질향상을 위한 출발점으로 사용될 수 있겠지요??

자, 그럼 히스토그램을 사용하여서 할 수 있는 몇가지들을 개괄적으로 살펴보도록 합시다.


1. 화질개선

원본영상

평활화를 통해 개선한 영상



 

 사람의 눈은 밝기보다 대비에 훨씬민감하다는 특징을 이용하여
 히스토그램을 펼친 조작을 행하여서 선명한 사진을 만들 수 있습니다.



2. 물체인식

임계치에 의한 이진영상 생성

 
  원본영상 : 영상의 픽셀밝기값이 0~255까지 골고루 분포한다
  이치화된 영상 : 영상 픽셀의 밝기값이 0 아니면 255의 두 값중 하나를 가진다.

영상이치화(Image binarization) 를 통하여 배경과 물체를 따로 구분하여 물체가 있다는 사실을 인식합니다. 
영상인식을 주 연구테마로 하는 컴퓨터 비전 분야에서는 많이 사용하는 것으로, 
이치화 임계치의 결정을 매우 어려운 문제로 고민하고 있습니다.

* 이치화 임계치 (threshold value) : 영상 이치화를 위해 선택하는 상수값 (T)



이번 포스팅은 히스토그램이란 무엇인가에 대하여 알아보았습니다.
다음시간에는 흑백영상의 히스토그램을 보기위한 코드를 작성해보는것을 시작으로
히스토그램의 활용을 계속 포스팅할 예정입니다. ^-^*


tip. 히스토그램으로 보는 저번 포스팅의 내용+_+     ::      포인트 상술연산!!

원영상과 +20 산술연산한 영상

원영상과 *1.2 산술연산을 한 영상


LookUp Table 연산

지금까지 포인트 단위의 산술연산에 관한 포스팅을 하였습니다.
어렵지 않은 내용이라 모두들 쉽게 이해하셨으리라 생각합니다.
실제로도 많이 사용되는 내용이기도 하고 구현 내용도 어렵지 않기 때문에,,
사람이 생각하기에는 크게 느리지 않은 연산이라고 생각하기 쉽지만..
사실 컴퓨터 입장에서는 각 포인트마다 연산을 다 해주어야 하기 때문에,, 많은 연산을 거쳐야 하는 함수임에 틀림 없습니다.

물론 지금 구현된 내용처럼 이미지가 작거나 (저번포스팅들에서 사용된 이미지는 512*512,256*256 이였습니다.)
하면 크게 속도차이가 보이지 않는것은 사실이지만,,,
사람이 살다보면 작은 해상도의 이미지만을 다루는 것이 아니기 때문에 좀 더 고속으로 연산할 수 있는 방법이 필요합니다.

이를 위해 나온것이 바로 LookUp Table연산 방식입니다.
이번포스팅에서는 저번 포스팅에서 다솜돌이 님께서 언급하셨던 고속 연산방식인 룩업테이블에 대하여 이야기하겠습니다.
(다솜돌이님 ㅋ 포스팅 순서가 있었어요 ㅋㅋㅋ 일부로 안쓴거라고요 ㅋㅋ)

1. 기존의 연산방법

 
   그렇게 느리다고 생각되지 않습니다만,,  이는 이미지의 크기가 작아서 라고 보시면 됩니다. (때마다 달랐지만..13ms)
 코드 보기
       public void Mul(int Const)
        {
            int TempNum;
            for (int X = 0; X < 512; X++)
            {
                for (int Y = 0; Y < 512; Y++)
                {
                    TempNum = TestData[X][Y] * Const;

                    TempNum = TempNum < 0 ? 0 : TempNum;
                    TempNum = TempNum > 255 ? 255 : TempNum;

                    TestData[X][Y] = (Byte)TempNum;
                }
            }
        }



2. LookUpTable을 사용한 경우
 

LUT를 사용한 연산

  같은 내용의 결과를 내는데 걸린 시간이 거의 1/4까지 줄어든 모습을 확인 할 수 있습니다.
  코드 보기
        public void MulUsingLookUpTable(int Const)
        {
            int TempNum;
            Byte[] LUT = new Byte[256];

            // LookUp Table을 완성합니다.
            for (int i = 0; i < 256; i++)
            {
                TempNum = i * Const;
                TempNum = TempNum > 255 ? 255 : TempNum;
                LUT[i] = (Byte) TempNum;
            }

            // LUT를 이용하여 연산을 수행합니다.
            for (int X = 0; X < 512; X++)
            {
                for (int Y = 0; Y < 512; Y++)
                {
                    TestData[X][Y] = LUT[ImageData[X][Y]];
                }
            }
        }



 뭐가 뭔지 모르겠다.
 위나 아래나 for문이 들어갔는데,, 오히려 LookUpTable방식에서는 256번의 for문이 있지않느냐?
 그럼 더 느린것이 아닌가?! 라고 하신다면.. 비밀인 여기입니다.

 연산수를 따져봅시다.
 기존의 방식 LUT의 방식 
 for (int X = 0; X < 512; X++)
            {
                for (int Y = 0; Y < 512; Y++)
                {
                    TempNum = TestData[X][Y] * Const;

                    TempNum = TempNum < 0 ?
                                       0 : TempNum;
                    TempNum = TempNum > 255 ?
                                       255 : TempNum;

                    TestData[X][Y] = (Byte)TempNum;
                }
            }

            for (int i = 0; i < 256; i++)
            {
                TempNum = i * Const;
                TempNum = TempNum > 255 ?
                                   255 : TempNum;
                LUT[i] = (Byte) TempNum;

            }       
      for (int X = 0; X < 512; X++)
            {
                for (int Y = 0; Y < 512; Y++)
                {
                    TestData[X][Y] = LUT[ImageData[X][Y]];
                }
            }
                            곱하기 연산의 수 512 * 512 = 262144
             Saturation을 위한 연산의 수 512 * 512 = 262144
    +                                               대입연산의 수 512
                      ===================================
                                                                     524800
                                                 곱하기 연산의 수 256
                                  Saturation을 위한 연산의 수 256
     +                                               대입연산의 수 512
            ================================
                                                                        1024
결과 : 13ms 결과 : 4ms 

 LUT방식은 미리 연산해야 하는 내용을 미리 연산 한 후 ,
 연산의 결과에 해당하는 값만을 대입하는 방식이므로 위의 결과와 같이 연산의 수를 대폭 줄일 수 있습니다.
 이를 통하여 좀 더 빠른 연산을 할 수 있는것이지요 ^^*
 (그림을 표현해서 설명하고 싶었는데,, 살짝귀차니즘이 ㄷㄷㄷㄷ;;;; 추후에 수정하겠습니다.;)

 사실 구현할때는 귀찮을 수 도 있지만,,
 좀더 빠른 결과를 위해서라면 귀차니즘을 극복하고 사용할 만한 방식인것은 충분합니다..

 이번 포스팅은 이만 마칩니다.



 이번시간에는 포인트 연산 중 두 프레임간의 산술연산에 대해 포스팅하겠습니다.
 많이 어려운 내용은 아니지만, 실제로 많이 사용되는 기본중 기본이라고 하니 자세히 알아두는게 좋겟습니다-
 
 구현된 결과는 파일로 첨부 해 봅니다.
(글을 수정하면 동영상도 올려보도록 하겠습니다.
 아직까지 만족할만한 예쁜동영상이 안나와서 ㄷㄷㄷ)

 픽셀단위의 산술연산을 할 경우는 상수에 의한 연산과 마찬가지로 ..
 기본 산술연산에 있는 네가지 + (덧셈) - (뺄셈) * (곱셈) / (나눗셈) 가 있습니다.

 간단하게 말하자면 산술연산시 상수값을 더하거나 빼는 것처럼
같은 위치의 픽셀의 밝기 값에 같은 위치의 픽셀의 밝기를 더하거나 빼서
새로운 영상을 만드는 처리방법입니다
.

서로다른 두 영상의 합(SUM)

원숭이와 동그라미 영상의 합


레나와 원 영상의 합


서로 다른 두 영상내에서 각각의 대응 픽셀의 밝기 값을 합해서 나온 결과 영상입니다.
물론 합한후의 픽셀의 밝기 값이 255를 초과하는 경우 255의 값을 가지게한 saturation기법을 사용하였습니다.
이를 통하여 원하는 부분의 그림만을 추출할 수 있도록 할 수 있어. 이미지 추출에 많이 사용된다고 합니다.



서로 다른 두 연산의 차 (SUB)

빼기연산을 이용한 불량검사

빼기연산을 이용한 불량검사2

빼기연산을 이용한 움직임 검출


 실제로 많이 사용한다고 하는 빼기연산의 예들입니다.
 처음과 두번째 그림처럼 어떠한 물체의 결함을 찾기 위해서 많이 사용된다고 합니다.
 또한 침입자 검출을 위하여 다음과 같은 연산을 하여도 침입자가 발생하엿다는 사실을 쉽게 알 수 있습니다.

 하지만, 이러한 빼기 연산을 통하여 결함을 찾거나, 침입자를 검출하기 위해서는, 촬영하는 카메라의 이동이 없어야 하는것!.
 만약 카메라 자체의 이동이 있다면 빼기연산을 하여도 결과가 무지 이상하게 나옵니다. -_-;;;
(적당한 이미지를 찾지못해서 이미지 첨부는.. 수정으로 미루겠습니다. ㅠ)

 곱하기, 나누기 연산-_-ㅋ

 물론 상수를 이용한 산술연산처럼 두 이미지에서도 곱하기 나누기 연산을 사용할 수 있습니다.
 위의 이미지를 사용하여 나온 결과는 이러합니다...

두 이미지 같의 곱셈연산

두 이미지 간의 나눗셈연산


 만..
 적당히,, 좋은 예의 이미지를 찾지 못하였기 때문에,, 구현결과는 다음과 같습니다..
 (사실 이 연산들을 어디에 사용해야할 지 잘 모르겠습니다.. ㅠㅠ)
 추후에 어디에 사용되는 연산인고-_-; 를 알게되면 이 내용을 초금 수정할 예정.....입니다..


 p.s 앗 한가지 신기한것


 두 프래임간의 덧셈 연산인데,
 이를 통하여 손을 거쳐서 뒷모습이 보이는 모습을 볼 수 있지 않은가요??ㅋ
 ... 저만 신기하다면 쿨럭..;;;


 구현된 내용의 소스는 이러합니다. 
 


 어렵지 않아서 쉽게 이해하 실 수 있으실 겁니다.
 

 
 


Saturation과 Wrap

디지털 이미지의 컬러수는 사실 제한되어 있습니다.
(다만 그것을 우리가 느끼지 못할 정도로 많은 수의 컬러수를 가지고 있을 뿐입니다.)
물론 Gray 이미지 역시 명암 값은 제한되어 있습니다.

저번 포스팅에서 사용하였던 Raw파일에서의 파일포멧은 1byte에 한개의 픽셀정보를 가지고 있는,,
즉 256개의 gray level을 가진 이미지 였습니다.
즉, 0에서 255까지의 256가지의 그래이 컬러를 표현할 수 있다는 의미지요.

자 그럼, 저번 포스팅 내용을 보시면서 의야해 하실만한 점이 떠오르실 텐데요,,,
바로 0보다 작은 수는 어떻게하지?? 255보다 큰 숫자는 어떻게 처리하지? 입니다.

예를들어 한 픽셀이 250의 값을 가지고 있고 여기에 + 10 연산을 한다고 가정해 봅시다.
그렇게 되면 연산된 픽셀의 값은 260...
한개의 픽셀정보를 가지고 있는 용량의 크기는 1byte이기 때문에 255이상의 숫자를 다룰수가 없습니다.
그렇다고 갑자기 파일 포멧을 바꾸어서 한 픽셀을 2byte로 표현할 수도 없는 노릇입니다.

자, 그렇다면 이미지에서 260은 어떻게 표현하면 될까요??
방법은 두가지가 있습니다.

1. Saturation

Saturation을 표현한 그래프


Saturation

1. 침윤(浸潤), 삼투;【화학】 포화 (상태) 《습도 100%의 상태》
2.【광학】 (색의) 채도(彩度) 《색의 포화도;백색과의 혼합 정도》
3.【군사】 (압도적인) 집중 공격

Saturation은 255의 이상인 값들은 모두 255로 표현하는 방법입니다.
그래프에는 표현되지 않았지만, 마찬가지로 0 이하의 값들은 모두 0으로 표현하게 됩니다.

구현은 어렵지 않습니다.
말 그대로 0이하의 값들은 0으로 표현해주고 255이상의 값들은 255로 표현해 주면 되기 때문입니다.
구현내용은 다음과 같습니다.
                    TempNum = TempNum < 0 ? 0 : TempNum;
                    TempNum = TempNum > 255 ? 255 : TempNum;

 대부분의 이미지 툴에서 사용하는 방식으로 아시면 됩니다.
참고로, 저번 포스팅에서는 Saturation의 방식으로 이미지를 표현하였습니다.

원본이미지

Saturation으로 표현된 +150



2. Wrap

Wrap을 표현한 그래프

Wrap

1.a (감)싸다, 입다 《up, in, with》
2. 감추다, 덮어싸다 《up, in, with》;[종종 수동형으로] 보호하다 《in》
3. [보통 수동형으로] 몰두[열중]하다 《in》
4. <일·회의 등을> 끝내다, 마치다;<숙제 등을> 다 쓰다 《up》;<뉴스 등을> 요약하다

256 = 0, 257 = 1, 258 = 3 ... 501 = 0,,, 와 같이
255의 이상의 값이나, 혹은 0 이하의 값들을 , 0~255를 주기로 계속 반복적으로 표현하는 방식입니다.

구현은 딱히 하지 않습니다.
왜냐하면 위의 Saturation의 방법을 사용하지 않으면 저절로 Wrap방식으로 되기 때문입니다.
자주 사용하는 방식은 Saturation인데 왜 절로 Wrap이 되냐, 라고 하시냐면
그것은 컴퓨터의 데이터 저장방식 때문입니다.

1byte라고 하는것은 0과 1을 표현할 수 있는 1bit의 8개 모임입니다.
즉 1byte를 통해 다음과 같은 수를 표현할 수 있습니다.

00000000 ~ 11111111 (2진수) => 0~ 255 (10진수)

256를 표현하기 위해서, 혹은 그 이상의 수를 표현하기 위해서든 더 많은 bit들이 필요합니다.
참고로 256을 이진수로 나타내면 이렇습니다. => 100000000
이중, 1byte가 표현할 수 있는 비트수는 8개 이므로 100000000중 100000000만이 표현되게 됩니다.

이렇기 때문에, 아무런 구현을 해주지 않으면 저절로 Warp의 방식으로 이미지가 표현되게 됩니다.

원본이미지

Wrap으로 표현된 +150



대부분의 이미지툴은 이 방식을 사용하지 않기 때문에,
그냥 보신다면 어딘가 잘못된거같은 이미지다 . 라는 느낌을 받으실 겁니다.


이번 포스팅에서는 Saturation과 Wrap의 방식을 알아보았습니다.
다음 포스팅에서는 두 이미지글 가지고 포인트 연산에 관한 이야기를 하고자합니다.
감사합니다.



 이번시간에는 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
 혹 질문이 있으신 분은 요기 말고 저기에 해주시기 바랍니다 ㅋㅋㅋ
 아주 친절한 답변이 있을거에요~~

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



 

 안녕하세요.
 이번 포스팅에서는 포인트 연산 , 그중에서 상수값에 의한 산술연산에 대해 알아보고자 합니다.
 구현된 결과는 다음과 같습니다.



 픽셀단위의 산술연산을 할 경우는
 기본 산술연산에 있는 네가지 + (덧셈) - (뺄셈) * (곱셈) / (나눗셈) 가 있습니다.

 간단하게 말하자면 산술연산시 상수값을 더하거나 빼는 것처럼
 픽셀의 밝기 값에 상수값을 더하거나 빼서 새로운 영상을 만드는 처리방법입니다.

 
 덧셈연산 ->    변환이미지[X][Y] = 원래이미지[X][Y] + 상수값
 뺄셈연산 ->    변환이미지[X][Y] = 원래이미지[X][Y] - 상수값
 곱셈연산 ->    변환이미지[X][Y] = 원래이미지[X][Y] * 상수값
 나눗셈연산 -> 변환이미지[X][Y] = 원래이미지[X][Y] / 상수값

 그리 어렵지는 않습니다만,  결과와 함께 이야기를 자세히 풀어보겠습니다.
 이미지는 그 유명한 Lena를 사용하였습니다.

  밝아지기 위한 이미지 산술연산

      1. 더하기

원본

+60



 다음 이미지는  Lena의 원본이미지와 더하기 산술연산을 한 결과 이미지 입니다.
 원본 영상에 비해 전체적으로 밝아진것을 확인 할 수 있습니다.

     2. 곱하기
 

원본

*4



 다음 이미지는 Lena의 원본이미지와 곱셈산술연산을 한 이미지 입니다.
 역시 원본 영상에 비해 밝아진 것을 확인 할 수 있습니다만
 더하기 산술연산과의 차이는 역시 약간의 차이를 확인 할 수 있습니다.

 더하기 산술연산의 경우 모든 영상 데이터를 일정한 값만큼 증가시키는데 반해서 
 곱하기 산술연산의 경우는 원래 작은값은 작게증가하고 큰값은 더 크게 증가시켜서
 밝기의 대비 (constrast)를 키워지는 효과가 있습니다.
 그렇기 때문에 영상의 가시화가 더 좋아지는 것을 확인할 수 있습니다.
 

어두워 지기 위한 산술연산

   1. 빼기

원본

-60



 다음 이미지는  Lena의 원본이미지와 빼기 산술연산을 한 결과 이미지 입니다.
 원본 영상에 비해 전체적으로 어두워것을 확인 할 수 있습니다.

   2. 나누기


 다음 이미지는 Lena의 원본이미지와 나누기산술연산을 한 이미지 입니다.
 역시 원본 영상에 비해 어두워진 것을 확인 할 수 있습니다만
 빼기 산술연산과의 차이는 역시 약간의 차이를 확인 할 수 있습니다.

 위의 밝아진 영상과 반대로
 빼기 산술연산의 경우 모든 영상 데이터를 일정한 값만큼 감소시키는데 반해서 
 나누기 산술연산의 경우는 원래 작은값은 작게감소하고 큰값은 더 크게 감소시켜서
 영상의 가시화가 더 떨어지는 것을 확인할 수 있습니다.


코드는 다음과 같습니다.
C#을 이용하여 구현하였지만, 크게 무리 없이 이해가능할 것이라고 생각합니다.





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

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

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

(흑백영상의 팔레트)




이번 포스팅에서는 비트맵포멧의 구조를 알아보도록 하겠습니다.
보통은 DIB를 많이 사용하기 때문에 많은 포스팅에서는 DIB와 관련된 포멧구조만 설명하는 경향이있는데,
이번 포스팅에서는 저번포스팅에서 말씀드렸던 것처럼


DDB를 무시하고 넘어갈 수 없는 이유로 DDB의 구조와 DIB의 헤더구조를 알아보도록 하겠습니다.


일단,,
Bitmap 파일포멧은 다른 파일포멧(JPG,GIF 등등)들과 달리 압축을 수행하지 않으며
헤드가 있는 여러형식의 파일중에서 헤더구조가 가장 간단합니다.
(당연할 수 밖에 없지 않나요? 압축이 되면 된만큼 헤더에는 정보가 많아야 할 테니까요~)
어렵다고 느껴지시겠지만,, 이것으로 위안삼으세요-_ㅠ 힝


DDB () - 장치에 종속적인 비트맵

 typedef struct tagBITMAP
{
LONG bmType;                 // - bmType : 비트맵 타입;;  ( 보통 0을 가지고 있습니다.)
LONG bmWidth;                // - bmWidth : 이미지의 가로크기 
LONG bmHeight;               // - bmHeight : 이미지의 세로크기
LONG bmWidthBytes;        // - bmWidthBytes : bitmap 이미지의 한줄에 표현될 바이트 수, 
                                                                 (비트맵은 word단위로 표현되므로 항상 짝수)
WORD bmPlanes;             // - bmPlanes : 색상면의 개수
WORD bmBitsPixel;           // - bmBitsPixel : 한 픽셀에 필요한 비트의 수
LPVOID bmBits;                // - bmBits : 실제 비트맵 데이터를 가르키는 포인터
                                                        (단 bmBits 는 반드시 char배열,1바이트배열의 포인터)
} BITMAP;

이러한 DDB는  CreateBitmap()  함수를 통하여 쉽게 만들 수 있습니다.
이 함수는 간단하게 DDB를 만들어 주는데,
SelectObject()함수로 DC를 선택할때 CreateBitmap()함수는 속도가 느리기 때문에
성능적인 측면을 고려한다면 이 함수는 흑백비트맵을 만들때 주로 사용하고
만약 컬러비트맵을 만들고자 한다면 CreateCompatibleBitmap() 함수를 사용하는 것이 좋습니다.


1. CreateBitmap()함수를 살펴보자면

 HBITMAP CreateBitmap(int nWidth,int nHeight,UINT cPlanes,UINT cBitsPerPel,CONST VOID *lpvBits );

- 각각에 파라미터는 헤더정보에 들어가는 structer를 채우게되고 리턴값으로 DDB핸들이 리턴됩니다.

2. CreateCompatibleBitmap() 함수를 살펴봅시다.

 HBITMAP CreateCompatibleBitmap(HDC hdc,int nWidth,int nHeight );

- 주의해서 보셔야 할 부분은 디바이스컨텍스트를 파라미터로 받는다는 것인데, 바로 SelectObject()함수를
  이용하여 비트맵을 DC로 출력할 때 빠른속도를 내기 위해서입니다.
  또 디바이스컨텍스트와 픽셀포멧,생상수가 동일한 비트맵을 만들어줍니다.
- 나머지 두 인자는 이미지의 가로세로값을 초기화시켜줍니다.
- 단 이함수는 비트맵의 각 픽셀값은 초기화 되지 않으므로 일일히 초기화해주어야 하는 단점이 있습니다..



DIB () - 장치에 독립적인 비트맵

 파일헤드(BITMAPFILEHEADER)
 영상헤드(BITMAPINFOHEADER)
 팔레트정보(RGBQURD)
 영상데이터(거꾸로 들어있음)

DIB파일은 다음과 같은 구조로 이루어져 있습니다.
일단
1. 파일자체의 정보를 가지고 있는 파일헤드 (BITMAPFILEHEADER)
2. 비트맵 영상에 대한 크기나 흑백,컬러정보, 팔레트크기정보)등을 저장하기 위한 영상헤드 (BITMAPINFOHEADER)
3. 인덱스에 의한 컬러값을 저장하기위한 팔레트정보 (RGBQURD)
4. 이미지데이터 (거꾸로 들어있습니다.)
로 이루어져있습니다.

자세히 뜯어보면 이렇습니다.

1. BITMAPFILEHEADER - 파일 자체의 정보

 typedef struct tagBITMAPFILEHEADER
{
WORD bfType;            // - bfType : 비트맵파일인지 확인 (비트맵이라면. 반드시 BM (0x42,0x4d) )
DWORD bfSize;          // - bfSize : 비트맵 파일의 크기
WORD bfReserved1;   // - bfReserved1 : 예약되어 있는 값, 보통 0
WORD bfReserved2;   // - bfReserved2 : 예약되어 있는 값, 보통 0
DWORD bfOffBits;       // 실제 비트맵 데이터 값과 헤더의 오프셋 값 ( BITMAPFILEHEADER  + BITMAPINFO )
} BITMAPFILEHEADER;
 


2. BITMAPINFOHEADER - 비트맵 영상정보

 typedef struct tag BITMAPINFOHEADER
{
DWORD biSize;              // - biSize : BITMAPINFOHEADER 구조체의 크기
LONG biWidth;               // - biWidth : 비트맵의 가로픽셀의 수
LONG biHeight;              // - biHeight : 비트맵의 세로픽셀의 수
WORD biPlanes;            // - biPlanes : 장치에 있는 색상면의 개수 (반드시 1)
WORD biBitCount;           // - biBitCount : 한 픽셀을 표현할 수 있는 비트의 수
DWORD biCompression;  // - biCompression : 압축상태를 지정
                                    //   (BI_RGB : 압축되지 않은 비트맵,BI_RLE8 : 8bit압축 ,BI_RLE4 : 4bit압축 )
DWORD biSizeImage;      // - biSizeImage : 실제 이미지의 바이트크기 (압축되지 않은경우 0 )
LONG biXPelsPerMeter;  // - biXPelsPerMeter : 미터당 가로픽셀수
LONG biYPelsPerMeter;  // - biYPelsPerMeter : 미터당 세로픽셀수
DWORD biClrUsed;         // - biClrUsed  : 색상테이블의 색상중 실제 비트맵에서 사용되는 색상수
                                   // (0 : 비트맵은 사용할 수 있는 모든색상을 사용
                                   // , 그외 : RGBQUAD구조체배열의 크기는 이 멤버의 크기만큼 만들어짐)
DWORD biClrImportant;  // - iClrImportant : 비트맵을 출력하는데 필수적인 색상수 (0 : 모든 색상이 사용되어야함)

} BITMAPINFOHEADER;



3. RGBQUAD  - 인덱스의 컬러값

 typedef struct tag RGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;

} RGBQUAD;

-> 여기서 한가지 알아두어야 할 정보는 RGB 순서가아니라 BGR순서로 되어있다는 것이다 ㅋ
     rgbReserved는 그냥 예약된 숫자 ㅋ 큰 의미는 없다.



우선다음의GDI 함수를알아보고코드를살펴보자.

CreateCompatibleBitmap( ) 함수

HBITMAP CreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight );

• 이 함수는디바이스 컨텍스트와 호환되는, 즉픽셀 포맷과 색 상수 등이 같은 비트맵을 만드는데 CreateBitmap( ) 함수처럼 비트맵 이미지 데이터를 초기화할 수는 없습니다. 단순히 가로와 세로 값정도만을 설정할 수 있습니다.
• 함수를사용한후에는반드시DeleteObject() 함수를 호출하여 Object를 삭제할 수 있어야 합니다. (안그러면 메모리-_ㅠ)
 
CreateCompatibleDC( ) 함수

HDC CreateCompatibleDC(HDC hdc );

• 이 함수는 장치의 디바이스 컨텍스트와 호환되는디바이스 컨텍스트, 즉 메모리디바이스 컨텍스트를만들어줍니다.
 비트맵을 디바이스 컨텍스트에 선택할 때 이 함수를 이용하여 메모리 dc를 만들어 선택합니다.
 사용한 후에 마찬가지로 반드시 DeleteDC() 함수를 호출하여 메모리누수가 없도록 방지합니다.
• hdc 인자로 null이면 기본으로  현재 디스플레이 화면의 디바이스컨텍스트와 호환되는 디바이스컨텍스트핸들을 반환합니다.

SelectObject () 함수

HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj );

• 이 함수는 디바이스 컨텍스트에GDI 객체를선택할수 있게 합니다. GDI 객체란펜이나 브러시, 폰트, 비트맵 등을 말하는데 여기에서는 비트맵을 디바이스 컨텍스트에 선택하기 위해서 사용합니다. GDI 객체는반드시 디바이스 컨텍스트에 선택되어진후
사용되기때문에GDI 객체를사용할때에는반드시이 함수를사용해야된니다. 이함수를 사용하면 반환 값으로 선택되기 전의 GDI 객체가반환되는데이 값을 받아 두었다가 GDI 객체를사용한 후, 반드시 디바이스 컨텍스트에 이전 GDI 객체를 선택하게됩니다.
 

다음 포스팅에서는 비트맵 영상의 컬러표현에 대해서 알아보겠습니다.
 



 이번 포스팅부터 뒤에 몇몇 포스팅은 비트맵장치에 대해 다룰 예정입니다.

 비트맵이미지가 처음 소개된 곳은 의외라고 생각하 실진 모르겠지만 마이크로소프트가 윈도우를 제공하며
 처음 소개한 방식입니다. 아무래도 GUI형식의 os를 만들면서 화면에 출력되는 영상을 일일히 함수를 통하여
 그리는 것 보다  이미 그려진 그림을 뿌려주는 것이 속도면에서 훨씬 효율적이기에 개발된 포멧이 아닐까 싶습니다.
 
 비트맵은 말 그대로 Bit와 Map의 조화로 그림을 구성하는 픽셀정보가 2차원으로 저장되어 있습니다.
 (2차원배열) 그래서 비트맵이미지는 픽셀색상 , 이미지의 크기와 위치 해상도 정보를 헤더로 가지고있습니다.

 길게 한개에 몰아쓰는것보다 짧고 굵게 다루는것이 집중력과, 검색능률에 좋을듷하기도하궁,,
 헤더에 대한 정보는 다음 포스팅에 쓰기로하고
 어쩃든 이번시간에는 두가지 종류의 비트맵 DDB와 DIB의 차이에 대해서 다루도록할 생각입니다 오홍홍 ㅋ


 DDB ( Device Dependent Bitmap) 디바이스에 종속적인 비트맵


다음 그림은 window vista의 display setting과 관련된 메뉴의 캡쳐입니다. 

여기서 확인하셔야 하는것은 빨간 네모칸의 color부분,
비스타에서는 32bit의 Highest와 16bit  medium 두가지 설정이 있습니다. (xp는 조금 더 다양한 선택권이있는걸로 압니다.;;)

여기서 설정되는 color는 표현가능한 컬러의 수가 얼마나 되는가를 이야기 해 주는 것인데,, 
예를들어  16bit의 Medium을 선택하였다면,,
 216 = 65,536개의 색을 표현가능하다는 의미입니다.

DDB는 디바이스에 종속적인 비트맵으로 다시말하면 화면설정에 종속적인,, 화면설정에 따라서 표현이 달리되는 비트맵 이미지를 의미합니다.


예를 들어 a라는 그림이 32bit의 color설정이 되어있는 컴퓨터에서는 32bit의 그림으로 출력되고 
16bit의 color로 설정되어 있는 컴퓨터에서는 16bit의 그림으로 출력됩니다.
극단적으로 말씀드리면 , 흑백으로 설정되어있는 컴퓨터에서는 그림이 컬러이든 흑백이든 무조건 흑백으로 출력되고,
(그 그림은 컬러설정이 되어잇는 컴퓨터에서는 컬러로 보입니다)
컬러로 설정되어 있는 컴퓨터라면 그림이 흑백이든 컬러든 컬러로 출력된다는 의미입니다.
(그 그림은 흑백설정이 되어있는 컴퓨터에서는 흑백으로 보입니다.)

뭔가 의미가 이상하게 전달될 수도 있다 생각되는 이상한 의미긴하지만,, (그럴수밖에요,,이걸접할기회가적으니까요)
말 그대로 장치설정대로 출력되는 비트맵을 의미합니다.

이 비트맵은 bitmap을 출력하는데 필요한 모든정보를 header에 가지고 있지 않고
출력되는 컴퓨터 시스템의 디스플레이장치가가지고있는 부가적인 정보(팔레트, 픽셀포맷등)를 이용하여 출력하기 때문에
다른 종류의 디스플레이 장치에서는정확하게출력되지않는단점이 있습니다.
다만 장치의 정보와 일치하는 정보로 이미지를 출력하기 때문에 빠른속도로 이미지를 출력할 수 있는 장점이 있습니다.

이해가 안가신다면 개발자의 입장이 아니시라면,, 구지 이해하시려고 노력하실 필요 없습니다. 잘안쓰니까요-_-;;;
(앗 나만이해가 안갔던것인가-_-;;;;)


요약 - 화면설정에 종속적인 컬러표현


 DIB (Device Independedt Bitmap) 디바이스에 독립적인 비트맵

위와는 상대적인 개념으로 DIB는 화면설정이 32bit이든 16bit이든 상관없이, 나는 나나름대로 색을 표현할꺼야!!! 하는 비트맵이미지입니다. 우리가 쓰는 이미지들의 대부분은 DIB형식의 파일입니다.
이가 가능한 것은 Bitmap헤더에 bitmap을 출력하는데 필요한 모든 정보를 가지고 있기 때문에 가능합니다.
그래서, DDB와 반대로 어떠한 설정을 가진 장치에서 이미지를 출력하여 보더라도 동일한 이미지정보를 확인할 수있습니다.
즉 흑백이미지는 어느컴퓨터에서 보든 흑백이미지이고, 컬러이미지는 어느컴퓨터에서 보든 컬러라는 것입니다..

다만, DDB의 장점이였던 속도 문제가 여기서는 단점으로 꼽힐수있습니다.
만약 , 디스플레이 설정이 장치 독립적 비트맵의구성과 다르다면 적절한 픽셀 포맷의변환작업이 필요하고
팔레트에해당하는색상을 매핑시켜야하는 부담이 있어, 비트맵의 출력 속도가 떨어질수있는 단점이 있습니다.

하지만 하드웨어기술의 발달로 이정도 속도문제는 큰 문제가 되지 않아 DIB를 주로 사용하고 있습니다.

요약  - 화면설정에 독립적인 컬러표현,
        - 흑백영상은 시스템 설정이나 장치에 무관하게 흑백으로 나타나고 컬러영상은 항상 컬러로 나타남



 DIB가 최신의 기술이고 DIB를 많이 사용하고 있다고 하더라도,, DDB를 버려서는 안됩니다.

 1. 일단 속도면에서 DIB보다 DDB가 빠를 수 밖에 없습니다. 이게 아니더라도
 2. 결국은 DDB이기 때문입니다.   (디바이스 컨텍스트(Device Context)에 선택될 수있는비트맵은D D B뿐)
    즉, 결국은 디바이스에 종속되서 그림을 뿌려줘야하지 않겠습니까??
 3. 뿐만 아니라 프로그램내부에서의 생성과 파괴작업도 DDB가훨씬 효율적입니다.

 결국은 개발자라면 DIB와 DDB의 특징을 알아야 하며  서로 상호 변환할 줄도 알아야 한다고 생각합니다.
 


이번 포스팅에서는 간단히 DDB와 DIB에 대해서 다뤘습니다.
뭐 주저리 주저리 이래야한다 저래야한다 잔뜩말하긴했지만.. 그냥 이것이 무엇인가 하는 개념만 알고가시면 될 거같습니다.
DDB에 대해 설명이 아리까리해서 이상하다고 느껴져 골치아프시다면,,, 그냥 이해안하셔두됩니다 ㅋ
아까말씀드린것처럼 평소에 보지못했기 때문에 잘 이해가 안가는 것일수도 있으니까요~~

 다음 포스팅에서는 비트맵 포멧의 구조에 대해 다루겠습니다.

컴퓨터에 Image를 저장하기 위한 표준형식은 다양하게 존재합니다. ^^*

 간단하게 예를 들어 봐도
 용량이 쓸때없이 커서 사람들이 기피하는 Bitmap
 많은 사람들이 많이 사용하는 Jpg
 움직이는 그림을 저장할 때 많이 사용하는 gif
 그리고 들어본적 별로없는 raw  (사실 자주쓰는 이미지 뷰어인 알씨에서는 읽어내지못하는 포멧) 등등 까지해서,,

 이번포스팅에서는 다양한 이미지저장포멧에 대한 간단한 내용들을 다루겠스빈다.
 앞으로 써나가는 포스트들은 주로 Bitmap이나 raw형식의 파일만을 주로 다룰 예정이니,
 계속 포스팅을 보시는 분이라면 그부분에대해서 좀 더 자세히 보실 필요가 있습니다 ^^;
 (부족한다면 다른 좋은분의 포스팅을 찾아보는 것도 좋은 방법이지요...예예 ㅠㅠ)


 ======================================================================================================
 
  이미지 파일의 구조
 
 Header
 Image Data
Bitmap, jpg, gif등의 파일 형식
- Header와 Image Data를 가짐

  Image Data

raw파일 
-  Image Data만을 가짐

 ======================================================================================================

자주묻는질문,

1. Header에는 무슨정보가 들어가는가?
: 영상의 크기, 컬러의수, 펠리트 등의 다양한 정보들이 들어있습니다.
: 물론, 각 포멧에 따라 Header에 들어가는 정보들이 다르게 들어가있습니다.
   (다음 포스팅에서 기본적으로 Bitmap의 헤더에대해 포스팅하겠습니다.)
: 하지만 기본적으로 , 가로,세로,크기와 칼라정보등등 들이 들어가있습니다.
: 이미지를 출력할때 , 이 헤더 정보를 가지고 사용자의 정보입력이 없이 컴퓨터가 알아서
  그림을 알맞은 크기와 알맞은 색깔정보로 그림을 출력할 수 있다.

2. Raw 파일은 Header없이 어떻게 되는가??
: 엄밀히 말하자면 Raw파일에 반드시 헤더 정보가 없다 라고 할 수 없습니다.
  다만 헤더 정보가 없다 라고 이야기를 하는 이유는,, 
 1) 헤더정보가 이미지파일을 만드는 사용자의 임의로 넣고 싶은 정보를 넣는,, 즉 기본 포멧이 없습니다.
 2) 또 대부분의 Raw파일은 헤더파일이 없이 단순 이미지정보만 가지고 있습니다.
: 이미지를 출력할때는 반드시 필요한 정보가 있습니다. (예를들어, 아까 위에서말한 기본정보들)
  이러한 기본정보들은 헤더에 저장하는 편인데, Raw파일에는 헤더정보가 없습니다.
  그래서 사용자의 정보 입력이 없이는 raw파일을 출력할 수 가 없습니다.
  (그래서 알씨같은 이미지출력툴에서 raw파일을 출력할수 없습니다...;;)
  다만, 사용자가 이미지출력에 필요한 정보를 알고있다면 , 따로 정보를 입력하여 이미지를 출력할 수있습니다.
  (포토샵같은것을 이용하면 가능합니다 ^^*)
  (글고보니 포토샵은 이미지의 사이즈를 가지고 대략 가로세로를 예측해서 출력해주는 기능이있더군요 ㅋ)

3. JPG와 BMP, GIF파일은 무슨 차이가 있는가???

: 세 이미지 모두 헤더정보를 가지고있는 이미지 입니다. 하지만 이미지를 저장하는 방식의 차이가 있습니다.
 눈으로 확인해주세요.

 
BMP

 
JPG

GIF

(-_-,, 갓 20살때 셀카입니다.;; 우악)

 
 전문가나 민감하신분 아니면 큰 차이를 못느끼실테지만,,서도 ㅋ 

:   파일의 크기를 비교해보면 다음과 같습니다. 
  BMP : 242kb , JPG :  26.8kb , GIF : 43.2kb
  이같이 파일 사이즈에서 차이가 나는 이유는 파일의 압축률에 있습니다.
  이미지 정보를 저장하는 방법은 다양한데 , 한 픽셀의 색을 각값을가지고 표현하는 방법이 있는가하는반면(BMP)
  이미지에서 자주사용되는 색을 번호를 매겨 모아놓은 집합을 헤더파일에 저장하여놓고 
  이미지를 출력할때 팔레트에 대응하는 색을 출력하는 방법 등이 있습니다.
  이러한 여러가지 방 법을 통하여 이미지의 사이즈를 줄일 수 있는데,, 문제는 품질입니다.
  당연히 압축률이 거의없는 bmp파일은 사이즈가 큽니다. 그래서 웹에서는 잘 사용하지 않습니다.
  (다만 요새는 인터넷 업로드속도도 빠르고, 하드값도 싸져서인지,, 지원해주더라고요;;)
  어느정도 압축하되, 색정보를 잘 표현한것이 jpg이고 , 많은사람들이 기본적으로 사용하는 포멧입니다. ㅋ
  gif는 조금 더 압축한 것으로 사이즈가 더 작고, 움직이는 그림을 저장할 수있어 주로 베너같은 이미지에 사용됩니다.
 (다만-_-;; 이번은 워낙이미지가 작아서그런지 jpg보다 gif가 사이즈가 더 크게나왔네요 오홍홍;;;;;)
  각자 알맞은 포멧에 맞게 사용하는것이 좋겠지요,,,
 (BMP 최고화질, JPG 적절한 조화 , GIF 움직이는그림ㅋ)
:  물론 BMP파일을 JPG으로 변환하면 압축때문에 색손실이 있을수 있습니다.
   그렇다고,, JPG그림을 BMP로 바꾼다고 화질이 좋아지는것은 아닙니다. 
   압축되어 있는 정보에서 정보를 뽑아내기 때문에,, 쉽게말하면 JPG와 같은화질의 용량큰 BMP파일이 되는겁니다.;;





 사실 이미지 파일이라고 하면 엄청난 정보를 가지고 있을 것 같지만,, (나만그랬나;;;)
 컴퓨터가 가질 수 있는 정보가 0과 1인것을 생각하면 그냥 다른 파일들과 마찬가지로 하나의 정보들의 나열일 뿐
 너무 겁 먹을 필요가 없습니다. ^^*

 다음 포스팅부터 이것저것 많은걸 해보지요,,,,ㅋㅋ