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 を指定してもよい。どちらも同じ結果になるはず。たぶん。
[ ツッコむ ]
以上です。