[C++] OpenCVでのHough変換による直線と円の検出方法

OpenCVは、画像処理ライブラリであり、C++での画像解析に広く利用されています。Hough変換は、画像内の直線や円を検出するための手法です。

直線の検出には、HoughLines関数を使用します。この関数は、エッジ検出後の画像を入力として、直線のパラメータを返します。

円の検出には、HoughCircles関数を使用します。この関数は、グレースケール画像を入力として、円の中心座標と半径を返します。

これらの関数を活用することで、画像内の特定の形状を効率的に検出することが可能です。

この記事でわかること
  • Hough変換の基本的な概念とその歴史的背景
  • 直線検出と円検出のための画像前処理手法
  • OpenCVの関数を用いたHough変換の実装方法
  • 交通標識や天体写真、医療画像での応用例
  • 検出結果を描画するための具体的なプログラム例

目次から探す

OpenCVとHough変換の基礎知識

Hough変換の概要

Hough変換は、画像内の特定の形状を検出するための手法です。

特に、直線や円のような幾何学的形状を効率的に見つけることができます。

この手法は、画像のエッジ情報を利用して、形状のパラメータ空間に変換し、形状の存在を確認します。

Hough変換の基本的な考え方は、画像空間からパラメータ空間への変換です。

例えば、直線の場合、画像空間の各点はパラメータ空間の直線に対応します。

これにより、画像内の直線をパラメータ空間での交点として検出できます。

Hough変換の歴史と背景

Hough変換は、1962年にPaul Houghによって特許取得された手法です。

当初はバブルチェンバーの写真から直線を検出するために開発されました。

その後、1972年にRichard DudaとPeter Hartによって一般化され、現在の形で広く利用されています。

この手法は、計算機ビジョンや画像処理の分野で重要な役割を果たしており、特に自動運転や医療画像解析などの応用で活用されています。

直線検出と円検出の違い

Hough変換を用いた直線検出と円検出には、いくつかの違いがあります。

以下にその違いを数式を用いて説明します。

直線検出

直線は、一般的に次のように表現されます。

しかし、Hough変換では、直線を次の極座標形式で表現します。

ここで、(ρ)は原点から直線までの垂直距離、(θ)はx軸から垂線までの角度です。

この形式により、画像空間の点はパラメータ空間の直線に変換されます。

円検出

円は、次の方程式で表現されます。

ここで、(a)と(b)は円の中心座標、(r)は半径です。

Hough変換では、円の中心と半径をパラメータ空間で探索します。

円検出では、3次元のパラメータ空間((a, b, r))を使用します。

このように、直線検出と円検出では、パラメータ空間の次元や変換方法が異なりますが、どちらもHough変換の基本的な考え方に基づいています。

Hough変換による直線検出

画像の前処理

Hough変換を用いて直線を検出するためには、まず画像の前処理が必要です。

前処理は、画像からノイズを除去し、エッジを強調するために行います。

グレースケール変換

カラー画像を扱う場合、まずグレースケールに変換します。

これは、色情報を無視して輝度情報のみを使用することで、計算を簡略化し、処理速度を向上させるためです。

#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
    // 画像を読み込む
    cv::Mat image = cv::imread("image.jpg");
    cv::Mat grayImage;
    cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY); // グレースケールに変換

    // 変換後の画像を表示
    cv::imshow("Transformed Image", grayImage);
    cv::waitKey(0);

    return 0;
}

エッジ検出(Canny法)

次に、エッジ検出を行います。

Canny法は、エッジ検出のための一般的な手法で、ノイズに強く、エッジを明確に検出できます。

#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
    // 画像を読み込む
    cv::Mat image = cv::imread("image.jpg");
    cv::Mat grayImage;
    cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY); // グレースケールに変換
    cv::Mat edges;
    cv::Canny(grayImage, edges, 50, 150); // Canny法でエッジを検出
    // 変換後の画像を表示
    cv::imshow("Transformed Image", edges);
    cv::waitKey(0);

    return 0;
}

Hough直線変換の実装

Hough変換を用いて、エッジ画像から直線を検出します。

HoughLines関数の使い方

OpenCVのHoughLines関数を使用して、直線を検出します。

この関数は、エッジ画像といくつかのパラメータを入力として受け取り、検出された直線のパラメータを出力します。

std::vector<cv::Vec2f> lines;
cv::HoughLines(edges, lines, 1, CV_PI/180, 100); // 直線を検出

パラメータの調整方法

HoughLines関数の主なパラメータは以下の通りです。

スクロールできます
パラメータ説明
rho距離の解像度(ピクセル単位)
theta角度の解像度(ラジアン単位)
threshold直線とみなすための最小投票数

これらのパラメータを調整することで、検出精度を向上させることができます。

検出結果の描画

検出された直線を元の画像に描画します。

