2022/07/17(日) [n年前の日記]
#1 [prog] stbライブラリを試用
_昨日調べて
存在を知った、C/C++で画像処理をするためのstbライブラリを少しだけ試用。
_nothings/stb: stb single-file public domain libraries for C/C++
動作確認環境は Windows10 x64 21H2 + MSYS2 + MinGW64。g++ 12.1.0。GNU Make 4.3。
今回は画像のロードとセーブを試してみたかったので、stb_image.h と stb_image_write.h をDL。メインとなるソースコードと同じ場所に置いて利用した。
_nothings/stb: stb single-file public domain libraries for C/C++
動作確認環境は Windows10 x64 21H2 + MSYS2 + MinGW64。g++ 12.1.0。GNU Make 4.3。
今回は画像のロードとセーブを試してみたかったので、stb_image.h と stb_image_write.h をDL。メインとなるソースコードと同じ場所に置いて利用した。
◎ 画像ロード。 :
stb_image.h の使用例。画像(.png)を読み込んで、画像サイズと1ピクセルあたりのバイト数を出力する。
_01_loadimage.cpp
コンパイルは以下。ここでは静的リンク(スタティックリンク)をしている。
以下で実行。画像サイズと Byte per pixel が出力された。
stb_image.h の使い方としては、最初に以下を書いておく。
_01_loadimage.cpp
// load image with stb_image.h #include <stdio.h> #define STB_IMAGE_STATIC #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage\n\t01_loadimage.exe IN.png"); } auto filename = argv[1]; unsigned char *pixels; int width; int height; int bpp; pixels = stbi_load(filename, &width, &height, &bpp, 0); printf("Image size %d x %d\n", width, height); printf("Image bpp %d\n", bpp); stbi_image_free(pixels); }
コンパイルは以下。ここでは静的リンク(スタティックリンク)をしている。
g++ 01_loadimage.cpp -o 01_loadimage.exe -static -lstdc++ -lgcc -lwinpthread
以下で実行。画像サイズと Byte per pixel が出力された。
$ ./01_loadimage.exe in.png Image size 512 x 512 Image bpp 3
stb_image.h の使い方としては、最初に以下を書いておく。
#define STB_IMAGE_STATIC #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h"
- stb_image.h を使う場合、必ず、「#define STB_IMAGE_IMPLEMENTATION」と「#include "stb_image.h"」を記述する。
- STB_IMAGE_STATIC を定義しておくと、各関数の頭に static がつく、らしい。
- stbi_load() で画像のロード。
- 画像を使い終わったら stbi_image_free() で解放する。
◎ 画像セーブ。 :
stb_image_write.h の使用例。画像(.png)を読み込んで、グレースケールに変換して、out.png というファイル名で保存する。
_02_writeimage.cpp
コンパイル。
実行。
グレースケールの画像が得られた。
stb_image_write.h の使い方としては、最初に以下を書いておく。
ちなみに、stb_image_write.h 内のコメントによると、ソースコードの量を減らすためにpng画像の圧縮率は低い状態になっているそうで。zlib関係の関数を STBIW_ZLIB_COMPRESS に定義することで圧縮率は改善できると書いてあった。もちろん、zlib を使えるようにビルドしないといかんのだろうけど。
何にせよ、stb_image.h にしろ、stb_image_write.h にしろ、比較的簡単な記述で画像のロードやセーブができる上に、静的リンクもすんなりできてしまうとは…。これは便利だなと…。
_02_writeimage.cpp
// write png image with stb_image_write.h #include <stdio.h> #define STB_IMAGE_STATIC #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #define STB_IMAGE_WRITE_STATIC #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage\n\t02_writeimage.exe IN.png"); } auto filename = argv[1]; unsigned char *pixels; int width; int height; int bpp; // load image pixels = stbi_load(filename, &width, &height, &bpp, 0); printf("Image size %d x %d\n", width, height); printf("Image bpp %d\n", bpp); for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { int idx = (y * width + x) * bpp; unsigned int r = (unsigned int)pixels[idx + 0]; unsigned int g = (unsigned int)pixels[idx + 1]; unsigned int b = (unsigned int)pixels[idx + 2]; // convert greyscale if (1) { double grey = 0.299 * (double)r + 0.587 * (double)g + 0.114 * (double)b; if (grey < 0) grey = 0; if (grey > 255) grey = 255; unsigned int ui_grey = (unsigned int)grey; pixels[idx + 0] = ui_grey; pixels[idx + 1] = ui_grey; pixels[idx + 2] = ui_grey; } } // write image if (stbi_write_png("out.png", width, height, 3, pixels, width * 3)) { printf("Save out.png\n"); } else { printf("Failure save.\n"); } stbi_image_free(pixels); }
コンパイル。
g++ 02_writeimage.cpp -o 02_writeimage.exe -static -lstdc++ -lgcc -lwinpthread
実行。
$ ./02_writeimage.exe in.png Image size 512 x 512 Image bpp 3 Save out.png
グレースケールの画像が得られた。
stb_image_write.h の使い方としては、最初に以下を書いておく。
#define STB_IMAGE_WRITE_STATIC #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h"
- stb_image_write.h を使う場合、必ず、「#define STB_IMAGE_WRITE_IMPLEMENTATION」と「#include "stb_image_write.h"」を記述する。
- STB_IMAGE_WRITE_STATIC を定義しておくと、各関数の頭に static がつく、らしい。
- stbi_write_png() で、png画像の保存。
stbi_write_png(保存ファイル名, 画像横幅, 画像縦幅, bpp, ピクセルデータ群へのポインタ, 1ライン分のバイト数)ただ、巷のサンプルを見ると、一番最後で「0」を指定してる場合が多くて…。
ちなみに、stb_image_write.h 内のコメントによると、ソースコードの量を減らすためにpng画像の圧縮率は低い状態になっているそうで。zlib関係の関数を STBIW_ZLIB_COMPRESS に定義することで圧縮率は改善できると書いてあった。もちろん、zlib を使えるようにビルドしないといかんのだろうけど。
何にせよ、stb_image.h にしろ、stb_image_write.h にしろ、比較的簡単な記述で画像のロードやセーブができる上に、静的リンクもすんなりできてしまうとは…。これは便利だなと…。
◎ stbi_write_png() の最後の引数について。 :
stbi_write_png() の最後の引数がよく分からなかったけど、ソースを眺めた感じでは 0 を指定しても良かったらしい。
stbi_write_png() は、内部で stbi_write_png_to_mem() を呼んでいるけれど、この stbi_write_png_to_mem() の中で、値が 0 なら width * bpp を代入、みたいなことをしている。
なので、自分で指定してもいいし、面倒臭ければ 0 を指定してもよい。どちらも同じ結果になるはず。たぶん。
stbi_write_png() は、内部で stbi_write_png_to_mem() を呼んでいるけれど、この stbi_write_png_to_mem() の中で、値が 0 なら width * bpp を代入、みたいなことをしている。
なので、自分で指定してもいいし、面倒臭ければ 0 を指定してもよい。どちらも同じ結果になるはず。たぶん。
[ ツッコむ ]
以上です。