GDAL และ Python: จะรับพิกัดสำหรับเซลล์ทั้งหมดที่มีค่าเฉพาะได้อย่างไร


12

ฉันมีArc / Info Binary Grid --- โดยเฉพาะแรสเตอร์การไหลของ ArcGIS --- และฉันต้องการระบุเซลล์ทั้งหมดที่มีค่าเฉพาะ (หรืออยู่ในช่วงของค่า) ในที่สุดฉันต้องการไฟล์รูปร่างของคะแนนที่แสดงถึงเซลล์เหล่านี้

ฉันสามารถใช้ QGIS เพื่อเปิด hdr.adf และรับผลลัพธ์นี้เวิร์กโฟลว์คือ:

  • QGIS> เมนู Raster> Raster Calculator (ทำเครื่องหมายคะแนนทั้งหมดด้วยมูลค่าเป้าหมาย)
  • QGIS> เมนู Raster> รูปหลายเหลี่ยม
  • QGIS> เมนูเวกเตอร์> เมนูย่อยเรขาคณิต> รูปหลายเหลี่ยม centroids
  • แก้ไขเซนทรอยด์เพื่อลบโพลีเซนทรอยด์ที่ไม่ต้องการ (เหล่านั้น = 0)

วิธีการนี้ "ทำงานได้" แต่มันไม่ได้ดึงดูดความสนใจฉันเพราะมันสร้างไฟล์ 2 ไฟล์ที่ฉันต้องลบแล้วฉันต้องลบบันทึกที่ไม่ต้องการออกจาก shapefile ของ centroids (นั่นคือ = 0)

คำถามที่มีอยู่วิธีการเรื่องนี้ แต่มันเหมาะสำหรับ ArcGIS / ArcPy และฉันต้องการที่จะอยู่ในพื้นที่ฟอสส์

ใครบ้างมีสูตร / สคริปต์ GDAL / Python ที่มีอยู่แล้วที่สอบถามค่าเซลล์ของแรสเตอร์และเมื่อพบค่าเป้าหมาย --- หรือค่าในช่วงเป้าหมาย --- จะมีการเพิ่มเรคคอร์ดลงในรูปร่างไฟล์หรือไม่ สิ่งนี้จะไม่เพียง แต่หลีกเลี่ยงการโต้ตอบกับ UI แต่มันจะสร้างผลลัพธ์ที่สะอาดด้วยการผ่านครั้งเดียว

ฉันถ่ายภาพด้วยการทำงานกับงานนำเสนอของ Chris Garrardแต่งานแรสเตอร์ไม่ได้อยู่ใน wheelhouse ของฉันและฉันไม่ต้องการที่จะถ่วงคำถามด้วยรหัสที่อ่อนแอของฉัน

ทุกคนควรจะต้องการชุดข้อมูลที่แน่นอนที่จะเล่นกับฉันวางมันลงที่นี่เป็นที่ซิป


[แก้ไขหมายเหตุ]ทิ้งสิ่งนี้ไว้เบื้องหลังเพื่อลูกหลาน ดูการแลกเปลี่ยนความคิดเห็นกับ om_henners โดยทั่วไปค่า x / y (แถว / คอลัมน์) ถูกพลิก คำตอบเดิมมีบรรทัดนี้:

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

ฤvertedษีเช่นนี้:

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

เมื่อฉันพบปัญหาที่แสดงในภาพหน้าจอเป็นครั้งแรกฉันสงสัยว่าฉันใช้รูปทรงเรขาคณิตไม่ถูกต้องหรือไม่และฉันทดลองโดยพลิกค่าพิกัด x / y ในบรรทัดนี้:

point.SetPoint(0, x, y)

..เช่น..

point.SetPoint(0, y, x)

อย่างไรก็ตามนั่นไม่ได้ผล และฉันไม่คิดว่าจะลองพลิกค่าในการแสดงออก Numpy ของ om_henners เชื่ออย่างผิด ๆ ว่าการพลิกมันที่เส้นใดเส้นหนึ่งนั้นเทียบเท่ากัน ฉันคิดว่าปัญหาจริงเกี่ยวข้องกับx_sizeและy_sizeค่าตามลำดับ30และ-30ซึ่งจะใช้เมื่อดัชนีแถวและคอลัมน์ถูกใช้เพื่อคำนวณพิกัดจุดสำหรับเซลล์

[แก้ไขต้นฉบับ]

@om_henners ฉันกำลังพยายามแก้ปัญหาของคุณในคอนเสิร์ตพร้อมกับคู่หูคู่หนึ่งสำหรับการสร้างไฟล์รูปร่างแบบจุดโดยใช้ ogr ( invisibleroads.com , Chris Garrard ) แต่ฉันมีปัญหาที่จุดปรากฏราวกับว่าสะท้อนผ่านเส้นตรง ผ่าน 315/135 องศา

จุดสีฟ้าอ่อน : สร้างโดยวิธีการ QGISของฉันด้านบน

จุดสีม่วง : สร้างโดยรหัส py GDAL / OGRด้านล่าง

ป้อนคำอธิบายรูปภาพที่นี่


[แก้ไข]

