등고선지도에서 다각형 다듬기?


52

다음은 모든 레벨의 다각형을 사용할 수있는 등고선 맵입니다.

모든 정점을 정확한 위치에 유지하면서 다각형을 부드럽게 만드는 방법을 물어 보십시오.

실제로 형상이 그리드 데이터 위에 만들어지면 그리드 데이터를 부드럽게하도록 제안 할 수 있으므로 결과 형상이 더 부드러워집니다. 가우시안 필터와 같은 스무딩 기능은 작은 데이터 팩을 제거하고 세 번째 변수의 범위, 예를 들어 내 응용 프로그램에서 허용되지 않는 높이를 변경하기 때문에 이것은 내가 원하는 것으로 작동하지 않습니다.

실제로 나는 2D 다각형 (볼록, 오목, 자기 교차 등의 모든 유형)을 합리적으로 고통스럽지 않고 (코드 페이지를 잊어 버림) 부드럽게 할 수있는 코드 조각 ( Python 에서 선호 )을 찾고 있습니다.

참고 로 ArcGIS 에는 완벽하게 작동하는 기능 이 있지만 타사 상용 응용 프로그램을 사용하는 것은이 질문에 대한 나의 선택이 아닙니다.

여기에 이미지 설명을 입력하십시오


1)

Scipy. 보간 :

여기에 이미지 설명을 입력하십시오

보시다시피 결과 스플라인 (빨간색)은 만족스럽지 않습니다!

2)

여기에 주어진 코드를 사용한 결과가 있습니다 . 제대로 작동하지 않습니다!

여기에 이미지 설명을 입력하십시오

삼)

나에게 가장 좋은 해결책은 하나의 값만 변경하여 사각형이 점차적으로 부드럽게되는 다음 그림과 같은 것이어야합니다. 모든 형태의 다각형을 다듬는 비슷한 개념을 원합니다.

여기에 이미지 설명을 입력하십시오

스플라인이 점을 통과하는 조건을 충족시키는 경우 :

여기에 이미지 설명을 입력하십시오

4)

다음은 파이썬 에서 자신의 데이터에 대해 "whuber 's idea"를 한 줄씩 구현 한 것입니다 . 결과가 좋지 않기 때문에 약간의 버그가있을 수 있습니다.

여기에 이미지 설명을 입력하십시오

K = 2는 재앙이므로 k> = 4입니다.

5)

문제가있는 위치에서 한 지점을 제거했으며 결과 스플라인은 이제 whuber와 동일합니다. 그러나 왜이 방법이 모든 경우에 작동하지 않는지 의문입니다.

여기에 이미지 설명을 입력하십시오

6)

whuber의 데이터에 대한 원활한 스무딩은 다음과 같이 될 수 있습니다 (벡터 그래픽 소프트웨어로 그린). 추가 포인트가 부드럽게 추가되었습니다 (업데이트와 비교).

4) :

여기에 이미지 설명을 입력하십시오

7)

일부 상징적 인 모양에 대해서는 Python 버전의 whuber 코드 결과를 참조하십시오.

여기에 이미지 설명을 입력하십시오
참고 이 방법은 폴리 라인이 작동하지 않습니다 보인다. 모서리 폴리 라인 (윤곽선) 녹색은 내가 원하지만 빨간색이됩니다. 닫힌 폴리 라인이 예제에서와 같이 다각형으로 취급 될 수 있지만 등고선 맵은 항상 폴리 라인이므로이 문제를 해결해야합니다. 또한 업데이트 4에서 발생한 문제가 아직 해결되지 않았습니다.

8) [나의 마지막]

최종 솔루션은 다음과 같습니다 (완벽하지는 않습니다).

여기에 이미지 설명을 입력하십시오

별이 가리키는 부분에 대해 무언가를해야한다는 것을 기억하십시오. 내 코드에 버그가 있거나 제안 된 방법은 모든 상황을 고려하고 원하는 출력을 제공하기 위해 추가 개발이 필요합니다.


'다각형'윤곽선을 어떻게 생성합니까? DEM의 가장자리를 교차하는 윤곽이 절대로 닫히지 않기 때문에 항상 선이 아닐까요?
피스타치오

