Làm mịn đa giác trong bản đồ đường viền?


52

Đây là một bản đồ đường viền cho tất cả các đa giác các cấp có sẵn.

Hãy hỏi làm thế nào để làm mịn các đa giác giữ tất cả các đỉnh được bảo tồn ở vị trí chính xác của chúng?

Thật vậy, đường viền được tạo trên đầu dữ liệu lưới, bạn có thể đề xuất sau đó để làm mịn dữ liệu lưới và do đó đường viền kết quả sẽ mượt mà hơn. Lưu ý rằng điều này không hoạt động như mong muốn của tôi vì chức năng làm mịn như bộ lọc Gaussian sẽ loại bỏ các gói dữ liệu nhỏ và sẽ thay đổi phạm vi của biến thứ ba, ví dụ: chiều cao không được phép trong ứng dụng của tôi.

Trên thực tế, tôi đang tìm kiếm một đoạn mã (tốt nhất là bằng Python ) có thể làm mịn các đa giác 2D (bất kỳ loại nào: lồi, lõm, tự giao nhau, v.v.) không gây đau đớn (quên các trang mã) và chính xác.

FYI, có một chức năng trong ArcGIS thực hiện điều này một cách hoàn hảo, nhưng sử dụng các ứng dụng thương mại của bên thứ ba không phải là lựa chọn của tôi cho câu hỏi này.

nhập mô tả hình ảnh ở đây


1)

Scipy.interpolate:

nhập mô tả hình ảnh ở đây

Như bạn thấy các splines kết quả (màu đỏ) là không thỏa đáng!

2)

Đây là kết quả bằng cách sử dụng mã được đưa ra ở đây . Nó không hoạt động tốt!

nhập mô tả hình ảnh ở đây

3)

Đối với tôi, giải pháp tốt nhất nên là một cái gì đó giống như hình dưới đây trong đó một hình vuông đang được làm mịn dần bằng cách chỉ thay đổi một giá trị. Tôi hy vọng cho khái niệm tương tự để làm mịn bất kỳ hình thức đa giác.

nhập mô tả hình ảnh ở đây

Đáp ứng điều kiện spline vượt qua các điểm:

nhập mô tả hình ảnh ở đây

4)

Đây là cách tôi thực hiện từng dòng "ý tưởng của người làm" trong Python trên dữ liệu của anh ấy. Có thể có một số lỗi vì kết quả không tốt.

nhập mô tả hình ảnh ở đây

K = 2 là một thảm họa và vì vậy với k> = 4.

5)

Tôi đã xóa một điểm ở vị trí có vấn đề và spline kết quả bây giờ giống hệt với whuber. Nhưng vẫn còn một câu hỏi là tại sao phương pháp này không hoạt động cho tất cả các trường hợp?

nhập mô tả hình ảnh ở đây

6)

Một sự làm mịn tốt cho dữ liệu của người dùng có thể như sau (được vẽ bởi phần mềm đồ họa vector) trong đó một điểm bổ sung đã được thêm vào một cách trơn tru (so sánh với cập nhật

4):

nhập mô tả hình ảnh ở đây

7)

Xem kết quả từ phiên bản Python của mã trình duyệt cho một số hình dạng biểu tượng:

nhập mô tả hình ảnh ở đây
Lưu ý rằng phương pháp này dường như không hoạt động đối với polylines. Đối với đa giác góc (đường viền) màu xanh lá cây là những gì tôi muốn nhưng có màu đỏ. Điều này cần được giải quyết vì bản đồ đường viền luôn là polylines mặc dù polylines kín có thể được coi là đa giác như trong ví dụ của tôi. Cũng không phải là vấn đề nổi lên trong bản cập nhật 4 vẫn chưa được giải quyết.

8) [lần cuối của tôi]

Đây là giải pháp cuối cùng (không hoàn hảo!):

nhập mô tả hình ảnh ở đây

Hãy nhớ rằng bạn sẽ phải làm một cái gì đó về khu vực được chỉ bởi các ngôi sao. Có lẽ có một lỗi trong mã của tôi hoặc phương pháp được đề xuất cần phát triển thêm để xem xét tất cả các tình huống và để cung cấp đầu ra mong muốn.


Làm thế nào bạn tạo ra các đường viền 'đa giác'? không phải lúc nào chúng cũng là đường thẳng, vì một đường viền giao nhau với cạnh của DEM sẽ không bao giờ tự đóng lại?
quả hồ trăn

Tôi đã sử dụng hàm v.generalize trong GRASS để làm mịn các đường đồng mức với kết quả tốt, mặc dù có thể mất một lúc cho các bản đồ với các đường viền rất dày.
quả hồ trăn

