OpenCVで画像のアルファチャンネル(透過度)を扱う

普段は画像処理を使うときはRGBの3チャネルかグレースケールを扱うことが多いのですが、こないだ久しぶりにアルファチャンネルを持つRGBA画像を扱う機会があったので、OpenCVでのアルファチャンネルの読み込み方等々についてまとめておこうと思いました。

アルファは画像の透過度を示す値で、正規化の仕方にもよりますが、一般的には255で透過なし、0で完全透過になります。

最近のペイントソフトでは大体アルファを持たせた画像を作ることができますが、出力するときに透過度を保持して出力するようにしないといけないので注意してください。少なくともPNGとかTIFFは、(透過度を持たせる設定で出力すれば)透過度を保持できるはずです。

例えば以下の画像をペイントソフトで作ってみましたが、青が透けており、赤い円と青の正方形以外は完全に透過されています。

今回はRGBA画像を読み込み、A(アルファ)が閾値以上の部分だけを白、それ以外の部分を黒にしたマスクを吐き出すプログラムを作り、OpenCVでのアルファチャネルの読み込み方、扱い方を学習します。

今回の環境

・OS : Windows10(64bit)
・Visual Studio 2017 Community
・OpenCV 4.2.0
(上記全て環境構築済)

今回はOpenCVは環境済の状態でスタートするので、OpenCVの環境構築は以下の記事などを参照してください。

過去記事①:Visual Studio 2015でOpenCV 3.4環境構築(Windows10)

過去記事②:Nugetを使ってOpenCVの環境構築(Visual Studio 2015) 

ソースコード

以下に、A(アルファ)が閾値以上の部分だけをフィルタリングしたRGB画像を出力するプログラムのソースコードを示します。

#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "引数不足(入力画像名, 閾値)" << std::endl;
return -1;
}
// 画像読込
std::string filename = argv[1];
std::cout << "入力画像 : " << filename.c_str() << std::endl;
cv::Mat input_img = cv::imread(filename.c_str(), -1);
if (input_img.empty() == true) {
std::cerr << "画像読込失敗 : " << filename.c_str() << std::endl;
return -1;
}
// 閾値読込
int th = std::stoi(argv[2]);
// チャネル数の確認
std::cout << "チャネル数 : " << input_img.channels() << std::endl;
// 閾値以上のAlpha値の部分を255、閾値以下のAlpha値の部分を0にするマスクの生成
int width = input_img.cols;
int height = input_img.rows;
cv::Mat1b alpha_msk = cv::Mat::zeros(height, width, CV_8UC1);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int alpha_value = input_img.at<cv::Vec4b>(y, x)[3];
if (alpha_value > th) {
alpha_msk.at<unsigned char>(y, x) = 255;
}
}
}
cv::imwrite("alpha_msk.jpg", alpha_msk);
return 0;
}

実行結果

以下の画像で実験してみました。赤の部分がアルファ255、青の部分が127、他が0になっています。

実行結果は以下のようになります。

【th=127 : アルファが127より大きいところだけ白にする】

【th=126 : アルファが126より大きいところだけ白にする】

OpenCVでアルファを正常に扱えているようです。

ポイント

(1)imreadで画像を読み込む際に、以下のように2番目の引数に負の値を与えることでアルファチャネルを読み込むことができます。

■ 2番目の引数が>0のとき:
強制的に3チャンネルカラー画像として読み込まれます
■ 2番目の引数が=0のとき:
強制的にグレースケール画像として読み込まれます
■ 2番目の引数が<0のとき:
画像はそのままの画像として読み込まれます

cv::Mat input_img = cv::imread(filename.c_str(), -1);

(2)アルファの値はデフォルトでは4次元のベクトル(BGRA)の4つ目の要素(インデックス的には[3])に入るようでした。

int alpha_value = input_img.at<cv::Vec4b>(y, x)[3];

まとめ

OpenCVでアルファチャンネルを持った画像を扱う方法について学び、適当なプログラムを作ってみました。

OpenCVであればアルファ入りの画像も容易に扱えることがわかりました。

スポンサーリンク

シェアする

フォローする