トップへ
田村研究室

プログラミング技法とデータ構造

Computer Programming and Data Structures

2011
10/6

第3回 二次元配列(画像データ)

二次元配列

前回の配列を拡張し,二次元にしたものが二次元配列である.配列のインデックス(添字)を二つ使用して,table[3][4]などのように表現する.

実際のメモリは一次元のアドレスのため,この二次元配列の変数の要素は,table[0][0],table[0][1],table[0][2],,,table[1][0],table[1][1],,,,table[2][3]などのように順瓶に格納される.注意すべきは右側のインデックスの数字の方が連続しており,左側のインデックスは,右側のインデックスの数字が一通り巡った後で繰り上がるようにして一つ進む.

実際のメモリ上の格納ではなく,頭の中でイメージする場合には,方眼紙のように縦横に並んだ数字のイメージを持てばよい.右側のインデックスが横(X方向)で,左側のインデックスが縦(Y方向)を示すとして考えることが多い.

画像データへの応用

二次元のデータとして代表的なものが画像データである.工学基礎実験Iのテーマで行った画像処理実験を思い出して欲しい.表計算ソフトに表の形に展開した画像データを加工する実験を行ったはずである.あれはまさしく二次元配列のデータそのものといえる.

画像を扱うサンプルプログラムの例

WindowsのBMP形式のファイルを読み書きするサンプルプログラム例を示す.

#include <stdio.h>
#include <stdlib.h>
//#include <process.h>

#define Y_SIZE 512	// 処理できる最大画像
#define X_SIZE 512

// BMPファイルのフォーマットに従って用意した変数
typedef unsigned short WORD;
//typedef unsigned long DWORD;
typedef unsigned int DWORD;
WORD  bfType;
DWORD bfSize;
WORD  bfReserved1,
      bfReserved2;
DWORD bfOffBits;
DWORD biSize, 
      biWidth, biHeight;
WORD  biPlanes,
      biBitCount;
DWORD biCompression,       
      biSizeImage,
      biXPelsPerMeter,
      biYPelsPerMeter,
      biClrUsed, 
      biClrImportant;

unsigned char image_in[Y_SIZE][X_SIZE][3];	// 入力カラー画像配列
unsigned char image_out[Y_SIZE][X_SIZE][3];	//出力カラー画像配列
unsigned char image_bw[Y_SIZE][X_SIZE];		//濃淡画像配列
int width,height;                               //読み込んだ画像の幅と高さ

//********************************************
//   24Bitビットマップファイル読み込み       *
//********************************************
void readBMP(
		char *filename,							// BMPファイル名
		unsigned char image[Y_SIZE][X_SIZE][3]	// 24ビットRGB画像配列 
		    )
{
	FILE *fp;
	int i, j, k;
	
	// ファイルオープン 
	if ((fp = fopen(filename, "rb"))==NULL) {
	//visual studioでは次のように書き換え
	//if(fopen_s(&fp, filename, "rb") != 0) {
		printf("readBmp: Open error!\n");
		exit(1);
	}
	printf("input file : %s\n", filename);

	// ヘッダー情報読み込む
	fread(&bfType, sizeof(bfType), 1, fp);
	fread(&bfSize, sizeof(bfSize), 1, fp);
	fread(&bfReserved1, sizeof(bfReserved1), 1, fp);
	fread(&bfReserved2, sizeof(bfReserved2), 1, fp);
	fread(&bfOffBits, sizeof(bfOffBits), 1, fp);
	fread(&biSize, sizeof(biSize), 1, fp);
	fread(&biWidth, sizeof(biWidth), 1, fp);
	fread(&biHeight, sizeof(biHeight), 1, fp);
	fread(&biPlanes, sizeof(biPlanes), 1, fp);
	fread(&biBitCount, sizeof(biBitCount), 1, fp);
	fread(&biCompression, sizeof(biCompression), 1, fp);
	fread(&biSizeImage, sizeof(biSizeImage), 1, fp);
	fread(&biXPelsPerMeter, sizeof(biXPelsPerMeter), 1, fp);
	fread(&biYPelsPerMeter, sizeof(biYPelsPerMeter), 1, fp);
	fread(&biClrUsed, sizeof(biClrUsed), 1, fp);
	fread(&biClrImportant, sizeof(biClrImportant), 1, fp);
	// RGB画像データ読み込む
	for (i=0; i<(int)biHeight; i++)
	for (j=0; j<(int)biWidth; j++) {
		for (k=0; k<3; k++) {
			fread(&image[biHeight-i-1][j][2-k], 1, 1, fp);
		}
	}
	
	fclose(fp);
	width=(int)biWidth;
	height=(int)biHeight;
}


//******************************************************
//   24ビット-ビットマップデータをBMPファイルに出力    *
//******************************************************
void writeBMP(
		unsigned char image[Y_SIZE][X_SIZE][3],
		char *filename                         )
{
	FILE *fp;
	int i, j, k;
	
	// ファイルオープン 
	if ((fp = fopen(filename, "wb"))==NULL) {
	//visual studioでは次のように書き換え
	//if(fopen_s(&fp, filename, "wb") != 0) {
		printf("writeBmp: Open error!\n");
		exit(1);
	}
	printf("output file : %s\n", filename);

	// ヘッダー情報 
	fwrite(&bfType, sizeof(bfType), 1, fp);
	fwrite(&bfSize, sizeof(bfSize), 1, fp);
	fwrite(&bfReserved1, sizeof(bfReserved1), 1, fp);
	fwrite(&bfReserved2, sizeof(bfReserved2), 1, fp);
	fwrite(&bfOffBits, sizeof(bfOffBits), 1, fp);

	fwrite(&biSize, sizeof(biSize), 1, fp);
	fwrite(&biWidth, sizeof(biWidth), 1, fp);
	fwrite(&biHeight, sizeof(biHeight), 1, fp);
	fwrite(&biPlanes, sizeof(biPlanes), 1, fp);
	fwrite(&biBitCount, sizeof(biBitCount), 1, fp);
	fwrite(&biCompression, sizeof(biCompression), 1, fp);
	fwrite(&biSizeImage, sizeof(biSizeImage), 1, fp);
	fwrite(&biXPelsPerMeter, sizeof(biXPelsPerMeter), 1, fp);
	fwrite(&biYPelsPerMeter, sizeof(biYPelsPerMeter), 1, fp);
	fwrite(&biClrUsed, sizeof(biClrUsed), 1, fp);
	fwrite(&biClrImportant, sizeof(biClrImportant), 1, fp);

	// ビットマップデータ 
	for (i=0; i<(int)biHeight; i++)
	for (j=0; j<(int)biWidth; j++) {
		for (k=0; k<3; k++) {
			fwrite(&image[biHeight-i-1][j][2-k], 1, 1, fp);
		}
	}
	
	fclose(fp);
}


void main(void)
{
	int x,y;

	readBMP("input.bmp", image_in);	  // 画像の入力,RGB24ビットカラーBMP画像を配列に格納

	for(y=0;y<height;y++)
		for(x=0;x<width;x++){
			image_out[y][x][0]=image_in[y][x][1];
			image_out[y][x][1]=image_in[y][x][2];
			image_out[y][x][2]=image_in[y][x][0];
		}

	writeBMP(image_out, "output.bmp");		// RGBを入れ替えた(色調変化)画像の出力
}