[C++] OpenCVでのHough変換による直線と円の検出方法
OpenCVは、画像処理ライブラリであり、C++での画像解析に広く利用されています。Hough変換は、画像内の直線や円を検出するための手法です。
直線の検出には、HoughLines
関数を使用します。この関数は、エッジ検出後の画像を入力として、直線のパラメータを返します。
円の検出には、HoughCircles
関数を使用します。この関数は、グレースケール画像を入力として、円の中心座標と半径を返します。
これらの関数を活用することで、画像内の特定の形状を効率的に検出することが可能です。
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 | 検出する円の中心間の最小距離 |
param1 | Cannyエッジ検出の上限閾値 |
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変換の強力な検出能力を示しており、さまざまな分野での画像処理において有用です。
まとめ
この記事では、C++とOpenCVを用いたHough変換による直線と円の検出方法について詳しく解説しました。
Hough変換の基礎から実装方法、応用例までを通じて、画像処理における形状検出の重要性とその実践的な手法を学ぶことができました。
これを機に、実際のプロジェクトや研究にHough変換を活用し、さらなる画像処理技術の向上を目指してみてはいかがでしょうか。