背景
画像処理100本ノックが面白そうなのでやってみることにしました。
基本的には配列操作しかしないだろうし、不慣れなOpenCVでやるよりも自分が使いやすいものを使いたい、ということで簡単な画像入出力クラスを作ってみました。
PPM形式
作るのが簡単なのでPPM形式の画像を扱うことにします。PPM形式の画像は非常に単純な構造をしています。簡単なので説明は省略します。
コード
100本ノックの画像はJPEGで与えられているので、ImageJを使ってPPMに変換します。PPM形式の仕様を完全に満たすのは面倒なので、ここではImageJでの読み書きに問題がない範囲で実装しました。なので、任意のPPM画像を読み込めるわけではないことに注意が必要です。また、エラーチェックも省略しています。
#include <iostream>
#include <stdio.h>
class PPM
{
private:
int width;
int height;
int* R;
int* G;
int* B;
public:
PPM(int width, int height)
{
this->width = width;
this->height = height;
R = new int[width * height];
G = new int[width * height];
B = new int[width * height];
}
PPM(const char* filename)
{
FILE* fp = fopen(filename, "rb");
char tmp[256];
fscanf(fp, "%s\n", tmp);
if (fgetc(fp) == '#')//コメントありの場合
{
fseek(fp, -1, SEEK_CUR);
while (fgetc(fp) != '\n');//読み飛ばす
}
else fseek(fp, -1, SEEK_CUR);
fscanf(fp, "%d %d\n", &width,&height);
fscanf(fp, "%s\n", tmp);
R = new int[width * height];
G = new int[width * height];
B = new int[width * height];
for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++)
{
R[i + width * j] = fgetc(fp);
G[i + width * j] = fgetc(fp);
B[i + width * j] = fgetc(fp);
}
fclose(fp);
}
int Get_width() const
{
return width;
}
int Get_height() const
{
return height;
}
int &operator()(int i, int j, char rgb)
{
if(rgb=='r') return R[i+width*j];
if (rgb == 'g') return G[i + width * j];
if (rgb == 'b') return B[i + width * j];
}
void Flush(const char *filename)
{
FILE* fp = fopen(filename, "wb");
fprintf(fp, "P6\n");
fprintf(fp, "%d %d\n", width, height);
fprintf(fp, "255\n");
for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++)
{
fputc(R[i + width * j], fp);
fputc(G[i + width * j], fp);
fputc(B[i + width * j], fp);
}
fclose(fp);
}
~PPM()
{
delete[] R;
delete[] G;
delete[] B;
}
};
int main()
{
PPM ppm("imori.pnm");
int width = ppm.Get_width();
int height = ppm.Get_height();
PPM ppm2(width, height);
for(int j=0; j<height; j++)
for (int i = 0; i < width; i++)
{
ppm2(i, j, 'r') = ppm(i, j, 'r');
ppm2(i, j, 'g') = ppm(i, j, 'g');
ppm2(i, j, 'b') = ppm(i, j, 'b');
}
ppm2.Flush("iout.ppm");
return 0;
}
問題があれば随時修正予定です。