Làm cách nào để lấy tọa độ XY và giá trị ô của từng pixel trong raster bằng Python?


16

Tôi thực sự mới đối với Python và tôi muốn biết liệu có phương pháp nhanh nào để lấy giá trị ô của pixel raster theo pixel và tọa độ (tọa độ XY của tâm của mỗi pixel) bằng Python trong ArcGIS 10 không?

Để mô tả điều này hơn nữa, tôi cần lấy bản đồ X, ánh xạ Y và giá trị ô của pixel đầu tiên và gán ba giá trị đó cho ba biến và lặp lại bước này cho các pixel còn lại (lặp qua toàn bộ raster).


Tôi nghĩ rằng tôi cần phải mô tả câu hỏi của tôi nhiều hơn. Vấn đề là, tôi cần lấy vị trí XY của một pixel của raster đầu tiên và nhận các giá trị ô của một số raster khác tương ứng với vị trí XY đó. Quá trình này phải được lặp qua từng pixel của raster đầu tiên mà không tạo ra bất kỳ shapefile điểm trung gian nào vì nó sẽ thực sự tốn thời gian vì tôi phải xử lý raster với gần 8 tỷ pixel. Ngoài ra, tôi cần thực hiện việc này bằng Python trong ArcGIS 10.

@JamesS: Cảm ơn bạn rất nhiều vì lời đề nghị của bạn. Vâng, điều này sẽ làm việc cho một raster nhưng tôi cũng cần phải thu thập các giá trị ô cho một số raster khác. Vấn đề là, sau khi có tọa độ X và Y của pixel đầu tiên của raster thứ nhất, tôi cần lấy giá trị ô của raster thứ hai tương ứng với vị trí X, Y của raster thứ nhất, rồi raster thứ ba, v.v. Vì vậy, tôi nghĩ rằng khi lặp qua raster đầu tiên, việc lấy vị trí X và Y của pixel và nhận giá trị ô của raster khác tương ứng với vị trí đó nên được thực hiện đồng thời nhưng tôi không chắc chắn. Điều này có thể được thực hiện bằng cách chuyển đổi raster đầu tiên thành shapefile điểm và thực hiện trích xuất đa trị trích xuất thành hàm điểm trong ArcGIS 10 nhưng tôi

@hmfly: Cảm ơn, Có, phương thức này (RastertoNumpyarray) sẽ hoạt động nếu tôi có thể lấy tọa độ của một hàng và giá trị cột đã biết của mảng.

@whuber: Tôi không muốn thực hiện bất kỳ phép tính nào, tất cả những gì tôi cần làm là ghi tọa độ XY và giá trị ô vào tệp văn bản và đó là tất cả


Có lẽ bạn chỉ muốn làm một số toán học trên toàn bộ raster? Máy tính raster hoạt động theo pixel.
BWill

1
xin vui lòng mô tả mục đích của bạn chi tiết hơn.
BWill

Thông thường, các giải pháp hiệu quả và đáng tin cậy có được bằng cách sử dụng các phép toán Đại số bản đồ thay vì lặp qua các điểm. Những hạn chế trong triển khai đại số bản đồ của Nhà phân tích không gian ngăn cản cách tiếp cận này hoạt động trong mọi trường hợp, nhưng trong một số lượng lớn các tình huống đáng ngạc nhiên bạn không phải viết mã vòng lặp. Tính toán nào bạn cần thực hiện, chính xác?
whuber

Chỉnh sửa của bạn: tất nhiên đó là một mục đích hợp pháp. Các định dạng có thể được áp đặt cho bạn bởi nhu cầu của phần mềm tiếp tục. Nhưng nếu xem xét việc viết các bộ dữ liệu 8 tỷ (X, Y, value1, ..., value3) sẽ cần từ 224 tỷ byte (ở dạng nhị phân) và có lẽ 400 tỷ byte (trong ASCII), một trong số đó là một tập dữ liệu khá lớn, nó có thể đáng để tìm cách tiếp cận thay thế cho bất cứ điều gì mà cuối cùng bạn đang cố gắng thực hiện!
whuber

Câu trả lời:


11

