モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

OpenCV C++ データ型の基本的な使い方

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2019/11/14
最終更新最終更新
2024/07/26
記事区分記事区分
一般公開

目次

    C/C++やアルゴリズムに注目し、実践的な知識を発信しています!

    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 を扱った場合と同様にテキストなどを描画できます。

    #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;
    }
    

    テキストの描画

    #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]
    
    Likeボタン(off)0
    詳細設定を開く/閉じる
    アカウント プロフィール画像

    C/C++やアルゴリズムに注目し、実践的な知識を発信しています!

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    >>さらに詳しくステッカーを贈る
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      ログインする

      関連記事