17

ラスター マップ上で道路や河川などの線形フィーチャを識別し、SpatialLinesR を使用してそれらを線形空間オブジェクト (クラス)に変換したいと考えています。

およびパッケージrastersp使用して、フィーチャをラスターからポリゴン ベクター オブジェクト (SpatialPolygonsクラス) に変換できます。 rasterToPolygons()ラスターから特定の値のセルを抽出し、ポリゴン オブジェクトを返します。パッケージdissolve=TRUE内のルーチンを呼び出してこれを行うオプションを使用して、製品を単純化できます。rgeos

これはすべて問題なく動作しますが、私はそれをオブジェクトにしたいと考えていSpatialLinesます。これどうやってするの?

次の例を検討してください。

## Produce a sinuous linear feature on a raster as an example
library(raster)
r <- raster(nrow=400, ncol=400, xmn=0, ymn=0, xmx=400, ymx=400)
r[] <- NA
x <-seq(1, 100, by=0.01)
r[cellFromRowCol(r, round((sin(0.2*x) + cos(0.06*x)+2)*100), round(x*4))] <- 1

## Quick trick to make it three cells wide
r[edge(r, type="outer")] <- 1

## Plot
plot(r, legend=FALSE, axes=FALSE)

例としての線形フィーチャのラスター表現

## Convert linear feature to a SpatialPolygons object
library(rgeos)
rPoly <- rasterToPolygons(r, fun=function(x) x==1, dissolve=TRUE)
plot(rPoly)

線形フィーチャの SpatialPolygons 表現

ポリゴンを通る中心線を見つけるのが最善の方法でしょうか?
または、これを行うために利用できる既存のコードはありますか?

編集:これがスケルトン化と呼ばれることを指摘してくれた @mdsumner に感謝します。

4

4 に答える 4

19

これが私の努力です。計画は次のとおりです。

  • 線を密にする
  • ドロネー三角形分割を計算する
  • 中点を取得し、ポリゴン内にあるそれらの点を取得します
  • 距離加重最小全域木を構築する
  • グラフの直径のパスを見つける

手始めに高密度化コード:

densify <- function(xy,n=5){
  ## densify a 2-col matrix
  cbind(dens(xy[,1],n=n),dens(xy[,2],n=n))
}

dens <- function(x,n=5){
  ## densify a vector
  out = rep(NA,1+(length(x)-1)*(n+1))
  ss = seq(1,length(out),by=(n+1))
  out[ss]=x
  for(s in 1:(length(x)-1)){
    out[(1+ss[s]):(ss[s+1]-1)]=seq(x[s],x[s+1],len=(n+2))[-c(1,n+2)]
  }
  out
}

そして今、メインコース:

simplecentre <- function(xyP,dense){
require(deldir)
require(splancs)
require(igraph)
require(rgeos)

### optionally add extra points
if(!missing(dense)){
  xy = densify(xyP,dense)
} else {
  xy = xyP
}

### compute triangulation
d=deldir(xy[,1],xy[,2])

### find midpoints of triangle sides
mids=cbind((d$delsgs[,'x1']+d$delsgs[,'x2'])/2,
  (d$delsgs[,'y1']+d$delsgs[,'y2'])/2)

### get points that are inside the polygon 
sr = SpatialPolygons(list(Polygons(list(Polygon(xyP)),ID=1)))
ins = over(SpatialPoints(mids),sr)

### select the points
pts = mids[!is.na(ins),]

dPoly = gDistance(as(sr,"SpatialLines"),SpatialPoints(pts),byid=TRUE)
pts = pts[dPoly > max(dPoly/1.5),]

### now build a minimum spanning tree weighted on the distance
G = graph.adjacency(as.matrix(dist(pts)),weighted=TRUE,mode="upper")
T = minimum.spanning.tree(G,weighted=TRUE)

### get a diameter
path = get.diameter(T)

if(length(path)!=vcount(T)){
  stop("Path not linear - try increasing dens parameter")
}

### path should be the sequence of points in order
list(pts=pts[path+1,],tree=T)

}

以前のバージョンのバッファリングの代わりに、各中点から多角形の線までの距離を計算し、a) 内側にある点と、b) 内側の点の距離の 1.5 よりもエッジから遠い点のみを取得します。端から最も遠い。

長いセグメントがあり、緻密化されていない場合、ポリゴンがそれ自体でよじれると、問題が発生する可能性があります。この場合、グラフはツリーであり、コードはそれを報告します。

テストとして、線 (s、SpatialLines オブジェクト) をデジタル化し、それをバッファリング (p) してから、中心線を計算してそれらを重ね合わせました。

 s = capture()
 p = gBuffer(s,width=0.2)
 plot(p,col="#cdeaff")
 plot(s,add=TRUE,lwd=3,col="red")
 scp = simplecentre(onering(p))
 lines(scp$pts,col="white")

ソース ライン (赤)、ポリゴン (青)、復元された中心線 (白)

「onering」関数は、1 つのリングだけであるべき SpatialPolygons のものから 1 つのリングの座標を取得するだけです。

onering=function(p){p@polygons[[1]]@Polygons[[1]]@coords}

「キャプチャ」機能を使用して空間ライン フィーチャをキャプチャします。

capture = function(){p=locator(type="l")
            SpatialLines(list(Lines(list(Line(cbind(p$x,p$y))),ID=1)))}
于 2012-03-10T01:04:06.763 に答える
5

中心線を見つけるためのこの洗練されたアルゴリズムにリンクしてくれた gis.stackexchange.com の@klewisに感謝します(そこで私が尋ねた関連する質問への回答として)。

このプロセスでは、線形フィーチャを表すポリゴンのエッジ上の座標を見つけ、それらのポイントのボロノイ テッセレーションを実行する必要があります。線形フィーチャのポリゴン内にあるボロノイ タイルの座標は、中心線上にあります。これらの点を線に変えます。

ボロノイ テッセレーションは R でパッケージを使用して非常に効率的に行われ、deldirパッケージとポリゴンとポイントの交差が行われrgeosます。

## Find points on boundary of rPoly (see question)
rPolyPts <-  coordinates(as(as(rPoly, "SpatialLinesDataFrame"),
                "SpatialPointsDataFrame"))

## Perform Voronoi tessellation of those points and extract coordinates of tiles
library(deldir)
rVoronoi <- tile.list(deldir(rPolyPts[, 1], rPolyPts[,2]))
rVoronoiPts <- SpatialPoints(do.call(rbind, 
                 lapply(rVoronoi, function(x) cbind(x$x, x$y))))

## Find the points on the Voronoi tiles that fall inside 
## the linear feature polygon
## N.B. That the width parameter may need to be adjusted if coordinate
## system is fractional (i.e. if longlat), but must be negative, and less
## than the dimension of a cell on the original raster.
library(rgeos)
rLinePts <- gIntersection(gBuffer(rPoly, width=-1), rVoronoiPts)

## Create SpatialLines object
rLine <- SpatialLines(list(Lines(Line(rLinePts), ID="1")))

結果の SpatialLines オブジェクト: ラスターからの線形フィーチャを表す SpatialLines オブジェクト

于 2012-03-09T04:09:56.350 に答える
4

直接強制により、そのポリゴンの境界を SpatialLines として取得できます。

rLines <- as(rPoly, "SpatialLinesDataFrame")

座標を単一の「中心線」に要約することは可能ですが、私が知っていることはすぐにはわかりません. そのプロセスは一般に「スケルトン化」と呼ばれていると思います。

http://en.wikipedia.org/wiki/Topological_skeleton

于 2012-03-07T03:05:51.327 に答える