9

ノイズの多い X、Y ポイントのソートされていないリストがあります。ただし、それらは世界を通る道を形成します。線分を使用してこのデータの近似値を描画するアルゴリズムが必要です。

これは、ライン フィッティング アルゴリズムを使用して線形データの近似値を選択する方法に似ています。私の問題は、道が曲がりくねって世界中を曲がりくねっているので、難しいだけです。 代替テキスト http://www.praeclarum.org/so/pathfinder.png

これを達成するための標準/堅牢/理解しやすいアルゴリズムを知っている人はいますか?

質疑応答

うるさいってどういう意味ですか?パスを理想的に実現した場合、X 要素と Y 要素にガウス ノイズを追加して、その理想的なパスから点のセットをサンプリングします。そのノイズの平均または標準偏差はわかりません。std devで推測できるかもしれません...

ポイントは、近似しようとしている理想的だが複雑なパスの近くにありますが、そのパス上にはありませんか? はい。

パスの形状に関するアプリオリな情報はありますか? そのような情報を取得する他の方法はありますか?残念ながら違います。

4

10 に答える 10

5

Bezier Interpolationがあなたの問題に合うかもしれません。

ベジェ補間

ただし、これはパスへのポイントの順序付けには対応していません。考慮すべきいくつかのアプローチがあります。

  • 「最適な」タイプのパス (パス上の各ポイントでの最小の方向変更、* すべてのポイントを通る最短パスなど) は、NP 完全巡回セールスマン問題(TSP) を煮詰める可能性があります。
  • ノードをクラスタ化し、クラスタ間およびクラスタ内でルーティングするための「妥当な」パス。もちろん、クラスタが大きいほど、またはクラスタの数が多いほど、この小さな問題が大きな n TSP のように見えます。
  • ポイントを 1 つの軸で並べ替えます。軸が 2 つをはるかに超える場合は、いくつかの次元削減戦略が役立つ場合があります。例えば、独立成分分析。
于 2008-10-27T16:26:00.380 に答える
4

並べ替えられていないリストでは、各セグメントにどのポイントを含めるかがよくわからないため、最も近いポイントを使用できると思います。

1 つの方法は、開始点をランダムに選択し、各ステップの次の点として最も近い点を選択することです。最初の 2 点を集合 S に追加します。

RMS がある値を超えるまで S の点に線を当てはめ、次に S をクリアして新しい線を開始します。

連続する線の交点がセグメントの終点になります。

于 2008-10-27T16:33:51.987 に答える
2

これは、データの順序の問題に対処する可能性のあるヒューリスティックハックです。

  • あなたは十分なポイントを持っています
  • ポイント間の平均距離は、パスに期待される最小の曲率半径と比較して小さいです。
  • ポイント間の平均距離は、標準と比較して大きくありません。開発者 ノイズの
  • パスは自己交差ではありません(幸運になるかもしれませんが、保証はありません)

このように進めます:

  1. 開始点p1を(できればランダムではなく意味のある方法で)選択します。
  2. あるクラスタリング距離、p1のr_c内にあるすべての点を見つけます。予想される回転半径と比較すると小さいが、散乱と比較すると大きいr_cを選択します。
  3. このクラスターをC1と呼びます。
  4. C1の位置の平均点q1を見つけます。
  5. C1のポイントに線を合わせ、クラスターのエッジに(またはそのすぐ先に)投影し、元のデータで最も近いポイントを見つけます。その点にp2のラベルを付けます。
  6. データがなくなるまで、手順2〜5を繰り返します。

これで、順序付けされたポイントq1..qnの新しいリストができました。

私の頭のてっぺんから、非常に荒く、そしてかなり良い条件の下でのみ機能します...


ステップ(5)で、新しい投影線が前の線の最大角度内にあることを要求することで、自己交差動作を改善できる可能性があります。

于 2008-10-27T16:58:50.907 に答える
2

ベジエ曲線の問題は、サンプリングしたポイントを実際には通過せず、ポイント サンプルが少し歪んでいるにもかかわらずです。ベジエ曲線は実際には何マイルも離れている可能性があります。

より良い近似、および元の画像によりよく似ているように見える解決策は、Catmull-Rom スプラインです。これは、曲線内のすべての点を通過するためです。

于 2008-10-27T23:35:17.690 に答える
2

