画像をいじる下準備
早速画像処理開始、、、と言いたいところですが、少し下準備が必要であると考えました。
個人的な方針としては画像の各ピクセルの値を一度配列に格納してからいじるようにしたいので、まずは画像を読み込んで各ピクセルの値を配列に格納して、それを新たに出力するというプログラムを雛形として用意しようと思います。
そもそもppm形式の画像とは
ppm形式という言葉を僕は最近になって知りました。
そこで一応ppm形式について軽く書き留めておこうと思います。
ppm形式の画像をテキストエディタで見てみると、上記のような構造になっています。
ppm形式はRBGでフルカラーを表現できる'pixmap'です。
最初の2バイトがマジックナンバーとなっており、ファイル形式と、データがテキストかバイナリかを表します。
前回の記事でjpg形式からppm形式への変換をweb上のサービスを利用して行いましたが、webサービスではP6の形式に変換されてしまいました。
僕はバイナリではなくテキストの形式でピクセルをいじりたかったのでP6形式のppm画像ではなくP3形式のppm画像を入手する必要がありました。
そこで、今回はImageMagickというアプリケーションを利用してP3形式のppm画像に変換しました。
ImageMagickはコマンドライン上で操作するアプリケーションです。
brew install imagemagick
上記のコマンドでインストールします(Mac)。
インストールが終了したら、以下のコマンドで実際に画像を変換していきます。
convert -compress none imori.jpg imori.ppm
これだけで完了です。
雛形プログラムの作成
ここからはいよいよC言語でプログラムを書いていきます。
【注意】筆者のコードはいつもクソコードなのでご了承ください。コードの書き方や使用する関数の選択など、これからの記事も含めて何かアドバイスをいただけると嬉しいです!
以下が、今回のプログラムになります。
# include <stdio.h>
# define N 256
int main(void) {
FILE *infp;
FILE *outfp;
char magic[64];
char str[256];
int width;
int height;
int max;
char readline[N] = {'\0'};
infp = fopen("../imori.ppm", "r");
//magic
fgets(magic, N, infp);
//width, height
int num[4];
for(int i = 0; i < 2; i ++){
fscanf(infp, "%d", &num[i]);
}
width = num[0];
height = num[1];
//max
fscanf(infp, "%d", &max);
//image
int image[height][width*3];
for(int i = 0; i < height; i ++){
for(int j = 0; j < width*3; j ++){
fscanf(infp, "%d", &image[i][j]);
}
}
outfp = fopen("imori.ppm", "w");
fprintf(outfp, "%s", magic);
fprintf(outfp, "%d ", width);
fprintf(outfp, "%d\n", height);
fprintf(outfp, "%d\n", max);
for(int i = 0; i < height; i ++){
for(int j = 0; j < width*3; j ++){
fprintf(outfp, "%d ", image[i][j]);
}
fprintf(outfp, "\n");
}
return 0;
}
割と本当にクソコードです。
もう少し綺麗に書ける部分がありそうですが、とりあえず気にしません。
プログラムの内容
地道に1行ずつ読んで変数に格納するだけです。
入出力の関数については、これらを選択した理由は特にありませんが、あまり推奨されないものもあるようで何かアドバイスありましたらご教授お願いします。
メインとなるピクセルの値は2次元配列に格納しています。
触れなくても良いかと思いますが、画像のサイズはheight × widthですが、ppm形式の画像は各ピクセルの色をRBGで表しますので、実際に格納すべき値の数は縦がheight、横がwidth*3となります。
このプログラムではピクセルの値はいじっていないので入力した画像と同じ画像がカレントディレクトリに出力されます。
さて、これで準備はできたので次からいよいよ100本ノック、解いていきます!