OpenCV C++ データ型の基本的な使い方
[History] [Last Modified] (2020/02/11 13:17:29)
ここは
趣味のプログラミングを楽しむための情報共有サービス。記事の一部は有料設定にして公開できます。 詳しくはこちらをクリック📝
Recent posts
Popular pages

概要

OpenCV (C++) の基本的なデータ型について記載します。固定長の配列と、動的にメモリ領域を確保する可変長の配列があります。

固定長配列

点クラス

点クラスは、メンバ変数に .x,y,z でアクセスできる、固定長配列の一つです。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Point3i p(1, 2, 3);
    std::cout << p.x << std::endl; //=> 1
    std::cout << p.y << std::endl; //=> 2
    std::cout << p.z << std::endl; //=> 3
    return 0;
}

内積 (単精度、倍精度)

float dot = p.dot(p);
double ddot = p.ddot(p);

外積

p.cross(p)

スカラクラス

固定長配列の一つです。要素数は 4 です。四元数を表現できます。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Scalar s(1, 2, 3, 4);
    std::cout << s[0] << std::endl; //=> 1
    std::cout << s[1] << std::endl; //=> 2
    std::cout << s[2] << std::endl; //=> 3
    std::cout << s[3] << std::endl; //=> 4
    return 0;
}

サイズクラス

メンバ変数に .width,height でアクセスできる、固定長配列の一つです。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Size2i sz(2, 5);
    std::cout << sz.width << std::endl;  //=> 2
    std::cout << sz.height << std::endl; //=> 5
    std::cout << sz.area() << std::endl; //=> 10
    return 0;
}

長方形クラス

x軸、y軸と平行な長方形について、左上の点と辺の長さを指定します。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Rect r(0, 0, 2, 5);
    std::cout << r.x << std::endl; //=> 0
    std::cout << r.y << std::endl; //=> 0
    std::cout << r.width << std::endl; //=> 2
    std::cout << r.height << std::endl; //=> 5
    std::cout << r.area() << std::endl; //=> 10
    std::cout << r.tl() << std::endl; //=> [0, 0] ←左上の点
    std::cout << r.br() << std::endl; //=> [2, 5] ←右下の点
    std::cout << r.contains(cv::Point2i(1, 1)) << std::endl; //=> 1
    return 0;
}

長方形の中心点、サイズ、回転角度の三つで、x軸とy軸に平行ではない長方形を表現するクラスも存在します。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {

    cv::Point2f center(0, 0);
    cv::Size2f size(2, 5);
    float angle = 3.14 / 2.0;

    cv::RotatedRect rr(center, size, angle);

    std::cout << rr.center << std::endl; //=> [0, 0]
    std::cout << rr.size << std::endl; //=> [2 x 5]
    std::cout << rr.angle << std::endl; //=> 1.57

    return 0;
}

固定長行列クラス

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {

    cv::Matx33f m = cv::Matx33f::eye();
    std::cout << m << std::endl;

    std::cout << cv::Matx33f::all(1) << std::endl;
    std::cout << cv::Matx33f::ones() << std::endl;
    std::cout << cv::Matx33f::zeros() << std::endl;

    std::cout << m * m << std::endl;
    std::cout << m(0, 2) << std::endl;
    std::cout << m.get_minor<3, 1>(0, 2) << std::endl; // 部分行列
    std::cout << m.row(2) << std::endl;
    std::cout << m.col(2) << std::endl;
    std::cout << m.diag() << std::endl;
    std::cout << m.t() << std::endl; // 転置行列
    std::cout << m.inv() << std::endl;

    return 0;
}

固定長ベクタクラス

列数が 1 の固定長行列です。外積演算が可能です。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {

    cv::Vec3f v3f(1, 1, 1);

    std::cout << v3f(0) << std::endl; //=> 1
    std::cout << v3f[0] << std::endl; //=> 1
    std::cout << v3f.cross(v3f) << std::endl; //=> [0, 0, 0]

    return 0;
}

複素数クラス

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Complexd z(0, 0);
    std::cout << z.re << std::endl; //=> 0
    std::cout << z.im << std::endl; //=> 0
    return 0;
}

可変長配列

蜜な行列は cv::Mat で表現できます。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat m;
    m.create(5, 5, CV_32F);
    m.setTo(cv::Scalar(0.0)); // 初期化
    std::cout << m.at<float>(0, 0) << std::endl;
    return 0;
}

単位行列などは以下のように作成します。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat m = cv::Mat::eye(5, 5, CV_32F);
    // cv::Mat m = cv::Mat::zeros(5, 5, CV_32F);
    // cv::Mat m = cv::Mat::ones(5, 5, CV_32F);
    std::cout << m.at<float>(0, 0) << std::endl;
    return 0;
}

