GDAL ve Python: Belirli bir değere sahip tüm hücreler için koordinatlar nasıl alınır?


12

Bir Arc / Info Binary Grid --- özellikle bir ArcGIS akış birikim rasterim var ve belirli bir değere (veya bir değer aralığında) sahip tüm hücreleri tanımlamak istiyorum. Nihayetinde, bu hücreleri temsil eden noktaların şekil dosyası istiyorum.

Ben hdr.adf açmak ve bu sonucu almak için QGIS kullanabilirsiniz, iş akışı:

  • QGIS> Tarama menüsü> Tarama Hesaplayıcısı (tüm noktaları hedef değerle işaretleyin)
  • QGIS> Tarama menüsü> Çokgenleştir
  • QGIS> Vektör menüsü> Geometri alt menüsü> Çokgen sentroidleri
  • İstenmeyen poli centroidleri silmek için sentroidleri düzenleyin (bunlar = 0)

Bu yaklaşım "işi yapar", ancak silmem gereken 2 dosya oluşturduğu için bana hitap etmiyor, sonra istenmeyen kayıtları (lar) centroids dosya biçiminden (yani = 0) kaldırmak zorundayım.

Bir varolan soru konuya bakış, ama o ArcGIS / ArcPy için uygun hale gelecek ve ben FOSS uzayda kalmak istiyorum.

Herhangi bir raster hücre değerlerini sorgulayan mevcut bir GDAL / Python tarifi / komut dosyası var mı ve bir hedef değer - veya hedef aralıktaki bir değer bulunduğunda şekil dosyasına bir kayıt eklenir mi? Bu sadece UI etkileşimini önlemekle kalmaz, aynı zamanda tek bir geçişte temiz bir sonuç yaratır.

Chris Garrard'ın sunumlarından birine karşı çalışarak bir çekim yaptım , ancak raster çalışması tekerlek evimde değil ve soruyu zayıf kodumla karıştırmak istemiyorum.

Herkesin tam veri kümesinin oynamasını isterse, buraya .zip olarak koydum .


[Notları Düzenle] Bunu gelecek nesiller için geride bırakmak. Om_henners ile görüş alışverişine bakın. Temelde x / y (satır / sütun) değerleri çevrildi. Orijinal cevapta şu satır vardı:

(y_index, x_index) = np.nonzero(a == 1000)

ters, şöyle:

(x_index, y_index) = np.nonzero(a == 1000)

Ekran görüntüsünde gösterilen sorunla ilk karşılaştığımda, geometriyi yanlış uygulayıp uygulamadığımı merak ettim ve bu satırdaki x / y koordinat değerlerini çevirerek denedim:

point.SetPoint(0, x, y)

..gibi..

point.SetPoint(0, y, x)

Ancak bu işe yaramadı. Ve om_henners'ın Numpy ifadesindeki değerleri çevirmeyi denemedim, yanlış bir şekilde her iki hatta çevirmenin eşdeğer olduğuna inanıyorum. Gerçek bir sorun ile ilgilidir düşünmek x_sizeve y_sizesırasıyla değerleri 30ve -30satır ve sütun indisleri hücreleri için hesapla noktası koordinatları için kullanıldığında uygulanır.

[Orijinal Düzenleme]

@om_henners, ogr ( invisibleroads.com , Chris Garrard ) kullanarak nokta şekil dosyaları yapmak için birkaç tarifle birlikte çözümünüzü deniyorum , ancak noktaların bir çizgi boyunca yansıtılmış gibi göründüğü bir sorun yaşıyorum 315/135 derece arasında.

Açık mavi noktalar : yukarıdaki QGIS yaklaşımım tarafından oluşturuldu

Mor noktalar : aşağıda GDAL / OGR py kodu ile oluşturulmuştur

resim açıklamasını buraya girin


[Çözülmüş]

Bu Python kodu, @om_henners tarafından önerilen tam çözümü uygular. Test ettim ve işe yarıyor. Teşekkürler dostum!


from osgeo import gdal
import numpy as np
import osgeo.ogr
import osgeo.osr

path = "D:/GIS/greeneCty/Greene_DEM/GreeneDEM30m/flowacc_gree/hdr.adf"
print "\nOpening: " + path + "\n"

r = gdal.Open(path)
band = r.GetRasterBand(1)

(upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size) = r.GetGeoTransform()

a = band.ReadAsArray().astype(np.float)

# This evaluation makes x/y arrays for all cell values in a range.
# I knew how many points I should get for ==1000 and wanted to test it.
(y_index, x_index) = np.nonzero((a > 999) & (a < 1001))

# This evaluation makes x/y arrays for all cells having the fixed value, 1000.
#(y_index, x_index) = np.nonzero(a == 1000)

# DEBUG: take a look at the arrays..
#print repr((y_index, x_index))

# Init the shapefile stuff..
srs = osgeo.osr.SpatialReference()
#srs.ImportFromProj4('+proj=utm +zone=15 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs')
srs.ImportFromWkt(r.GetProjection())

driver = osgeo.ogr.GetDriverByName('ESRI Shapefile')
shapeData = driver.CreateDataSource('D:/GIS/01_tutorials/flow_acc/ogr_pts.shp')

