ラスター処理を使用してポイントが囲まれているかどうかを判断する


9

自然災害モデルのために、現在非常に厄介なベクター/ Pythonプロセスを改善しようとしています。現時点では、特定のポイントからの距離/方位線を生成して決定する長いスクリプトがあります。

  1. 交差するポリゴンのタイプ(森、草、沼など)
  2. そのポリゴンまでの距離
  3. これらの線のどれだけがポリゴンと交差し、どれだけ「囲まれている」かを決定します。

より多くの関与がありますが、それはそれの要点です。私はこれを改善する方法を見つけようとしていて、現在パート3で困惑しています。アイデアは、ポイントがポリゴンで完全に囲まれているかどうか、たとえば200m以内かどうかを判断することですPointAは囲まれていますが、PointBは約50%しか囲まれていません

そのため、添付画像では、ポリゴンで完全に囲まれているため、ポイントAをポイントBよりもリスクが高いとマーク付けします。これは約1300万ポイント繰り返されるため、簡単な作業ではありません。スクリプトを実行するのではなく、値を導出するためのサーフェスを用意します。これを行うには、水文学のツールやコストパスのバリエーションが必要だと思いますが、頭を悩ませることはできません。

これについてどうすればいいですか?


1
可視領域は任務次第ですが、1300万ポイントに適用されるとかなりの助けが必要になります!直径が(たとえば)200m未満のポリゴンの外部領域にあるポイントなど、周囲がチェックしやすいポイントを間引く方法について最初に考えます。「A」は除外できるが、「B」は除外できない可能性があります。「B」は、その可視領域(ポリゴン領域をビューをブロックする非常に「高い」場所にすること)がBの場所から200m以上離れているため、決して除外されません。
whuber

良い点@whuber。確かに、実際に近接によって実際に処理されたポイントの総数を減らすことができ、実際には固有の緯度経度も(アパートのブロックを50ポイントから1に減らすことができるようにジオコーディングされた住所を話している)、しかし私はまだ探している数百万の場所で。必要に応じて、すべてを重複するブロックに分割することもできます。可視領域を調査します。ありがとう!
Loz

別の簡単な画面は、環状の近傍を使用して、ポリゴンの0-1インジケーターグリッドの焦点平均を計算することです。値が1のセルでは、ポリゴンは囲まれている必要があるため、半径で外周全体を占めます。これは高速な計算であり、ポイントの場所やポリゴンの複雑さによっては、ポイントの大部分が除外される可能性があります。最初にグリッドを25-50 mなどのより粗い解像度に再サンプリングすることで、初期スクリーニングを高速化することもできます。
whuber

別の潜在的な処理ステップ、または前処理ステップは、ポイントの周辺の統計を比較するデータセットのラスタライズバージョンにポイントを渡すことです。ポイントの近傍の統計として「囲まれた」要件を抽象化するか、または「囲まれた」が必要な場合は、ラスター近傍を使用して「簡単な」ポイント(つまり、完全にリスク領域内のポイント)を見つけることができます。すべてのポイントから「簡単な」ポイントを解析し、残りのポイントに対してベクトル分析を使用します。
DPierce 2014年

すごい私のクエリは確かに多くの関心を生み出しています!提案やコメントを提供してくれた皆さんに感謝します。私はそれらすべてを通して私の方法で作業し、応答しますが、それらはすべて私がテストするのにしばらく時間がかかります。私は最終的に対応することを約束します!
Loz

回答:


6

コストパスソリューションがありますが、自分でコーディングする必要があります。問題の画像のすべての点 に適用すると、次のようになります(計算を高速化するために少し粗くしました)。

図0

黒いセルは周囲のポリゴンの一部です。ライトオレンジ(ショート)からブルー(ロング)までの色は、ポリゴンセルを妨害せずに見通し内トラバーサルによって到達できる最大距離(最大50セルまで)を示します。(この画像の範囲外のセルは、ポリゴンの一部として扱われます。)

データのラスター表現を使用してこれを行う効率的な方法について説明します。この表現では、すべての「周囲の」多角形セルは、たとえばゼロ以外の値を持ち、「透けて見える」可能性のあるセルはすべてゼロの値を持ちます。

ステップ1:近隣データ構造の事前計算

