0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ライブラリ無しで画像生成

Last updated at Posted at 2024-11-02

簡単そうだけど、OpenCVを使ったりbmpファイルのバイナリをいじったりと、地味にめんどくさい画像生成。ここではコンソールに文字を書くか、テキストファイルを書き込む機能さえあればどんな言語でも作れる画像ファイルを紹介する。CでもPythonでもなんでも。なんならScratchでも。
さっさと画像を生成して結果をチェックしたいときなんかにお勧め。

PPM画像ファイル

Netpbmという団体が開発している画像フォーマット。これはバイナリを書くのではなく、ASCII文字だけで表現するからコンソールさえあれば作れちゃう。

書き方

#はコメント。

P3 #PPMファイルであることを示す
2 3 #横2ピクセル、縦3ピクセル
255 #R,G,Bそれぞれ0から255までで示す
#ここから下、左上から右下に、改行じゃなくてスペースだけでもいいっぽい。
0 255 255
255 0 0
255 0 255
0 255 0
255 0 0
0 0 0

ピクセルはこの順番で、R,G,Bの順でスペース、改行で区切りながら書く。
Untitled.png

コードでの実装例

超適当、例えばimage.pyというpythonコードがあったとして、

print("P3")
print("2 3")
print("255")
print("0 255 255")
print("255 0 0")
print("255 0 255")
print("0 255 0")
print("255 0 0")
print("0 0 0")

こうあったとしよう。

コンソールでファイルの書き込み

py image.py > image.ppm
> file.txt

これを語尾につけることで、テキストファイルにコンソールに出力された内容を書き込むことができる。これはプログラミング言語関係なく、ターミナル共通の機能。
これで同じフォルダ上にimage.ppmというファイルが生成される。メモ帳で中身を確認するといいだろう。

PowerShellで実行する際、そのままだとUTF-16で書き込まれてしまうので正常に読み込めるファイルが生成されない。

コマンドプロンプトで実行するか、以下の記事を参考にpowershellでUTF-8で出力されるようにしよう。
もちろん、プログラミング言語にあるファイル書き込み機能を使っても問題ない。
https://zenn.dev/koh1nigeeee/articles/854c04fafa9c01

ファイル読み取り

生成したはいいけど、画像として読み取る方法が今のところない。フォトで読み取れるわけもなく。
実際古いフォーマットだから読み取れるソフトはあまり多くない。でも頼りになる無料ソフト二つ、FFmpegGIMPが対応しているから安心。
GIMPはDDだけし重くて本末転倒なので割愛、FFmpegで読み込む方法を紹介する。
一応FFmpegのインストール方法すら分からない人用にこんな記事を置いていく。

画像を確認するにはFFplayを使う。簡単だね。

ffplay -i image.ppm -vf "scale='300:-1':flags=neighbor"

小さい画像でもぼやけることなく画像をくっきり確認するためのフラグがついている。ウィンドウは長さ300にアップスケールされる。
image.png
こんな風に見えるはず。

ファイル変換

PNGにでも変換しよう。超簡単だね。

ffmpeg -i image.ppm image.png

透明度を追加

PPM+PGM(グレースケール画像)の組み合わせで画像に透明度を追加する。そのまま読み込める画像ではなくなっちゃうけどね。
同じくPGMもNetPBMの画像ファイルの一種。大まかな流れは同じ。

P2 # PGMファイルであることを示す
2 3
255 #グレースケール、明るさ0~255
0 #同じく改行じゃなくてスペースだけでもいいっぽい。
50
50
100
200
0

これもFFplayで確認できる。
image.png
PPMファイルに色を記録し、PGMファイルに透明度をグレースケールとして記録する。そして、次のFFmpegコマンドを実行して透明度付きのPNGファイルを生成する。

ffmpeg -i color.ppm -i alpha.pgm -filter_complex "[0:v][1:v]alphamerge" out.png

実行して、拡大してほかの画像の上に重ねてみた。左の物体がそれ。いいね。
aha.png

補足、実装例

こんな風に?

C++での実装例
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

void alpha(string *output, int Width, int Height);
void color(string *output, int Width, int Height);
int main()
{
    const int width = 200;
    const int height = 200;

    string col;
    string alp;
    //ポインタでからの文字列を渡してfstreamで書き出し
    color(&col, width, height);
    alpha(&alp, width, height);
    ofstream colorfile("color.ppm");
    colorfile << col;
    colorfile.close();
    ofstream alphafile("alpha.pgm");
    alphafile << alp;
    alphafile.close();
    return 0;
}
//PPMファイルの文字列を生成
void color(string *output, int Width, int Height)
{
    *output = "P3\n" + to_string(Width) + " " + to_string(Height) + "\n255";
    for (int i = 0; i < Height; i++)
    {
        for (int ii = 0; ii < Width; ii++)
        {
            *output += "\n" + to_string(i % 256) + " " + to_string(ii % 256) + " " + to_string((i + 128) % 256);
        }
    }
}
//PGMファイルの文字列を生成
void alpha(string *output, int Width, int Height)
{
    *output = "P2\n" + to_string(Width) + " " + to_string(Height) + "\n255\n";
    for (int i = 0; i < Height; i++)
    {
        for (int ii = 0; ii < Width; ii++)
        {
            *output += to_string((i + ii) % 256) + "\n";
        }
        *output += "\n";
    }
}

こんな画像になった。qiitaにアップロードしたら透明度が失われてしまう。。。
out.png

libavutilとかを使えばコードだけで完結しそうだけどそこまでしなくてもいいでしょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?