cv::Point の使い方【OpenCV/C++】〜座標の型と基本操作〜

OpenCV for C++
📌 準備: OpenCV の環境構築がまだの方はこちら → C++ 環境構築ガイドC#(OpenCvSharp)セットアップ

cv::Point の使い方【OpenCV/C++】〜座標の型と基本操作〜

cv::Point は OpenCV で 2D 座標(x, y)を表す基本型です。circlerectangle などの描画関数、ROI 指定、特徴点処理など、あらゆる場面で登場します。まず最小限の使い方を示します。

cv::Point pt(100, 200);   // x=100, y=200
cv::circle(img, pt, 5, cv::Scalar(0, 255, 0), -1);

動作環境

  • OpenCV 4.x
  • コンパイル例: g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4)

環境構築がまだの方は環境構築ガイドを先にどうぞ。


基本の使い方

cv::Point で座標を生成し、描画関数に渡すサンプルです。

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

int main()
{
    // 500x500 の白画像を作成
    cv::Mat img(500, 500, CV_8UC3, cv::Scalar(255, 255, 255));

    // cv::Point の基本的な生成方法
    cv::Point pt1(100, 150);
    cv::Point pt2(400, 350);

    // 座標値へのアクセス
    std::cout << "pt1: x=" << pt1.x << ", y=" << pt1.y << std::endl;

    // 2点間の差ベクトル(cv::Point は加減算をサポート)
    cv::Point diff = pt2 - pt1;
    std::cout << "diff: x=" << diff.x << ", y=" << diff.y << std::endl;

    // 2点間の距離(norm はベクトルのノルムを返す)
    double dist = cv::norm(pt2 - pt1);
    std::cout << "distance: " << dist << std::endl;

    // 描画関数に渡す
    cv::circle(img, pt1, 10, cv::Scalar(255, 0, 0), -1);   // 青い点
    cv::circle(img, pt2, 10, cv::Scalar(0, 0, 255), -1);   // 赤い点
    cv::line(img, pt1, pt2, cv::Scalar(0, 0, 0), 2);        // 2点を結ぶ線

    cv::imshow("Point Demo", img);
    cv::waitKey(0);
    return 0;
}

実行結果:

pt1: x=100, y=150
pt2: x=400, y=350
diff: x=300, y=200
distance: 360.555

実行すると 500×500 の白画像ウィンドウが表示され、左上寄りに青い点、右下寄りに赤い点、両者を結ぶ黒い直線が描かれます。

コード解説

内容
cv::Point pt1(100, 150) x=100, y=150 の整数座標を生成
pt1.x / pt1.y メンバ変数で各軸の値を取得
pt2 - pt1 点同士の加減算。結果も cv::Point
cv::norm(pt2 - pt1) ユークリッド距離を計算
cv::circle(img, pt1, ...) 第2引数に cv::Point をそのまま渡せる

引数と戻り値(型の種類)

cv::Point は実際にはテンプレートエイリアスです。精度に応じて使い分けます。

型名 エイリアス 要素型 主な用途
cv::Point cv::Point2i int 描画・ROI などピクセル座標全般
cv::Point2f float 特徴点・サブピクセル精度の座標
cv::Point2d double 高精度なカメラ・幾何演算
cv::Point3i int 3D 座標(整数)
cv::Point3f float 3D 座標(float)

メンバ一覧(2D の場合)

メンバ 説明
.x T X 座標
.y T Y 座標
dot(pt) double 内積
cross(pt) double 外積(2D では Z 成分のスカラー)
ddot(pt) double 倍精度内積
inside(rect) bool 矩形内にあるか判定

実践例

実践例 1: Point2f で特徴点を扱い、整数座標に変換して描画する

サブピクセル精度の座標を持つ Point2f は、描画関数に渡す前に Point へ明示的にキャストします。

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