layer = shapeData.CreateLayer('ogr_pts', srs, osgeo.ogr.wkbPoint)
layerDefinition = layer.GetLayerDefn()

# Iterate over the Numpy points..
i = 0
for x_coord in x_index:
    x = x_index[i] * x_size + upper_left_x + (x_size / 2) #add half the cell size
    y = y_index[i] * y_size + upper_left_y + (y_size / 2) #to centre the point

    # DEBUG: take a look at the coords..
    #print "Coords: " + str(x) + ", " + str(y)

    point = osgeo.ogr.Geometry(osgeo.ogr.wkbPoint)
    point.SetPoint(0, x, y)

    feature = osgeo.ogr.Feature(layerDefinition)
    feature.SetGeometry(point)
    feature.SetFID(i)

    layer.CreateFeature(feature)

    i += 1

shapeData.Destroy()

print "done! " + str(i) + " points found!"

1
Kodunuz için hızlı ipucu: Raster projeksiyonu şekil dosyası projeksiyonunuz olarak kullanabilirsiniz srs.ImportFromWkt(r.GetProjection())(bilinen bir proje dizesinden bir projeksiyon oluşturmak yerine).
om_henners

Kodunuz, yalnızca numaranızı = 1000 içerecek şekilde numpy filtrenizi yazdığınız gibi raster hücre değerini içermemesi dışında aradığım her şeyi yapar. Raster hücre değerlerini çıktı? Teşekkürler!
Brent Edwards

Yanıtlar:


19

GDAL'de rasterleri sayısal bir dizi olarak içe aktarabilirsiniz.

from osgeo import gdal
import numpy as np

r = gdal.Open("path/to/raster")
band = r.GetRasterBand(1) #bands start at one
a = band.ReadAsArray().astype(np.float)

Sonra numpy kullanarak bir boolan ifadesiyle eşleşen bir dizinin dizinlerini almak basit bir konudur:

(y_index, x_index) = np.nonzero(a > threshold)
#To demonstate this compare a.shape to band.XSize and band.YSize

Raster geotransformundan, sol üst x ve y koordinatları ve hücre boyutları gibi bilgiler alabiliriz.

(upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size) = r.GetGeoTransform()

Sol üst hücre karşılık gelir a[0, 0]. Y boyutu her zaman negatif olacaktır, bu nedenle x ve y indekslerini kullanarak her bir hücrenin koordinatlarını dizinlere göre hesaplayabilirsiniz.

x_coords = x_index * x_size + upper_left_x + (x_size / 2) #add half the cell size
y_coords = y_index * y_size + upper_left_y + (y_size / 2) #to centre the point

Buradan, OGR kullanarak şekil dosyası oluşturmak için yeterince basit bir mesele. Bazı örnek kodlar için, nokta bilgileriyle yeni bir veri kümesinin nasıl oluşturulacağı konusunda bu soruya bakın .


Selam dostum, bunu uygularken küçük bir sorun yaşıyorum. Kullandığım kodu ve ne aldığımı gösteren bir screeshot içerecek şekilde soruyu güncelledim. Temel olarak .py kodu, QGIS yaklaşımının ürettiğinin ayna görüntüsünü (nokta yerleşimi) yaratır. Uygulamamdaki noktalar raster sınırlarının dışında kalıyor, bu yüzden sorun kodumla ilgili olmalı. : = Biraz ışık tutacağınızı umuyorum. Teşekkürler!
elrobis

Bunun için üzgünüm - tamamen kötüyüm. GDAL'da bir raster içe aktardığınızda satırlar y yönünü ve sütunlar x yönünü gösterir. Yukarıdaki kodu güncelledim, ancak hile ile endeksleri elde etmektir(y_index, x_index) = np.nonzero(a > threshold)
om_henners

1
Ayrıca, her ihtimale karşı, hücredeki noktayı ortalamak için her iki yönde koordinatlara hücre boyutunun yarısının eklenmesine dikkat edin.
om_henners

Evet, sorun buydu. (Ekran kapma gösterildiği gibi) ilk bu hata karşılaşılan zaman yanlış noktası geometrisi uygulanan olsaydı y olarak x / y saygısız çalıştı bu yüzden, merak / x I yapıldığı zaman .shp--- sadece vermedi ne de yakın bir yerde değildi. X değeri yüzbinlerce ve y milyonlarca olduğu için şok olmadım, bu yüzden beni oldukça karışık bıraktı. Numpy ifadesinde onları geri çevirmeyi denemedim. Yardımınız için çok teşekkürler, bu harika. Tam olarak ne istediğimi. :)
elrobis

4

QGIS'de neden Sexante araç kutusunu kullanmıyorsunuz ? ArcGIS için Model Builder gibi. Bu şekilde işlemleri zincirleyebilir ve tek bir işlem olarak ele alabilirsiniz. Yanılmıyorsam, ara dosyaların silinmesini ve istenmeyen kayıtların kaldırılmasını otomatikleştirebilirsiniz.


1

Verileri postgis'e (tarama desteği ile) aktarmak ve buradaki işlevleri kullanmak yararlı olabilir. Bu öğreticide ihtiyacınız olan öğeler olabilir.

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.