Kontur haritasındaki çokgenleri düzleştirme


52

Tüm seviye poligonlarının mevcut olduğu kontur haritası.

Tüm köşeleri tam konumlarında tutularak çokgenleri nasıl düzgün tutacağınızı soralım mı?

Aslında, kontur bir ızgara verilerinin üstüne yapılır, daha sonra ızgara verilerini yumuşatmayı önerebilir ve bu nedenle ortaya çıkan kontur daha yumuşak olur. Gaussian filtresi gibi yumuşatma işlevi küçük veri paketlerini kaldıracağı ve üçüncü değişkenin aralığını değiştirecek, örneğin uygulamamda izin verilmeyen yükseklik.

Aslında 2B çokgenlerin (herhangi bir tür: dışbükey, içbükey, kendiliğinden kesişen vb.) Düzgünleştirilmesini (herhangi bir tür: dışbükey, içbükey, kendi kendine kesişen vb.) Makul derecede ağrısız (kod sayfalarını unutun) ve doğru bir kod parçası (tercihen Python'da ) arıyorum .

Bilginize, ArcGIS'te bunu mükemmel yapan bir işlev var , ancak üçüncü taraf ticari uygulamaları kullanmak bu soru için benim tercihim değil.

görüntü tanımını buraya girin


1)

Scipy.interpolate:

görüntü tanımını buraya girin

Gördüğünüz gibi ortaya çıkan lekeler (kırmızı) tatmin edici değil!

2)

Burada verilen kodu kullanarak sonucudur burada . İyi çalışmıyor!

görüntü tanımını buraya girin

3)

Bana göre en iyi çözüm, bir karenin aşamalı olarak yalnızca bir değeri değiştirerek düzeltildiği aşağıdaki şekildeki gibi olmalıdır. Çokgenlerin herhangi bir biçimini düzeltmek için benzer bir kavram umuyorum.

görüntü tanımını buraya girin

Spline koşulunu yerine getirmek puanları geçer:

görüntü tanımını buraya girin

4)

İşte benim veri üzerinde Python'da satır satır "whuber's fikri" . Sonuçlar iyi olmadığı için bazı hatalar olabilir.

görüntü tanımını buraya girin

K = 2 bir felakettir ve bu nedenle k> = 4'tür.

5)

Sorunlu konumdaki bir noktayı kaldırdım ve ortaya çıkan spline artık whuber'inkiyle aynı. Ancak bu, yöntemin neden tüm durumlar için işe yaramadığı sorusudur?

görüntü tanımını buraya girin

6)

Whuber'un verileri için iyi bir pürüzsüzleştirme, ilave bir noktanın sorunsuz bir şekilde eklendiği (güncelleme ile karşılaştırılan) aşağıdaki gibi olabilir (vektör grafik yazılımı ile çizilir)

4):

görüntü tanımını buraya girin

7)

Bazı ikonik şekiller için whuber kodunun Python versiyonunun sonucuna bakın:

görüntü tanımını buraya girin
Bu yöntemin polilinler için işe yaramadığını unutmayın . Köşe polyline için (kontur) yeşil istediğim ama kırmızı aldım. Kontur haritaları her zaman poliller olduğundan, ele alınmasına ihtiyaç vardır, ancak kapalı poliller örneklerimdeki gibi çokgenler olarak da kullanılabilir. Ayrıca 4. güncellemede ortaya çıkan sorunun henüz ele alınmadığı da söylenemez.

8) [son]

İşte son çözüm (mükemmel değil!):

görüntü tanımını buraya girin

Yıldızların işaret ettiği bölge hakkında bir şeyler yapmanız gerekeceğini unutmayın. Kodumda bir hata olabilir veya önerilen yöntem tüm durumları göz önünde bulundurmak ve istenen çıktıları sağlamak için daha fazla geliştirmeye ihtiyaç duyar.


'Çokgen' kontürleri nasıl üretiyorsunuz? DEM'in kenarını kesişen bir kontur asla kendi üzerine kapanmayacağından, her zaman çizgi olmaz mıydı?
Antep fıstığı

Çok yoğun konturlu haritalarda biraz zaman alabilir, ancak v.generalize işlevini GRASS'ta kontur çizgilerini düzgün sonuçlarla düzgünleştirmek için kullandım.
Antep fıstığı