GRASS의 v.generalize 함수를 사용하여 괜찮은 결과로 등고선을 부드럽게 할 수 있지만 매우 조밀 한 등고선이 있는지도에는 시간이 걸릴 수 있습니다.
피스타치오

@pistachionut 등고선 레벨이 폴리 라인이라고 생각할 수 있습니다. 첫 번째 단계에서 순수한 코드 를 찾고 있습니다. 사용할 수없는 경우 Python 용 경량 패키지입니다.
개발자

아마도 scipy.org/Cookbook/Interpolation 은 스플라인하려는 것처럼 들리기 때문에 보라
PolyGeo

1
링크의 @Pablo Bezier 곡선은 폴리 라인에 적합합니다. whuber는 다각형에서 거의 잘 작동합니다. 그래서 그들은 함께 문제를 해결할 수있었습니다. 지식을 무료로 공유해 주셔서 감사합니다.
개발자

답변:


37

일련의 숫자를 스플라인하는 대부분의 방법은 다각형을 스플라인합니다. 트릭은 끝점에서 스플라인을 부드럽게 "닫는"것입니다. 이렇게하려면 끝 주위에 꼭짓점을 "감싼"것입니다. 그런 다음 x 및 y 좌표를 개별적으로 스플라인하십시오.

의 실제 예는 다음과 같습니다 R. spline기본 통계 패키지에서 사용 가능한 기본 큐빅 절차를 사용합니다. 더 많은 제어를 위해 원하는 거의 모든 절차를 대체하십시오. 단순히 "제어점"으로 사용하는 것이 아니라 숫자를 통해 스플라인해야합니다 (즉, 보간).

#
# Splining a polygon.
#
#   The rows of 'xy' give coordinates of the boundary vertices, in order.
#   'vertices' is the number of spline vertices to create.
#              (Not all are used: some are clipped from the ends.)
#   'k' is the number of points to wrap around the ends to obtain
#       a smooth periodic spline.
#
#   Returns an array of points. 
# 
spline.poly <- function(xy, vertices, k=3, ...) {
    # Assert: xy is an n by 2 matrix with n >= k.

    # Wrap k vertices around each end.
    n <- dim(xy)[1]
    if (k >= 1) {
        data <- rbind(xy[(n-k+1):n,], xy, xy[1:k, ])
    } else {
        data <- xy
    }

    # Spline the x and y coordinates.
    data.spline <- spline(1:(n+2*k), data[,1], n=vertices, ...)
    x <- data.spline$x
    x1 <- data.spline$y
    x2 <- spline(1:(n+2*k), data[,2], n=vertices, ...)$y

    # Retain only the middle part.
    cbind(x1, x2)[k < x & x <= n+k, ]
}

사용법을 설명하기 위해 작지만 복잡한 다각형을 만들어 봅시다.

#
# Example polygon, randomly generated.
#
set.seed(17)
n.vertices <- 10
theta <- (runif(n.vertices) + 1:n.vertices - 1) * 2 * pi / n.vertices
r <- rgamma(n.vertices, shape=3)
xy <- cbind(cos(theta) * r, sin(theta) * r)

앞의 코드를 사용하여 스플라인을 만듭니다. 스플라인을 더 매끄럽게 만들려면 정점 수를 100에서 늘리십시오. 덜 매끄럽게하려면 정점 수를 줄입니다.

s <- spline.poly(xy, 100, k=3)

결과를보기 위해 (a) 첫 번째와 마지막 정점 사이의 간격을 보여주는 (즉, 경계 폴리 라인을 닫지 않는 ) 원래 다각형을 빨간색으로 표시 합니다. (b) 스플라인이 회색으로 표시되어 간격이 한 번 더 나타납니다. 간격이 너무 작기 때문에 끝 점이 파란색 점으로 강조 표시됩니다.

plot(s, type="l", lwd=2, col="Gray")
lines(xy, col="Red", lty=2, lwd=2)
points(xy, col="Red", pch=19)
points(s, cex=0.8)
points(s[c(1,dim(s)[1]),], col="Blue", pch=19)

