点群フィルタリング、ダウンサンプリング、クラスタリング、セグメンテーション、ソート

1. 点群フィルタリングとノイズ低減アルゴリズム

統計的フィルタリング:

コンセプト: 明らかにまばらに分布している外れ値を削除します。指定された平均と分散に基づいて、分散の外側の点を削除します。

手順: 各ポイントについて、最も近い K ポイントの距離を計算し、平均を求めます。このとき、点群内の各点は平均値を持ちます。すべての平均と分散を計算し、123 の分散しきい値に基づいて外れ値をフィルターで除外します。

判定点の k 個の最近傍点の平均距離が、全体標準偏差 + 平均距離 (全体距離の平均と標準) の 1 倍より大きい場合、それは外れ値となります。

ストレートパスフィルター:

点群の属性に応じて、フィルタリングする範囲を設定します。たとえば、一般的な xyz 範囲です。

半径フィルター:

半径 R を設定し、R 内の点の数を数えます。しきい値未満の場合は外れ値です。

メディアンフィルター:

画像や信号からノイズを除去するために使用されます。具体的な実装は、スライディング ウィンドウ内のピクセル値を中間値に置き換えてフィルタリングを実装することです。

中央値を代理として選択するため、外れ値の影響を受けません。

平均フィルター:

ドメイン ウィンドウ内の平均値を計算してピクセル値を置き換えると、ノイズ除去の効果が得られますが、画像の細部が破壊され、画像がぼやけてしまいます。画像や信号を滑らかにする効果があります。

ガウスフィルター:

画像を滑らかにし、画像内のノイズを軽減するために使用されます。まず、ガウス カーネルのサイズと標準偏差を決定します。標準偏差によって、ガウス カーネルの形状と滑らかさが決まります。これら 2 つに基づいて 2 次元ガウス重み行列を生成し、畳み込みを実行します。標準偏差が大きいほど、曖昧になります。ガウス カーネルが大きくなるほど、ぼやけやすくなります。

2. 点群ダウンサンプリングアルゴリズム

1. ランダムダウンサンプリング

2. ボクセルのダウンサンプリング

点群をボクセルに変換した後、各ボクセル内の点をランダムに選択する方が高速であり、ボクセル内の平均値を求めることもできます。

3. 最遠点でのダウンサンプリング

毎回点を選択し、次回はそこから最も遠い残りの点を見つけて繰り返しを続けます。ノイズポイントの影響を受けやすく、一部の密なポイントは削除できます。

3. 点群クラスタリングアルゴリズム

1.K-meansクラスタリングアルゴリズム

K は不明なので手動で設定する必要があります。エルボー法を使用して K のサイズをトラバースし、損失が最も低いものを選択できます。

初期点に対してより敏感であり、いくつかの初期化方法を選択し、最終的に損失が最小のものを選択できます。

ノイズ ポイントの問題では、平均する代わりに、クラス内の他のポイントまでの距離が最も短いポイントを中心ポイントとして選択できます。

アルゴリズム プロセス: 最初に K 個の中心点をランダムに選択し、次にどの中心点が各点に最も近いか、およびそれがどのカテゴリに属する​​かを計算します。次に、各クラスの平均値が新しい中心点として計算され、反復が開始されます。一定の回数まで、または中心点がほとんど変化しないまで。

アルゴリズムの複雑さは次のとおりです: t (反復回数) * k (中心点の数) * N (点の総数) * d (各点の次元)。

2.平均値シフトクラスタリングアルゴリズム

半径 R の球の中心として点をランダムに選択し、半径内の点の平均を新しい中心点として見つけて、このように繰り返します。中心点が変化しなくなるまで、またはほとんど変化しないまで。プロセスのすべてのポイントがこのカテゴリに分類されます。次に、収束した中心点と既存の中心点の間の距離がしきい値より大きいかどうかを判断し、そうでない場合はマージします。

meansshift は反復ごとにこの中心点と他のすべての点の間の距離を計算する必要があるため、非常に時間がかかります。私たちのアイデアは、すべての点の既存の中心点を見つけることであり、これにはほとんど時間がかかりません。

簡易バージョン: データを走査し、データと既存の中心点の間の距離を計算し、しきい値未満の場合は 1 つのカテゴリに分類し、カテゴリの新しい中心値を更新します。

