LoginSignup
29
33

More than 5 years have passed since last update.

OpenCVのcv::Matの要素の型、型のバイト数、チャンネル数、バイト列が連続かを取得する

Posted at

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
29
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
33