Як отримати координати XY та значення комірки кожного пікселя в растрі за допомогою Python?


16

Я дійсно новачок у Python, і я хотів би знати, чи існує швидкий метод отримання значень комірок растрового пікселя за пікселем та координат (карта XY координати центру кожного пікселя) за допомогою Python в ArcGIS 10?

Щоб описати це далі, мені потрібно отримати карту X, відобразити Y і значення комірки першого пікселя і призначити ці три значення у трьом змінним і повторити цей крок для решти інших пікселів (цикл через весь растр).


Я думаю, що мені потрібно більше описати своє питання. Проблема полягає в тому, що мені потрібно отримати місце розташування XY пікселя першого растру і отримати значення комірок кількох інших растрах, що відповідають цьому розташуванню XY. Цей процес повинен проходити цикл через кожен піксель першого растру, не створюючи жодного проміжного формату проміжних точок, оскільки це буде дійсно дуже трудомістким, оскільки мені доведеться обробляти растр майже 8 мільярдів пікселів. Також мені потрібно це зробити за допомогою Python в ArcGIS 10.

@JamesS: Дякую вам за пропозицію. Так, це буде працювати для одного растру, але мені потрібно зібрати значення комірок для кількох інших растрових. Проблема полягає в тому, що після отримання координат X і Y першого пікселя першого растру мені потрібно отримати значення комірки другого растру, що відповідає тому розташуванню X, Y першого растру, потім третьому растру і так далі. Отже, я думаю, що при перегляді першого растра, отримання X і Y пікселя та отримання значень комірок іншого растру, що відповідає цьому розташуванню, слід робити одночасно, але я не впевнений. Це можна зробити, перетворивши перший растр у точковий файл форми та виконавши Витяг багатозначень у функцію точок в ArcGIS 10, але я '

@hmfly: Дякую, так, цей метод (RastertoNumpyarray) буде працювати, якщо я можу отримати координату відомого значення рядка та стовпця масиву.

@whuber: Я не хочу робити жодних обчислень, все, що мені потрібно зробити, це записати координати XY і значення комірок у текстовий файл, і це все


Можливо, ви просто хочете зайнятися математикою на цілому растрі? Растрові калькулятори працюють піксель за пікселем.
BWill

1
будь ласка, опишіть своє призначення більш докладно.
BWill

Зазвичай ефективні та надійні рішення отримують за допомогою операцій Map Algebra, а не циклічного перегляду точок. Обмеження в застосуванні алгебри просторової аналітики заважають такому підходу працювати в будь-якому випадку, але в дивно великій кількості ситуацій вам не доведеться кодувати цикл. Який розрахунок потрібно точно виконати?
whuber

Перегляньте свої зміни: звичайно, це законна мета. Формат може бути нав'язаний вами потребами програмного забезпечення в подальшому. Але враховуючи, що для написання 8 мільярдів (X, Y, value1, ..., value3) кортежів буде потрібно від 224 мільярдів байт (у двійкових) і, можливо, 400 мільярдів байт (в ASCII), кожен з яких є досить великим набором даних, це можливо, варто знайти альтернативні підходи до того, що саме ви в кінцевому рахунку намагаєтеся досягти!
whuber

Відповіді:


11

За ідеєю @ Dango я створив і протестував (на невеликих растрах з однаковою мірою і розміром комірки) наступний код:

import arcpy, numpy

inRaster = r"C:\tmp\RastersArray.gdb\InRaster"
inRaster2 = r"C:\tmp\RastersArray.gdb\InRaster2"

##Get properties of the input raster
inRasterDesc = arcpy.Describe(inRaster)

#coordinates of the lower left corner
rasXmin = inRasterDesc.Extent.Xmin
rasYmin = inRasterDesc.Extent.Ymin

# Cell size, raster size
rasMeanCellHeight = inRasterDesc.MeanCellHeight
rasMeanCellWidth = inRasterDesc.MeanCellWidth
rasHeight = inRasterDesc.Height
rasWidth = inRasterDesc.Width