@pistachionut Bạn có thể coi các mức đường viền là đa tuyến. Tôi đang tìm kiếm mã thuần ở giai đoạn đầu tiên. Nếu không có sẵn thì gói ánh sáng cho Python.
Nhà phát triển

Có lẽ hãy xem scipy.org/Cookbook/Interpolation vì nghe có vẻ như bạn muốn spline
PolyGeo

1
@Pablo Đường cong Bezier trong liên kết của bạn hoạt động tốt cho polylines. whuber hoạt động gần như tốt cho đa giác. Vì vậy, họ cùng nhau có thể giải quyết câu hỏi. Cảm ơn rất nhiều vì đã chia sẻ kiến ​​thức của bạn miễn phí.
Nhà phát triển

Câu trả lời:


37

Hầu hết các phương pháp để nối chuỗi các số sẽ tách đa giác. Bí quyết là làm cho các spline "đóng lên" trơn tru ở các điểm cuối. Để làm điều này, "bọc" các đỉnh xung quanh các đầu. Sau đó tách riêng tọa độ x- và y.

Đây là một ví dụ làm việc trong R. Nó sử dụng splinethủ tục khối mặc định có sẵn trong gói thống kê cơ bản. Để kiểm soát nhiều hơn, hãy thay thế hầu hết mọi thủ tục bạn thích: chỉ cần đảm bảo rằng nó sẽ phân tách qua các số (nghĩa là nội suy chúng) thay vì chỉ sử dụng chúng làm "điểm kiểm soát".

#
# 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, ]
}

Để minh họa việc sử dụng nó, hãy tạo một đa giác nhỏ (nhưng phức tạp).

#
# 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)

Spline nó bằng cách sử dụng mã trước. Để làm cho spline mượt mà hơn, hãy tăng số lượng đỉnh từ 100; để làm cho nó ít mịn hơn, giảm số lượng đỉnh.

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

Để xem kết quả, chúng ta vẽ (a) đa giác ban đầu bằng màu đỏ nét đứt, hiển thị khoảng cách giữa các đỉnh đầu tiên và cuối cùng (nghĩa là không đóng đa tuyến biên của nó); và (b) spline màu xám, một lần nữa cho thấy khoảng cách của nó. (Vì khoảng cách quá nhỏ, điểm cuối của nó được tô sáng bằng các chấm màu xanh.)

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)

Đa giác nối


5
Câu trả lời tốt đẹp. Có cách nào để đảm bảo các đường viền không bị cắt ngang do kết quả của việc làm mịn không?
Kirk Kuykendall

Đó là một câu hỏi hay, @Kirk. Tôi không biết về bất kỳ phương pháp nào để đảm bảo không vượt qua khỏi hình thức làm mịn này. (Trên thực tế, tôi thậm chí không thấy cách đảm bảo rằng đa tuyến được làm mịn là không tự giao nhau. Đây không phải là vấn đề lớn đối với hầu hết các đường viền.) Để làm được điều đó, bạn cần quay lại bản gốc DEM và thay vào đó sử dụng một phương pháp tốt hơn để tính các đường viền ở vị trí đầu tiên. (Có những phương pháp tốt hơn - họ đã được biết đến trong một thời gian dài -. Nhưng AFAIK một số GISes phổ biến nhất không sử dụng chúng)
whuber

Đầu tiên, tôi vẫn đang làm việc để thực hiện câu trả lời của bạn bằng Python, nhưng chưa thành công. Thứ hai, kết quả sẽ là gì nếu bạn áp dụng phương pháp của mình trên một hình vuông? Bạn có thể đề cập đến những người tôi đã rút ra trong câu hỏi.
Nhà phát triển

1
Tôi chấp nhận điều này như câu trả lời vì nó đưa ra một giải pháp tốt. Mặc dù nó không phải là một ý tưởng hoàn hảo nhưng nó đã cho tôi một số ý tưởng làm việc xung quanh, hy vọng tôi sẽ tìm được giải pháp thỏa mãn những điểm tôi đã đề cập ở trên trong câu hỏi và nhận xét của mình. Bạn cũng có thể xem xét nhận xét của người đăng ký cho câu hỏi [QC], có những mẹo hay ở đó. Cuối cùng tôi nên nói rằng bản dịch sang python gần như đơn giản khi cài đặt gói Scipy đáng yêu. Cũng xem xét nhận xét của Pablo trong QC là giải pháp có thể cho polylines, tức là các đường cong Bezier. Chúc mọi người may mắn.
Nhà phát triển

