■ TL;DR あなたのBMP、実は"非準拠"かも?
- 現象:α付き画像をBMP保存 → ビューアで透過情報が消えちゃう!やだー!
- 原因:OpenCVが BGRX(Extra) 形式でファイル保存!Xに透過度情報を入れていたので、アプリによって扱いマチマチ
- 解決:OpenCV 4.13 から BGRA(本物のα) として保存できるように!
■ はじめに
OpenCVで何もコーデック有効にしなくても使える実は便利なBMP Encoder/Decoder。ところが、OpenCV 4.12.0以前だとちょーっと困った振る舞いしてました。
□ Microsoft曰く
BITMAPINFOHEADERには詳細が書いてないので、仕方が無いのでBITMAPV5HEADERで。
- https://learn.microsoft.com/ja-jp/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
- https://learn.microsoft.com/ja-jp/windows/win32/api/wingdi/ns-wingdi-bitmapv5header
ビットマップの色は最大 2^32 です。 BITMAPV5HEADERの bV5Compression メンバーがBI_RGB場合、BITMAPINFO の bmiColors メンバーは NULL になります。 ビットマップ配列の各 DWORD は、ピクセルの青、緑、赤の相対的な強度を表します。 blue の値は、最下位の 8 ビットで、その後に緑と赤のそれぞれ 8 ビットが続きます。 各 DWORD の上位バイトは使用されません
お分かりいただけるだろうか・・・ 32bitで保存する場合、B,G,R,A(Alpha)ではなく、BGRX(extra)で保存されるのである…。というか、X部分は使われないと断言されている。アルファじゃない!!
つまり、OpenCVで、CV_8UC4の画像を作ってBMPファイルに保存しても、IMREAD_UNCHANGEDフラグ付きで読み込むとCV_8UC3の画像で戻ってくるのは、マイクロソフトさんの仕様準拠なら当たり前!ということですね…… 😢
ただし実はこれ、OpenCV側でEncoderとDecoderで仕様が食い違ってるバグがあったりしたわけなのです。
RI_RGB
| Encoder | Decoder (IMREAD_UNCHANGED) |
|
|---|---|---|
| CV_8UC3 | 3ch |
3ch |
| CV_8UC4 | 4ch |
3ch |
□ OpenCV v4.13.0からは
OpenCV v4.13.0からは、4ch(32bpp)の画像データを保存するときに(デフォルトで)RI_BITFIELDSを使ってαチャネルも保存できるようになりましたー!!つまり、cv::IMREAD_UNCHANGEDを指定すると、4チャンネルがかえってくるよー!
「いやいや、うちの連携アプリはRI_BMPしか使えんのよ。そう簡単に変えられても困る・・・」という声もあるかもしれないので、互換モードも完備でございます!
RI_BITFIELDS
| Encoder | Decoder (IMREAD_UNCHANGED) |
|
|---|---|---|
| CV_8UC4 | 4ch |
4ch |
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <iostream>
int main()
{
cv::Mat src(320,240, CV_8UC4, cv::Scalar(64,128,92,45));
cv::imwrite("src.bmp", src);
cv::Mat dst;
dst = cv::imread("src.bmp", cv::IMREAD_UNCHANGED);
std::cout << src.channels() << std::endl;
std::cout << dst.channels() << std::endl;
return 0;
}
$ ./a.out
4
4
□ で、解決だと思うじゃろ?クックックック...
さて、規格マニアな方にはもう一歩。実はこの‘BI_BITFIELDS'でAlphaチャネルって仕様準拠でじゃないともいえるのです👿
bV5RedMask
各ピクセルの赤の成分を指定するカラー マスク。 bV5Compression が BI_BITFIELDS に設定されている場合にのみ有効です。
bV5GreenMask
各ピクセルの緑のコンポーネントを指定するカラー マスク。 bV5Compression が BI_BITFIELDS に設定されている場合にのみ有効です。
bV5BlueMask
各ピクセルの青色の成分を指定するカラー マスク。 bV5Compression が BI_BITFIELDS に設定されている場合にのみ有効です。
bV5AlphaMask
各ピクセルのアルファ 成分を指定するカラー マスク。
あれ? bV5AlphaMaskが何時、有効なのか書いてない 、ということは厳密にいうと……(げほんごほん)
■ まとめ:あなたのBMP、実は"非準拠"かも?
- 現象:α付き画像をBMP保存 → ビューアで透過情報が消えちゃう!やだー!
- 原因:OpenCVが BGRX(Extra) 形式でファイル保存!Xに透過度情報を入れていたので、アプリによって扱いマチマチ
- 解決:OpenCV 4.13 から BGRA(本物のα) として保存できるように!
明日は 「[Universal Intrinsic] vc=va+vb; はもうダメです。突然こんな事いってごめんね。でも本当です。」 です!! 実はもうUniversal Intrinsicでこの書き方は使えません!ビルドエラーになってしまいます!!ということで、ちょーっとだけ新しいやり方を覚えていってください、簡単ですから!!というご紹介になります。お楽しみに!!