1. シトマシ検出器
1.1 アルゴリズムの特徴:
- Shi-Tomasi 検出器は、Harris アルゴリズムの改良版を使用します。これにより、画像エッジを処理する際のパフォーマンスが向上し、より安定したコーナーを検出できます。
- Shi-Tomasi 検出器は、特徴点での共分散行列を計算し、それに対して固有値分解を実行することにより、各特徴点のコーナー応答関数を取得します。
- Shi-Tomasi 検出器は、さまざまなアプリケーション シナリオに適応するために、しきい値を設定することで検出されるコーナーの数を制御できます。
- Shi-Tomasi 検出器は、SIFT や SURF などの他のコーナー検出アルゴリズムよりも計算がはるかに高速であるため、リアルタイムのコンピューター ビジョン アプリケーションに適しています。
結論として、Shi-Tomasi 検出器は、高速、正確、制御可能なコーナー検出アルゴリズムとして、コンピューター ビジョンの分野で幅広い用途があります。
1.2 アルゴリズムのステップ
-
ソーベル微分フィルターまたは他の勾配推定アルゴリズムを使用して、画像内の各ピクセルの x 方向と y 方向の勾配を計算します。
-
各ピクセルについて、2x2 局所自己相関行列 M を計算します。
M = ( ∑ x , y ∈ N ( I x ) 2 ∑ x , y ∈ NI x I y ∑ x , y ∈ NI x I y ∑ x , y ∈ N ( I y ) 2 ) , M=\begin{ pmatrix} \sum_{x,y\in N}(I_x)^2 & \sum_{x,y\in N}I_xI_y \\ \sum_{x,y\in N}I_xI_y & \sum_{x,y\ N}(I_y)^2 \end{pmatrix} において、M=(∑x , y ∈ N(私×)2∑x , y ∈ N私×私はい∑x , y ∈ N私×私はい∑x , y ∈ N(私はい)2)、
このうち、N は現在のピクセルを中心とする近傍ウィンドウを表します。
-
M の固有値 λ1 と λ2 を計算します。
-
このピクセルがコーナーポイントであるかどうかを判断します。使用される方法は、λ1 と λ2 を組み合わせて応答関数 R を計算することです。
一般的な応答関数には次のものがあります。
R = 最小 ( λ 1 , λ 2 ) R = λ 1 + λ 2 R = λ 1 λ 2 R = {\rm min}(\lambda_1, \lambda_2)\\ R = \lambda_1 + \lambda_2 \\ R = \frac{\lambda_1}{\lambda_2}R=分( l1、私2)R=私1+私2R=私2私1
通常、最初の関数はコーナー スコアの計算に使用され、すべてのピクセル ポイントのスコアが比較されてコーナー ポイントであるかどうかが判断されます。
- 非最大値抑制を実行して、繰り返されるコーナーを削除します。
- まず Shi-Tomasi コーナー検出を実行して、検出されたすべてのコーナーとその応答値 (キーポイント スコア) を取得します。
各キー ポイントについて、その周囲の特定のサイズ (3x3 や 5x5 など) の近傍にあるすべてのキー ポイントの応答値を計算し、それらの中で最大の応答値を見つけて、この値を現在のキーの応答値と比較します。点。
現在のキーポイントの応答値が最大でない場合、そのキーポイントは候補リストから削除されます。それ以外の場合は、ポイントを保持し、次のポイントまで処理を続行します。
bool compShiTomasiScore(const cv::Mat& img, const Eigen::Vector2i& px, double* score) {
CHECK_NOTNULL(score);
CHECK(img.type() == CV_8UC1);
constexpr int kHalfPatchSize = 4;
constexpr int kPatchSize = 2 * kHalfPatchSize;
constexpr int kPatchArea = kPatchSize * kPatchSize;
const int x_min = px(0) - kHalfPatchSize;
const int x_max = px(0) + kHalfPatchSize;
const int y_min = px(1) - kHalfPatchSize;
const int y_max = px(1) + kHalfPatchSize;
if (x_min < 1 || x_max >= img.cols - 1 || y_min < 1 || y_max >= img.rows - 1)
return false;
float dXX = 0.0;
float dYY = 0.0;
float dXY = 0.0;
const int stride = img.step.p[0];
for (int y = y_min; y < y_max; ++y) {
const uint8_t* ptr_left = img.data + stride * y + x_min - 1;
const uint8_t* ptr_right = img.data + stride * y + x_min + 1;
const uint8_t* ptr_top = img.data + stride * (y - 1) + x_min;
const uint8_t* ptr_bottom = img.data + stride * (y + 1) + x_min;
for (int x = 0; x < kPatchSize; ++x, ++ptr_left, ++ptr_right, ++ptr_top, ++ptr_bottom) {
float dx = *ptr_right - *ptr_left;
float dy = *ptr_bottom - *ptr_top;
dXX += dx * dx;
dYY += dy * dy;
dXY += dx * dy;
}
}
// Find and return smaller eigenvalue:
dXX = dXX / (2.0f * kPatchArea);
dYY = dYY / (2.0f * kPatchArea);
dXY = dXY / (2.0f * kPatchArea);
*score = 0.5f * (dXX + dYY - std::sqrt((dXX - dYY) * (dXX - dYY) + 4 * dXY * dXY));
return true;
}
これは Shi-Tomasi 検出器のアルゴリズム ステップであり、画像内の目立つコーナーを検出することで、特徴マッチングやオブジェクト追跡などのコンピューター ビジョン タスクに役立ちます。
1.3 8 近傍非最大抑制アルゴリズム
8 近傍非最大抑制アルゴリズム。非最大抑制はコンピュータ ビジョンで一般的に使用される手法で、画像内の冗長な特徴点を削除し、最も代表的な特徴点のみを保持するのに役立ちます。この関数は、入力スコア マップ スコアとコーナー グリッド グリッドに対して動作し、フィルター処理されたコーナー コーナーを出力します。
特定の実装では、関数はスコア マトリックスの各点をトラバースすることによって中心点 (center) とその周囲の 8 点 (p1 ~ p8) の座標を決定し、コーナー グリッド (k ) での位置を特定します。中心点のスコアが設定されたしきい値より小さい場合、直接スキップされます。それ以外の場合は、この点と周囲の点のスコア関係を確認し、非最大抑制の条件が満たされない場合はスキップします。スコアが他のポイントよりも高く、現在のコーナー ポイントのスコアよりも大きい場合は、コーナー ポイント情報を更新し、特にポイントの座標、スケール (つまり、ピラミッド レイヤーの数、レベル) を含むコーナー リストに追加します。 、スコア、角度、その他の情報。角度を計算するには getAngleAtPixelUsingHistogram() 関数を呼び出す必要があります。
非最大抑制プロセス全体が各ピラミッド レベルで 1 回実行され、さまざまなスケールで処理されて、よりグローバルなコーナー フィーチャが取得されます。
// 8-neighbor nonmax suppression
const int stride = score.step;
for (int y = border; y < score.rows - border; ++y) {
const float* p = &score.at<float>(y, border);
for (int x = border; x < score.cols - border; ++x, ++p) {
const int k = grid.getCellIndex(x, y, scale);
if (grid.occupancy_.at(k))
continue;
const float* const center = p;
if (*center < threshold)
continue;
if (*(center + 1) >= *center)
continue;
if (*(center - 1) > *center)
continue;
const float* const p1 = (center + stride);
const
float* const p2 = (center - stride);
if (*p1 >= *center)
continue;
if (*p2 > *center)
continue;
if (*(p1 + 1) >= *center)
continue;
if (*(p1 - 1) > *center)
continue;
if (*(p2 + 1) >= *center)
continue;
if (*(p2 - 1) > *center)
continue;
Corner& c = corners.at(k);
if (*p > c.score) {
c.x = x * scale;
c.y = y * scale;
c.level = level - 1;
c.score = *p;
c.angle = getAngleAtPixelUsingHistogram(img_pyr[level], Eigen::Vector2i(x, y), 4);
}
}
}