ポイントが互いに近接している場合は、通常の「直線」(直交線) にすることができます。通常の平滑化アルゴリズムを使用します。世界がフラットに見えます。

距離が離れている場合は、大円を使用してポイントからポイントへ移動することで、地球の丸みを補正する必要があります。そうしないと、直線が長くなります。

ポイントが遠すぎて直線を作成できない場合は、選択します。

さらに、各ポイントを「訪問」する必要があるのか​​、単に近くに行く必要があるのか​​、その近くがどれだけ近いかを知る必要があります。

コースを飛行機、船、または他の旅行者に送る必要がある場合は、おそらく各ポイントを訪れる必要があります。オブジェクトから GPS データを取得する場合、画面上にコースをプロットしてノイズを除去したいだけでしょう。


編集内容を確認した後: これがプロットしたい軌道を移動するオブジェクトである場合、x/y 値の代わりに方向と速度を滑らかにしたい場合があります。(測定値 (x) を固定し、Y 間隔を増やすと、平滑化がはるかに簡単になります。)

于 2008-10-27T16:25:50.943 に答える
1

私のアプローチは、最初にポイントのリストを並べ替えてから、ベジェ曲線を使用することです。

秘訣はもちろんソートです。1つのランダムな点から始めて、最も近い点を見つけます。これら2つが接続されていると仮定します。これらの2つのエンドポイントを使用して、それらに最も近いポイントを見つけます。端点までの距離が小さい方がその点に接続されていると仮定します。すべてのポイントが接続されるまで繰り返します。

このアプローチにはまだいくつかの問題があると思いますが、おそらくそれを出発点として使用することができます(しゃれを意図した)。

編集:さまざまな開始点で数回実行してから、結果がどこで異なるかを確認できます。それは少なくともあなたにある程度の自信を与えます、それはどのポイントが互いに接続されているかです。

于 2008-10-27T17:14:08.927 に答える
1

別の制約を必要としない完全に異なるアプローチですが、詳細はアプリケーションによって異なる場合があります。パスの周りに「密集した点群」がある場合に最適です。

曲線と点群の差を定義する「コスト」関数を使用します。パラメータ化された曲線と標準の最適化アルゴリズムを使用します。- または - 最初から最後まで直線の曲線で開始し、遺伝的アルゴリズムを使用して修正します。

典型的なコスト関数は、各ポイントと曲線の間の最小距離を取得し、2 乗を合計することです。

最適化または遺伝的アルゴリズムを提案するのに十分な経験はありませんが、それができると確信しています:)

遺伝的アルゴリズムは次のように想像できます。パスはウェイポイントから構築されます。最初から最後まで N 個のウェイポイントを直線上に配置することから始めます。(N は問題に応じて選択できます)。変異は次のとおりです。

  1. 各セグメントで、rnd() < x の場合、中間に新しいウェイポイントが導入されます。
  2. ウェイポイントごとに、X 座標と Y 座標がわずかに異なります。

コスト関数に全長を含める必要があります。分割は必要ないかもしれませんし、より多くのウェイポイントが導入されるにつれて x (「分割チャンス」) を減らす必要があるかもしれません。(2) を開始点と終点に適用する場合と適用しない場合があります。

やってみると面白いかも…

于 2008-10-27T19:18:38.690 に答える
1

「ソートされていないリスト」とは、ポイントのセットが完成している間、それらがどの順序で移動されたかわからないことを意味すると思いますか?

ガウス ノイズは基本的に無視する必要があります。元のノイズのないパスを再構築する試みを可能にする情報はまったく与えられません。したがって、私たちができる最善のことは、ポイントが正しいと仮定することだと思います。

この時点で、タスクは「一連のポイントを通る最適なパスを見つける」ことで構成され、「最適」はあいまいなままです。ユークリッド空間で一連の点を並べ替えようとするコードを作成しました。直線がより直線になる並べ替えを優先します。メトリクスは簡単に実装できましたが、それに基づく順序付けを改善する良い方法が思いつかなかったので、ランダムにポイントを交換してより良い配置を探しました。

そこで、これを行う PLT スキーム コードをいくつか示します。

#lang scheme

(require (only-in srfi/1 iota))

; a bunch of trig
(define (deg->rad d)
  (* pi (/ d 180)))

(define (rad->deg r)
  (* 180 (/ r pi)))