int main()
{
    cv::Mat img(400, 400, CV_8UC3, cv::Scalar(30, 30, 30));

    // 浮動小数点精度の座標群(例: 特徴検出の結果を模擬)
    std::vector<cv::Point2f> pts_f = {
        {100.3f, 200.7f},
        {250.1f, 150.9f},
        {320.5f, 310.2f}
    };

    for (const auto& pf : pts_f) {
        // Point2f → Point(int)へキャスト
        cv::Point pi = static_cast<cv::Point>(pf);
        cv::circle(img, pi, 6, cv::Scalar(0, 255, 255), 2);

        // 座標テキストを描画
        std::string label = "(" + std::to_string(static_cast<int>(pf.x))
                          + "," + std::to_string(static_cast<int>(pf.y)) + ")";
        cv::putText(img, label, pi + cv::Point(8, -8),
                    cv::FONT_HERSHEY_SIMPLEX, 0.45,
                    cv::Scalar(255, 255, 255), 1);
    }

    cv::imshow("Point2f Demo", img);
    cv::waitKey(0);
    return 0;
}

実行すると、暗い背景に黄色の丸が3つ描かれ、それぞれの横に座標ラベルが表示されます。


実践例 2: inside() で画像の範囲内チェック

処理前に座標が画像の範囲内かどうかを確認する典型パターンです。

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

int main()
{
    cv::Mat img = cv::imread("input.jpg");
    if (img.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    // 画像サイズに対応した矩形
    cv::Rect bounds(0, 0, img.cols, img.rows);

    std::vector<cv::Point> pts = {
        {100, 200},
        {-5, 300},       // 範囲外(x が負)
        {5000, 100}      // 範囲外(x が大きすぎ)
    };

    for (const auto& pt : pts) {
        if (pt.inside(bounds)) {
            cv::circle(img, pt, 5, cv::Scalar(0, 255, 0), -1);
            std::cout << pt << " -> 範囲内" << std::endl;
        } else {
            std::cout << pt << " -> 範囲外(スキップ)" << std::endl;
        }
    }

    cv::imshow("Inside Check", img);
    cv::waitKey(0);
    return 0;
}

実行結果(画像サイズが 640×480 の場合):

[100, 200] -> 範囲内
[-5, 300] -> 範囲外(スキップ)
[5000, 100] -> 範囲外(スキップ)

cv::Pointoperator<< を持つため std::cout にそのまま渡せます。範囲外座標を描画関数に渡すと assertion エラーや未定義動作につながるため、このチェックは実務で重要です。


つまずきポイント

⚠️ Point2f を描画関数に直接渡すとコンパイルエラーになる

cv::circlecv::rectangle の座標引数は cv::Point(= Point2i)を期待します。Point2f を渡すと暗黙変換されずコンパイルエラーになります。

// NG: Point2f をそのまま渡す
cv::Point2f pf(100.5f, 200.3f);
cv::circle(img, pf, 5, cv::Scalar(255, 0, 0), -1);  // コンパイルエラー

// OK: 明示的にキャスト
cv::circle(img, static_cast<cv::Point>(pf), 5, cv::Scalar(255, 0, 0), -1);

⚠️ Point の x, y は col, row(x が列方向・y が行方向)

cv::Mat のアクセスは mat.at<uchar>(row, col)(行, 列) の順ですが、cv::Point(x=col, y=row) の順です。PointMat::at を組み合わせるときに反転させてしまうバグが多発します。

cv::Point pt(col, row);            // Point は (x=列, y=行)
uchar val = img.at<uchar>(pt.y, pt.x);   // Mat::at は (行, 列) なので pt.y, pt.x の順
// img.at<uchar>(pt) と書くと内部で自動変換される(こちらが安全)
uchar val2 = img.at<uchar>(pt);    // pt を直接渡すほうがミスが少ない

⚠️ 算術演算の型に注意

Point(int)と Point2f(float)を混在させた演算はコンパイルエラーになります。型を統一するか明示的にキャストしてください。

cv::Point   pi(10, 20);
cv::Point2f pf(1.5f, 2.5f);
// auto result = pi + pf;  // コンパイルエラー
auto result = cv::Point2f(pi) + pf;  // OK: pi を Point2f に昇格

関連する関数


まとめ

  • cv::Point は整数座標、cv::Point2f はサブピクセル精度と用途に応じて使い分ける。
  • 描画関数は cv::Point(整数)を要求するため、Point2f からは static_cast<cv::Point> でキャストする。
  • inside() による範囲チェックを挟むことで、境界外アクセスによるクラッシュを防げる。

🛠 画像処理のプロが開発するSDK/API

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

タイトルとURLをコピーしました