รหัส Python นี้ใช้โซลูชันที่สมบูรณ์ตามที่เสนอโดย @om_henners ฉันทดสอบแล้วและใช้งานได้ ขอบคุณคน!


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
เคล็ดลับอย่างรวดเร็วสำหรับโค้ดของคุณ: คุณสามารถใช้การฉายภาพแรสเตอร์เป็นการฉายภาพ Shapefile ของคุณด้วยsrs.ImportFromWkt(r.GetProjection())(แทนที่จะต้องสร้างการฉายภาพจากสตริง proj ที่รู้จัก)
om_henners

รหัสของคุณทำทุกสิ่งที่ฉันกำลังมองหายกเว้นว่ามันจะไม่รวมค่าแรสเตอร์ของเซลล์ตามที่คุณเขียนตัวกรอง numpy ของคุณเพื่อรวมเฉพาะค่า = 1000 คุณช่วยชี้ให้ฉันในทิศทางที่ถูกต้องเพื่อรวมค่าเซลล์แรสเตอร์ใน เอาท์พุท? ขอบคุณ!
Brent Edwards

คำตอบ:


19

ใน GDAL คุณสามารถนำเข้าแรสเตอร์เป็นอาร์เรย์ที่ไม่มีค่าได้

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)

จากนั้นใช้ numpy มันเป็นเรื่องง่ายที่จะได้รับการจัดทำดัชนีของอาเรย์ที่ตรงกับการแสดงออกของ boolan:

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

จาก geotransform เราสามารถรับข้อมูลได้เช่นพิกัด x บนซ้ายและ y และขนาดของเซลล์

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

a[0, 0]ด้านซ้ายบนมือถือเพื่อสอดคล้อง ขนาด Y จะเป็นค่าลบเสมอดังนั้นการใช้ดัชนี x และ y คุณสามารถคำนวณพิกัดของแต่ละเซลล์ตามดัชนี

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

จากที่นี่เป็นเรื่องง่ายพอที่จะสร้าง shapefile โดยใช้ OGR สำหรับตัวอย่างโค้ดดูคำถามนี้สำหรับวิธีสร้างชุดข้อมูลใหม่พร้อมข้อมูลจุด


เฮ้ fella ฉันมีปัญหาเล็กน้อยในการดำเนินการนี้ ฉันได้อัปเดตคำถามเพื่อรวมรหัสที่ฉันใช้อยู่และสิ่งที่ฉันได้รับ โดยพื้นฐานแล้วโค้ด. py กำลังสร้างภาพสะท้อน (ตำแหน่งจุด) ของวิธีการที่ QGIS กำลังสร้าง คะแนนในการดำเนินการของฉันอยู่นอกขอบเขตแรสเตอร์ดังนั้นปัญหาต้องอยู่ในรหัสของฉัน : = ฉันหวังว่าคุณจะหลั่งน้ำตาแสง ขอบคุณ!
elrobis

ขออภัยเกี่ยวกับสิ่งนั้น - สิ่งที่ไม่ดีของฉัน เมื่อคุณนำเข้าแรสเตอร์ใน GDAL แถวจะเป็นทิศทาง y และคอลัมน์เป็นทิศทาง x ฉันได้อัปเดตโค้ดด้านบนแล้ว แต่เคล็ดลับคือการรับดัชนีด้วย(y_index, x_index) = np.nonzero(a > threshold)
om_henners

1
นอกจากนี้ในกรณีที่บันทึกการเพิ่มขนาดครึ่งหนึ่งของเซลล์ลงในพิกัดทั้งสองทิศทางเพื่อจัดกึ่งกลางของจุดในเซลล์
om_henners

ใช่นั่นเป็นปัญหา เมื่อฉันพบข้อผิดพลาดนั้นเป็นครั้งแรก (ตามที่แสดงในหน้าจอคว้า) ฉันสงสัยว่าฉันได้นำรูปทรงเรขาคณิตของจุดมาใช้อย่างไม่ถูกต้องหรือไม่ดังนั้นฉันจึงพยายามพลิก x / y เป็น y / x เมื่อฉันทำ.shp--- ทำงานหรืออยู่ใกล้ ๆ ฉันไม่ตกใจเพราะค่า x อยู่ในหลักแสนและ y อยู่ในหลักล้านดังนั้นมันจึงทำให้ฉันค่อนข้างสับสน ฉันไม่คิดว่าจะลองพลิกพวกมันกลับไปที่การแสดงออกของ Numpy ขอบคุณมากสำหรับความช่วยเหลือของคุณมันเจ๋งมาก สิ่งที่ฉันต้องการ :)
elrobis

4

ทำไมไม่ใช้กล่องเครื่องมือ Sexanteใน QGIS มันเป็นเหมือนเครื่องมือสร้างโมเดลสำหรับ ArcGIS ด้วยวิธีนี้คุณสามารถเชื่อมโยงการปฏิบัติงานและถือเป็นปฏิบัติการเดียว คุณสามารถทำการลบไฟล์ระดับกลางและลบบันทึกที่ไม่ต้องการโดยอัตโนมัติหากฉันไม่เข้าใจผิด


1

มันอาจจะเป็นประโยชน์ในการนำเข้าข้อมูลไปยัง postgis (ด้วยการสนับสนุนแบบ raster) และใช้ฟังก์ชั่นที่นั่น บทช่วยสอนนี้อาจมีองค์ประกอบที่คุณต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.