การเขียนอาร์เรย์ numpy ไปยังไฟล์ raster


30

ฉันใหม่กับ GIS

ฉันมีรหัสบางอย่างที่แปลงภาพอินฟราเรดของดาวอังคารเป็นแผนที่ความเฉื่อยทางความร้อนซึ่งจะถูกเก็บไว้เป็นอาร์เรย์แบบสองมิติ ฉันบันทึกแผนที่เหล่านี้เป็นไฟล์ hdf5 แล้ว แต่ฉันต้องการบันทึกเป็นภาพแรสเตอร์จริงๆเพื่อให้สามารถประมวลผลได้ใน QGIS ฉันผ่านการค้นหาหลายครั้งเพื่อค้นหาวิธีการทำ แต่ไม่มีโชค ฉันได้ลองทำตามคำแนะนำในบทช่วยสอนที่http://www.gis.usu.edu/~chrisg/python/แต่ไฟล์ที่ฉันสร้างโดยใช้รหัสตัวอย่างของเขาเปิดเป็นกล่องสีเทาธรรมดาเมื่อฉันนำเข้า QGIS ฉันรู้สึกว่าถ้าใครบางคนสามารถแนะนำขั้นตอนที่ง่ายที่สุดเท่าที่เป็นไปได้สำหรับตัวอย่างที่เรียบง่ายของสิ่งที่ฉันต้องการจะทำแล้วฉันอาจจะสามารถก้าวหน้าได้บ้าง ฉันมี QGIS และ GDAL ฉันมีความสุขมากที่ได้ติดตั้งเฟรมเวิร์กอื่น ๆ ที่ทุกคนสามารถแนะนำได้ ฉันใช้ Mac OS 10.7

ดังนั้นถ้าเช่นฉันมีอาร์เรย์ของความเฉื่อยความร้อนที่ดูเหมือน:

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

และสำหรับแต่ละพิกเซลฉันมีละติจูดและลองจิจูด:

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

ผู้ใดที่แนะนำให้แปลงข้อมูลนี้เป็นไฟล์แรสเตอร์ที่ฉันสามารถเปิดใน QGIS ได้


คุณหมายถึงสไลด์ใดในการกวดวิชา
RK

คำตอบ:


23

วิธีการแก้ปัญหาที่เป็นไปได้หนึ่งในการแก้ไขปัญหาของคุณ: แปลงเป็นASCII Raster, documention ที่อยู่ที่นี่ สิ่งนี้น่าจะง่ายสำหรับงูหลาม

ดังนั้นด้วยข้อมูลตัวอย่างของคุณด้านบนคุณจะพบกับสิ่งต่อไปนี้ในไฟล์ .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

สิ่งนี้จะช่วยให้ทั้ง QGIS และ ArcGIS ประสบความสำเร็จและเก๋ใน ArcGIS ดูเหมือนว่า: รุ่นแรสเตอร์ของด้านบน

ภาคผนวก: ในขณะที่คุณสามารถเพิ่มลงใน QGIS ตามที่ระบุไว้ถ้าคุณลองและเข้าไปในคุณสมบัติของมัน (เพื่อจัดทำมัน), QGIS 1.8.0 หยุดทำงาน ฉันกำลังจะรายงานว่าเป็นข้อผิดพลาด หากสิ่งนี้เกิดขึ้นกับคุณเช่นกันแสดงว่ามี GIS ฟรีอื่น ๆ อีกมากมายที่นั่น


ขอบคุณมาก และฉันคิดว่าการเขียนอาร์เรย์ของฉันเป็นไฟล์ ascii ฉันสามารถแปลงเป็นรูปแบบไบนารีโดยใช้ฟังก์ชั่นการแปลงที่เขียนไว้ล่วงหน้า
EddyTheB

FYI ฉันไม่มีปัญหาเกี่ยวกับ QGIS ฉันยังมีรุ่น 1.8.0 เช่นกัน
EddyTheB

31

ด้านล่างเป็นตัวอย่างที่ฉันเขียนสำหรับเวิร์กช็อปที่ใช้โมดูล Python แบบ numpy และ gdal มันจะอ่านข้อมูลจากไฟล์. tif หนึ่งไฟล์ไปยังอาร์เรย์ที่ไม่มีการจัดประเภทใหม่ของค่าในอาร์เรย์จากนั้นเขียนกลับออกมาเป็น. tif