3.DBSCANクラスタリングアルゴリズム

フィルタリングが組み込まれたクラスタリング アルゴリズム。まず、半径 R を設定します。半径内の点の数が一定数未満のものをノイズ点、残りをコア点とします。密度ベースのクラスタリング アルゴリズムに基づいて、コア点の半径内のコア点は、同じカテゴリ内で、このカテゴリに対して R 内の他のコア ポイントを繰り返します。R にこの核心点だけが存在するまで。そのような点をすべての点から削除し、上記の繰り返しを続けます。

R 選択スキル: 一般に、最初に点を選択し、その点と他のすべての点の間の距離を計算し、次にそれを並べ替えて前後で大きく変化した場所を見つけます。その後、R が突然変異点を選択します。これを大きすぎるとクラスターが少なくなり、小さすぎるとクラスターが多くなりますので、適切に調整してください。

min_point の値は通常小さすぎるため、複数回試行できます。

4. 点群セグメンテーションアルゴリズム

1.ランサック

これは、サンプルから継続的にランダムにサンプリングし、外れ値誤差を計算するランダム サンプリング アルゴリズムです。サンプリング方程式に属する内部点の数が特定のしきい値より大きい限り、サンプリング方程式は直接終了します。

#include <iostream>
#include <vector>
#include <cmath>
#include <random>

struct Point {
  double x;
  double y;
};

// 计算两点之间的距离
double distance(const Point& p1, const Point& p2) {
  return std::sqrt(std::pow(p2.x - p1.x, 2) + std::pow(p2.y - p1.y, 2));
}

// 使用 RANSAC 算法拟合直线
void ransacLineFitting(const std::vector<Point>& points,
                      int maxIterations,
                      double distanceThreshold,
                      double inlierRatioThreshold,
                      std::vector<Point>& inliers,
                      double& slope,
                      double& intercept) {
  std::random_device rd;
  std::mt19937 rng(rd());
  std::uniform_int_distribution<int> uni(0, points.size() - 1);

  int bestInlierCount = 0;

  for (int iteration = 0; iteration < maxIterations; ++iteration) {
    // 随机选择两个点
    int index1 = uni(rng);
    int index2 = uni(rng);

    const Point& p1 = points[index1];
    const Point& p2 = points[index2];

    // 计算斜率和截距
    slope = (p2.y - p1.y) / (p2.x - p1.x);
    intercept = p1.y - slope * p1.x;

    // 用于保存内点
    std::vector<Point> currentInliers;

    for (const Point& point : points) {
      // 计算点到直线的距离
      double d = std::abs(point.y - slope * point.x - intercept);

      // 判断是否是内点
      if (d < distanceThreshold) {
        currentInliers.push_back(point);
      }
    }

    // 更新最佳内点数和内点集合
    if (currentInliers.size() > bestInlierCount) {
      bestInlierCount = currentInliers.size();
      inliers = std::move(currentInliers);

      // 计算内点比例
      double inlierRatio = static_cast<double>(bestInlierCount) / points.size();

      // 如果内点比例达到阈值,提前退出循环
      if (inlierRatio > inlierRatioThreshold) {
        break;
      }
    }
  }
}

int main() {
  // 构造示例数据点云
  std::vector<Point> points {
    {0.0, 0.5},
    {1.0, 2.0},
    {2.0, 3.5},
    {3.0, 4.5},
    {4.0, 6.0},
    {5.0, 7.5},
    {6.0, 9.0},
    {7.0, 10.5}
  };

  // RANSAC 参数
  int maxIterations = 1000;       // 最大迭代次数
  double distanceThreshold = 0.5; // 内点阈值
  double inlierRatioThreshold = 0.8; // 内点比例阈值

  // 输出结果保存变量
  std::vector<Point> inliers;
  double slope, intercept;

  // 使用 RANSAC 拟合直线
  ransacLineFitting(points, maxIterations, distanceThreshold, inlierRatioThreshold,
                    inliers, slope, intercept);

  // 输出拟合结果
  std::cout << "拟合直线方程:y = " << slope << "x + " << intercept << std::endl;
  std::cout << "内点数量:" << inliers.size() << std::endl;

  return 0;
}

おすすめ

転載: blog.csdn.net/slamer111/article/details/131750126