##Calculate coordinates basing on raster properties
#create numpy array of coordinates of cell centroids
def rasCentrX(rasHeight, rasWidth):
    coordX = rasXmin + (0.5*rasMeanCellWidth + rasWidth)
    return coordX
inRasterCoordX = numpy.fromfunction(rasCentrX, (rasHeight,rasWidth)) #numpy array of X coord

def rasCentrY(rasHeight, rasWidth):
    coordY = rasYmin + (0.5*rasMeanCellHeight + rasHeight)
    return coordY
inRasterCoordY = numpy.fromfunction(rasCentrY, (rasHeight,rasWidth)) #numpy array of Y coord

#combine arrays of coordinates (although array for Y is before X, dstack produces [X, Y] pairs)
inRasterCoordinates = numpy.dstack((inRasterCoordY,inRasterCoordX))


##Raster conversion to NumPy Array
#create NumPy array from input rasters 
inRasterArrayTopLeft = arcpy.RasterToNumPyArray(inRaster)
inRasterArrayTopLeft2 = arcpy.RasterToNumPyArray(inRaster2)

#flip array upside down - then lower left corner cells has the same index as cells in coordinates array
inRasterArray = numpy.flipud(inRasterArrayTopLeft)
inRasterArray2 = numpy.flipud(inRasterArrayTopLeft2)


# combine coordinates and value
inRasterFullArray = numpy.dstack((inRasterCoordinates, inRasterArray.T))

#add values from second raster
rasterValuesArray = numpy.dstack((inRasterFullArray, inRasterArray2.T))

На основі @hmfly коду ви можете мати доступ до бажаних значень:

(height, width, dim )=rasterValuesArray.shape
for row in range(0,height):
    for col in range(0,width):
        #now you have access to single array of values for one cell location

На жаль, є одне "але" - код підходить для масивів NumPy, якими можна обробляти системну пам'ять. Для моєї системи (8 Гб) найбільший масив становив близько 9000,9000.

Оскільки мій досвід не дає мені додаткової допомоги, ви можете розглянути кілька пропозицій щодо роботи з великими масивами: /programming/1053928/python-numpy-very-large-matrices

arcpy.RasterToNumPyArrayметод дозволяє вказати підмножину растрових, перетворених на масив NumPy ( довідкова сторінка ArcGIS10 ), що може бути корисно при збиранні великого набору даних у підматриці.


Код Марцина - супер! дякую, але він не пише X, Y растру з однаковою роздільною здатністю растру, я маю на увазі, що x і y ростуть на 1 м, а не, наприклад) 100 метрів .... Чи є у вас пропозиція виправити що Спасибі

7

Якщо ви просто хочете отримати значення пікселів (рядок, стовпець), ви можете написати скрипт arcpy таким чином:

import arcpy
raster = arcpy.Raster("yourfilepath")
array = arcpy.RasterToNumPyArray(raster)
(height, width)=array.shape
for row in range(0,height):
    for col in range(0,width):
        print str(row)+","+str(col)+":"+str(array.item(row,col))

Але, якщо ви хочете отримати координату пікселя, NumPyArray не може вам допомогти. Ви можете перетворити растр у точку інструментом RasterToPoint, і тоді ви можете отримати координату за формою поданої форми.


7

Найпростіший метод виведення координат та значень комірок у текстовий файл в ArcGIS 10 - це вибіркова функція , відсутність необхідності в коді і особливо немає необхідності переходити до кожної комірки. У растровому калькуляторі ArcGIS <= 9.3x він раніше був таким же простим, як і виводивoutfile.csv = sample(someraster) би текстовий файл усіх (ненульових) значень комірок та координат (у форматі z, x, y). У ArcGIS 10 схоже, що аргумент "in_location_data" тепер є обов'язковим, тому вам потрібно використовувати синтаксис Sample(someraster, someraster, outcsvfile).

Змінити: Ви також можете вказати декілька растрів: Sample([someraster, anotherraster, etc], someraster, outcsvfile). Чи буде це працювати на 8 мільярдів клітинок, я не маю ідеї ...