จากคำอธิบายของคุณดูเหมือนว่าคุณอาจจะประสบความสำเร็จในการเขียนไฟล์ที่ถูกต้อง แต่คุณเพียงแค่ต้องเป็นสัญลักษณ์ใน QGIS ถ้าฉันจำได้อย่างถูกต้องเมื่อคุณเพิ่มแรสเตอร์เป็นครั้งแรกมันมักจะแสดงสีทั้งหมดถ้าคุณไม่มีแผนที่สีที่มีอยู่แล้ว

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 เมื่อล้างออก - กำลังทุบหัวของฉันกับกำแพงพยายามหาวิธี 'บันทึก' สิ่งนั้น!
badgley

ฉันต้องเพิ่มoutDs = Noneเพื่อให้มันได้รับการบันทึก
JaakL

23

ในที่สุดฉันก็ได้พบกับโซลูชันนี้ซึ่งฉันได้รับจากการสนทนานี้ ( http://osgeo-org.1560.n6.nabble.com/gdal-dev-numpy-array-to-raster-td4354924.html ) ฉันชอบเพราะฉันสามารถเปลี่ยนจากอาร์เรย์แบบ numpy ไปเป็นไฟล์ tif raster ได้ ฉันขอขอบคุณสำหรับความคิดเห็นที่สามารถปรับปรุงวิธีการแก้ปัญหาได้ ฉันจะโพสต์ไว้ที่นี่ในกรณีที่คนอื่นค้นหาคำตอบที่คล้ายกัน

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
"การหมุนเป็นสองเท่า" เพื่ออธิบายผลของการหมุนบิตของ y ต่อ x และหมุน x ของ x บน y ดูlists.osgeo.org/pipermail/gdal-dev/2011-July/029449.htmlซึ่งพยายามอธิบายความสัมพันธ์ระหว่างพารามิเตอร์ "การหมุน"
Dave X

โพสต์นี้มีประโยชน์จริง ๆ ขอบคุณ อย่างไรก็ตามในกรณีของฉันฉันได้รับไฟล์ tif ที่เป็นสีดำสนิทเมื่อฉันเปิดเป็นรูปภาพนอก ArcGIS การอ้างอิงเชิงพื้นที่ของฉันคือ British National Grid (EPSG = 27700) และหน่วยเป็นเมตร
FaCoffee

ฉันได้โพสต์คำถามที่นี่: gis.stackexchange.com/questions/232301/ …
FaCoffee

คุณทราบวิธีตั้งค่าการเข้ารหัส IAU2000: 49900 Mars หรือไม่
K. -Michael Aye

4

นอกจากนี้ยังมีทางออกที่ดีใน GDAL / OGR Cookbook อย่างเป็นทางการสำหรับ Python

สูตรนี้สร้างแรสเตอร์จากอาร์เรย์

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)

สูตรนี้ดี แต่มีปัญหากับไฟล์ TIFF สุดท้าย ค่า lat-lon ของพิกเซลไม่เหมาะสม
Shubham_geo

คุณอาจเห็นความไม่ลงรอยกันแปลก ๆ ระหว่าง ESRI WKT และ OGC WKT: gis.stackexchange.com/questions/129764/…
Adam Erickson

สิ่งหนึ่งที่ฉันพบคือวิธีที่คุณพูดถึงจะเปลี่ยนอาร์เรย์เป็นแรสเตอร์ได้อย่างง่ายดาย แต่เราต้องระบุตำแหน่งเชิงภาพนี้ด้วยมุมบนซ้ายและขวาล่างประสานงานโดยใช้ gdal_translate วิธีหนึ่งในการดำเนินการดังกล่าวมีสองขั้นตอนดังนี้: 1) หาค่า lat-lon ด้านบนซ้ายและขวาล่างผ่าน gdalinfo 2) จากนั้นผ่าน gdal_translate ใช้ geotiff (สร้างด้วยวิธีการแปลงอาร์เรย์เป็นแรสเตอร์) เพื่อกำหนดตำแหน่งทางภูมิศาสตร์ด้วยพิกัด Lat-lon ด้านบนซ้ายและล่างขวา
Shubham_geo

0

ทางเลือกอื่นสำหรับแนวทางที่แนะนำในคำตอบอื่น ๆ คือใช้rasterioแพ็คเกจ ฉันมีปัญหาในการสร้างสิ่งเหล่านี้โดยใช้gdalและพบว่าไซต์นี้มีประโยชน์

สมมติว่าคุณมีไฟล์ tif ( other_file.tif) และอาร์เรย์ numpy ( numpy_array) ที่มีความละเอียดและขอบเขตเท่ากันกับไฟล์นี้นี่เป็นวิธีที่เหมาะกับฉัน:

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.