OpenCV

C++とOpenCVで学ぶハフ変換による直線と円の検出実践ガイド

C++でのOpenCVハフ変換は、画像から直線や円などの形状を抽出する技術です。

処理前にエッジ検出や平滑化を行い、OpenCVのHoughLinesHoughCirclesを使用して特徴を捉えます。

簡単に形状検出が可能なため、実用的な画像解析に柔軟に対応できます。

ハフ変換の基本

直線検出の仕組み

画像中の直線を検出する処理は、エッジ検出で得られた情報をもとに、画像内の点をパラメータ空間に変換して投票を行う方法です。

具体的には、各点から直線のパラメータである距離 ρ と角度 θ に変換し、累積投票で多くの票を獲得したパラメータが直線として抽出されます。

この仕組みでは、画像のエッジ情報が直線の特徴として反映されるため、エッジ検出の正確さが重要となります。

円検出の仕組み

円の検出は、直線検出と同様に、エッジ情報を利用します。

画像中の各点に対して、円の中心位置と半径の組み合わせを求め、投票によって候補円を特定します。

この方法では、円のパラメータ(中心座標と半径)を正確に設定することで、目的の円を効率よく検出することができます。

C++ OpenCVでの実装例

直線検出の実装

コード例と説明

以下のサンプルコードは、直線検出の実装例です。

コード中には簡単なコメントを入れて、各処理の目的を示しています。

#include <opencv2/opencv.hpp>
#include <vector>
#include <cmath>
int main() {
    // 画像をグレースケールで読み込みます
    cv::Mat grayImage = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
    if (grayImage.empty()) {
        return -1;
    }
    // Cannyエッジ検出でエッジを抽出します
    cv::Canny(grayImage, grayImage, 50, 150);
    // ハフ変換で直線を検出します
    std::vector<cv::Vec2f> lines;
    cv::HoughLines(grayImage, lines, 1, CV_PI / 180, 100);
    // 結果表示のため、グレースケール画像をカラーに変換します
    cv::Mat colorImage;
    cv::cvtColor(grayImage, colorImage, cv::COLOR_GRAY2BGR);
    // 検出された直線を赤色の線で描画します
    for (size_t i = 0; i < lines.size(); i++) {
        float rho = lines[i][0];
        float theta = lines[i][1];
        double a = std::cos(theta);
        double b = std::sin(theta);
        double x0 = a * rho;
        double y0 = b * rho;
        cv::Point pt1(cvRound(x0 + 1000 * (-b)), cvRound(y0 + 1000 * (a)));
        cv::Point pt2(cvRound(x0 - 1000 * (-b)), cvRound(y0 - 1000 * (a)));
        cv::line(colorImage, pt1, pt2, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
    }
    // 結果のウィンドウを表示します
    cv::imshow("Detected Lines", colorImage);
    cv::waitKey(0);
    return 0;
}

円検出の実装

コード例と説明

次に、円検出の実装例を示します。

画像に対してガウシアンブラーで平滑化を行い、ハフ変換で円を検出する処理です。

#include <opencv2/opencv.hpp>
#include <vector>
int main() {
    // 画像をグレースケールで読み込みます
    cv::Mat grayImage = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
    if (grayImage.empty()) {
        return -1;
    }
    // ガウシアンブラーでノイズを低減します
    cv::GaussianBlur(grayImage, grayImage, cv::Size(9, 9), 2, 2);
    // ハフ変換で円を検出します
    std::vector<cv::Vec3f> circles;
    cv::HoughCircles(grayImage, circles, cv::HOUGH_GRADIENT, 1, grayImage.rows / 8, 100, 30, 1, 30);
    // 結果表示のため、グレースケール画像をカラーに変換します
    cv::Mat colorImage;
    cv::cvtColor(grayImage, colorImage, cv::COLOR_GRAY2BGR);
    // 円の中心と輪郭を描画します
    for (size_t i = 0; i < circles.size(); i++) {
        cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius = cvRound(circles[i][2]);
        // 中心を緑色の小さな円で描画します
        cv::circle(colorImage, center, 3, cv::Scalar(0, 255, 0), -1);
        // 外枠を赤色で描画します
        cv::circle(colorImage, center, radius, cv::Scalar(0, 0, 255), 3);
    }
    // 結果のウィンドウを表示します
    cv::imshow("Detected Circles", colorImage);
    cv::waitKey(0);
    return 0;
}

パラメータ設定と調整

直線検出向けパラメータ

距離 ρ と角度 θ の設定

直線検出では、パラメータの分解能を設定する必要があります。

  • ρ は画像内の各点から直線までの最短距離で、1ピクセル単位の分解能を設定することが一般的です。
  • θ は角度の分解能で、通常は π/180(1度刻み)の設定が用いられます

これらのパラメータを適切に設定することで、直線の検出精度を向上させることができます。

円検出向けパラメータ

円の検出条件と閾値

円検出では、以下のパラメータを調整することで、目的の円を正確に抽出することができます。

  • 検出器の解像度(最小値や最大値など)
  • 投票の閾値として用いるパラメータ
  • 検出した円同士の最低距離(最小中心間距離)

これらの設定は、画像のサイズや円の大きさによって調整する必要があり、実際の画像に合わせて試行錯誤することがおすすめです。

エッジ検出と前処理

Cannyエッジ検出の利用

ハフ変換を適用する前に、画像のエッジ情報を明確に抽出する必要があります。

cv::Canny関数を用いると、画像内のエッジがしっかりと抽出され、直線や円の検出精度が向上します。

また、エッジが明瞭になることで、不要なノイズの影響を軽減できます。

ガウシアンブラーの適用

円検出の前処理として、ノイズ除去のためにガウシアンブラーを適用することがおすすめです。

cv::GaussianBlur関数を利用することで、画像の平滑化が行われ、エッジ検出時の誤検出が減少します。

この前処理により、画像全体が柔らかくなり、円検出の結果も安定しやすくなります。

まとめ

直線と円の検出には、各種前処理やパラメータ設定が重要なポイントです。

実装例を参考に、画像処理の特性に合わせた調整を実施すれば、成果が期待できます。

今回紹介した内容を元に、柔軟な検出手法をぜひ試してみてください。

Back to top button
目次へ