스플라인 다각형


5
좋은 대답입니다. 스무딩으로 인해 윤곽이 교차하지 않도록 보장 할 수있는 방법이 있습니까?
Kirk Kuykendall

좋은 질문입니다, @Kirk. 이 형태의 스무딩에서 비교 차를 보장하는 방법을 모릅니다. (실제로, 평활화 된 폴리 라인이 자체 교차하지 않음을 보장하는 방법조차 알지 못합니다. 그러나 대부분의 등고선에는 큰 문제가 아닙니다.) 그렇게하려면 원본으로 돌아 가야합니다. 대신 DEM 대신 더 나은 방법을 사용하여 윤곽을 계산하십시오. (이 있습니다 - 그들은 오랫동안 알려져있다 - 더 나은 방법이 있지만 AFAIK 가장 인기 GISes 중 일부는 사용하지 않습니다.)
whuber의

먼저, 나는 아직도 파이썬으로 답변을 구현하려고 노력하고 있지만 성공하지 못했습니다. 둘째, 방법을 사각형에 적용하면 결과는 무엇입니까? 내가 질문에 그린 것을 참조 할 수 있습니다.
개발자

1
나는 이것이 좋은 해결책을 제시하기 때문에 대답으로 받아 들였다. 완벽하지는 않지만 문제를 해결해 줄 아이디어가 있었지만, 내 질문과 의견에서 위에서 언급 한 사항을 만족시키는 솔루션을 찾을 수 있기를 바랍니다. 당신은 또한 질문 [QC]에 대한 whuber의 의견을 고려할 수 있습니다. 거기에는 좋은 트릭이 있습니다. 마지막으로 파이썬으로의 번역은 멋진 Scipy 패키지가 설치되어있는 것이 거의 간단하다고 말해야합니다. 또한 폴리 라인, 즉 베 지어 곡선에 대한 가능한 솔루션으로 QC에서 Pablo의 의견을 고려하십시오. 모두 행운을 빌어 요.
개발자

1
당신의 답변을보고, 나는 내 수학을 잘 돌보지 않는 것을 후회합니다 !!!
vinayan

2

나는 이것이 오래된 게시물이라는 것을 알고 있지만 내가 찾고있는 것에 대해 Google에 나타 났으므로 솔루션을 게시 할 것이라고 생각했습니다.

나는 이것을 2D 커브 피팅 연습으로 보지 않고 오히려 3D 연습으로 보았습니다. 데이터를 3D로 간주하여 곡선이 서로 교차하지 않도록하고 다른 윤곽의 정보를 사용하여 현재 곡선의 추정치를 향상시킬 수 있습니다.

다음 iPython 추출물은 SciPy에서 제공하는 3 차 보간법을 사용합니다. 내가 그린 z 값은 모든 윤곽선의 높이가 같은 거리에있는 한 중요하지 않습니다.

In [1]: %pylab inline
        pylab.rcParams['figure.figsize'] = (10, 10)
        Populating the interactive namespace from numpy and matplotlib

In [2]: import scipy.interpolate as si

        xs = np.array([0.0, 0.0, 4.5, 4.5,
                       0.3, 1.5, 2.3, 3.8, 3.7, 2.3,
                       1.5, 2.2, 2.8, 2.2,
                       2.1, 2.2, 2.3])
        ys = np.array([0.0, 3.0, 3.0, 0.0,
                       1.1, 2.3, 2.5, 2.3, 1.1, 0.5,
                       1.1, 2.1, 1.1, 0.8,
                       1.1, 1.3, 1.1])
        zs = np.array([0,   0,   0,   0,
                       1,   1,   1,   1,   1,   1,
                       2,   2,   2,   2,
                       3,   3,   3])
        pts = np.array([xs, ys]).transpose()

        # set up a grid for us to resample onto
        nx, ny = (100, 100)
        xrange = np.linspace(np.min(xs[zs!=0])-0.1, np.max(xs[zs!=0])+0.1, nx)
        yrange = np.linspace(np.min(ys[zs!=0])-0.1, np.max(ys[zs!=0])+0.1, ny)
        xv, yv = np.meshgrid(xrange, yrange)
        ptv = np.array([xv, yv]).transpose()

        # interpolate over the grid
        out = si.griddata(pts, zs, ptv, method='cubic').transpose()

        def close(vals):
            return np.concatenate((vals, [vals[0]]))

        # plot the results
        levels = [1, 2, 3]
        plt.plot(close(xs[zs==1]), close(ys[zs==1]))
        plt.plot(close(xs[zs==2]), close(ys[zs==2]))
        plt.plot(close(xs[zs==3]), close(ys[zs==3]))
        plt.contour(xrange, yrange, out, levels)
        plt.show()