1
Nhìn thấy câu trả lời của bạn, tôi rất tiếc vì không chăm sóc tốt môn toán của mình !!!
vinaya

2

Tôi biết đây là một bài viết cũ, nhưng nó đã xuất hiện trên Google cho một cái gì đó tôi đang tìm kiếm, vì vậy tôi nghĩ rằng tôi đã đăng giải pháp của mình.

Tôi không thấy đây là một bài tập phù hợp với đường cong 2D, mà là một bài tập 3D. Bằng cách xem xét dữ liệu dưới dạng 3D, chúng tôi có thể đảm bảo rằng các đường cong không bao giờ giao nhau và có thể sử dụng thông tin từ các đường viền khác để cải thiện ước tính của chúng tôi cho đường cong hiện tại.

Trích xuất iPython sau đây sử dụng phép nội suy bậc ba do SciPy cung cấp. Lưu ý rằng các giá trị z mà tôi đã vẽ không quan trọng, miễn là tất cả các đường viền đều có chiều cao tương đương nhau.

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()

Kết quả nội suy khối

Kết quả ở đây không có vẻ tốt nhất, nhưng với rất ít điểm kiểm soát, chúng vẫn hoàn toàn hợp lệ. Lưu ý cách đường được trang bị màu xanh lá cây được kéo ra để theo đường viền màu xanh rộng hơn.


Các đường cong mịn được trang bị phải ở gần nhất có thể với đa giác / đa tuyến ban đầu.
Nhà phát triển

1

Tôi đã viết gần như chính xác gói bạn đang tìm kiếm ... nhưng nó đã ở Perl, và đã hơn một thập kỷ trước: GD :: Polyline . Nó đã sử dụng các đường cong Bezier hình khối 2D và sẽ "làm mịn" một Đa giác tùy ý hoặc "Đa tuyến" (tên của tôi sau đó được gọi là "LineString").

Thuật toán gồm hai bước: đưa ra các điểm trong Đa giác, thêm hai điểm kiểm soát Bezier giữa mỗi điểm; sau đó gọi một thuật toán đơn giản để thực hiện xấp xỉ piecewise của spline.

Phần thứ hai là dễ dàng; phần đầu tiên là một chút nghệ thuật. Đây là cái nhìn sâu sắc: xem xét "phân khúc kiểm soát" một chiếc Vertex N : vN. Đoạn điều khiển là ba điểm đồng tuyến tính : [cNa, vN, cNb]. Điểm trung tâm là đỉnh. Độ dốc của bộ điều khiển này bằng với độ dốc từ Vertex N-1 đến Vertex N + 1. Độ dài của phần bên trái của phân khúc này là 1/3 chiều dài từ Vertex N-1 đến Vertex N và chiều dài của phần bên phải của phân khúc này là 1/3 chiều dài từ Vertex N đến Vertex N + 1.

Nếu đường cong ban đầu là bốn đỉnh: [v1, v2, v3, v4]thì mỗi đỉnh bây giờ sẽ có một đoạn điều khiển có dạng : [c2a, v2, c2b]. Xâu chuỗi chúng lại với nhau như thế này: [v1, c1b, c2a, v2, c2b, c3a, v3, c3b, c4a, v4]và nhai bốn cái cùng một lúc như bốn điểm Bezier : [v1, c1b, c2a, v2], sau đó [v2, c2b, c3a, v3], v.v. Bởi vì [c2a, v2, c2b]là đồng tuyến tính, đường cong kết quả sẽ trơn tru ở mỗi đỉnh.

Vì vậy, điều này cũng đáp ứng yêu cầu của bạn để tham số hóa "độ chặt" của đường cong: sử dụng giá trị nhỏ hơn 1/3 cho đường cong "chặt hơn", đường cong lớn hơn để phù hợp với "vòng lặp". Trong cả hai trường hợp, đường cong kết quả luôn đi qua các điểm đã cho ban đầu.

Điều này dẫn đến một đường cong trơn tru "bao quanh" Đa giác ban đầu. Tôi cũng đã có một số cách để "khắc họa" một đường cong mượt mà ... nhưng tôi không thấy điều đó trong mã CPAN.

Dù sao, hiện tại tôi không có phiên bản bằng Python, tôi cũng không có bất kỳ số liệu nào. NHƯNG ... nếu / khi tôi chuyển cái này sang Python, tôi chắc chắn sẽ đăng ở đây.


Không thể đánh giá mã Perl, thêm đồ họa để chứng minh nó hoạt động như thế nào nếu có thể.
Nhà phát triển
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.