GDAL та Python: Як отримати координати для всіх комірок, що мають певне значення?


12

У мене є Arc / Info Binary Grid --- конкретно, растр накопичення потоку ArcGIS ---, і я хотів би визначити всі клітини, що мають конкретне значення (або в діапазоні значень). Зрештою, мені б хотілося сформулювати точку зображень цих комірок.

Я можу використовувати QGIS, щоб відкрити hdr.adf і отримати цей результат, робочий процес такий:

  • QGIS> Растрове меню> Растровий калькулятор (позначте всі точки з цільовим значенням)
  • QGIS> Растрове меню> Полігонізувати
  • QGIS> Векторне меню> Підменю Геометрія> Центроїди полігонів
  • Відредагуйте центроїди, щоб видалити небажані поліцентроїди (ті = 0)

Такий підхід "виконує роботу", але мені це не подобається, оскільки він створює 2 файли, які я повинен видалити, тоді я повинен видалити небажані записи (файли) з форм-файлу центроїдів (тобто ті = 0).

До цього питання підходить існуюче питання, але воно розроблене для ArcGIS / ArcPy, і я хотів би залишитися в просторі FOSS.

Чи є у когось існуючий рецепт / скрипт GDAL / Python, який допитує значення растрових комірок, і коли знайдено цільове значення --- або значення в цільовому діапазоні ---, запис додається до файлу форми? Це дозволить не тільки уникнути взаємодії з інтерфейсом користувача, але й створить чистий результат за один прохід.

Я зняв це, працюючи проти однієї з презентацій Кріса Гаррарда , але растрова робота не в моїй рубці, і я не хочу забивати питання своїм слабким кодом.

Якщо хтось захоче грати з точним набором даних, я розміщую його як .zip .


[Редагувати примітки] Залишаючи це позаду для нащадків. Дивіться обмін коментарями з om_henners. В основному значення x / y (рядок / стовпець) були перевернуті. Оригінальна відповідь мала такий рядок:

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

перевернутий, як це:

(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 , Кріс Гаррард ), але у мене виникає проблема, коли точки з’являються так, ніби відображені через проходження лінії через 315/135-градус.

Світло-сині точки : створені моїм підходом до QGIS , вище

Фіолетові точки : створені за допомогою GDAL / OGR py-коду , наведеного нижче

введіть тут опис зображення


[Вирішено]

Цей код 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
Короткий підказки щодо вашого коду: ви можете використовувати растрову проекцію як проектну srs.ImportFromWkt(r.GetProjection())форму вашої форми (замість того, щоб створювати проекцію з відомої рядка програми).
om_henners

Ваш код робить все, що я шукаю, за винятком того, що він не включає значення растрової комірки, оскільки ви написали фільтр numpy, щоб містити лише значення = 1000. Чи можете ви вказати мені в правильному напрямку, щоб включити значення растрових комірок у вихід? Дякую!
Брент Едвардс

Відповіді:


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

З растрової геотрансформи можна отримати таку інформацію, як верхній лівий координати 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

Звідси досить простою справою створити файл форми за допомогою OGR. Для деяких зразкових кодів див. Це запитання щодо того, як генерувати новий набір даних із інформацією про точку.


Привіт, приятелю, у мене є невеличка проблема, що реалізує це. Я оновив питання, щоб включити код, який я використовую, і резюме того, що я отримую. В основному код .py створює дзеркальне зображення (розміщення точок) того, що генерує підхід QGIS. Бали в моєму виконанні знаходяться поза межами растрових меж, тому питання повинно бути з моїм кодом. : = Я сподіваюся, що ти зможеш пролити трохи світла. Дякую!
elrobis

Вибачте з цього приводу - абсолютно моє погано. Коли ви імпортуєте растр у GDAL, рядки - це напрямок y, а стовпці - х. Я оновив код вище, але хитрість полягає в тому, щоб отримати індекси з(y_index, x_index) = np.nonzero(a > threshold)
om_henners

1
Крім того, про всяк випадок відзначте додавання половини розміру комірки до координат в обох напрямках, щоб централювати точку в комірці.
om_henners

Так, це було проблемою. Коли я вперше зіткнувся з цією помилкою (як показано на захопленні екрана), я задумався, чи неправильно я застосував геометрію точки, тому спробував перевернути x / y як y / x, коли я зробив .shp--- тільки те, що не робота, і ніде вона не була близько. Я не був шокований, оскільки значення x в сотнях тисяч, а y - у мільйонах, тому воно залишило мене дуже заплутаним. Я не думав намагатися відвернути їх назад за виразом Омела. Дякую за допомогу, це класно. Саме те, що я хотів. :)
elrobis

4

Чому б не використовувати панель інструментів Sexante в QGIS? Це схоже на Model Builder для ArcGIS. Таким чином, ви можете ланцюгові операції і трактувати це як одну операцію. Ви можете автоматизувати видалення проміжних файлів та видалення небажаних записів, якщо я не помиляюся.


1

Це може бути корисно імпортувати дані в postgis (з підтримкою растру) та використовувати там функції. У цьому підручнику можуть бути потрібні вам елементи.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.