例えば CV_32F ではなく CV_32FC3 を指定すると、行列を 3 チャンネル作成できます。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat m;
    m.create(5, 5, CV_32FC3);
    m.setTo(cv::Scalar(1.0, 2.0, 3.0)); // 各チャンネルの行列をそれぞれ初期化

    std::cout << m.at<cv::Vec3f>(0, 0)[0] << std::endl; //=> 1
    std::cout << m.at<cv::Vec3f>(0, 0)[1] << std::endl; //=> 2
    std::cout << m.at<cv::Vec3f>(0, 0)[2] << std::endl; //=> 3

    return 0;
}

部分行列

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat m = cv::Mat::eye(5, 5, CV_32F);

    std::cout << m.row(0) << std::endl;
    std::cout << m.col(0) << std::endl;

    std::cout << m.rowRange(0, 2) << std::endl;
    std::cout << m.colRange(0, 2) << std::endl;

    std::cout << m(cv::Range(0, 2), cv::Range(0, 2)) << std::endl;

    return 0;
}

疎な行列

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    int size[] = {10, 10};
    cv::SparseMat sm(2, size, CV_32F);

    sm.ref<float>(1, 1) = 5;
    std::cout << sm.value<float>(1, 1) << std::endl; //=> 5
    std::cout << sm.nzcount() << std::endl; //=> 1 (ゼロ以外の要素数)
    sm.erase(1, 1);
    return 0;
}

演算用の関数

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat m = cv::Mat::eye(5, 5, CV_32F);
    cv::Mat m2;

    std::cout << cv::abs(m + m) << std::endl;

    cv::normalize(m, m2);
    std::cout << cv::norm(m2) << std::endl;

    std::cout << cv::sum(m) << std::endl;
    std::cout << cv::trace(m) << std::endl;

    return 0;
}

テキスト表示など

画像ファイルは蜜な可変長行列 cv::Mat として読み込めますPython から OpenCV を扱った場合と同様にテキストなどを描画できます。

Uploaded Image

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat img = cv::imread("aaa.png", -1);
    if(img.empty()) {
        return -1;
    }

    std::cout << img.size() << std::endl; //=> [200 x 200]
    std::cout << img.channels() << std::endl; //=> 4

    cv::circle(img, cv::Point(100, 100), 100, cv::Scalar(255, 0, 0)); // BGR

    cv::namedWindow("Example", cv::WINDOW_AUTOSIZE);
    cv::imshow("Example", img);
    cv::waitKey(0);
    cv::destroyWindow("Example");
    return 0;
}

テキストの描画

Uploaded Image

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat img = cv::imread("aaa.png", -1);
    if(img.empty()) {
        return -1;
    }

    std::cout << img.size() << std::endl; //=> [200 x 200]
    std::cout << img.channels() << std::endl; //=> 4

    cv::putText(img, cv::String("Hello"), cv::Point(0, 200), cv::FONT_HERSHEY_PLAIN, 5, cv::Scalar(255, 0, 0));

    cv::namedWindow("Example", cv::WINDOW_AUTOSIZE);
    cv::imshow("Example", img);
    cv::waitKey(0);
    cv::destroyWindow("Example");
    return 0;
}

ロドリゲス変換

三次元空間における回転の表現には、3x3 回転行列 の他に、回転軸を表現するベクトルを用いるものがあります。ベクトルの大きさで回転量を表現します。ベクトルによる回転の表現は、行列の場合と比較してより直感的です。

両者は相互に変換できます。OpenCV における実装は cv::Rodrigues です。

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Vec3f v(0, 0, CV_PI / 2.0);
    cv::Mat R;
    cv::Rodrigues(v, R);
    std::cout << R << std::endl;

    cv::Mat R2 = (cv::Mat_<float>(3, 3) <<
                  cos(CV_PI / 2.0), -sin(CV_PI / 2.0), 0,
                  sin(CV_PI / 2.0), cos(CV_PI / 2.0), 0,
                  0, 0, 1);
    cv::Vec3f v2;
    cv::Rodrigues(R2, v2);
    std::cout << v2 << std::endl;
    return 0;
}

実行例

[-4.3711388e-08, -1, 0;
 1, -4.3711388e-08, 0;
 0, 0, 1]
[0, 0, 1.5708]
Related pages
    概要 OpenCV3 C++ を用いて画像から特定の色の領域を取り出す方法のうち、HSV 色空間における色相を指定する方法と、バックプロジェクション (逆投影法) を利用する方法の二つを記載します。 HSV 色空間における色相を指定する方法 色を表現する空間には RGB の他に HSV (Hue 色相、Saturation 彩度、Value 明度)
    概要 カメラキャリブレーション (Camera Calibration, Camera Resectioning) を行うと、レンズの歪みを表現するパラメータや、カメラのワールド座標系での位置姿勢を推定できます。 チェスボードのようなキャリブレーション専用のボードが利用されます。 キャリブレーションで得られたパラメータを用いると、例えば歪みを補正することができます。