Viết mảng numpy vào tập tin raster


30

Tôi mới biết về GIS.

Tôi có một số mã chuyển đổi hình ảnh hồng ngoại của Sao Hỏa thành các bản đồ quán tính nhiệt, sau đó được lưu trữ dưới dạng các mảng numpy 2D. Tôi đã lưu các bản đồ này dưới dạng tệp hdf5 nhưng tôi thực sự muốn lưu chúng dưới dạng hình ảnh raster để tôi có thể xử lý chúng trong QGIS. Tôi đã trải qua nhiều tìm kiếm để tìm cách làm điều này nhưng không có may mắn. Tôi đã thử làm theo các hướng dẫn trong hướng dẫn tại http://www.gis.usu.edu/~chrisg/python/ nhưng các tệp tôi tạo bằng mã ví dụ của anh ấy mở dưới dạng hộp màu xám khi tôi nhập chúng vào QGIS. Tôi cảm thấy nếu ai đó có thể đề xuất thủ tục đơn giản nhất có thể cho một ví dụ đơn giản về những gì tôi muốn làm thì tôi có thể đạt được một số tiến bộ. Tôi có QGIS và GDAL, tôi rất vui khi cài đặt các khung công tác khác mà bất kỳ ai cũng có thể giới thiệu. Tôi sử dụng Mac OS 10.7.

Vì vậy, nếu ví dụ tôi có một mảng quán tính nhiệt trông giống như:

TI = ( (0.1, 0.2, 0.3, 0.4),
       (0.2, 0.3, 0.4, 0.5),
       (0.3, 0.4, 0.5, 0.6),
       (0.4, 0.5, 0.6, 0.7) )

Và với mỗi pixel tôi có vĩ độ và kinh độ:

lat = ( (10.0, 10.0, 10.0, 10.0),
        ( 9.5,  9.5,  9.5,  9.5),
        ( 9.0,  9.0,  9.0,  9.0),
        ( 8.5,  8.5,  8.5,  8.5) )
lon = ( (20.0, 20.5, 21.0, 21.5),
        (20.0, 20.5, 21.0, 21.5),
        (20.0, 20.5, 21.0, 21.5),
        (20.0, 20.5, 21.0, 21.5) ) 

Quy trình nào mọi người sẽ đề nghị để chuyển đổi dữ liệu này thành tệp raster mà tôi có thể mở trong QGIS?


Những slide trên hướng dẫn mà bạn đang đề cập đến?
RK

Câu trả lời:


23

Một giải pháp khả thi cho vấn đề của bạn: Chuyển đổi nó thành Raster ASCII, tài liệu hướng dẫn tại đây . Điều này khá dễ thực hiện với python.

Vì vậy, với dữ liệu mẫu của bạn ở trên, bạn sẽ kết thúc với phần sau trong tệp .asc:

ncols 4
nrows 4
xllcorner 20
yllcorner 8.5
cellsize 0.5
nodata_value -9999
0.1 0.2 0.3 0.4
0.2 0.3 0.4 0.5
0.3 0.4 0.5 0.6
0.4 0.5 0.6 0.7

Điều này thêm thành công vào cả QGIS và ArcGIS và được cách điệu trong ArcGIS giống như thế này: phiên bản raster ở trên

Phụ lục: Mặc dù bạn có thể thêm nó vào QGIS như đã lưu ý, nếu bạn thử và đi vào các thuộc tính cho nó (để cách điệu nó), QGIS 1.8.0 bị treo. Tôi sắp báo cáo rằng đó là một lỗi. Nếu điều này cũng xảy ra với bạn, thì có rất nhiều hệ thống GIS miễn phí khác.


Thật tuyệt vời, cảm ơn. Và tôi tưởng tượng rằng đã viết mảng của mình dưới dạng tệp ascii, tôi có thể chuyển đổi nó thành định dạng nhị phân bằng hàm chuyển đổi được viết sẵn.
EddyTheB

FYI, tôi không gặp vấn đề treo với QGIS, tôi cũng có phiên bản 1.8.0.
EddyTheB

31

Dưới đây là một ví dụ mà tôi đã viết cho một hội thảo sử dụng các mô-đun Python gọn gàng và gdal. Nó đọc dữ liệu từ một tệp .tif thành một mảng numpy, thực hiện một phân loại lại các giá trị trong mảng và sau đó ghi lại nó thành một .tif.

Từ lời giải thích của bạn, có vẻ như bạn có thể đã thành công trong việc viết ra một tệp hợp lệ, nhưng bạn chỉ cần tượng trưng cho nó trong QGIS. Nếu tôi nhớ chính xác, khi bạn lần đầu tiên thêm raster, nó thường hiển thị tất cả một màu nếu bạn không có bản đồ màu có sẵn.

