記事がオリジナルの記事である場合、許可なく複製することはできません。
元のブロガーのブログアドレス:https : //blog.csdn.net/qq21497936
オリジナルのブロガーのブログナビゲーション:https : //blog.csdn.net/qq21497936/article/details / 102478062
この記事のブログアドレス:https : //blog.csdn.net/qq21497936/article/details/105544972
読者、知識は無限大、人材は乏しい、需要を変える、専門家を見つける、または自分で研究する
ディレクトリ
2.一般に、点(x0、y0)の場合、この点の直線のセットによって均一に定義できます。
3.与えられた点(x0、y0)について、極座標で極座標と極直径および極角平面を通過するすべての直線は、正弦曲線になります。
4.画像内のすべての点に対して上記の操作を実行して、一連のグラフを取得します。
5.以上より、平面θ-rのある点で交差する曲線の数を求めることにより、直線を検出できます。
プロジェクトテンプレート:対応するバージョン番号v1.38.0
OpenCV開発コラム(ポータルをクリック)
OpenCV開発ノート(43):Red Fat Manは、累積確率ハフライン変換(画像とテキストの両方+理解しやすい+プログラムソースコードの両方)の詳細を理解するのに8分かかります
序文
赤いデブ男も来ます!!!
ノイズ除去とエッジ検出の後、特徴抽出が実行されます。グラフィックスを識別するための基本的な方法の1つは、ハフ変換です。ハフ変換は、画像処理における特徴抽出技術です。前の記事では、ハフライン変換について説明しましたこの章では、ハフライン変換におけるハフライン変換の累積確率について説明します。
前回の記事では、ハフ変換の8分の理解だけでは不十分なので、理解を深めるために、もう一度原理を説明します。ハフ変換は重要な検出方法の1つです。検出効果を比較します。
デモ
ハフ変換
概観
ハフ変換(Hough Transform)は、画像処理における特徴抽出技術であり、修正プロセスは、パラメータ空間での累積結果の極大値を計算し、特定の形状に適合するセットをハフ変換結果として取得します。
従来のハフ変換は、画像内の直線を検出するために使用されていましたが、その後、ハフ変換は、任意の形状のオブジェクト、主に円と楕円の認識に拡張されました。
ハフ変換は、2つの座標空間間の変換を使用して、1つの空間で同じ形状の曲線または直線を別の座標コントロール上の点にマッピングしてピークを形成し、形状の検出の問題を統計的なピークの問題に変換します。
以下に示すように、OpenCVのハフ変換は2つのタイプに分けられ、ライン変換は3つのタイプに分けられます。
累積確率ハフライン変換
概観
ハフライン変換は、その名前から実際に直線用であることを知ることができます。明らかに、これは直線を見つける方法です。ここでは特に注意を払っています。ハフライン変換を使用する前に、画像の前処理が必要です:ノイズ除去、エッジ検出、ハフライン変換は直線のみを探し、エッジバイナリイメージしか認識できないため、入力は2値化(シングルチャネル8ビット)イメージのみです。
ハフライン変換は、次のように3つのタイプに分けられます。
ハフライン変換では多数のラインが検出されますが、実際には役に立たないラインもあります。
原理
1.直線画像の2次元空間は2つの変数で表すことができます
- デカルト座標系:パラメータの傾きと切片(m、b)で表すことができます。
- 極座標系(ハフ変換で採用されている方法)では、パラメーターは極径と極角(r、θ)で表すことができます。
ハフ変換は、極座標を使用して直線を表します。
したがって、直線の式は次のとおりです。
rの式は次のとおりです。
2.一般に、点(x0、y0)の場合、この点の直線のセットによって均一に定義できます。
rθ= x0 *cosθ+ y0 *sinθ
各ペア(rθ、θ)は、点(x0、y0)を通る直線を表します。
3.与えられた点(x0、y0)について、極座標で極座標と極直径および極角平面を通過するすべての直線は、正弦曲線になります。
たとえば、特定の点x0 = 8およびy0 = 6の場合、計算原理は次のとおりです。
次の曲線を得ることができます:
r> 0や0 <θ<2πなどの特定の条件のみを描画します(注:0は垂直線、π/ 2度は水平線を意味します)。
4.画像内のすべての点に対して上記の操作を実行して、一連のグラフを取得します。
2つの異なる点で上記の操作の後に得られた曲線が平面θ-rで交差する場合、それらは同じ直線を通過することを意味します。
たとえば、上記の例に従って、ポイントx1 = 9、y1 = 4およびx2 = 12、y2 = 3を次のようにプロットし続けます。
これら3つの曲線は、平面内のポイント(0.925、9.6 )と比較され、座標は平面内のパラメーターのペアθ-rまたはポイント(x0、y0)、(x1、y1)および(x2、y2)を表します直線なので、実際には平面内の各点の各角度の距離を計算しています。それを曲線に描画した後、3つの点が交差すると、次の図に示すように、3つの点は直線上になります。
(ある点で交差する曲線の数がしきい値(同じ直線上の点の数)を超えています。たとえば、上の図では、3つの点が直線を形成でき、直線のジャンプを検出できると想定されています。
5.以上より、平面θ-rのある点で交差する曲線の数を求めることにより、直線を検出できます。
1つの点で交差する曲線が多いほど、この点の焦点によって表される直線がより多くの点で構成されます。一般に、直線上のポイントのしきい値を設定することにより、ポイントで交差するカーブの数を定義できます。これにより、直線が検出されます。
上記はハフ変換です。画像内の各ポイントの対応するカーブの交差を追跡します。ポイントを横切るカーブの数がしきい値(同じライン上のポイント数のしきい値)を超える場合、交差は考慮されます。代表的なパラメーターのペア(θ、rθ)は、元の画像では直線です。
累積確率のプロトタイプハフ変換関数
void HoughLinesP( InputArray image,
OutputArray lines,
double rho,
double theta,
int threshold,
double minLineLength = 0,
double maxLineGap = 0 );
- パラメータ1: InputArrayタイプの画像、8ビットのソース画像、シングルチャネルのバイナリ画像。元の画像を読み込み、関数でこの形式に変更してから、ここに入力できます。
- パラメータ2:タイプがOutputArrayのライン。HoughLines関数を呼び出した後、ハフ変換によって検出されたラインの出力ベクトルを格納します。各線は2つの要素のベクトル(r、θ)で構成され、rは座標の原点からの距離を表し、θはラジアン線の回転角度です(0は垂直線を表し、π/ 2度は水平線を表します)
- パラメータ3:ダブルタイプrho、rhoは直線の距離、1ピクセルの場合、長さ1-> 2-> 3の直線を検出、2の場合、2-> 4-> 6は1と3を無視あまりにも。
- パラメーター4:タイプdoubleのシータ、ラジアン、すべてがラインであっても、ラインとラインの間のラジアン精度、360度のポイント、ラジアンがπの場合、0°から始まることを意味しますπラジアン(180°、線を検出);
- パラメーター5:int タイプのしきい値、累積平面のしきい値パラメーター。つまり、図で部品を直線として識別するときに累積平面で到達する必要のある値。閾値よりも大きい閾値線分結果とに復帰することにより検出することができます。
- パラメータ6:double タイプのminLineLength。デフォルトは0です。これは、最小の線分の長さを意味します。この設定パラメータより短い線分は検出できません。
- パラメータ7:タイプがdoubleのmaxLineGap。デフォルトは0 で、同じ線上の点を接続するために許可される最大距離。
補足データ関数プロトタイプ
cvRound():返回跟参数最接近的整数值,即四舍五入;
cvFloor():返回不大于参数的最大整数值,即向下取整;
cvCeil():返回不小于参数的最小整数值,即向上取整;
デモのソースコード
void OpenCVManager::testHoughLinesP()
{
QString fileName1 =
"E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/16.jpg";
cv::Mat srcMat = cv::imread(fileName1.toStdString());
int width = 400;
int height = 300;
cv::resize(srcMat, srcMat, cv::Size(width, height));
cv::Mat colorMat = srcMat.clone();
cv::String windowName = _windowTitle.toStdString();
cvui::init(windowName);
cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 3),
srcMat.type());
cv::cvtColor(srcMat, srcMat, CV_BGR2GRAY);
int threshold1 = 200;
int threshold2 = 100;
int apertureSize = 1;
int rh0 = 1; // 默认1像素
int theta = 1; // 默认1°
int threshold = 100; // 默认检测到同一直线的100个点
int minLineLength = 50; // 检测线的最小长度
int maxLineGap = 10; // 同一条线点与点的最大距离
while(true)
{
qDebug() << __FILE__ << __LINE__;
windowMat = cv::Scalar(0, 0, 0);
cv::Mat mat;
cv::Mat dstMat;
cv::Mat grayMat;
// 转换为灰度图像
// 原图先copy到左边
cv::Mat leftMat = windowMat(cv::Range(0, srcMat.rows),
cv::Range(0, srcMat.cols));
cv::cvtColor(srcMat, grayMat, CV_GRAY2BGR);
cv::addWeighted(leftMat, 0.0f, grayMat, 1.0f, 0.0f, leftMat);
{
cvui::printf(windowMat,
width * 1 + 100,
height * 0 + 20,
"threshold1");
cvui::trackbar(windowMat,
width * 1 + 100,
height * 0 + 50,
200,
&threshold1,
0,
255);
cvui::printf(windowMat,
width * 1 + 100,
height * 0 + 100, "threshold2");
cvui::trackbar(windowMat,
width * 1 + 100,
height * 0 + 130,
200,
&threshold2,
0,
255);
cv::Canny(srcMat, dstMat, threshold1, threshold2, apertureSize * 2 + 1);
// copy
mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::cvtColor(dstMat, grayMat, CV_GRAY2BGR);
cv::addWeighted(mat, 0.0f, grayMat, 1.0f, 0.0f, mat);
cvui::printf(windowMat,
width * 1 + 100,
height * 1 + 20 - 120,
"rho / 100");
cvui::trackbar(windowMat,
width * 1 + 100,
height * 1 + 50 - 120,
200,
&rh0,
1,
1000);
cvui::printf(windowMat,
width * 1 + 100,
height * 1 + 100 - 120,
"theta = value / 2");
cvui::trackbar(windowMat,
width * 1 + 100,
height * 1 + 130 - 120,
200,
&theta,
1,
720);
cvui::printf(windowMat,
width * 1 + 100,
height * 1 + 180 - 120,
"min points");
cvui::trackbar(windowMat,
width * 1 + 100,
height * 1 + 210 - 120,
200,
&threshold,
2,
300);
cvui::printf(windowMat,
width * 1 + 100,
height * 1 + 260 - 120,
"minLineLength = value / 10");
cvui::trackbar(windowMat,
width * 1 + 100,
height * 1 + 290 - 120,
200,
&minLineLength,
0,
1000);
cvui::printf(windowMat,
width * 1 + 100,
height * 1 + 340 - 120,
"maxLineGap = value / 10");
cvui::trackbar(windowMat,
width * 1 + 100,
height * 1 + 370 - 120,
200,
&maxLineGap,
0,
1000);
// 边缘检测后,进行霍夫线检测
// 使用霍夫线变化检测所有角度范围内的直线
std::vector<cv::Vec2f> lines;
cv::HoughLines(dstMat, // 输入8位
lines, // 输出线 std::vector<std::Vec2f>
rh0 / 100.0f, // 初步像素精度
theta / 720.0 * CV_PI, // 初步偏移角度精度
threshold, // 必须达到的点的数量
0, // 标准霍夫变换,为0
0, // 标准霍夫变换,为0
0, // 检测角度范围最小为0
CV_PI); // 检测角度范围最大为π,即360°
// 在图中绘制出每条线段
dstMat = colorMat.clone();
qDebug() << __FILE__ << __LINE__ << lines.size();
for(int index = 0; index < lines.size(); index++)
{
float rho = lines[index][0];
float theta = lines[index][1];
cv::Point pt1;
cv::Point pt2;
double a = cos(theta);
double b = sin(theta);
double x0 = a * rho;
double 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(dstMat, pt1, pt2, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
}
// copy
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
// 使用概率霍夫线变化检测所有长度范围内的直线
cv::Canny(srcMat, dstMat, threshold1, threshold2, apertureSize * 2 + 1);
std::vector<cv::Vec4i> lines2;
cv::HoughLinesP(dstMat, // 输入8位
lines2, // 输出线 std::vector<std::Vec4i>
rh0/100.0f, // 初步像素精度
theta / 720.0 * CV_PI, // 初步偏移角度精度
threshold, // 必须达到的点的数量
minLineLength / 10.0f, // 检测线的最小长度
maxLineGap / 10.0f); // 检测线的最大距离
// 在图中绘制出每条线段
dstMat = colorMat.clone();
for(int index = 0; index < lines.size(); index++)
{
// 画线
cv::Vec4i line = lines2[index];
cv::line(dstMat,
cv::Point(line[0], line[1]),
cv::Point(line[2], line[3]),
cv::Scalar(0, 0, 255),
1,
cv::LINE_AA);
}
// copy
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
cv::Range(srcMat.cols * 1, srcMat.cols * 2));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
// 更新
cvui::update();
// 显示
cv::imshow(windowName, windowMat);
// esc键退出
if(cv::waitKey(25) == 27)
{
break;
}
}
}
プロジェクトテンプレート:対応するバージョン番号v1.38.0
対応するバージョン番号v1.38.0
参考ブログ投稿
https://blog.csdn.net/shenziheng1/article/details/75307410
オリジナルのブロガーのブログのアドレス:https://blog.csdn.net/qq21497936
オリジナルのブロガーがナビゲーションブログ:https://blog.csdn.net/qq21497936/article/details/102478062を
この記事のブログのアドレス:HTTPS://ブログ.csdn.net / qq21497936 /記事/詳細/ 105544972