最初に、あるセルが別のセルをブロックすることの意味を決定する必要があります。私が見つけることができる最も公平なルールの1つはこれです:行と列の積分座標を使用して(そして正方形のセルを想定)、原点(0,0)のビューからセル(i、j)をブロックする可能性があるセルを考えてみましょう。座標がiおよびjと最大で1だけ異なるすべてのセルの中で(i、j)を(0,0)に接続する線分に最も近いセル(i '、j')を指定します一意のソリューションを生成します(たとえば、(i、j)=(1,2)((0,1)と(1,1)の両方が同じように機能します))、関係を解決するいくつかの手段が必要です。グリッド内の円形の近傍の対称性を尊重すると、この関係の解決に適しています。座標を無効にするか、座標を切り替えると、これらの近傍が保持されます。したがって、ブロックするセルを決定できます(i、

このルールを説明するのが、で記述された次のプロトタイプコードですR。このコードは、グリッド内の任意のセルの「周囲」を決定するのに便利なデータ構造を返します。

screen <- function(k=1) {
  #
  # Returns a data structure:
  #   $offset is an array of offsets
  #   $screened is a parallel array of screened offset indexes.
  #   $distance is a parallel array of distances.
  # The first index always corresponds to (0,0).
  #
  screened.by <- function(xy) {
    uv <- abs(xy)
    if (reversed <- uv[2] > uv[1]) {
      uv <- rev(uv)
    }
    i <- which.min(c(uv[1], abs(uv[1]-uv[2]), uv[2]))
    ij <- uv + c(floor((1-i)/3), floor(i/3)-1)
    if (reversed) ij <- rev(ij)
    return(ij * sign(xy))
  }
  #
  # For each lattice point within the circular neighborhood,
  # find the unique lattice point that screens it from the origin.
  #
  xy <- subset(expand.grid(x=(-k:k), y=(-k:k)), 
               subset=(x^2+y^2 <= k^2) & (x != 0 | y != 0))
  g <- t(apply(xy, 1, function(z) c(screened.by(z), z)))
  #
  # Sort by distance from the origin.
  #
  colnames(g) <- c("x", "y", "x.to", "y.to")
  ij <- unique(rbind(g[, 1:2], g[, 3:4]))
  i <- order(abs(ij[,1]), abs(ij[,2])); ij <- ij[i, , drop=FALSE]
  rownames(ij) <- 1:length(i)
  #
  # Invert the "screened by" relation to produce the "screened" relation.
  #
  # (Row, column) offsets.
  ij.df <- data.frame(ij, i=1:length(i))
  #
  # Distances from the origin (in cells).
  distance <- apply(ij, 1, function(u) sqrt(sum(u*u)))
  #
  # "Screens" relation (represented by indexes into ij).
  g <- merge(merge(g, ij.df), ij.df, 
             by.x=c("x.to", "y.to"), by.y=c("x","y"))
  g <- subset(g, select=c(i.x, i.y))
  h <- by(g$i.y, g$i.x, identity)

  return( list(offset=ij, screened=h, distance=distance) )
}

の値はscreen(12)、このスクリーニング関係のこの描写を生成するために使用されました。矢印は、細胞からそれらをすぐにスクリーニングするものへの矢印です。色相は、この近傍の中央にある原点への距離に比例します。

図1

この計算は高速で、特定の近傍に対して一度だけ実行する必要があります。たとえば、5 mのセルを持つグリッドで200 mを見ると、近傍サイズは200/5 = 40単位になります。

ステップ2:選択したポイントに計算を適用する

残りは簡単です:(x、y)にあるセル(行と列の座標)がこの近傍データ構造に対して「囲まれている」かどうかを判断するには、(i、j)のオフセットから再帰的にテストを実行します=(0,0)(近傍の原点)。(x、y)+(i、j)のポリゴングリッドの値がゼロ以外の場合、表示はそこでブロックされます。それ以外の場合は、オフセット(i、j)でブロックされた可能性のあるすべてのオフセットを考慮する必要があります(これらは、によって返されるデータ構造を使用してO(1)時間で見つかりますscreen)。ブロックされているものがない場合は、境界に達しており、(x、y)は囲まれていないと結論付けるため、計算を停止します(近隣の残りのポイントを検査する必要はありません)。

アルゴリズム中に到達した最遠の見通し距離を追跡することにより、さらに有用な情報を収集できます。これが望ましい半径より小さい場合、セルは囲まれます。そうでなければ、そうではありません。

ここでR、このアルゴリズムのプロトタイプを。Rは再帰の実装に必要な(単純な)スタック構造をネイティブでサポートしていないため、見た目よりも長く、スタックもコーディングする必要があります。実際のアルゴリズムは、約3分の2の経路から始まり、必要なのは数十行程度です。(そしてそれらの半分は単にグリッドの端の周りの状況を処理し、近傍内の範囲外のインデックスをチェックします。これはk、周囲の行と列でポリゴングリッドを拡張し、ポリゴングリッドを保持するために、RAMを少し増やしてインデックス範囲チェックが必要です。)

#
# Test a grid point `ij` for a line-of-sight connection to the perimeter
# of a circular neighborhood.  
#   `xy` is the grid.
#   `counting` determines whether to return max distance or count of stack ops.
#   `perimeter` is the assumed values beyond the extent of `xy`.
#
# Grid values of zero admit light; all others block visibility
# Returns maximum line-of-sight distance found within `nbr`.
#
panvisibility <- function(ij, xy, nbr=screen(), counting=FALSE, perimeter=1) {
  #
  # Implement a stack for the algorithm.
  #
  count <- 0 # Stack count
  stack <- list(ptr=0, s=rep(NA, dim(nbr$offset)[1]))
  push <- function(x) {
    n <- length(x)
    count <<- count+n         # For timing
    stack$s[1:n + stack$ptr] <<- x
    stack$ptr <<- stack$ptr+n
  }
  pop <- function() {
    count <<- count+1         # For timing
    if (stack$ptr <= 0) return(NULL)
    y <- stack$s[stack$ptr]
    #stack$s[stack$ptr] <<- NA # For debugging
    stack$ptr <<- stack$ptr - 1
    return(y)
  }
  #
  # Initialization.
  #
  m <- dim(xy)[1]; n <- dim(xy)[2]
  push(1) # Stack the *indexes* of nbr$offset and nbr$screened.
  dist.max <- -1
  #
  # The algorithm.
  #
  while (!is.null(i <- pop())) {
    cell <- nbr$offset[i, ] + ij
    if (cell[1] <= 0 || cell[1] > m || cell[2] <= 0 || cell[2] > n) {
      value <- perimeter
    } else {  
      value <- xy[cell[1], cell[2]]
    }
    if (value==0) {
      if (nbr$distance[i] > dist.max) dist.max <- nbr$distance[i]
      s <- nbr$screened[[paste(i)]]
      if (is.null(s)) {
        #exited = TRUE
        break
      }
      push(s)
    }
  }
  if (counting) return ( count )
  return(dist.max)
}

図2:例

この例では、多角形のセルは黒です。色は、非多角形のセルの最大見通し距離(50セルまで)を示します。範囲は、距離が短い場合は薄いオレンジ色から距離が長い場合は濃い青色です。(セルの幅と高さは1ユニットです。)目に見える明らかな縞は、「川」の中央にある小さなポリゴンの「島」によって作成されます。それぞれが他のセルの長い線をブロックしています。

アルゴリズムの分析

スタック構造は、セルが囲まれていない証拠のための近傍可視性グラフの深さ優先検索を実装します。セルがどのポリゴンからも離れている場合、この検索で​​は、半径kの円形近傍のO(k)セルのみを検査する必要があります。最悪のケースは、近傍内に散在するポリゴンセルの数が少ないが、近傍の境界に到達できない場合に発生します。これらは、O(k ^ 2)である各近傍のほとんどすべてのセルを検査する必要があります。操作。

次の動作は、発生する典型的なものです。 kの値が小さい場合、ポリゴンがグリッドの大部分を埋めない限り、ほとんどの非ポリゴンセルは明らかに囲まれておらず、アルゴリズムはO(k)のようにスケーリングされます。中間値の場合、スケーリングはO(k ^ 2)のように見えます。kが非常に大きくなると、ほとんどのセルが囲まれ、その事実は近傍全体が検査される前に決定できます。これにより、アルゴリズムの計算作業は実際的な限界に達します。この制限は、近傍半径がグリッド内の接続された最大の非多角形領域の直径に近づくと達成されます。

例として、countingのプロトタイプにコード化されたオプションをscreen使用して、各呼び出しで使用されるスタック操作の数を返します。これは計算の労力を測定します。次のグラフは、近傍半径の関数としてスタック操作の平均数をプロットしています。予測された動作を示します。

図3

これを使用して、グリッド上の1300万点を評価するために必要な計算を推定できます。k = 200/5 = 40の近傍が使用されていると仮定します。その場合、平均で数百のスタック操作が必要になります(ポリゴングリッドの複雑さと、1億3千万個のポイントがポリゴンに対して配置されている場所によって異なります)。これは、効率的なコンパイル済み言語では、最大で数千の単純な数値演算を意味します。必要になります(加算、乗算、読み取り、書き込み、オフセットなど)。ほとんどのPCは、その速度で約100万ポイントの周囲を評価できます。(R実装は、この種のアルゴリズムでは不十分であるため、はるかに遅く、プロトタイプとしか見なせません。したがって、合理的に効率的で適切な言語での効率的な実装が望まれます。C++そして、Pythonが頭に浮かびます。ポリゴングリッド全体がRAMにあると仮定すると、1百万ポイント以下の評価を1分以内で完了する可能性があります。

グリッドが大きすぎてRAMに収まらない場合、この手順をグリッドのタイル部分に適用できます。それらはk行と列でオーバーラップする必要があるだけです。結果をモザイク化するとき、オーバーラップで最大値をとります。

その他の用途

水域「フェッチ」は、そのポイントの「周囲性」と密接に関連しています。実際、水体の直径以上の近傍半径を使用する場合、水体のすべてのポイントに(無方向)フェッチのグリッドを作成します。より小さな近傍半径を使用することにより、すべての最高フェッチポイントで少なくともフェッチの下限を取得します。これは、一部のアプリケーションでは十分な場合があります(そして、計算の労力を大幅に削減できます)。特定の方向への「スクリーニング」関係を制限するこのアルゴリズムのバリアントは、それらの方向でフェッチを効率的に計算する1つの方法です。そのような亜種はのコードを変更する必要があることに注意してくださいscreen。のコードpanvisibilityはまったく変わりません。


2

ラスターソリューションを使用してこれをどのように実行するかは確実にわかりますが、ポイント数を減らしたとしても、非常に大きく/高解像度であるため、グリッドまたはグリッドのセットを処理するのは困難です。それを考えると、gdbでトポロジを活用する方が効率的かもしれないのではないかと思います。あなたは次のようなものですべての内部ボイドを見つけることができます:

arcpy.env.workspace = 'myGDB'
arcpy.CreateTopology_management('myGDB', 'myTopology', '')    
arcpy.AddFeatureClassToTopology_management('myTopology', 'myFeatures', '1','1')    
arcpy.AddRuleToTopology_management ('myToplogy', 'Must Not Have Gaps (Area)', 'myFeatures', '', '', '')    
arcpy.ValidateTopology_management('myTopology', 'Full_Extent')
arcpy.ExportTopologyErrors_management('myTopology', 'myGDB', 'topoErrors')
arcpy.FeatureToPolygon_management('topoErrors_line','topoErrorsVoidPolys', '0.1')`

その後topoErrorsVoidPolys、通常のパターンなどで作業できますIntersect_analysis()。から目的のポリゴンを抽出する必要がありtopoErrorsVoidPolysます。@whuberは、この種のものについて、gis.stackexchange.comの他の場所にかなり優れた投稿を多数掲載しています。


それは興味深い前処理のアイデアです。(バッファリングや交差などにより)200mの制限を組み込むように簡単に調整できると思います。グリッドがかなり大きくなるというあなたのポイントは確かに本当の懸念事項です。問題の解決策は純粋にラスターベースまたは純粋にベクターベースでなければならないというGISのルールはありません(ただし、1つの表現から別の表現に変換するのにはかなりの理由があるはずという原則があります)ここで、あなたが示唆しているように、正確にそれを行うことには大きなメリットがあるかもしれません。
whuber

0

あなたが本当にラスターに行きたいなら...私はこの疑似コードの行に沿って何かをします(私がAMLスローバックであることが明らかであるので、単にうんざりしないでください!:p)

  1. ポイント( "pts_g")とポリゴン( "polys_g"(
  2. voids = regiongroup(con(isnull(polys_g)、1))
  3. 不要な外部ポリゴン/オープンユニバース領域を排除するために、ボイドを調整するために何かをする必要があるかもしれません
  4. pts_surrounded = con(voids、pts_g)

ちょっとそれを補うので、洗練が必要かもしれません。


あなたの解決策は(たとえば、200mの)制限距離を参照しないため、質問に正しく応答しないようです。
whuber

あなたが正しい。これは私の他の答えにも当てはまります。私はを使用できるExpand()と思いますが、その時点で、@ radouxjuからの答えは機能的に同等で、おそらくより速くなると思います。(可視領域に対しては何もありません。あまり使用しないでください)。
Roland

時間がなくなったときに編集しようとしていました。を拡張して、それExpand()を実行し、pts_gCon()交差するために使用したいpolys_g
Roland

0

距離のしきい値(ここでは200 mについて話します)を使用する場合、最良の解決策はベクトル分析を使用することです。

1)各ポイントの周囲に200 mのバッファーを作成します(図では黒)

2)バッファとポリゴンの間の交差ツール(分析)を使用します(図の青色)。周囲のポリゴンの境界とバッファの間でこれを行うと見栄えが良くなりますが、最終結果は同じです。

3)ポリゴンへの機能(管理)を使用して、ポイントが完全に囲まれたポリゴンを作成します(図の赤)

4)位置(管理)または空間結合(分析)でレイヤーを選択して、囲まれているポイントを特定します。空間結合を使用すると、埋め込みポリゴンに関する情報(ポリゴンの領域、ゾーン統計など)を取得できます。これは、さらに処理するのに役立ちます。

代替案2b)必要に応じて、周囲のポリゴンを200 m以内の場所で選択すると、「囲い」の種類を特定できますが、2)ほど厳密ではありません。

ここに画像の説明を入力してください

「迷路事件」を考えると、これは役立つかもしれません:場所から「脱出」するのにどれくらいの時間がかかるかを評価します。

  • 完全に含まれるか完全に無料のポイントを分析から除外することができます

  • 次に、障害物をラスターに変換し、ポリゴンがある場合は値をNoDataに、そうでない場合はメーターのセルサイズに値を設定します(これによりコストラスターが作成されます)。

  • 3番目に、新しく生成されたコストラスターを使用してコスト距離を計算できます

  • 最後に、ラスターに変換された(環を形成する)バッファー境界に基づいて、ゾーン統計をテーブルとして使用します。すべての方向に脱出できる場合、最小値は約200です(分析のセルサイズによって異なります)。しかし、迷路にいる場合、最大値は200より大きくなります。したがって、ゾーン統計の最大値から200を引いたものが、連続した値になり、「脱出」がどれほど難しいかを示します。


「囲まれた」の定義を明確にしてください。質問の説明は、ポリゴンの一部がそのポイントの周りのすべての方向(200 mの距離まで)に表示される場合、ポイントは「囲まれた」と見なす必要があることを示しています。ステップ(3)でそれを正確にどのようにテストしますか?(ベクトル分析を使用するのは簡単ではありません!)
whuber

少しイラストを追加しましたが、そのように説明する方が簡単です。バッファがすべての方向でポリゴンと交差しない場合、ループは閉じられません。ループが近くない場合、これはポリゴンを作成しません。
radouxju 2014年

「ループ」または「クローズ」の意味がわかりません。半径r(200 m未満)の円がポリゴン内に完全に含まれていない場合でも、点を「囲む」ことができることに注意してください。迷路を考えてみてください。ポリゴンは、迷路の廊下を除くすべてです。迷路はその中のどこからでも脱出できますが、ほとんどのポイントは迷路の外側が見えないという意味で「囲まれています」。
whuber

私の理解から、大胆なことはあなたが逃げることができないどこかを意味します。図では、Bからはエスケープできますが、Aからはエスケープできません。一方、可視領域を使用する場合、Bは囲まれているように見えます(画像にスケールバーがないため、200 mではないかもしれませんが、すべての方向から見ると、ポリゴンの境界が表示されます)。@Lozの詳細が必要だと思います
radouxju

「エスケープできない」がチェックの基準である場合、これはまったく難しい質問ではありません。ポリゴンの補集合を領域グループ化し、一意の外部コンポーネントのみを保持し、その中に含まれているかどうかをチェックします。私はそれをかなり漠然と述べていることに同意しますが、質問をよく読むと、特に考えられるすべての方位を見ることへの言及は、「囲まれた」が意図されている意味を明らかにすると思います。
whuber
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.