OpenCVにおいてフィルタ系の処理を記述する際には cv::Mat が格納しているデータの型とチャンネル数をチェックする必要がある。
1.1系で主流だった IplImage 構造体の場合はヘッダに十分な記述があり、どのメンバをチェックすればよいかわかりやすかったが、2.4系で主流の cv::Mat クラスはヘッダのコメントが不十分であるため若干わかりにくい(筆者が「わからなかったらヘッダを読め」という人なのである)。
備忘的にまとめておく。
- mat.type() で型とチャンネル数の組み合わせ(CV_8UC3, CV_64FC2など)を得られる。
- mat.depth() で型(CV_8U, CV_64Fなど)を得られる。
- mat.channels() でチャンネル数を得られる。
- mat.isContinuous() でバイト列が連続かどうかを得られる。
以下は cv::Mat から型の情報を取得するサンプルコード。
# include <opencv2/core/core.hpp>
# include <iostream>
# include <cassert>
void print_info(const cv::Mat& mat)
{
using namespace std;
// 要素の型とチャンネル数の組み合わせ。
// 紙面の都合により、サンプルで使用する値のみ記述
cout << "type: " << (
mat.type() == CV_8UC3 ? "CV_8UC3" :
mat.type() == CV_16SC1 ? "CV_16SC1" :
mat.type() == CV_64FC2 ? "CV_64FC2" :
"other"
) << endl;
// 要素の型
cout << "depth: " << (
mat.depth() == CV_8U ? "CV_8U" :
mat.depth() == CV_16S ? "CV_16S" :
mat.depth() == CV_64F ? "CV_64F" :
"other"
) << endl;
// チャンネル数
cout << "channels: " << mat.channels() << endl;
// バイト列が連続しているか
cout << "continuous: " <<
(mat.isContinuous() ? "true" : "false")<< endl;
}
void some_filter(const cv::Mat& in, cv::Mat& out)
{
// フィルタが unsigned char 3チャンネルのみ受け付ける場合のチェック
// 大抵の場合、チェックが失敗する時は呼び出し側の実装がミスってるので
// assert()で落ちてしまって良いと思う
assert(in.type() == CV_8UC3 && "input image must be CV_8UC3");
}
int main(int argc, char* argv[])
{
using namespace std;
// unsigned char 3チャンネル
cout << "print_info(cv::Mat(10,10,CV_8UC3));" << endl;
print_info(cv::Mat(10,10,CV_8UC3));
cout << endl;
// signed short 1チャンネル
cout << "print_info(cv::Mat(10,10,CV_16SC1));" << endl;
print_info(cv::Mat(10,10,CV_16SC1));
cout << endl;
// double 2チャンネル
cout << "print_info(cv::Mat(10,10,CV_64FC2));" << endl;
print_info(cv::Mat(10,10,CV_64FC2));
cout << endl;
// double 2チャンネルの部分行列
// ROI(region of interest)として、画像の一部分の矩形領域を処理する場合、
// バイト列が不連続になる。したがって isContinuous() は false を返す。
cout << "print_info(cv::Mat(10,10,CV_64FC2)(cv::Rect(2,2,3,3)));" << endl;
print_info(cv::Mat(10,10,CV_64FC2)(cv::Rect(2,2,3,3)));
cout << endl;
return 0;
}
実行結果
print_info(cv::Mat(10,10,CV_8UC3));
type: CV_8UC3
depth: CV_8U
channels: 3
continuous: true
print_info(cv::Mat(10,10,CV_16SC1));
type: CV_16SC1
depth: CV_16S
channels: 1
continuous: true
print_info(cv::Mat(10,10,CV_64FC2));
type: CV_64FC2
depth: CV_64F
channels: 2
continuous: true
print_info(cv::Mat(10,10,CV_64FC2)(cv::Rect(2,2,3,3)));
type: CV_64FC2
depth: CV_64F
channels: 2
continuous: false