티스토리 뷰
BMP 파일포맷은 압축을 수행하지 않으며 헤드가 있는 여러 형식의 파일 중 구조가 가장 간단하다.
· 파일헤드(BITMAPFILEHEADER)
· 영상헤드(BITMAPINFOHEADER)
· 팔레트정보(RGBQUAD)
· 영상데이터(거꾸로 들어있음)
비트맵 파일에 대한 정보 (파일헤드)
- '파일자체' 의 정보를 저장하고 있는 구조체로써 다음과 같이 미리 정의가 되어 있다.
- 사용자는 단지 구조체 변수를 선언해서 사용만 하면 된다.
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 'BM' 이라는 값을 저장함
DWORD bfSize; // 바이트 단위로 전체파일 크기
WORD bfReserved1; // 예약된 변수
WORD bfReserved2; // 예약된 변수
DWORD bfOffBits; // 영상데이터 위치까지의 거리
} BITMAPFILEHEADER;
오픈한 파일이 비트맵 파일인지 아닌지 확인하기 위한 변수가 bfType 이다. BMP 파일의 처음 두 바이트는 항상 "BM" 문자가 저장되어 있다.
bfOffBits 는 파일 시작부분에서 실제 영상데이터가 존재하는 위치까지 바이트 단위의 거리를 나타낸다. 오프셋 (offset) 이라고 한다.
WORD 는 2바이트 (unsigned short), DWORD 는 4 바이트 (unsigned long) 변수를 나타낸다.
'영상 자체' 에 대한 정보 (영상헤드)
- 비트맵 영상에 대한 크기나 흑백, 컬러 정보, 팔레트 크기 정보 등을 저장하기 위하여 파일헤드 바로 다음에 위치하는 구조체 변수이다.
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; // 이 구조체의 크기
LONG biWidth; // 픽셀단위로 영상의 폭
LONG biHeight; // 영상의 높이
WORD biplanes; // 비트 플레인 수 (항상 1)
WORD biBitCount; // 픽셀당 비트수 (컬러, 흑백 구별)
DWORD biCompression; // 압축유무
DWORD biSizeImage; // 영상의 크기 (바이트 단위)
LONG biXPelsPerMeter; // 가로 해상도
LONG biYPelsPerMeter; // 세로 해상도
DWORD biClrUsed; // 실제 사용 색상 수
DWORD biClrImportant; // 중요한 색상 인덱스
} BITMAPINFOHEADER;
이 구조체에서 중요한 정보는 영상화일의 크기를 나타내는 두 변수 biHeight 와 biWidth,
흑백인지 컬러인지를 나타내는 biBitCount 변수, 팔레트의 크기를 나타내는 biCirUsed 변수 등이다.
biBitCount 변수가 8 이면 흑백영상이거나 2^8 = 256 개의 컬러수를 사용하는 컬러영상,
24 라면 트루컬러 영상, 16 이면 2^16 개의 컬러수를 사용하는 영상이다.
팔레트
- 팔레트는 인덱스에 의한 컬러값을 저장하기 위한 구조체이다. 이 구조체를 사용하여 팔레트의 수 만큼 배열을 할당하여 저장한다.
- 256 컬러모드의 영상은 팔레트배열 크기가 256 개, 16 비트 컬러 영상은 팔레트 크기가 2^16 개이다. biClrUsed 변수를 참조하면 된다.
- 흑백영상의 경우 팔레트는 256 개이며, 트루컬러의 경우는 인덱스 저장이 아니라 데이터값을 직접 저장하므로 팔레트가 없다.
typedef struct tagRGBQUAD
{
BYTE rgbBlue; // B 성분 (파란색)
BYTE rgbGreen; // G 성분 (녹색)
BYTE rgbRed; // R 성분 (빨간색)
BYTE rgbReserved1; // 예약된 변수
} RGBQUAD;
DIB 사용시 주의점
- 실제로 비트맵 영상이 저장될 때는 이미지가 거꾸로 저장되어 있다.
- 따라서, 비트맵에서 영상데이터를 나중에 영상처리를 위해 사용할 배열로 다시 저장할 때는 거꾸로 반전시켜 저장해주면 된다.
for (i = 0; i< biHeight; i++) {
for (j = 0; j< biWidth; j++) {
GrayImg[ i * biWidth + j ] = lpMem[ ( biHeight - i - 1 ) * rwsize + j ]
}
}
BMP 에서 읽어들인 영상버퍼 lpMem 에 있는 영상데이터를 나중에 사용할 임의의 배열 GrayImg 로 복사하는 코드이다.
이미지의 상하가 서로 반전되어 치환되고 있음을 알 수 있다. "rwsize"변수는 아래에서 설명한다.
영상 가로길이는 4바이트의 배수
- 비트맵은 메모리 저장시, 가로줄의 크기는 항상 4 바이트의 배수가 되어야 한다.
- 실제 사용하는 영상의 가로길이는 4 바이트의 배수가 아닐 수 있으므로 이럴 경우는 4 의 배수바이트로 바꾸어 저장한다.
- 예를 들어 지금 BMP 로 저장할 흑백영상 데이터의 실제 크기가 78 x 60 이라면 가로픽셀 78 은 78 byte 이고,
4 의 배수가 아니므로 80 바이트로 만들고 나머지 두 바이트는 아무 값이나 넣어준다.
- 실제 저장되는 메모리는 80 x 60 픽셀의 크기가 된다.
- rwsize 변수는 BITMAPINFOHEADER 구조체의 biWidth 와 biBitCount 값을 사용하여 4 바이트의 배수로 만든다.
#define WIDTHBYTES(bits) ((bits + 31) / 32 * 4) // 4 바이트 배수로 변환
호출시: int rwsize = WIDTHBYTES(biBitCount * biWidth);