import numpy, sys
from osgeo import gdal
from osgeo.gdalconst import *


# register all of the GDAL drivers
gdal.AllRegister()

# open the image
inDs = gdal.Open("c:/workshop/examples/raster_reclass/data/cropland_40.tif")
if inDs is None:
  print 'Could not open image file'
  sys.exit(1)

# read in the crop data and get info about it
band1 = inDs.GetRasterBand(1)
rows = inDs.RasterYSize
cols = inDs.RasterXSize

cropData = band1.ReadAsArray(0,0,cols,rows)

listAg = [1,5,6,22,23,24,41,42,28,37]
listNotAg = [111,195,141,181,121,122,190,62]

# create the output image
driver = inDs.GetDriver()
#print driver
outDs = driver.Create("c:/workshop/examples/raster_reclass/output/reclass_40.tif", cols, rows, 1, GDT_Int32)
if outDs is None:
    print 'Could not create reclass_40.tif'
    sys.exit(1)

outBand = outDs.GetRasterBand(1)
outData = numpy.zeros((rows,cols), numpy.int16)


for i in range(0, rows):
    for j in range(0, cols):

    if cropData[i,j] in listAg:
        outData[i,j] = 100
    elif cropData[i,j] in listNotAg:
        outData[i,j] = -100
    else:
        outData[i,j] = 0


# write the data
outBand.WriteArray(outData, 0, 0)

# flush data to disk, set the NoData value and calculate stats
outBand.FlushCache()
outBand.SetNoDataValue(-99)

# georeference the image and set the projection
outDs.SetGeoTransform(inDs.GetGeoTransform())
outDs.SetProjection(inDs.GetProjection())

del outData

1
+1 cho xả nước - đang đập đầu tôi vào tường cố gắng tìm ra cách 'cứu' thứ đó!
badgley

Tôi đã phải thêm outDs = Noneđể lưu nó
JaakL

23

