Busan IT/영상처리2015. 11. 5. 22:51

==================================Outline====================================

비트맵 구조체

----------------------------------------------------------------------------

비트맵 구조체

크기가 가로 400픽셀, 세로 400픽셀인 비트맵 파일을 임의로 생성하여 비트맵파일에 대해서 알아보기로 하자.

 

 


각 픽셀이 RGB로 표현되기 때문에 이 비트맵 파일의 용량은 (400 * 400) * 3이고, 54byte는 헤더파일이다헤더 파일은 실제내용을 간추린 정보를 제공하는데 이것을 오버 헤더라고 한다.


 

비트맵 파일은 픽셀 단위로 데이터를 저장한다. 1byte(8bits)에는 한가지 색에 대한 정보를 가지고 있다.  1픽셀은 3byte로 구성되는데,  각 바이트는 빨(Red), 녹(Green), 파(Blue)로 이루어져 있다.

 

**빛의 3원색:  빨강, 녹색, 파랑 

**색의 3원색:  자주, 노랑, 청록

 

 

** 빛은 섞을수록 밝아지고 색은 섞을수록 어두워진다.

위에서 만든 비트맵 파일을 헥사뷰를 사용하여 출력해본다. 54byte가 'FF'가 아닌 값으로 표시되고 있음을 알 수 있다. 

 

54Byte는 비트맵 파일의 헤더부분이며 비트맵 파일에 대한 정보를 담고 있다. 비트맵 파일의 구조체를 살펴보도록 하자. 


 

/* BITMAPFILEHEADER 구조체 */

typedef struct tagBITMAPFILEHEADER{ //bmfh

WORD bfType; // 파일의 형태, 0x42, 0x4d (BM) 이어야함

WORD bfSize; // 비트맵 파일의 크기 (Byte단위)

WORD bfReserved1; // 예약. 0으로 설정

WORD bfReserved2; // 예약2. 0으로설정

DWORD bfOffBits; // 실제 비트맵데이터까지의 오프셋값

// 실제로는 bfOffBits = BITMAPFILEHEADER크기 + BITMAPINFOHEADER크기 + RGBQUAD 구조체배열의크기 이다.

} BITMAPFILEHEADER;

 

/* BITMAPINFOHEADER 구조체 */

typedef struct tagBITMAPINFOHEADER{ //bmfh

DWORD biSize; // 이 구조체의 크기. 구조체 버전확인할수 있다.

LONG biWidth; // 비트맵의 가로 픽셀수

LONG biHeight; // 비트맵의 세로 픽셀수

WORD biPlanes; // 플레인의 갯수 반드시 1이어야함

WORD biBitCount; // 한 픽셀이 구성되는 비트의수

DWORD biCompression; // 압축방법. BI_RGB일땐 비압축 BI_RLE8, BI_RLE4인경우 run length encode방법으로 압축

DWORD biSizeImage; // 이미지의 크기. 압축이 안되어있을때는 0

LONG biXPelsPerMeter; // 가로 해상도

LONG biYPelsPerMeter; // 세로 해상도

DWORD biClrUsed; // 색상테이블을 사용하였을때 실제 사용되는 색상수

DWORD biClrImportant; // 비트맵을 출력하는데 필수 색상수

} BITMAPINFOHEADER;

 

비트맵 파일 구조체를 참고하여 구조체 멤버들을 출력해보자. 

 

400 * 400 크기의 BMP파일의 경우 한 픽셀당 3byte를 차지하고 그 값을 red, greeb, blue의 정도는 8bit(256) 나누어 표시할 수 있다. 파일의 총 크기는 480054byte이고 54byte는 헤더파일임으로 파일의 시작점에서 54byte 떨어진 지점부터의 데이터를 조작함으로써 BMP파일을 변형시킬 수 있다.

BMP파일을 조작하여 여러 가지 색깔로 변형시켜보자.

**BMP이미지를 수정하여 원본에 덮어 쓰도록 하자.