Редагувати: Зауважте, я не перевіряв це в ArcGIS 10, але використовував вибірку функції протягом років у <= 9.3 (та Workstation).

Редагувати: Я зараз протестував у ArcGIS 10, і він не виводить текстовий файл Інструмент автоматично змінює розширення файлу на ".dbf". Однак ... наступний код python працює як оператори алгебри карти SOMA та MOMA досі підтримуються в ArcGIS 10:

import arcgisscripting
gp=arcgisscripting.create()
gp.multioutputmapalgebra(r'%s=sample(%s)' % (outputcsv,inputraster))

Дуже хороша. Дякую, що вказали на це - я цього інструменту раніше не помічав. Звичайно, набагато акуратніше і простіше, ніж моє рішення!
JamesS

6

Один із способів зробити це - використовувати інструмент Raster_To_Point , за яким слід інструмент Add_XY_Coordinate . Ви отримаєте файл форми, де кожен рядок у таблиці атрибутів представляє піксель із растру зі стовпцями для X_Coord , Y_Coord та Cell_Value . Потім ви можете перевести цикл на цю таблицю за допомогою курсору (або експортувати її до чогось типу Excel, якщо вам зручніше).

Якщо у вас є лише один растр для обробки, це, мабуть, не варто сценаріїв - просто використовуйте інструменти з ArcToolbox. Якщо вам потрібно зробити це на багатьох растрах, ви можете спробувати щось подібне:

[ Примітка: у мене немає ArcGIS 10 і я не знайомий з ArcPy, тому це лише дуже приблизний контур. Це не перевірено і майже напевно потрібно буде налаштувати його, щоб змусити його працювати.]

import arcpy, os
from arcpy import env

# User input
ras_fold = r'path/to/my/data'           # The folder containing the rasters
out_fold = r'path/to/output/shapefiles' # The folder in which to create the shapefiles

# Set the workspace
env.workspace = ras_fold

# Get a list of raster datasets in the raster folder
raster_list = arcpy.ListRasters("*", "All")

# Loop over the rasters
for raster in raster_list:
    # Get the name of the raster dataset without the file extension
    dataset_name = os.path.splitext(raster)[0]

    # Build a path for the output shapefile
    shp_path = os.path.join(out_fold, '%s.shp' % dataset_name)

    # Convert the raster to a point shapefile
    arcpy.RasterToPoint_conversion(raster, shp_path, "VALUE")

    # Add columns to the shapefile containing the X and Y co-ordinates
    arcpy.AddXY_management(shp_path)

Потім ви можете перевести цикл на таблиці атрибутів shapefile за допомогою курсору пошуку або (можливо, простіше) за допомогою dbfpy . Це дозволить вам зчитувати дані з вашого растру (тепер він зберігається у формі файла .dbf таблиці) у змінні python.

from dbfpy import dbf

# Path to shapefile .dbf
dbf_path = r'path\to\my\dbf_file.dbf'

# Open the dbf file
db = dbf.Dbf(dbf_path)

# Loop over the records
for rec in db:
    cell_no = rec['POINTID'] # Numbered from top left, running left to right along each row
    cell_x = rec['POINT_X']
    cell_y = rec['POINT_Y']
    cell_val = rec['GRID_CODE']

    # Print values
    print cell_no, cell_x, cell_y, cell_val

3

Можливо, ви могли б створити світовий файл для растру, приховати растр до нумерованого масиву. то якщо ви перейдете через масив, ви отримаєте значення комірок, а якщо поточно оновити x, y зі світового файлу, ви також матимете координати для кожного значення комірки. сподіваюся, що це корисно.


Якщо вас не цікавить метод інструменту Raster to Point, запропонований JamesS, я б сказав, що це шлях.
nmpeterson

3

Код Марцина спрацював нормально, за винятком проблем у функціях rasCentrX та rasCentrY, що спричинило появу координат вихідного сигналу з різною роздільною здатністю (як це зазначало Grazia). Моє виправлення було змінити