for (size_t i = 0; i < lines.size(); i++) {
    float rho = lines[i][0], theta = lines[i][1];
    cv::Point pt1, pt2;
    double a = cos(theta), b = sin(theta);
    double x0 = a*rho, y0 = b*rho;
    pt1.x = cvRound(x0 + 1000*(-b));
    pt1.y = cvRound(y0 + 1000*(a));
    pt2.x = cvRound(x0 - 1000*(-b));
    pt2.y = cvRound(y0 - 1000*(a));
    cv::line(image, pt1, pt2, cv::Scalar(0,0,255), 2); // 直線を描画
}

サンプルプログラム

以下に、Hough変換を用いた直線検出のサンプルプログラムを示します。

#include <opencv2/opencv.hpp>
int main() {
    cv::Mat image = cv::imread("input.jpg"); // 画像を読み込む
    cv::Mat grayImage;
    cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY); // グレースケールに変換
    cv::Mat edges;
    cv::Canny(grayImage, edges, 50, 150); // Canny法でエッジを検出
    std::vector<cv::Vec2f> lines;
    cv::HoughLines(edges, lines, 1, CV_PI/180, 100); // 直線を検出
    for (size_t i = 0; i < lines.size(); i++) {
        float rho = lines[i][0], theta = lines[i][1];
        cv::Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000*(-b));
        pt1.y = cvRound(y0 + 1000*(a));
        pt2.x = cvRound(x0 - 1000*(-b));
        pt2.y = cvRound(y0 - 1000*(a));
        cv::line(image, pt1, pt2, cv::Scalar(0,0,255), 2); // 直線を描画
    }
    cv::imshow("Detected Lines", image); // 結果を表示
    cv::waitKey(0);
    return 0;
}

このプログラムは、入力画像からエッジを検出し、Hough変換を用いて直線を検出します。

検出された直線は赤色で描画され、結果が表示されます。

Hough変換による円検出

画像の前処理

円検出を行うためには、まず画像の前処理を行います。

直線検出と同様に、ノイズを除去し、エッジを強調することが重要です。

グレースケール変換

カラー画像を扱う場合、最初にグレースケールに変換します。

これにより、計算が簡略化され、処理速度が向上します。

#include <opencv2/opencv.hpp>
cv::Mat image = cv::imread("input.jpg"); // 画像を読み込む
cv::Mat grayImage;
cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY); // グレースケールに変換

エッジ検出(Canny法)

次に、エッジ検出を行います。

Canny法は、エッジを明確に検出するための一般的な手法です。

cv::Mat edges;
cv::Canny(grayImage, edges, 50, 150); // Canny法でエッジを検出

Hough円変換の実装

Hough変換を用いて、エッジ画像から円を検出します。

HoughCircles関数の使い方

OpenCVのHoughCircles関数を使用して、円を検出します。

この関数は、エッジ画像といくつかのパラメータを入力として受け取り、検出された円のパラメータを出力します。

std::vector<cv::Vec3f> circles;
cv::HoughCircles(grayImage, circles, cv::HOUGH_GRADIENT, 1, grayImage.rows/8, 200, 100, 0, 0); // 円を検出

パラメータの調整方法

HoughCircles関数の主なパラメータは以下の通りです。

スクロールできます
パラメータ説明
method検出方法(通常はcv::HOUGH_GRADIENT)
dp画像解像度に対する累積バッファの解像度の逆数
minDist検出する円の中心間の最小距離
param1Cannyエッジ検出の上限閾値
param2円とみなすための累積バッファの閾値
minRadius検出する円の最小半径
maxRadius検出する円の最大半径

これらのパラメータを調整することで、検出精度を向上させることができます。

検出結果の描画

検出された円を元の画像に描画します。

for (size_t i = 0; i < circles.size(); i++) {
    cv::Vec3i c = circles[i];
    cv::Point center = cv::Point(c[0], c[1]);
    int radius = c[2];
    cv::circle(image, center, radius, cv::Scalar(0, 255, 0), 2); // 円を描画
    cv::circle(image, center, 2, cv::Scalar(0, 0, 255), 3); // 中心を描画
}

サンプルプログラム

以下に、Hough変換を用いた円検出のサンプルプログラムを示します。

#include <opencv2/opencv.hpp>
int main() {
    cv::Mat image = cv::imread("input.jpg"); // 画像を読み込む
    cv::Mat grayImage;
    cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY); // グレースケールに変換
    cv::Mat edges;
    cv::Canny(grayImage, edges, 50, 150); // Canny法でエッジを検出
    std::vector<cv::Vec3f> circles;
    cv::HoughCircles(grayImage, circles, cv::HOUGH_GRADIENT, 1, grayImage.rows/8, 200, 100, 0, 0); // 円を検出
    for (size_t i = 0; i < circles.size(); i++) {
        cv::Vec3i c = circles[i];
        cv::Point center = cv::Point(c[0], c[1]);
        int radius = c[2];
        cv::circle(image, center, radius, cv::Scalar(0, 255, 0), 2); // 円を描画
        cv::circle(image, center, 2, cv::Scalar(0, 0, 255), 3); // 中心を描画
    }
    cv::imshow("Detected Circles", image); // 結果を表示
    cv::waitKey(0);
    return 0;
}

