- この記事は、 1: フロンティアの紹介--> 2: 質問 --> 3: 解決策の構成に従って説明されています。
1: フロンティアの紹介
orb-slam2 の void Frame::ComputeStereoMatches() 関数は、双眼カメラのコンストラクター Frame::Frame() によって呼び出され、1 フレームで双眼カメラによって取得された左右の画像とステレオによって奥行きが取得されます。左右の写真情報の一致。orb-slam2 の処理手順は次のとおりです (作成者: guoqing を参照)。
2 つの画像フレームの疎なステレオ マッチング (つまり、ORB 特徴点のマッチング、非ピクセル単位の密なマッチング、ただしラインの位置合わせは満足)
入力: ステレオ修正画像 img_left および img_right の 2 フレームに対応するオーブ特徴点セット
- 行特徴点統計: img_right の各行に設定された ORB 特徴点をカウントします。ステレオ マッチング (行検索/極線検索) を使用して同じ名前の点を検索し、ピクセルごとの判断を回避するのに便利です。 。
- 粗マッチング ステップ1の結果に従い、img_leftのi行目のオーブ特徴点piに対して、img_rightのi行目のオーブ特徴点集合の中から類似するオーブ特徴点を検索し、qiを取得する
- 完全一致 点 qi を中心として半径 r の範囲内でブロックマッチング(正規化 SAD)を行い、マッチング結果をさらに最適化します。
- サブピクセル精度の最適化 手順3で取得した視差はuchar/int型の精度であり、実際の視差とは限りません、float精度の実際の視差はサブピクセルの差分(放物線補間)により取得します。
- 最適な視差値/深度選択 Winner-Taken Algorithm (WTA) により最適なマッチング ポイントを取得します。
- 外れ値を削除します。ブロック マッチングの類似性しきい値の判定では、正規化された悲しい値が最小ですが、正しい一致である必要があるとは限りません。照明の変化や弱いテクスチャなどにより、誤った一致が発生します。
出力: スパース特徴点視差マップ/深度マップ (サブピクセル精度) mvDepth マッチング結果 mvuRight
双眼カメラの構造の特殊性により、エピポーラ線は列と平行になります。そのため、1.行特徴点統計では、右図の各行に設定されたORB特徴点をカウントし、特徴点が一致した場合、左図の特徴点が一致した場合には、画像の場合、行の ORB 特徴点セットに基づいてカウントできるため、ピクセルごとの比較が回避されます。
私の質問は、右側の行の特徴点をカウントする操作にあります。
2: 疑い
右側の行の特徴点を数える操作:
1. ピラミッドの第 0 層 (元の画像) の高さを行として、右画像の特徴点を行ごとに数えます。
// 金字塔底层(0层)图像高 nRows
const int nRows = mpORBextractorLeft->mvImagePyramid[0].rows;
つまり、ピラミッド全体から抽出された特徴点は、第0層の行に従って均一に整理されます。
2. 2 次元ベクトルを使用して、各行のオーブ特徴点のインデックスを格納します
vector<vector<size_t> > vRowIndices(nRows, vector<size_t>());
for(int i=0; i<nRows; i++) vRowIndices[i].reserve(200);
// 右图特征点数量,N表示数量 r表示右图,且不能被修改
const int Nr = mvKeysRight.size();
for(int iR = 0; iR < Nr; iR++) {
// 获取特征点ir的y坐标,即行号
const cv::KeyPoint &kp = mvKeysRight[iR];
// 获取特征点ir的y坐标,即行号
const float &kpY = kp.pt.y;
// 这里考虑到了不同金字塔层提取的特征点的尺度问题,动态变化上下行搜索范围
// 但是为什么不考虑不同金字塔特征点ir的y坐标的尺度问题呢?
// 就这样把它归为第0层的某行特征点?
const float r = 2.0f * mvScaleFactors[mvKeysRight[iR].octave];
const int maxr = ceil(kpY + r);
const int minr = floor(kpY - r);
for(int yi=minr;yi<=maxr;yi++)
vRowIndices[yi].push_back(iR);
}
私の質問は次のとおりです。
異なるピラミッド層で抽出された特徴点のスケールが考慮されるようになり、上下の探索範囲が動的に変更されます(ただし、エピポーラ線の原理により、一致する特徴点は右側の同一線上にあるはずです)画像ではありますが、誤差を考慮すると、やはり最も近い上下のライン トラバースになります)
しかし、異なるピラミッド層の特徴点 ir の y 座標のスケールを考慮してはどうでしょうか? それをレイヤー 0 の特定の特徴点の行として分類するだけですか?
3: 解決する
コードがこれを認識すると、スタックしてしまいます。なぜ異なるピラミッド層の特徴点のy座標を第0層として使用できるのか理解できませんでした。作者はここでミスをしたのではないかと思います...
後ほど、ORBextractor.cc のファンクター ORBextractor::operator() のピラミッド層をもう一度見てみましょう。
// Step 6 对非第0层图像中的特征点的坐标恢复到第0层图像(原图像)的坐标系下
// ? 得到所有层特征点在第0层里的坐标放到_keypoints里面
// 对于第0层的图像特征点,他们的坐标就不需要再进行恢复了
if (level != 0)
{
// 获取当前图层上的缩放系数
float scale = mvScaleFactor[level];
// 遍历本层所有的特征点
for (vector<KeyPoint>::iterator keypoint = keypoints.begin(), keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
// 特征点本身直接乘缩放倍数就可以了
keypoint->pt *= scale;
}
異なるピラミッド層で抽出された特徴点の座標は、第0層画像(元画像)の座標系に復元されていることがわかります。
orb-slam2 はコードが多く、ある点に注意しないと固まってしまいます。私と同じ混乱を抱えている誰かを助けることを願って、それを共有します。