(define (euclidean-length v)
  (sqrt (apply + (map (lambda (x) (expt x 2)) v))))

(define (dot a b)
  (apply + (map * a b)))

(define (angle-ratio a b)
  (/ (dot a b)
     (* (euclidean-length a) (euclidean-length b))))

; given a list of 3 points, calculate the likelihood of the
; angle they represent. straight is better.
(define (probability-triple a b c)
  (let ([av (map - a b)]
        [bv (map - c b)])
    (cos (/ (- pi (abs (acos (angle-ratio av bv)))) 2))))

; makes a random 2d point. uncomment the bit for a 3d point
(define (random-point . x)
  (list (/ (random 1000) 100)
        (/ (random 1000) 100)
        #;(/ (random 1000) 100)))

; calculate the likelihood of an entire list of points
(define (point-order-likelihood lst)
  (if (null? (cdddr lst))
      1
      (* (probability-triple (car lst)
                             (cadr lst)
                             (caddr lst))
         (point-order-likelihood (cdr lst)))))

; just print a list of points
(define (print-points lst)
  (for ([p (in-list lst)])
    (printf "~a~n"
            (string-join (map number->string
                              (map exact->inexact p))
                         " "))))

; attempts to improve upon a list
(define (find-better-arrangement start
                                 ; by default, try only 10 times to find something better
                                 [tries 10]
                                 ; if we find an arrangement that is as good as one where
                                 ; every segment bends by 22.5 degrees (which would be
                                 ; reasonably gentle) then call it good enough. higher
                                 ; cut offs are more demanding.
                                 [cut-off (expt (cos (/ pi 8))
                                                (- (length start) 2))])
  (let ([vec (list->vector start)]
        ; evaluate what we've started with
        [eval (point-order-likelihood start)])
    (let/ec done
      ; if the current list exceeds the cut off, we're done
      (when (> eval cut-off)
        (done start))
      ; otherwise, try no more than 'tries' times...
      (for ([x (in-range tries)])
        ; pick two random points in the list
        (let ([ai (random (vector-length vec))]
              [bi (random (vector-length vec))])
          ; if they're the same...
          (when (= ai bi)
            ; increment the second by 1, wrapping around the list if necessary
            (set! bi (modulo (add1 bi) (vector-length vec))))
          ; take the values from the two positions...
          (let ([a  (vector-ref vec ai)]
                [b  (vector-ref vec bi)])
            ; swap them
            (vector-set! vec bi a)
            (vector-set! vec ai b)
            ; make a list out of the vector
            (let ([new (vector->list vec)])
              ; if it evaluates to better
              (when (> (point-order-likelihood new) eval)
                ; start over with it
                (done (find-better-arrangement new tries cut-off)))))))
      ; we fell out the bottom of the search. just give back what we started with
      start)))

; evaluate, display, and improve a list of points, five times
(define points (map random-point (iota 10)))
(define tmp points)
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
(set! tmp (find-better-arrangement tmp 10))
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
(set! tmp (find-better-arrangement tmp 100))
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
(set! tmp (find-better-arrangement tmp 1000))
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
(set! tmp (find-better-arrangement tmp 10000))
(printf "~a~n" (point-order-likelihood tmp))
(print-points tmp)
于 2008-11-08T00:14:00.647 に答える
0

質問への回答から「黄金の曲線」を知っているようです。@jameshが提案した「黄金の曲線」のベジェ曲線を見つけて描画することをお勧めします。

于 2008-10-27T17:00:29.827 に答える
0

あなたは何点持っていますか?
前述のように、ポイントが比較的少ない場合は、ベジエ曲線を使用することをお勧めします。ポイントが多い場合は、dmckee の提案に従ってクラスターを構築します。

ただし、ポイントの順序を定義するための別の制約も必要です。ポイントを選択する方法については多くの優れた提案がありましたが、別の制約を導入しない限り、可能な解決策が得られます。

私が考えることができる可能な制約:

  • 最短経路
  • 最も直線的なセグメント
  • 最小総絶対回転数
  • 方向の好み (つまり、交差するよりも水平/垂直の方が可能性が高い)

いずれの場合も、制約を満たすには、おそらくシーケンスのすべての順列をテストする必要があります。「良い推測」から始めると、他の推測をすぐに終わらせることができます。

于 2008-10-27T18:54:20.457 に答える