coordX = rasXmin + (0.5*rasMeanCellWidth + rasWidth)

до

coordX = rasXmin + ((0.5 + rasWidth) * rasMeanCellWidth)

і

  coordY = rasYmin + (0.5*rasMeanCellHeight + rasHeight)

до

  coordY = rasYmin + ((0.5 + rasHeight) * rasMeanCellHeight)

Я використовував код для перетворення сітки ESRI у файл CSV. Це було досягнуто шляхом видалення посилання на inRaster2, а потім за допомогою csv.writer для виведення координат і значень:

out = csv.writer(open(outputCSV,"wb"), delimiter=',', quoting=csv.QUOTE_NONNUMERIC)
out.writerow(['X','Y','Value'])
(height, width, dim )=inRasterFullArray.shape
for row in range(0,height):
    for col in range(0,width):
        out.writerow(inRasterFullArray[row,col])

Я також не знайшов, що транспонинг потрібен

inRasterFullArray = numpy.dstack((inRasterCoordinates, inRasterArray.T))

так перетворено, що в

inRasterFullArray = numpy.dstack((inRasterCoordinates, inRasterArray))

2

Некрасивий, але високоефективний:

  1. Створіть нову точкову функцію з 4 балами за межами кутів растру. Переконайтеся в тій же системі координат, що і у растрі.
  2. Додайте подвійні поля "xcor" та "ycor"
  3. Обчисліть геометрію, щоб отримати координати для цих полів
  4. Просторовий аналітик-> Інтерполяція-> Тенденція -> Лінійна регресія
  5. Налаштування навколишнього середовища: оснащення растрових розмірів і розмір комірок, як і растр
  6. Виконайте окремо для 'xcor' та 'ycor'
  7. Виходять рейтинги з координатами як значення комірок, використовуються як вхідні дані для сценаріїв.

2

Просте рішення з використанням пакетів python з відкритим кодом:

import fiona
import rasterio
from pprint import pprint


def raster_point_coords(raster, points):

    # initialize dict to hold data
    pt_data = {}

    with fiona.open(points, 'r') as src:
        for feature in src:
            # create dict entry for each feature
            pt_data[feature['id']] = feature

    with rasterio.open(raster, 'r') as src:
        # read raster into numpy array
        arr = src.read()
        # rasterio always reads into 3d array, this is 2d, so reshape
        arr = arr.reshape(arr.shape[1], arr.shape[2])
        # get affine, i.e. data needed to work between 'image' and 'raster' coords
        a = src.affine

    for key, val in pt_data.items():
        # get coordinates
        x, y = val['geometry']['coordinates'][0], val['geometry']['coordinates'][1]
        # use affine to convert to row, column
        col, row = ~a * (x, y)
        # remember numpy array is indexed array[row, column] ie. y, x
        val['raster_value'] = arr[int(row), int(col)]

    pprint(pt_data) 

if __name__ == '__main__':
    # my Landsat raster
    ras = '/data01/images/sandbox/LT05_040028_B1.tif'
    # my shapefile with two points which overlap raster area
    pts = '/data01/images/sandbox/points.shp'
    # call function
    raster_point_coords(ras, pts)

Fiona зручна, оскільки ви можете відкрити файл форми, переглядати функції та (як у мене) додати їх до dictоб'єкта. Дійсно, сама Фіона featureподібна до dictтого ж, тому до неї легко отримати доступ. Якби мої точки мали якісь атрибути, вони відображалися б у цьому диктаті разом з координатами, id тощо.

Растеріо зручно, тому що його легко читати в растрі як нудотний масив, легкий і швидкий тип даних. У нас також є доступ до dictрастрових властивостей, включаючи affine, тобто всі дані, необхідні для перетворення растрових x, y координат у рядки масиву, координати колу. Дивіться чудове пояснення @ perrygeo тут .

Ми закінчуємо pt_dataтипом, dictякий містить дані для кожної точки та вилучені raster_value. Ми легко могли б переписати файл форми також із витягнутими даними, якби хотіли.

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