2015年12月05日
C言語で24ビットBMP画像を読み込み加工する
C言語でprewittフィルタとsobelフィルタのプログラムを作ったのですがBMP画像の読み込みで四苦八苦したのでメモしておきます。
作るプログラムについて
プログラム概要としては、
24ビットBMPを読み込む
グレースケールに加工する
フィルタを適用する
画像を保存する
って感じです。特に画像の読み込みと書き込みについて書いていきます。
そもそもファイルとは
コンピュータで扱えるファイルは0と1の羅列です。それ以上でもそれ以下でもないです。これを読み込んでいきます。
24ビットBMPの構造
Windowsで扱う場合は大雑把に言うと、先頭14バイトがファイルヘッダー、その次の40バイトが情報ヘッダー、そして残りが画素の情報です。実際に加工を施すのはファイルヘッダーと情報ヘッダーを除いた画素の情報だけなので、BMPを読み込むときはこの三つを分けておく必要があります。BMPの構造について詳しくはググってください。ここでは省略します。
BMP構造
プログラム
プログラムについて説明していきます。このプログラムは実行ファイルがあるフォルダ内の「in.bmp」というファイル名の24bitBMPを読み込んで、同じフォルダ内に「out.bmp」として出力します。加工などはしていないので全く同じ画像が出力されます。24bitBMPはペイントなどで画像を開いて「名前を付けて保存」でファイルに24ビットBMPを選択すれば簡単に作れます。なおこのプログラムではサイズは512×512までです。
必要なヘッダファイルをインクルードします。
#include
#include
main関数です。
int main(void){
必要な変数を宣言しています。画素情報は0~255なので必ずunsigned charにします。charでは-128~127の範囲となるので0~255のRGB情報をうまく格納できません。
unsigned char img[512][512][3]; //読み込んだ画素情報を保存する
unsigned char BitMapFileHeader[14]; //BMPのファイルヘッダーを保存する
unsigned int biSize; //BMPのサイズを保存する
int biWidth; //BMPの幅を保存する
int biHeight; //BMPの高さを保存する
unsigned char BitMapInfoHeader[28]; //上記3つ以外のBMPの情報ヘッダーを保存する
int i,j,c; //for文用
FILE *fp; //ファイルポインタ
ファイルを開きます。rbは読み込みモードです。
fp = fopen("in.bmp","rb");
ファイルの読み込みに成功したらfreadを使用してファイルの情報を変数に読み込んでいきます。freadは第一引数の変数に第二引数のサイズの第三引数の数だけ第四引数から読み込んでいきます。第一引数の型のサイズと第二引数のサイズは一致している必要があります。たとえば最初のfreadではBMPファイルの先頭にあるファイルヘッダーを読み込んでいるのでsizeof(char)を14個分、すなわちファイルヘッダー14バイトをファイルを開いたfpから読み込んでいます。freadは読み込みが完了したら注目点を次に移します。次にfreadを使うときはファイルの15バイト目から読み込みます。
残っているのは情報ヘッダーと画素情報なのでまずは情報ヘッダーを読み込みます。情報ヘッダーの先頭にはint型でBMPファイルのサイズの情報です。sizeof(int)の1個分読み込んで変数に保存します。環境にもよりますがsizeof(int)、すなわち4バイトを1個分読み込んだので次はBMPファイルの19バイト目から読み込みます。次にはint型でBMPの幅と高さの情報です。それぞれ同様にして読み込みます。情報ヘッダー40バイトのうち4バイトのint型3個分読み込んだので残りは28バイトですが今回はあとの部分は特に必要ないのでまとめて読み込みます。sizeof(char)、すなわち1バイトの28個分28バイトです。
以上でヘッダー情報の読み込みが終了したので次は画素情報の読み込みに移ります。情報ヘッダーの読み込みで取得した幅と高さの分だけ画素情報をRGBのそれぞれについて3重のfor文で読み込み最初に宣言した配列に格納していきます。
すべての読み込みが終了したらfcloseでファイルを閉じます。
以下ファイルの読み込み部分のソースです。
fread(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを読み込む
fread(&biSize,sizeof(int),1,fp); //情報ヘッダーにあるサイズを読み込む
fread(&biWidth,sizeof(int),1,fp); //情報ヘッダーにある幅を保存
fread(&biHeight,sizeof(int),1,fp); //情報ヘッダーにある高さを保存
fread(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを保存
for(i = 0; i < biWidth; i++){ //0から幅まで
for(j = 0; j < biHeight; j++){ //0から高さまで
for(c = 0; c < 3; c++){ //RGBのそれぞれ
fread(&img[i][j][c],sizeof(char),1,fp); //画素の情報を読み込んで保存する
}
}
}
fclose(fp); //ファイルを閉じる
これで読み込みが完了しました。あとは読み込んだ画素情報にフィルタをかけるなりグレースケール化するなり特定の色だけを消すなり自由自在です。
加工が完了したら今度は加工後の画像を新しいファイルに保存します。ファイルの保存はfreadがfwriteに代わるだけで読み込みとほとんど同じです。
wb書き込みモードでファイルを開きます。
fp = fopen("out.bmp","wb");
読み込みのときに読み込んで変数に保存した情報を書き込んでいきます。読み込みのときと同じ順番、ファイルヘッダー、情報ヘッダー、画素情報の順です。
fwrite(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを書き込む
fwrite(&biSize,sizeof(int),1,fp); //情報ヘッダーへファイルサイズを書き込む
fwrite(&biWidth,sizeof(int),1,fp); //情報ヘッダーへ幅を書き込む
fwrite(&biHeight,sizeof(int),1,fp); //情報ヘッダーへ高さを書き込む
fwrite(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを書き込む
for(i = 0; i < biWidth; i++){ //0から幅まで
for(j = 0; j < biHeight; j++){ //0から高さまで
for(c = 0; c < 3; c++){ //RGBのそれぞれ
fwrite(&img[i][j][c],sizeof(char),1,fp); //画素の情報を保存する
}
}
}
fclose(fp); //ファイルを閉じる
}
プログラムは以上です。コピーして保存し、コンパイルし、in.bmpを同じフォルダ内に設置して実行するとファイル名out.bmpの全く同じ画像を同じフォルダ内に出力してくれると思います。
プログラムの全文です。
#include<stdio.h>
#include<math.h>
int main(void){
unsigned char img[512][512][3]; //読み込んだ画素情報を保存する
unsigned char BitMapFileHeader[14]; //BMPのファイルヘッダーを保存する
unsigned int biSize; //BMPのサイズを保存する
int biWidth; //BMPの幅を保存する
int biHeight; //BMPの高さを保存する
unsigned char BitMapInfoHeader[28]; //上記3つ以外のBMPの情報ヘッダーを保存する
int i,j,c; //for文用
FILE *fp; //ファイルポインタ
fp = fopen("in.bmp","rb");
fread(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを読み込む
fread(&biSize,sizeof(int),1,fp); //情報ヘッダーにあるサイズを読み込む
fread(&biWidth,sizeof(int),1,fp); //情報ヘッダーにある幅を保存
fread(&biHeight,sizeof(int),1,fp); //情報ヘッダーにある高さを保存
fread(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを保存
for(i = 0; i < biWidth; i++){ //0から幅まで
for(j = 0; j < biHeight; j++){ //0から高さまで
for(c = 0; c < 3; c++){ //RGBのそれぞれ
fread(&img[i][j][c],sizeof(char),1,fp); //画素の情報を読み込んで保存する
}
}
}
fclose(fp); //ファイルを閉じる
fp = fopen("out.bmp","wb"); //パスのファイルへ書き込み
fwrite(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを書き込む
fwrite(&biSize,sizeof(int),1,fp); //情報ヘッダーへファイルサイズを書き込む
fwrite(&biWidth,sizeof(int),1,fp); //情報ヘッダーへ幅を書き込む
fwrite(&biHeight,sizeof(int),1,fp); //情報ヘッダーへ高さを書き込む
fwrite(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを書き込む
for(i = 0; i < biWidth; i++){ //0から幅まで
for(j = 0; j < biHeight; j++){ //0から高さまで
for(c = 0; c < 3; c++){ //RGBのそれぞれ
fwrite(&img[i][j][c],sizeof(char),1,fp); //画素の情報を保存する
}
}
}
fclose(fp); //ファイルを閉じる
}
画像のグレースケール加工とフィルタ加工はまた今度書きます。
ずいぶんほったらかしたけど書いたよ!
prewittフィルタとsobelフィルタのC言語による実装
作るプログラムについて
プログラム概要としては、
24ビットBMPを読み込む
グレースケールに加工する
フィルタを適用する
画像を保存する
って感じです。特に画像の読み込みと書き込みについて書いていきます。
そもそもファイルとは
コンピュータで扱えるファイルは0と1の羅列です。それ以上でもそれ以下でもないです。これを読み込んでいきます。
24ビットBMPの構造
Windowsで扱う場合は大雑把に言うと、先頭14バイトがファイルヘッダー、その次の40バイトが情報ヘッダー、そして残りが画素の情報です。実際に加工を施すのはファイルヘッダーと情報ヘッダーを除いた画素の情報だけなので、BMPを読み込むときはこの三つを分けておく必要があります。BMPの構造について詳しくはググってください。ここでは省略します。
BMP構造
プログラム
プログラムについて説明していきます。このプログラムは実行ファイルがあるフォルダ内の「in.bmp」というファイル名の24bitBMPを読み込んで、同じフォルダ内に「out.bmp」として出力します。加工などはしていないので全く同じ画像が出力されます。24bitBMPはペイントなどで画像を開いて「名前を付けて保存」でファイルに24ビットBMPを選択すれば簡単に作れます。なおこのプログラムではサイズは512×512までです。
必要なヘッダファイルをインクルードします。
#include
#include
main関数です。
int main(void){
必要な変数を宣言しています。画素情報は0~255なので必ずunsigned charにします。charでは-128~127の範囲となるので0~255のRGB情報をうまく格納できません。
unsigned char img[512][512][3]; //読み込んだ画素情報を保存する
unsigned char BitMapFileHeader[14]; //BMPのファイルヘッダーを保存する
unsigned int biSize; //BMPのサイズを保存する
int biWidth; //BMPの幅を保存する
int biHeight; //BMPの高さを保存する
unsigned char BitMapInfoHeader[28]; //上記3つ以外のBMPの情報ヘッダーを保存する
int i,j,c; //for文用
FILE *fp; //ファイルポインタ
ファイルを開きます。rbは読み込みモードです。
fp = fopen("in.bmp","rb");
ファイルの読み込みに成功したらfreadを使用してファイルの情報を変数に読み込んでいきます。freadは第一引数の変数に第二引数のサイズの第三引数の数だけ第四引数から読み込んでいきます。第一引数の型のサイズと第二引数のサイズは一致している必要があります。たとえば最初のfreadではBMPファイルの先頭にあるファイルヘッダーを読み込んでいるのでsizeof(char)を14個分、すなわちファイルヘッダー14バイトをファイルを開いたfpから読み込んでいます。freadは読み込みが完了したら注目点を次に移します。次にfreadを使うときはファイルの15バイト目から読み込みます。
残っているのは情報ヘッダーと画素情報なのでまずは情報ヘッダーを読み込みます。情報ヘッダーの先頭にはint型でBMPファイルのサイズの情報です。sizeof(int)の1個分読み込んで変数に保存します。環境にもよりますがsizeof(int)、すなわち4バイトを1個分読み込んだので次はBMPファイルの19バイト目から読み込みます。次にはint型でBMPの幅と高さの情報です。それぞれ同様にして読み込みます。情報ヘッダー40バイトのうち4バイトのint型3個分読み込んだので残りは28バイトですが今回はあとの部分は特に必要ないのでまとめて読み込みます。sizeof(char)、すなわち1バイトの28個分28バイトです。
以上でヘッダー情報の読み込みが終了したので次は画素情報の読み込みに移ります。情報ヘッダーの読み込みで取得した幅と高さの分だけ画素情報をRGBのそれぞれについて3重のfor文で読み込み最初に宣言した配列に格納していきます。
すべての読み込みが終了したらfcloseでファイルを閉じます。
以下ファイルの読み込み部分のソースです。
fread(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを読み込む
fread(&biSize,sizeof(int),1,fp); //情報ヘッダーにあるサイズを読み込む
fread(&biWidth,sizeof(int),1,fp); //情報ヘッダーにある幅を保存
fread(&biHeight,sizeof(int),1,fp); //情報ヘッダーにある高さを保存
fread(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを保存
for(i = 0; i < biWidth; i++){ //0から幅まで
for(j = 0; j < biHeight; j++){ //0から高さまで
for(c = 0; c < 3; c++){ //RGBのそれぞれ
fread(&img[i][j][c],sizeof(char),1,fp); //画素の情報を読み込んで保存する
}
}
}
fclose(fp); //ファイルを閉じる
これで読み込みが完了しました。あとは読み込んだ画素情報にフィルタをかけるなりグレースケール化するなり特定の色だけを消すなり自由自在です。
加工が完了したら今度は加工後の画像を新しいファイルに保存します。ファイルの保存はfreadがfwriteに代わるだけで読み込みとほとんど同じです。
wb書き込みモードでファイルを開きます。
fp = fopen("out.bmp","wb");
読み込みのときに読み込んで変数に保存した情報を書き込んでいきます。読み込みのときと同じ順番、ファイルヘッダー、情報ヘッダー、画素情報の順です。
fwrite(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを書き込む
fwrite(&biSize,sizeof(int),1,fp); //情報ヘッダーへファイルサイズを書き込む
fwrite(&biWidth,sizeof(int),1,fp); //情報ヘッダーへ幅を書き込む
fwrite(&biHeight,sizeof(int),1,fp); //情報ヘッダーへ高さを書き込む
fwrite(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを書き込む
for(i = 0; i < biWidth; i++){ //0から幅まで
for(j = 0; j < biHeight; j++){ //0から高さまで
for(c = 0; c < 3; c++){ //RGBのそれぞれ
fwrite(&img[i][j][c],sizeof(char),1,fp); //画素の情報を保存する
}
}
}
fclose(fp); //ファイルを閉じる
}
プログラムは以上です。コピーして保存し、コンパイルし、in.bmpを同じフォルダ内に設置して実行するとファイル名out.bmpの全く同じ画像を同じフォルダ内に出力してくれると思います。
プログラムの全文です。
#include<stdio.h>
#include<math.h>
int main(void){
unsigned char img[512][512][3]; //読み込んだ画素情報を保存する
unsigned char BitMapFileHeader[14]; //BMPのファイルヘッダーを保存する
unsigned int biSize; //BMPのサイズを保存する
int biWidth; //BMPの幅を保存する
int biHeight; //BMPの高さを保存する
unsigned char BitMapInfoHeader[28]; //上記3つ以外のBMPの情報ヘッダーを保存する
int i,j,c; //for文用
FILE *fp; //ファイルポインタ
fp = fopen("in.bmp","rb");
fread(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを読み込む
fread(&biSize,sizeof(int),1,fp); //情報ヘッダーにあるサイズを読み込む
fread(&biWidth,sizeof(int),1,fp); //情報ヘッダーにある幅を保存
fread(&biHeight,sizeof(int),1,fp); //情報ヘッダーにある高さを保存
fread(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを保存
for(i = 0; i < biWidth; i++){ //0から幅まで
for(j = 0; j < biHeight; j++){ //0から高さまで
for(c = 0; c < 3; c++){ //RGBのそれぞれ
fread(&img[i][j][c],sizeof(char),1,fp); //画素の情報を読み込んで保存する
}
}
}
fclose(fp); //ファイルを閉じる
fp = fopen("out.bmp","wb"); //パスのファイルへ書き込み
fwrite(&BitMapFileHeader,sizeof(char),14,fp); //ファイルヘッダーを書き込む
fwrite(&biSize,sizeof(int),1,fp); //情報ヘッダーへファイルサイズを書き込む
fwrite(&biWidth,sizeof(int),1,fp); //情報ヘッダーへ幅を書き込む
fwrite(&biHeight,sizeof(int),1,fp); //情報ヘッダーへ高さを書き込む
fwrite(&BitMapInfoHeader,sizeof(char),28,fp); //残りの情報ヘッダーを書き込む
for(i = 0; i < biWidth; i++){ //0から幅まで
for(j = 0; j < biHeight; j++){ //0から高さまで
for(c = 0; c < 3; c++){ //RGBのそれぞれ
fwrite(&img[i][j][c],sizeof(char),1,fp); //画素の情報を保存する
}
}
}
fclose(fp); //ファイルを閉じる
}
画像のグレースケール加工とフィルタ加工はまた今度書きます。
ずいぶんほったらかしたけど書いたよ!
prewittフィルタとsobelフィルタのC言語による実装
【このカテゴリーの最新記事】
-
no image
-
no image
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/4488046
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック