画像処理入門
~画像(Bitmap)の入出力(2)~
―――――――――――――――――――――――――――――――――
画像処理のために最初にすること、画像の読み込みと書き込みについてです。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ここではカラーBitmap画像を読み込み、モノクロに変換後にBitmap画像を出力するプログラムを紹介します。
↓
※ Visual Studio 2008にて開発しています。
”stdafx.h”のインクルード、main関数の引数など、ご自分の開発環境に合わせてご利用ください。
#include "stdafx.h" #include <stdlib.h>
//ファイルヘッダーの構造体 typedef struct { char bfType[2]; //2 byte -> データのタイプ int bfSize; //4 byte -> ファイルのサイズ short int bfReserved1; //2 byte -> 予約 short int bfReserved2; //2 byte -> 予約 int bfOffBits; //4 byte -> 画像データ間でのオフセット } BmpFileHeader;
//情報ヘッダーの構造体 typedef struct { int biSize; //4 byte -> 情報ヘッダーのサイズ int biWidth; //4 byte -> 画像の横幅 int biHeight; //4 byte -> 画像の縦幅 short int biPlanes; //2 byte short int biBitCount; //2 byte -> 1 pixelのサイズ int biCompression; //4 byte int biSizeImage; //4 byte int biXPixPerMeter; //4 byte int biYPixPerMeter; //4 byte int biClrUsed; //4 byte int biClrImporant; //4 byte } BmpInfoHeader;
//Bitmapの構造体 typedef struct { unsigned char **r; //赤成分 unsigned char **g; //緑成分 unsigned char **b; //青成分 int width; int height; } BmpImg;
//動的メモリの確保 unsigned char **memory2Duc(int x_size, int y_size) { int i; // 制御変数 unsigned char **tmp;
if((tmp = (unsigned char **) calloc(x_size, sizeof(unsigned char *))) == NULL) { fprintf(stderr,"Err memory2Duc\n"); exit(1); }
for(i = 0; i < x_size; i++) if((tmp[i] = (unsigned char *) calloc(y_size, sizeof(unsigned char))) == NULL) { fprintf(stderr,"Err memory2Duc\n"); exit(1); } return tmp; } //動的メモリの開放 void Free2Duc(unsigned char **tmp,int col) { int i; for(i=0;i<col;i++) free(tmp[i]); free(tmp); }
//Bitmapの読み込み BmpImg BmpRead(char *fname) { BmpImg img; int x,y; unsigned char **r,**g,**b; FILE *fp=NULL; BmpFileHeader filehead; BmpInfoHeader infohead;
//ビットマップファイルオープン fp = fopen(fname,"rb"); if(fp==NULL){ fprintf(stderr,"can not open : %s\n",fname); exit(1); }
//ファイルヘッダ読み込み fread(&filehead.bfType,2,1,fp); fread(&filehead.bfSize,4,1,fp); fread(&filehead.bfReserved1,2,1,fp); fread(&filehead.bfReserved2,2,1,fp); fread(&filehead.bfOffBits,4,1,fp);
//Bitmapでなければ終了 if(filehead.bfType[0]!='B' || filehead.bfType[1]!='M') { fprintf(stderr,"This file is not bitmap format.\n"); exit(2); }
//情報ヘッダ読み込み fread(&infohead.biSize,4,1,fp); fread(&infohead.biWidth,4,1,fp); fread(&infohead.biHeight,4,1,fp); fread(&infohead.biPlanes,2,1,fp); fread(&infohead.biBitCount,2,1,fp); fread(&infohead.biCompression,4,1,fp); fread(&infohead.biSizeImage,4,1,fp); fread(&infohead.biXPixPerMeter,4,1,fp); fread(&infohead.biYPixPerMeter,4,1,fp); fread(&infohead.biClrUsed,4,1,fp); fread(&infohead.biClrImporant,4,1,fp);
//24bitでなければ終了 if(infohead.biBitCount!=24) { fprintf(stderr,"This file is not 24 bit-bitmap format.\n"); exit(2); }
//配列を準備する r = memory2Duc(infohead.biHeight, infohead.biWidth); g = memory2Duc(infohead.biHeight, infohead.biWidth); b = memory2Duc(infohead.biHeight, infohead.biWidth);
//配列に画像データを格納する for(y=infohead.biHeight-1; y>=0; y--) { for(x=0; x<infohead.biWidth; x++) { fread(&b[y][x],1,1,fp); fread(&g[y][x],1,1,fp); fread(&r[y][x],1,1,fp); } fseek( fp, infohead.biWidth%4, SEEK_CUR); }
//BmpImgへのデータの格納 img.r = r; img.g = g; img.b = b; img.width = infohead.biWidth; img.height = infohead.biHeight;
fclose(fp);
//BmpImgデータを返す return img; }
//Bitmapの書き込み void BmpWrite(char *fname, BmpImg img) { int i,x,y; FILE *fp = NULL; BmpFileHeader filehead; BmpInfoHeader infohead; int linesize; int remainder; unsigned char zero = 0;
remainder = img.width%4;
//ビットマップファイルオープン fp = fopen(fname,"wb"); if(fp==NULL){ fprintf(stderr,"can not open : %s\n",fname); exit(1); } //ファイルヘッダ書き込み filehead.bfType[0] = 'B'; filehead.bfType[1] = 'M'; filehead.bfSize = img.height * (img.width * 3+remainder) + 14 + 40; filehead.bfReserved1 = 0; filehead.bfReserved2 = 0; filehead.bfOffBits = 14 + 40;
fwrite(&filehead.bfType[0],1,1,fp); fwrite(&filehead.bfType[1],1,1,fp); fwrite(&filehead.bfSize,4,1,fp); fwrite(&filehead.bfReserved1,2,1,fp); fwrite(&filehead.bfReserved2,2,1,fp); fwrite(&filehead.bfOffBits,4,1,fp);
//情報ヘッダ書き込み infohead.biSize = 40; infohead.biWidth = img.width; infohead.biHeight = img.height; infohead.biPlanes = 1; infohead.biBitCount = 24; infohead.biCompression = 0; infohead.biSizeImage = filehead.bfSize - 54; infohead.biXPixPerMeter = 3780; infohead.biYPixPerMeter = 3780; infohead.biClrUsed = 0; infohead.biClrImporant = 0;
fwrite(&infohead.biSize,4,1,fp); fwrite(&infohead.biWidth,4,1,fp); fwrite(&infohead.biHeight,4,1,fp); fwrite(&infohead.biPlanes,2,1,fp); fwrite(&infohead.biBitCount,2,1,fp); fwrite(&infohead.biCompression,4,1,fp); fwrite(&infohead.biSizeImage,4,1,fp); fwrite(&infohead.biXPixPerMeter,4,1,fp); fwrite(&infohead.biYPixPerMeter,4,1,fp); fwrite(&infohead.biClrUsed,4,1,fp); fwrite(&infohead.biClrImporant,4,1,fp);
//画像データ書き込み for(y=img.height-1; y>=0; y--) { for(x=0; x<img.width; x++) { fwrite(&img.b[y][x],1,1,fp); fwrite(&img.g[y][x],1,1,fp); fwrite(&img.r[y][x],1,1,fp); } for(i=0; i<remainder; i++) fwrite(&zero,1,1,fp); } fclose(fp); }
int _tmain(int argc, _TCHAR* argv[]) { int i,j; int buf; BmpImg img;
//Bitmap読み込み img = BmpRead("data.bmp"); //カラー → モノクロ変換処理 for(i=0;i<img.height;i++) for(j=0;j<img.width;j++){ buf = (int)(( img.r[i][j] + img.g[i][j] + img.b[i][j] ) / 3.0 ); img.r[i][j] = img.g[i][j] = img.b[i][j] = buf; } //Bitmap書き込み BmpWrite("data_mono.bmp",img);
return 0; }
|