このプログラムは、入力画像からエッジを検出し、Hough変換を用いて円を検出します。

検出された円は緑色で描画され、中心は赤色で示されます。

結果が表示され、円の検出が確認できます。

応用例

Hough変換は、さまざまな分野での画像処理に応用されています。

以下に、具体的な応用例をいくつか紹介します。

交通標識の検出

交通標識の検出は、自動運転技術や交通監視システムにおいて重要な役割を果たします。

Hough変換を用いることで、標識の形状(例えば、円形の標識)を効率的に検出できます。

  • 円形標識の検出: 円形の交通標識は、Hough円変換を用いて検出できます。

標識の色やサイズに応じて、前処理やパラメータを調整することで、精度を向上させることが可能です。

  • 直線標識の検出: 一部の標識は直線を含む形状を持つため、Hough直線変換を併用することで、より多くの標識を検出できます。

天体写真での星の検出

天体写真における星の検出は、天文学の研究や星空観察において重要です。

Hough変換を用いることで、星の位置や形状を特定することができます。

  • 星の位置検出: 星は通常、円形に近い形状を持つため、Hough円変換を用いて星の位置を特定できます。

星の輝度やサイズに応じて、パラメータを調整することで、ノイズを除去し、正確な検出が可能です。

  • 星団の解析: 複数の星が集まる星団の解析にも応用できます。

星団内の星の分布や密度を解析することで、天文学的な知見を得ることができます。

医療画像での細胞検出

医療画像における細胞の検出は、病理学や診断において重要な役割を果たします。

Hough変換を用いることで、細胞の形状や位置を効率的に検出できます。

  • 細胞の形状検出: 細胞は通常、円形や楕円形の形状を持つため、Hough円変換を用いて細胞の形状を特定できます。

細胞の大きさや形状に応じて、パラメータを調整することで、精度を向上させることが可能です。

  • 異常細胞の検出: 異常な形状を持つ細胞を検出することで、病気の早期発見や診断に役立てることができます。

Hough変換を用いることで、異常細胞の形状を効率的に特定できます。

これらの応用例は、Hough変換の強力な検出能力を示しており、さまざまな分野での画像処理において有用です。

よくある質問

Hough変換の計算量はどのくらいですか?

Hough変換の計算量は、主にパラメータ空間のサイズに依存します。

直線検出の場合、パラメータ空間は通常、距離(ρ)と角度(θ)の2次元です。

円検出の場合、パラメータ空間は中心座標(a, b)と半径(r)の3次元になります。

計算量は、エッジ検出されたピクセル数とパラメータ空間の解像度に比例します。

高解像度のパラメータ空間を使用すると、計算量が増加しますが、検出精度が向上します。

パラメータの調整が難しいのですが、どうすれば良いですか?

パラメータの調整は、Hough変換の精度に大きく影響します。

以下の方法で調整を試みると良いでしょう。

  • エッジ検出の閾値: Canny法の閾値を調整することで、エッジの検出精度を改善できます。

エッジが多すぎる場合は閾値を上げ、少なすぎる場合は下げてみてください。

  • Hough変換の閾値: HoughLinesHoughCirclesの閾値を調整することで、検出する形状の数を制御できます。

閾値を下げると検出数が増え、上げると減ります。

  • パラメータ空間の解像度: 距離や角度の解像度を調整することで、検出精度を向上させることができます。

解像度を高くすると精度が上がりますが、計算量も増加します。

他の形状も検出できますか?

Hough変換は、直線や円以外の形状にも応用可能ですが、標準的なHough変換ではこれらの形状に特化しています。

他の形状を検出するためには、以下の方法を検討できます。

  • 拡張Hough変換: 楕円やその他の形状を検出するための拡張版があります。

これらは、特定の形状に対するパラメータ空間を定義することで実現されます。

  • テンプレートマッチング: 特定の形状を検出するために、テンプレートマッチングを使用することも可能です。

これは、画像内の特定のパターンを検索する手法です。

  • 機械学習: 機械学習アルゴリズムを使用して、特定の形状を学習し、検出することもできます。

これにより、複雑な形状やパターンを検出することが可能です。

まとめ

この記事では、C++とOpenCVを用いたHough変換による直線と円の検出方法について詳しく解説しました。

Hough変換の基礎から実装方法、応用例までを通じて、画像処理における形状検出の重要性とその実践的な手法を学ぶことができました。

これを機に、実際のプロジェクトや研究にHough変換を活用し、さらなる画像処理技術の向上を目指してみてはいかがでしょうか。

  • URLをコピーしました!
目次から探す