각 색에 대한 출력 정보는 0 ~ FF로 표현된다. '0'이 가장 낮은 단계이며 'FF'가 가장 높은 단계이다. 가로 픽셀이 400, 세로 픽셀이 400인 비트맵 구조체에서 가로 한 줄의 용량은 400 * 3이다. 좌측 상단에서 우측 하단까지 'for문'을 사용하여 데이터의 값을 입력할 값을 설정해주면 된다.

각 픽셀의 첫 번째 바이트는 blue, 두 번째 바이트는 green, 세 번째 바이트는 red이다. 비트맵 파일의 정보를 수정하여 색이 어떻게 바뀌는지 출력해보자.







소스 코드는 아래와 같다.

/*** 소스 ***/ 

#include <stdio.h>
#include <fcntl.h>
#include <windows.h>


int main(int iNum, char * cpArr[])
{
  int iRtn;
  int iFd;
  BITMAPFILEHEADER stBFHead;
  BITMAPINFOHEADER stBIHead;
  char cBuf[16*16];
  unsigned char * ucpBuf;
  
  unsigned int uiCntX;
  unsigned int uiCntY;

  

  iFd = open(cpArr[1], O_RDWR|O_BINARY);  
  if(iFd == 0)
  {
    printf("파일을 열 수 없습니다.\n");
    return -1;
  }

  iRtn = read(iFd, &stBFHead, sizeof(BITMAPFILEHEADER));
  if(iRtn == 0)
  {
    printf("파일을 읽을 수 없습니다.\n");
    close(iFd);            
    return -1;
  }
  if0x4D42 != (stBFHead.bfType) )
  {
    printf("BMP파일이 아닙니다.\n");
    close(iFd);            
    return -1;
  }
  iRtn = lseek(iFd, sizeof(BITMAPFILEHEADER), SEEK_SET);
  if(iRtn != sizeof(BITMAPFILEHEADER) )
  {
    printf("읽어들일 부분이 잘못 지정되었습니다.\n");
    close(iFd);            
    return -1;
  }
  iRtn = read(iFd, &stBIHead, sizeof(BITMAPINFOHEADER));
  if(iRtn == 0)
  {
    printf("INFO헤더가 존재하지 않습니다.\n");
    close(iFd);            
    return -1;
  }

  ucpBuf = (void *)malloc(stBIHead.biSizeImage);
  if(0 == ucpBuf)
  {
    printf("사용 가능한 메모리가 부족합니다.\n");
    close(iFd);
    return -1;
  }
  lseek(iFd, sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER), SEEK_SET);
  iRtn = read(iFd, ucpBuf, stBIHead.biSizeImage);
  

  if(iRtn == 0)
  {
    printf("데이터를 읽을 수 없습니다.\n");
    close(iFd);        
    free(ucpBuf);
    return -1;
  }
  for(uiCntY=0; uiCntY < stBIHead.biHeight; ++uiCntY)
  {
    for(uiCntX=0; uiCntX < stBIHead.biWidth; ++uiCntX)
    {
      ucpBuf[uiCntY * (stBIHead.biWidth * 3) + (uiCntX * 3) + 0= 0//blue  
      ucpBuf[uiCntY * (stBIHead.biWidth * 3) + (uiCntX * 3) + 1= 0//green
      ucpBuf[uiCntY * (stBIHead.biWidth * 3) + (uiCntX * 3) + 2= 0xFF; //red            
    }
  }
  lseek(iFd, 54, SEEK_SET);
  iRtn = write(iFd, ucpBuf, stBIHead.biSizeImage);
  if(iRtn == 0)
  {
    printf("데이터 쓰기에 실패 했습니다.\n");
    close(iFd);        
    free(ucpBuf);
    return -1;
  }

  lseek(iFd, 54, SEEK_SET);
  iRtn = read(iFd, cBuf, 16*16);  

  
  
  
  close(iFd);
  free(ucpBuf);
  
  return 0;

} 

 

 

 

 

반응형
Posted by newind2000