@pistachionut Kontur seviyelerinin çoklu çizgiler olduğunu düşünebilirsiniz. İlk aşamada saf kodu arıyorum . Mevcut değilse, Python için ışık paketi.
Geliştirici

Muhtemelen scipy.org/Cookbook/Ipopolation'a bakınız çünkü spline etmek istediğinize benziyor
PolyGeo

1
Bağlantınızdaki @Pablo Bezier eğrisi, poliller için iyi sonuç verir. Whuber çokgenler için neredeyse iyi çalışıyor. Böylece birlikte soruya cevap verebilirler. Bilginizi ücretsiz olarak paylaştığınız için teşekkür ederiz.
Geliştirici

Yanıtlar:


37

Sayı dizilerini eğirmek için kullanılan çoğu yöntem çokgenleri eğirecektir. İşin püf noktası, spline'ların uç noktalarda yumuşak bir şekilde "yakınlaşmasını" sağlamaktır. Bunu yapmak için uçların etrafındaki köşeleri "sarın". Ardından x ve y koordinatlarını ayrı olarak işaretleyin.

İşte çalışan bir örnek R. splineTemel istatistik paketinde mevcut olan varsayılan kübik prosedürü kullanır . Daha fazla kontrol için yedek hemen her prosedür tercih: sadece emin spline yapmak yoluyla onları kullanarak sadece sayılar (yani, onları araya) yerine "kontrol noktaları."

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

Kullanımını göstermek için, küçük (ama karmaşık) bir çokgen oluşturalım.

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

Yukarıdaki kodu kullanarak Spline. Spline'ı daha pürüzsüz hale getirmek için, köşelerin sayısını 100'den arttırın; daha az pürüzsüz hale getirmek için, köşelerin sayısını azaltın.

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

Sonuçları görmek için, (a) ilk çokgenler arasındaki boşluğu gösteren (yani, sınır polinesini kapatmamak gibi) , orijinal poligonu kesik kırmızı renkte çiziyoruz; ve (b) spline gri renkli olup, aradaki boşluğu bir kez daha göstermektedir. (Boşluk çok küçük olduğundan, uç noktaları mavi noktalarla vurgulanır.)

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)

Benekli poligon


5
Güzel cevap Konturların yumuşatmanın sonucu olarak geçmeyeceğini garanti etmenin bir yolu var mı?
Kirk Kuykendall