Theo ý tưởng của @ Dango tôi đã tạo và thử nghiệm (trên các raster nhỏ có cùng phạm vi và kích thước ô) mã sau đây:

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

Dựa trên mã @hmfly, bạn có thể có quyền truy cập vào các giá trị mong muốn:

(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

Thật không may, có một "nhưng" - mã phù hợp với các mảng NumPy có thể được xử lý bởi bộ nhớ hệ thống. Đối với hệ thống của tôi (8GB), mảng lớn nhất là khoảng 9000.9000.

Vì kinh nghiệm của tôi không cho phép tôi cung cấp thêm trợ giúp, bạn có thể xem xét một số đề xuất về việc xử lý các mảng lớn: /programming/1053928/python-numpy-very-large-matrices

arcpy.RasterToNumPyArrayphương thức cho phép chỉ định tập hợp con của raster được chuyển đổi thành mảng NumPy ( trang trợ giúp ArcGIS10 ) những gì có thể hữu ích khi phân đoạn dữ liệu lớn thành các mô hình con.


Mã của Marcin là siêu! cảm ơn, nhưng nó không viết X, Y của raster với cùng độ phân giải của raster. Ý tôi là x và y tăng 1 m và không, ví dụ) 100 mét .... Bạn có gợi ý nào để khắc phục không cảm ơn

7

Nếu bạn chỉ muốn nhận các giá trị pixel thông qua (hàng, cột), bạn có thể viết một tập lệnh phức tạp như thế này:

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

Nhưng, nếu bạn muốn có tọa độ của pixel, NumPyArray không thể giúp bạn. Bạn có thể chuyển đổi raster thành điểm bằng Công cụ RasterToPoint, và sau đó bạn có thể lấy tọa độ theo Shape.


7

Phương pháp đơn giản nhất để xuất tọa độ và giá trị ô vào tệp văn bản trong ArcGIS 10 là hàm mẫu , không cần mã và đặc biệt là không cần lặp trên mỗi ô. Trong máy tính raster ArcGIS <= 9.3x, nó thường đơn giản như outfile.csv = sample(someraster)sẽ xuất ra một tệp văn bản của tất cả các giá trị và tọa độ ô (không null) (ở định dạng z, x, y). Trong ArcGIS 10, có vẻ như đối số "in_location_data" hiện bắt buộc nên bạn cần sử dụng cú pháp Sample(someraster, someraster, outcsvfile).

Chỉnh sửa: Bạn cũng có thể chỉ định nhiều trình quét : Sample([someraster, anotherraster, etc], someraster, outcsvfile). Liệu điều này có hoạt động trên 8 tỷ tế bào hay không, tôi không biết ...

Chỉnh sửa: Lưu ý, tôi chưa thử nghiệm điều này trong ArcGIS 10, nhưng đã sử dụng chức năng mẫu trong nhiều năm trong <= 9.3 (và Máy trạm).

Chỉnh sửa: Bây giờ tôi đã thử nghiệm trong ArcGIS 10 và nó sẽ không xuất ra tệp văn bản. Công cụ tự động thay đổi phần mở rộng tập tin thành ".dbf". Tuy nhiên ... mã python sau hoạt động như các câu lệnh đại số bản đồ SOMA và MOMA vẫn được hỗ trợ trong ArcGIS 10:

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

Rất đẹp. Cảm ơn bạn đã chỉ ra điều này - tôi đã không nhận thấy công cụ này trước đây. Chắc chắn gọn gàng hơn và đơn giản hơn giải pháp của tôi!
JamesS

6

Một cách để làm điều này là sử dụng công cụ Raster_To_Point, sau đó là công cụ Add_XY_Coordins . Bạn sẽ kết thúc với một shapefile trong đó mỗi hàng trong bảng thuộc tính biểu thị một pixel từ raster của bạn với các cột cho X_Coord , Y_CoordCell_Value . Sau đó, bạn có thể lặp qua bảng này bằng cách sử dụng một con trỏ (hoặc xuất nó sang một cái gì đó như Excel nếu bạn thích).

Nếu bạn chỉ có một raster để xử lý, có lẽ nó không đáng để viết kịch bản - chỉ cần sử dụng các công cụ từ ArcToolbox. Nếu bạn cần làm điều này cho nhiều người quét, bạn có thể thử một cái gì đó như thế này:

[ Lưu ý: Tôi không có ArcGIS 10 và không quen thuộc với ArcPy, vì vậy đây chỉ là một phác thảo rất thô. Nó chưa được kiểm tra và gần như chắc chắn sẽ cần tinh chỉnh để làm cho nó hoạt động.]

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)

Sau đó, bạn có thể lặp qua các bảng thuộc tính shapefile bằng cách sử dụng Con trỏ tìm kiếm hoặc (có thể đơn giản hơn) bằng cách sử dụng dbfpy . Điều này sẽ cho phép bạn đọc dữ liệu từ raster của bạn (hiện được lưu trữ trong bảng shbefile .dbf) thành các biến 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

Có lẽ bạn có thể tạo một tập tin thế giới cho raster, chuyển đổi raster thành một mảng numpy. sau đó nếu bạn lặp qua mảng, bạn sẽ nhận được các giá trị ô và nếu bạn nâng cấp cập nhật x, y từ tệp thế giới, bạn cũng sẽ có tọa độ cho từng giá trị ô. hy vọng đó là hữu ích.


Nếu bạn không quan tâm đến phương pháp công cụ Raster to Point do JamesS đề xuất, tôi sẽ nói rằng đây là cách để đi.
nmpeterson

3

Mã của Marcin hoạt động tốt, ngoại trừ một sự cố trong các hàm rasCentrX và rasCentrY đã khiến tọa độ ouput xuất hiện ở một độ phân giải khác (như quan sát của Grazia). Cách khắc phục của tôi là thay đổi

coordX = rasXmin + (0.5*rasMeanCellWidth + rasWidth)

đến

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

  coordY = rasYmin + (0.5*rasMeanCellHeight + rasHeight)

đến

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

Tôi đã sử dụng mã để chuyển đổi Lưới ESRI thành tệp CSV. Điều này đạt được bằng cách xóa tham chiếu đến inRaster2, sau đó sử dụng csv.writer để xuất tọa độ và giá trị:

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

Tôi cũng không tìm thấy chuyển vị là cần thiết trong

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

đã chuyển đổi thành

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

2

Xấu xí nhưng hiệu quả cao:

  1. Tạo một tính năng điểm mới với 4 điểm bên ngoài các góc của raster đang đề cập. Hãy chắc chắn trong cùng một hệ tọa độ như raster trong câu hỏi.
  2. Thêm trường đôi 'xcor' và 'ycor'
  3. Tính toán hình học để có tọa độ cho các trường này
  4. Nhà phân tích không gian-> Nội suy-> Xu hướng -> Hồi quy tuyến tính
  5. Cài đặt môi trường: snap raster và kích thước ô giống như raster trong câu hỏi
  6. Thực hiện riêng cho 'xcor' và 'ycor'
  7. Các bộ ra có tọa độ là giá trị ô, sử dụng làm đầu vào cho tập lệnh.

2

Một giải pháp đơn giản sử dụng các gói python mã nguồn mở:

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 rất tiện lợi khi bạn có thể mở một shapefile, lặp qua các tính năng và (như tôi có) nối chúng vào một dictđối tượng. Thật vậy, featurebản thân Fiona cũng giống dictnhư vậy, vì vậy rất dễ truy cập các thuộc tính. Nếu các điểm của tôi có bất kỳ thuộc tính nào, chúng sẽ xuất hiện trong dict này cùng với tọa độ, id, v.v.

Rasterio rất tiện dụng vì nó dễ đọc trong raster dưới dạng một mảng gọn gàng, kiểu dữ liệu nhẹ và nhanh. Chúng tôi cũng có quyền truy cập vào một dictthuộc tính raster bao gồm affine, đó là tất cả dữ liệu chúng tôi cần để chuyển đổi tọa độ raster x, y thành hàng mảng, tọa độ col. Xem giải thích tuyệt vời của @ perrygeo tại đây .

Chúng tôi kết thúc với một pt_dataloại dictcó dữ liệu cho từng điểm và trích xuất raster_value. Chúng tôi có thể dễ dàng viết lại shapefile với dữ liệu được trích xuất nếu muốn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.