Raster dosyaya numpy dizi yazma


30

GIS’te yeniyim.

Mars'ın kızılötesi görüntülerini termal atalet haritalarına dönüştüren bazı kodlarım var, bunlar daha sonra 2D numpy dizileri olarak saklanıyor. Bu haritaları hdf5 dosyası olarak kaydediyordum ancak QGIS'de işleyebilmem için onları raster görüntüler olarak kaydetmeyi çok isterdim. Bunun nasıl yapılacağını bulmak için birden fazla arama yaptım ama şanssız. Http://www.gis.usu.edu/~chrisg/python/ adresindeki kılavuzdaki talimatları izlemeyi denedim, ancak QGIS'e aktarırken örnek kodunu kullanarak ürettiğim dosyalar düz gri kutular olarak açılıyor. Birisi, yapmak istediğim şeyin basitleştirilmiş bir örneğine mümkün olan en basit prosedürü önerebilirse, biraz ilerleme kaydedebileceğimi hissediyorum. QGIS ve GDAL'im var, herkesin önerebileceği başka çerçeveler kurmaktan mutluluk duyarım. Mac OS 10.7 kullanıyorum.

Öyleyse, mesela benzeyen bir dizi termal atalet dizisine sahipsem:

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

Her piksel için enlem ve boylam var:

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

İnsanlar bu verileri QGIS'de açabileceğim bir raster dosyasına dönüştürmek için hangi prosedürü önerir?


Öğretici üzerinde hangi slayda başvuruyorsunuz?
RK

Yanıtlar:


23

Sorununuza olası bir çözüm: Belli olduğu ASCII Raster'e dönüştürün . Bu python ile yapmak oldukça kolay olmalı.

Bu nedenle, yukarıdaki örnek verilerinizle, bir .asc dosyasında aşağıdakilerle sonuçlanır:

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

Bu, hem QGIS hem de ArcGIS'e başarıyla eklenir ve ArcGIS'de stilize edilmiştir: yukarıdaki raster sürümü

Zeyilname: Belirtildiği gibi QGIS'e ekleyebilirsiniz, ancak özelliklerine girmeye çalışırsanız (stilize etmek için), QGIS 1.8.0 kilitlenir. Bunu bir hata olarak bildirmek üzereyim. Bu sizin de başınıza gelirse, dışarıda bir sürü serbest CBS var.


Bu harika, teşekkürler. Ve dizimi bir ascii dosyası olarak yazmış olmanın, önceden yazılmış bir dönüştürme işlevini kullanarak onu ikili bir biçime dönüştürebileceğimi hayal ediyorum.
EddyTheB

Bilginize, ben QGIS ile asılma sorunu yoktu, ben de 1.8.0 sürümü var.
EddyTheB

31

Aşağıda numpy ve gdal Python modüllerini kullanan bir atölye için yazdığım bir örnek var. Bir .tif dosyasındaki verileri bir numpy dizisine okur, dizideki değerlerin bir sınıfını yapar ve daha sonra bir .tif komutuna geri yazar.

Açıklamanızdan, geçerli bir dosya yazmayı başarabilmiş gibi görünüyorsunuz, ancak dosyayı QGIS'te sembolize etmeniz gerekiyor. Doğru hatırlıyorsam, bir raster eklediğinizde, önceden varolan bir renk haritanız yoksa, genellikle tek bir renk gösterir.

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
Kızarma için +1 - bir şeyi nasıl 'kurtaracağınızı' bulmaya çalışırken başımı duvara çarpıyordu!
badgley

outDs = None
Kurtarmak

23

Sonunda bu tartışmadan edindiğim bu çözüme değindim ( http://osgeo-org.1560.n6.nabble.com/gdal-dev-numpy-array-to-raster-td4354924.html ). Sevdim çünkü doğrudan bir numpy dizisinden bir tif raster dosyasına gidebiliyorum. Çözümü geliştirebilecek yorumlar için minnettar olurum. Başka birinin de benzer bir cevabı araması durumunda buraya göndereceğim.

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
"Döndürme bitinin x üzerindeki y değerini ve döndürülen x bitinin y üzerindeki etkisini hesaba katmak için" dönüş iki kezdir ". Bkz lists.osgeo.org/pipermail/gdal-dev/2011-July/029449.html "rotasyon" parametreleri arasındaki ilişkileri açıklamaya çalışır.
Dave X

Bu yazı gerçekten yararlı, teşekkürler. Ancak benim durumumda ArcGIS dışında bir görüntü olarak açtığımda tamamen siyah bir tif dosyası alıyorum. Mekansal referansım İngiliz Ulusal Izgarasıdır (EPSG = 27700) ve birimler metredir.
FaCoffee


IAU2000: 49900 Mars şifrelemesinin nasıl ayarlanacağını öğrendiniz mi?
K.-Michael Aye

4

Python resmi GDAL / OGR Yemek Kitabında da güzel bir çözüm var .

Bu tarif diziden raster oluşturur

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)

Bu tarif iyi fakat son tiff dosyasında bir sorun var. Piksellerin laton değerleri uygun değil.
Shubham_geo

ESRI WKT ve OGC WKT arasındaki garip uyumsuzluklar görüyor olabilirsiniz: gis.stackexchange.com/questions/129764/…
Adam Erickson

Karşılaştığım şeylerden biri, sizin belirttiğiniz yöntem kesinlikle diziyi kolaylıkla raster olarak değiştirmektir. Fakat bu rasterin üst sol ve alt sağ gdal_translate kullanılarak koordine edilmesiyle georeferans yapmamız gerekiyor. Bunu yapmanın bir yolu iki adımı izlemektir: 1) İlk önce sol üst ve alt sol kolon değerlerini gdalinfo 2 ile bulun) 2) Sonra, gdal_translate ile geotiff'i kullanın (yukarıda belirtilen diziyi raster dönüştürme yaklaşımı ile üretilir) üst sol ve alt sağ yan lon koordinatlarıyla georeference.
Shubham_geo

0

Diğer cevaplarda önerilen yaklaşıma bir alternatif de rasteriopaketi kullanmaktır . Bunları kullanarak üreten sorunlarım vardı gdalve bu siteyi yararlı buldum .

Başka bir tif dosyasına ( other_file.tif) ve numpy_arraybu dosyayla aynı çözünürlüğe ve ölçüye sahip bir numpy dizisine ( ) sahip olduğunuzu varsayarak , bu benim için işe yarayan yaklaşımdır:

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.