Bu iyi bir soru, @Kirk. Bu düzleştirme biçiminden geçmemeyi garanti edecek herhangi bir yöntemin farkında değilim. (Aslında, düzleştirilmiş polyline'ın kendiliğinden kesişen olmadığını garanti etmeyi bile görmüyorum. Bu, çoğu kontür için büyük bir sorun değil.) Bunu yapmak için, orijinaline geri dönmeniz gerekecek. DEM ve konturları ilk etapta hesaplamak için daha iyi bir yöntem kullanın. (Orada vardır - onlar uzun zamandır bilinmektedir - daha iyi yöntemler ancak AFAIK en popüler GISes bazı bunları kullanmayın.)
whuber

Öncelikle cevabınızı Python'da uygulamak için çalışıyorum ancak başarılı olamadım. İkincisi, yönteminizi bir kareye uygularsanız sonuç ne olur? Bu soruya çizdiğimlere atıfta bulunabilirsiniz.
Geliştirici

1
Bunu iyi bir çözüm olduğu için cevap olarak kabul ettim. Mükemmel bir fikir olmasa da, bana etrafta çalışan bazı fikirler verdi, ancak benim sorum ve yorumlarımda yukarıda belirtilen hususları karşılayan bir çözüm bulacağımı umuyorum. Ayrıca, whuber'in [QC] sorusu hakkındaki yorumlarını da düşünebilirsiniz, orada iyi hileler var. Son olarak, python'a yapılan çevirinin güzel Scipy paketinin kurulu olması neredeyse basit olduğunu söylemeliyim. Ayrıca Pablo'nun QC'deki yorumunu poliller için, yani Bezier eğrileri için olası bir çözüm olarak düşünün. Herkese iyi şanslar.
Geliştirici

1
cevaplarını görünce matematiğime iyi bakmadığım için pişmanım !!!
vinayan

2

Bunun eski bir yayın olduğunu biliyorum, ancak Google’da aradığım bir şey çıktı, bu yüzden çözümümü göndereceğimi düşündüm.

Bunu 2B eğriye uygun bir egzersiz olarak görmüyorum, bunun yerine 3B olarak görüyorum. Verileri 3B olarak göz önüne alarak, eğrilerin asla birbirini geçmemesini sağlayabilir ve mevcut hat için tahminimizi geliştirmek için diğer kontürlerden gelen bilgileri kullanabiliriz.

Aşağıdaki iPython özü, SciPy tarafından sağlanan kübik enterpolasyonu kullanır. Tüm konturların yüksekliği eşit olduğunda, çizdiğim z değerlerinin önemli olmadığını unutmayın.

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übik İnterpolasyonlu Sonuç

Buradaki sonuçlar en iyi görünmüyor, ancak çok az kontrol noktası ile hala mükemmel şekilde geçerli. Yeşil renkteki çizginin daha geniş mavi konturu takip etmek için nasıl çekildiğine dikkat edin.


Takılan pürüzsüz eğriler orijinal poligon / polyline mümkün olduğunca yakın durmalıdır.
Geliştirici

1

Neredeyse aradığınız paketi tam olarak yazdım ... ama Perl'deydi ve on yıldan fazla bir zaman önce: GD :: Polyline . 2B kübik Bezier eğrilerini kullandı ve keyfi bir Poligon veya "Polyline" ("şimdi genel olarak" LineString "olarak adlandırılanlar için ismimi)" pürüzsüz "hale getirdi.

Algoritma iki adımdı: Çokgen'deki noktalar göz önüne alındığında, her nokta arasına iki Bezier kontrol noktası ekleyin; daha sonra spline'a parça parça bir yakınlaştırma yapmak için basit bir algoritma çağırın.

İkinci bölüm kolaydır; ilk bölüm biraz sanat eseriydi. İşte fikir oldu: bir "kontrol segmenti" Bir Vertex N düşünün: vN. Kontrol bölümü, üç eş-doğrusal makas: [cNa, vN, cNb]. Merkez noktası tepe idi. Bu kontrol bölümünün eğimi Vertex N-1'den Vertex N + 1'e olan eğime eşitti. Bu bölümün sol kısmının uzunluğu, Vertex N-l'den Vertex N'e kadar olan uzunlukun 1 / 3'ü ve bu bölümün sağ kısmının uzunluğu, Vertex N'den Vertex N + l'e kadar olan 1/3 idi.

Orijinal eğrisi dört köşe ise: [v1, v2, v3, v4]o zaman her köşe artık formun bir kontrol segment: [c2a, v2, c2b]. Bunları bir araya [v1, c1b, c2a, v2, c2b, c3a, v3, c3b, c4a, v4]toplayın: ve bunları dört Bezier noktasının işaret ettiği gibi bir defada dürtün: [v1, c1b, c2a, v2]sonra [v2, c2b, c3a, v3], vb. Çünkü [c2a, v2, c2b]eş doğrusal olan, elde edilen eğri, ayrılan noktada düz olacaktır.

Bu aynı zamanda eğrinin "sıkılığını" parametreleştirme gerekliliğini de karşılar: "daha sıkı" bir eğri için 1/3'ten küçük bir değer kullanın, "loopier" için daha büyük bir eğri kullanın. Her iki durumda da ortaya çıkan eğri daima verilen orijinal noktalardan geçer.

Bu, orijinal Poligonu "sınırlayan" yumuşak bir eğriyle sonuçlandı. Ayrıca düzgün bir eğriyi "yazmak" için de bir yolum vardı ... ama bunu CPAN kodunda görmüyorum.

Her neyse, şu anda Python'da bir sürümü yok, ne de bir rakamım yok. AMA ... eğer / bunu Python'a aktardığımda, buraya göndereceğimden emin olacağım.


Perl kodu değerlendirilemiyor, mümkünse nasıl çalıştığını göstermek için grafikler ekleyin.
Geliştirici
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.