3 차 보간 결과

여기의 결과는 가장 좋지는 않지만 제어점이 거의 없으므로 여전히 완벽하게 유효합니다. 더 넓은 파란색 윤곽선을 따르기 위해 녹색 맞춤 선을 어떻게 빼내는 지 확인하십시오.


장착 된 부드러운 곡선은 원래 다각형 / 폴리 라인에 최대한 가깝게 유지되어야합니다.
개발자

1

나는 당신이 찾고있는 패키지를 거의 정확하게 썼습니다 ... 그러나 그것은 Perl에 있었고 10 년 전에있었습니다 : GD :: Polyline . 2D 큐빅 베 지어 곡선을 사용했으며 임의의 다각형 또는 "폴리 라인"(이제 일반적으로 "LineString"이라고하는 이름)을 "부드럽게"만들었습니다.

알고리즘은 두 단계로 이루어졌습니다. 다각형의 점이 주어지면 모든 점 사이에 두 개의 베 지어 제어점을 추가합니다. 그런 다음 간단한 알고리즘을 호출하여 스플라인을 조각 단위로 근사화합니다.

두 번째 부분은 쉽습니다. 첫 번째 부분은 약간의 예술이었습니다. 통찰력은 다음과 같습니다. "제어 세그먼트"를 Vertex N :으로 간주하십시오 vN. 제어 세그먼트는 세 개의 동일 선형 점 [cNa, vN, cNb]입니다. 중심점은 꼭짓점이었습니다. 이 제어 세그의 기울기는 정점 N-1에서 정점 N + 1까지의 기울기와 같았습니다. 이 세그먼트의 왼쪽 부분의 길이는 정점 N-1에서 꼭지점 N까지의 1/3 길이였으며,이 세그먼트의 오른쪽 부분의 길이는 정점 N에서 꼭지점 N + 1까지의 길이 1/3이었습니다.

원래 곡선이 4 개의 정점 인 경우 : [v1, v2, v3, v4]각 정점은 이제 다음 형식의 제어 세그먼트를 얻습니다 [c2a, v2, c2b]. 이것을 다음과 같이 [v1, c1b, c2a, v2, c2b, c3a, v3, c3b, c4a, v4]묶으십시오 : 4 개의 베 지어가 가리키는대로 한 번에 4 개씩 자르십시오 : [v1, c1b, c2a, v2],, [v2, c2b, c3a, v3]등등. [c2a, v2, c2b]동일 선상에 있기 때문에 결과 곡선은 각 정점에서 매끄럽게됩니다.

따라서 이는 곡선의 "견고성"을 매개 변수화하기위한 요구 사항도 충족합니다. "조임력있는"곡선의 경우 1/3보다 작은 값을 사용하고 "루피 어"맞춤의 경우 더 큰 값을 사용하십시오. 두 경우 모두 결과 곡선은 항상 원래의 주어진 점을 통과합니다.

이로 인해 원래 다각형을 "할당"하는 부드러운 곡선이 만들어졌습니다. 또한 부드러운 곡선을 "새김"하는 방법이 있었지만 CPAN 코드에서는 볼 수 없습니다.

어쨌든, 현재로서는 파이썬으로 사용할 수있는 버전이 없으며 수치도 없습니다. 그러나 ...이를 파이썬으로 이식하면 여기에 게시해야합니다.


Perl 코드를 평가할 수없고 그래픽을 추가하여 가능한 경우 작동 방식을 보여줍니다.
개발자
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.