Cuối cùng tôi đã đạt được giải pháp này, mà tôi đã đạt được từ cuộc thảo luận này ( http://osgeo-org.1560.n6.nabble.com/gdal-dev-numpy-array-to-raster-td4354924.html ). Tôi thích nó bởi vì tôi có thể đi thẳng từ một mảng numpy đến một tệp raster tif. Tôi rất biết ơn về những bình luận có thể cải thiện giải pháp. Tôi sẽ đăng nó ở đây trong trường hợp bất cứ ai khác tìm kiếm một câu trả lời tương tự.

import numpy as np
from osgeo import gdal
from osgeo import gdal_array
from osgeo import osr
import matplotlib.pylab as plt

array = np.array(( (0.1, 0.2, 0.3, 0.4),
                   (0.2, 0.3, 0.4, 0.5),
                   (0.3, 0.4, 0.5, 0.6),
                   (0.4, 0.5, 0.6, 0.7),
                   (0.5, 0.6, 0.7, 0.8) ))
# My image array      
lat = np.array(( (10.0, 10.0, 10.0, 10.0),
                 ( 9.5,  9.5,  9.5,  9.5),
                 ( 9.0,  9.0,  9.0,  9.0),
                 ( 8.5,  8.5,  8.5,  8.5),
                 ( 8.0,  8.0,  8.0,  8.0) ))
lon = np.array(( (20.0, 20.5, 21.0, 21.5),
                 (20.0, 20.5, 21.0, 21.5),
                 (20.0, 20.5, 21.0, 21.5),
                 (20.0, 20.5, 21.0, 21.5),
                 (20.0, 20.5, 21.0, 21.5) ))
# For each pixel I know it's latitude and longitude.
# As you'll see below you only really need the coordinates of
# one corner, and the resolution of the file.

xmin,ymin,xmax,ymax = [lon.min(),lat.min(),lon.max(),lat.max()]
nrows,ncols = np.shape(array)
xres = (xmax-xmin)/float(ncols)
yres = (ymax-ymin)/float(nrows)
geotransform=(xmin,xres,0,ymax,0, -yres)   
# That's (top left x, w-e pixel resolution, rotation (0 if North is up), 
#         top left y, rotation (0 if North is up), n-s pixel resolution)
# I don't know why rotation is in twice???

output_raster = gdal.GetDriverByName('GTiff').Create('myraster.tif',ncols, nrows, 1 ,gdal.GDT_Float32)  # Open the file
output_raster.SetGeoTransform(geotransform)  # Specify its coordinates
srs = osr.SpatialReference()                 # Establish its coordinate encoding
srs.ImportFromEPSG(4326)                     # This one specifies WGS84 lat long.
                                             # Anyone know how to specify the 
                                             # IAU2000:49900 Mars encoding?
output_raster.SetProjection( srs.ExportToWkt() )   # Exports the coordinate system 
                                                   # to the file
output_raster.GetRasterBand(1).WriteArray(array)   # Writes my array to the raster

output_raster.FlushCache()

3
"Vòng quay được tính bằng hai lần" để tính hiệu ứng của một bit được xoay của y trên x và bit được xoay của x trên y. Xem danh sách.osgeo.org/pipermail/gdal-dev/2011-July/029449.html cố gắng giải thích mối quan hệ tương quan giữa các tham số "xoay".
Dave X

Bài đăng này thực sự hữu ích, cảm ơn. Tuy nhiên, trong trường hợp của tôi, tôi nhận được một tệp tif hoàn toàn màu đen khi tôi mở nó dưới dạng hình ảnh bên ngoài ArcGIS. Tham chiếu không gian của tôi là Lưới quốc gia Anh (EPSG = 27700), và các đơn vị là mét.
FaCoffee

Tôi đã đăng một câu hỏi ở đây: gis.stackexchange.com/questions/232602/ trên
FaCoffee

Bạn đã tìm hiểu làm thế nào để thiết lập mã hóa Sao Hỏa IAU2000: 49900 chưa?
K.-Michael Aye

4

Ngoài ra còn có một giải pháp hay trong Sách dạy nấu ăn GDAL / OGR chính thức cho Python.

Công thức này tạo ra một raster từ một mảng

import gdal, ogr, os, osr
import numpy as np


def array2raster(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array):

    cols = array.shape[1]
    rows = array.shape[0]
    originX = rasterOrigin[0]
    originY = rasterOrigin[1]

    driver = gdal.GetDriverByName('GTiff')
    outRaster = driver.Create(newRasterfn, cols, rows, 1, gdal.GDT_Byte)
    outRaster.SetGeoTransform((originX, pixelWidth, 0, originY, 0, pixelHeight))
    outband = outRaster.GetRasterBand(1)
    outband.WriteArray(array)
    outRasterSRS = osr.SpatialReference()
    outRasterSRS.ImportFromEPSG(4326)
    outRaster.SetProjection(outRasterSRS.ExportToWkt())
    outband.FlushCache()


def main(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array):
    reversed_arr = array[::-1] # reverse array so the tif looks like the array
    array2raster(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,reversed_arr) # convert array to raster


if __name__ == "__main__":
    rasterOrigin = (-123.25745,45.43013)
    pixelWidth = 10
    pixelHeight = 10
    newRasterfn = 'test.tif'
    array = np.array([[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1],
                      [ 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1],
                      [ 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1],
                      [ 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1],
                      [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1],
                      [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                      [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])


    main(newRasterfn,rasterOrigin,pixelWidth,pixelHeight,array)

Công thức này là tốt nhưng có một vấn đề với tập tin tiff cuối cùng. Các giá trị lat-lon của pixel là không phù hợp.
Shubham_geo

Bạn có thể thấy sự không tương thích kỳ lạ giữa ESRI WKT và OGC WKT: gis.stackexchange.com/questions/129764/ Kẻ
Adam Erickson

Một điều tôi gặp phải là, cách mà bạn đề cập chắc chắn sẽ thay đổi mảng thành raster một cách dễ dàng. Nhưng chúng ta cần định vị lại raster này với phối hợp trên cùng bên trái và dưới cùng bên phải bằng cách sử dụng gdal_translate. Một cách để làm điều đó là theo hai bước: 1) Trước tiên, hãy tìm các giá trị lat-lon trên cùng bên trái và dưới cùng bên phải thông qua gdalinfo 2) Sau đó, thông qua gdal_translate sử dụng trình duyệt địa lý (được tạo bằng cách tiếp cận được đề cập ở trên về chuyển đổi mảng sang raster) để đo lường địa lý với tọa độ lat-lon trên cùng bên trái và dưới cùng bên phải.
Shubham_geo

0

Một cách khác để tiếp cận được đề xuất trong các câu trả lời khác là sử dụng rasteriogói. Tôi gặp vấn đề khi tạo những thứ này bằng cách sử dụng gdalvà thấy trang web này hữu ích.

Giả sử bạn có một tệp tif khác ( other_file.tif) và một mảng numpy ( numpy_array) có cùng độ phân giải và mức độ như tệp này, đây là cách tiếp cận hiệu quả với tôi:

import rasterio as rio    

with rio.open('other_file.tif') as src:
    ras_data = src.read()
    ras_meta = src.profile

# make any necessary changes to raster properties, e.g.:
ras_meta['dtype'] = "int32"
ras_meta['nodata'] = -99

with rio.open('outname.tif', 'w', **ras_meta) as dst:
    dst.write(numpy_array, 1)
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.