การสร้างแรสเตอร์ที่แต่ละเซลล์บันทึกระยะห่างจากทะเล?


10

ฉันต้องการสร้างแรสเตอร์ที่มีความละเอียด 25 เมตร× 25 เมตรซึ่งแต่ละเซลล์มีระยะห่างจากแนวชายฝั่งที่ใกล้ที่สุดซึ่งคำนวณจากจุดศูนย์กลางของเซลล์ การทำเช่นนี้ทั้งหมดที่ฉันต้องเป็นshapefile ของแนวชายฝั่งของนิวซีแลนด์

ฉันได้ลองทำตามบทช่วยสอนของ Dominic Royeเพื่อใช้ใน R ซึ่งใช้งานได้ดี มันปรับลงไปที่ความละเอียดประมาณ 1 km × 1 km แต่ถ้าฉันพยายามที่จะใช้ RAM ที่สูงกว่านี้ก็ต้องใช้งานได้ดีกว่าบนพีซีของฉัน (ต้องใช้ RAM 70 ~ GB) หรืออื่น ๆ ที่ฉันมีการเข้าถึงด้วย ในการบอกว่าฉันคิดว่านี่เป็นข้อ จำกัด ของ R และฉันสงสัยว่า QGIS อาจมีวิธีการคำนวณที่มีประสิทธิภาพมากกว่าในการสร้างแรสเตอร์นี้ แต่ฉันใหม่สำหรับมันและฉันไม่สามารถเข้าใจได้ว่าจะทำอย่างไร

ฉันได้ลองติดตามการสร้างแรสเตอร์ด้วยระยะทางถึงฟีเจอร์โดยใช้ QGIS แล้วหรือยัง เพื่อสร้างใน QGIS แต่มันกลับข้อผิดพลาดนี้:

_core.QgsProcessingException: ไม่สามารถโหลดเลเยอร์แหล่งที่มาสำหรับ INPUT: C: /..../ Coastline / nz-coastlines-and-Islands-polygons-topo-150k.shp ไม่พบ

และฉันไม่แน่ใจว่าทำไม

ใครบ้างมีคำแนะนำเกี่ยวกับสิ่งที่อาจจะผิดหรือเป็นทางเลือกในการทำเช่นนี้?

แก้ไข:

แรสเตอร์ที่ฉันหวังว่าจะผลิตจะมีประมาณ 59684 แถวและ 40827 คอลัมน์เพื่อให้มันซ้อนทับกับแรสเตอร์ขาดน้ำประจำปีจาก LINZ หากแรสเตอร์ที่ผลิตมีขนาดใหญ่กว่าแรสเตอร์ขาดน้ำประจำปีฉันสามารถตัดมันใน R แม้ว่า ...

สิ่งหนึ่งที่ฉันคิดว่าอาจเป็นปัญหาที่อาจเกิดขึ้นคือรูปร่างของชายฝั่งทะเลของนิวซีแลนด์มีทะเลจำนวนมากระหว่างเกาะและฉันไม่สนใจที่จะคำนวณระยะทางสู่ชายฝั่งสำหรับเซลล์เหล่านี้ ฉันแค่ต้องการคำนวณค่าของเซลล์ที่มีที่ดินบางส่วนเท่านั้น ฉันไม่แน่ใจว่าจะทำอย่างไรหรือว่าเป็นปัญหาจริง


1
คุณกำลังเรียกใช้สคริปต์เพื่อทำสิ่งนี้หรือไม่? หรือคุณใช้เครื่องมือใน QGIS? มีบางอย่างที่ต้องตรวจสอบแม้ว่ามันจะฟังดูเหมือนว่าควรตรวจสอบว่าไฟล์นั้นมีอยู่จริงในที่ที่คุณบอกว่าทำ ... และตรวจสอบว่าคุณได้อ่านและเขียนการเข้าถึงโฟลเดอร์นั้น
Keagan Allan

ขณะนี้ใช้เครื่องมือ แต่ฉันค่อนข้างกระตือรือร้นที่จะเรียนรู้สคริปต์ แต่ไม่แน่ใจว่าจะเริ่มจากตรงไหน ฉันแน่ใจว่าไฟล์นั้นมีอยู่เนื่องจากฉันได้โหลดไฟล์. shp ลงใน QGIS และจะปรากฏเป็นรูปภาพ ฉันควรมีสิทธิ์เข้าถึงเพื่ออ่าน / เขียนเช่นกันเนื่องจากฉันเป็นผู้ดูแลระบบของเครื่องและอยู่ในดรอปบ็อกซ์ของฉัน
André.B

ลองย้ายออกจาก Dropbox ไปยังไดรฟ์ในเครื่อง อาจมีปัญหากับเส้นทางที่ทำให้ QGIS ปฏิเสธ สิ่งที่คุณต้องการทำควรเป็นเรื่องง่ายใน QGIS คุณใช้ QGIS รุ่นใดอยู่
Keagan Allan

1
ตกลงลองแปลงรูปหลายเหลี่ยมเป็นแรสเตอร์ เครื่องมือตั้งใน QGIS ต้องการอินพุตแบบแรสเตอร์ เล่นรอบกับการตั้งค่าตามความช่วยเหลือของเครื่องมือ: docs.qgis.org/2.8/en/docs/user_manual/processing_algs/gdalogr/... โปรดทราบว่ามันยังคงเป็นกระบวนการที่เข้มข้นฉันกำลังทดสอบเพื่อความสนุกตอนนี้และมันใช้งานมา 30 นาทีแล้วและยังดำเนินต่อไป ...
Keagan Allan

1
คุณพยายามสร้างเอาต์พุตแบบแรสเตอร์ขนาดใดในแง่ของแถวและคอลัมน์? จริงๆแล้วคุณจะสามารถทำงานร่วมกับแรสเตอร์นั้นได้เมื่อคุณสร้างมันขึ้นมา? หากขนาดไฟล์ของทุกอย่างเป็นปัญหาคุณสามารถสร้างไทล์เล็ก ๆ ซึ่งเป็นสิ่งที่คุณสามารถทำแบบขนานบนคลัสเตอร์หรือคลาวด์เพื่อความเร็ว
Spacedman

คำตอบ:


9

ด้วยPyQGISและGDAL python ไลบรารี่นั้นไม่ยากอย่างที่คิด คุณต้องการพารามิเตอร์การแปลงสภาพทางภูมิศาสตร์ (x บนซ้าย, ความละเอียดพิกเซล x, การหมุน, y บนซ้าย, การหมุน, ความละเอียดพิกเซล ns) และหมายเลขแถวและคอลัมน์สำหรับการสร้างภาพแรสเตอร์ สำหรับการคำนวณระยะทางไปยังชายฝั่งทะเลที่ใกล้ที่สุดนั้นจำเป็นต้องมีชั้นเวกเตอร์สำหรับแสดงแนวชายฝั่ง

ด้วยPyQGISแต่ละจุดแรสเตอร์เป็นจุดศูนย์กลางของเซลล์จะถูกคำนวณและระยะห่างจากชายฝั่งจะถูกวัดโดยใช้วิธี 'closestSegmentWithContext' จากคลาสQgsGeometry ห้องสมุดหลามGDALใช้สำหรับสร้างแรสเตอร์ด้วยค่าระยะทางเหล่านี้ในแถว x คอลัมน์แถว

รหัสต่อไปนี้ใช้สำหรับสร้างแรสเตอร์ระยะทาง (ความละเอียด 25 ม. x25 ม. และ 1,000 แถว x 1,000 คอลัมน์) เริ่มต้นที่จุด (397106.7689872353, 4499634.06675821); ใกล้กับชายฝั่งตะวันตกของสหรัฐอเมริกา

from osgeo import gdal, osr
import numpy as np
from math import sqrt

registry = QgsProject.instance()

line = registry.mapLayersByName('shoreline_10N')

crs = line[0].crs()

wkt = crs.toWkt()

feats_line = [ feat for feat in line[0].getFeatures()]

pt = QgsPoint(397106.7689872353, 4499634.06675821)

xSize = 25
ySize = 25

rows = 1000
cols = 1000

raster = [ [] for i in range(cols) ]

x =   xSize/2
y = - ySize/2

for i in range(rows):
    for j in range(cols):
        point = QgsPointXY(pt.x() + x, pt.y() + y)
        tupla = feats_line[0].geometry().closestSegmentWithContext(point)
        raster[i].append(sqrt(tupla[0]))

        x += xSize
    x =  xSize/2
    y -= ySize

data = np.array(raster)

# Create gtif file 
driver = gdal.GetDriverByName("GTiff")

output_file = "/home/zeito/pyqgis_data/distance_raster.tif"

dst_ds = driver.Create(output_file, 
                       cols, 
                       rows, 
                       1, 
                       gdal.GDT_Float32)

#writting output raster
dst_ds.GetRasterBand(1).WriteArray( data )

transform = (pt.x(), xSize, 0, pt.y(), 0, -ySize)

#setting extension of output raster
# top left x, w-e pixel resolution, rotation, top left y, rotation, n-s pixel resolution
dst_ds.SetGeoTransform(transform)

# setting spatial reference of output raster 
srs = osr.SpatialReference()
srs.ImportFromWkt(wkt)
dst_ds.SetProjection( srs.ExportToWkt() )

dst_ds = None

หลังจากรันโค้ดข้างต้นแรสเตอร์ที่เป็นผลลัพธ์จะถูกโหลดใน QGIS และดูเหมือนว่าในภาพต่อไปนี้ (pseudocolor ที่มี 5 คลาสและ Spectral ramp) โปรเจคคือ UTM 10 N (EPSG: 32610)

ป้อนคำอธิบายรูปภาพที่นี่


นี่อาจไม่ใช่ปัญหา แต่สิ่งหนึ่งที่ฉันกังวลเล็กน้อยคือรูปหลายเหลี่ยมนั้นเป็นของนิวซีแลนด์และเกาะที่อยู่โดยรอบซึ่งหมายความว่ามันมีทะเลรอบ ๆ จำนวนมาก ฉันกำลังพยายามทำให้หัวของฉันอยู่รอบ ๆ รหัส แต่ด้วยตัวอย่างของคุณฉันจะสามารถกำหนดค่าสำหรับเซลล์ทั้งหมดในทะเลเป็น NA หรือไม่ ฉันสนใจระยะทางจากทะเลถึงจุดบนบกเท่านั้น
André.B

ขออภัยล่วงหน้าหากนี่เป็นคำถามที่โง่ แต่ฉันจะเลือกจุดเริ่มต้นใหม่ในนิวซีแลนด์ในแบบที่คุณตั้งค่าพิกัดสำหรับรัฐได้อย่างไร นอกจากนี้ฉันจะเก็บไว้ใน EPSG: 2193 ได้อย่างไร
André.B

7

อาจเป็นทางออกให้ลอง:

  1. สร้างกริด (พิมพ์ "จุด" อัลกอริทึม "สร้างกริด")
  2. คำนวณระยะทางที่ใกล้ที่สุดระหว่างคะแนนของคุณ (ตาราง) และบรรทัดของคุณ (ชายฝั่ง) ด้วยอัลกอริทึม "เข้าร่วมแอตทริบิวต์โดยใกล้ที่สุด" ระวังที่จะเลือกเพื่อนบ้านที่ใกล้ที่สุด 1 คนเท่านั้น

ตอนนี้คุณควรมีเลเยอร์จุดใหม่ที่มีระยะทางไปยังชายฝั่งเหมือนในตัวอย่างนี้ ป้อนคำอธิบายรูปภาพที่นี่

  1. หากจำเป็นคุณสามารถแปลงเลเยอร์จุดใหม่ของคุณเป็นแรสเตอร์ (อัลกอริทึม "rasterize")

ป้อนคำอธิบายรูปภาพที่นี่


2

ภายใน QGIS คุณสามารถลองใช้ปลั๊กอิน GRASS เท่าที่ฉันรู้ว่ามันจัดการหน่วยความจำได้ดีกว่า R และฉันคาดว่าโซลูชันอื่นจะล้มเหลวในพื้นที่ขนาดใหญ่

คำสั่ง GRASS เรียกว่า r.grow.distance ซึ่งคุณสามารถค้นหาได้ในแถบเครื่องมือการประมวลผล โปรดทราบว่าคุณต้องแปลงบรรทัดเป็นแรสเตอร์ในตอนแรก

ป้อนคำอธิบายรูปภาพที่นี่

ปัญหาอย่างหนึ่งของคุณอาจเป็นขนาดของเอาต์พุตดังนั้นคุณสามารถเพิ่มตัวเลือกการสร้างที่มีประโยชน์เช่น (สำหรับไฟล์ tif) BIGTIFF = ใช่, TILED = YES, COMPRESS = LZW, PREDICTOR = 3


มีวิธีที่ฉันสามารถกำจัดพื้นที่ทะเลเพื่อลดขนาด / เวลาในการคำนวณหรือไม่?
André.B

ในทางทฤษฎีถ้าคุณใช้ระยะทางจากการดู (ทั้งหมดเห็นพิกเซลที่มีค่าเท่ากันนั่นคือรูปหลายเหลี่ยม) แทนที่จะเป็นจากแนวชายฝั่งคุณควรประหยัดเวลาในการคำนวณ ขนาดที่ไม่บีบอัดของแรสเตอร์ควรเท่ากัน แต่การบีบอัดจะมีประสิทธิภาพมากกว่าดังนั้นคุณควรลดขนาดสุดท้ายด้วย
radouxju

0

ฉันจะลองวิธีอื่น ๆ หากคุณกำลังใช้ poligon ของ NZ ให้แปลงรูปหลายเหลี่ยมเป็นเส้น หลังจากนั้นสร้างบัฟเฟอร์บนขอบเขตสำหรับระยะ 25 เมตรจากขอบเขต (บางที centorid อาจช่วยในการยับยั้งเวลาที่จะหยุด) จากนั้นตัดบัฟเฟอร์ด้วยโพลีกอนแล้วแปลงรูปหลายเหลี่ยมนั้นเป็นแรสเตอร์ ฉันไม่แน่ใจว่าจะใช้งานได้ แต่แน่นอนว่าคุณจะต้องใช้ RAM น้อยกว่า และ PostGiS นั้นยอดเยี่ยมเมื่อคุณมีปัญหาด้านประสิทธิภาพ

หวังว่ามันจะช่วยอย่างน้อย :)


0

ตอนแรกฉันไม่ได้ตอบคำถามของตัวเอง แต่เพื่อนร่วมงานของฉัน (ที่ไม่ได้ใช้เว็บไซต์นี้) เขียนรหัสไพ ธ อนจำนวนมากเพื่อทำสิ่งที่ฉันเป็นอยู่หลังจากนั้น รวมถึงการ จำกัด เซลล์ให้มีระยะห่างจากชายฝั่งสำหรับเซลล์ภาคพื้นดินเท่านั้นและปล่อยให้เซลล์จากทะเลเป็น NAs รหัสต่อไปนี้ควรจะสามารถเรียกใช้จากคอนโซล python ใด ๆ โดยมีเพียงสิ่งเดียวเท่านั้นที่จำเป็นต้องมีการแก้ไข:

1) วางไฟล์สคริปต์ในโฟลเดอร์เดียวกับไฟล์รูปร่างที่สนใจ

2) เปลี่ยนชื่อของ shapefile ในสคริปต์ python เป็นชื่อของ shapefile ของคุณ

3) กำหนดความละเอียดที่ต้องการและ;

4) เปลี่ยนขอบเขตเพื่อให้เข้ากับ rasters อื่น ๆ

รูปร่างที่ใหญ่กว่าสิ่งที่ฉันใช้จะต้องใช้ RAM จำนวนมาก แต่อย่างอื่นสคริปต์จะทำงานได้อย่างรวดเร็ว (ประมาณสามนาทีเพื่อสร้างแรสเตอร์ความละเอียด 50 ม. และสิบนาทีสำหรับแรสเตอร์ความละเอียด 25 ม.)

#------------------------------------------------------------------------------

from osgeo import gdal, ogr
import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt
import time

startTime = time.perf_counter()

#------------------------------------------------------------------------------

# Define spatial footprint for new raster
cellSize = 50 # ANDRE CHANGE THIS!!
noData = -9999
xMin, xMax, yMin, yMax = [1089000, 2092000, 4747000, 6224000]
nCol = int((xMax - xMin) / cellSize)
nRow = int((yMax - yMin) / cellSize)
gdal.AllRegister()
rasterDriver = gdal.GetDriverByName('GTiff')
NZTM = 'PROJCS["NZGD2000 / New Zealand Transverse Mercator 2000",GEOGCS["NZGD2000",DATUM["New_Zealand_Geodetic_Datum_2000",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6167"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4167"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",173],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",1600000],PARAMETER["false_northing",10000000],AUTHORITY["EPSG","2193"],AXIS["Easting",EAST],AXIS["Northing",NORTH]]'

#------------------------------------------------------------------------------ 

inFile = "new_zealand.shp" # CHANGE THIS!!

# Import vector file and extract information
vectorData = ogr.Open(inFile)
vectorLayer = vectorData.GetLayer()
vectorSRS = vectorLayer.GetSpatialRef()
x_min, x_max, y_min, y_max = vectorLayer.GetExtent()

# Create raster file and write information
rasterFile = 'nz.tif'
rasterData = rasterDriver.Create(rasterFile, nCol, nRow, 1, gdal.GDT_Int32, options=['COMPRESS=LZW'])
rasterData.SetGeoTransform((xMin, cellSize, 0, yMax, 0, -cellSize))
rasterData.SetProjection(vectorSRS.ExportToWkt())
band = rasterData.GetRasterBand(1)
band.WriteArray(np.zeros((nRow, nCol)))
band.SetNoDataValue(noData)
gdal.RasterizeLayer(rasterData, [1], vectorLayer, burn_values=[1])
array = band.ReadAsArray()
del(rasterData)

#------------------------------------------------------------------------------

distance = ndimage.distance_transform_edt(array)
distance = distance * cellSize
np.place(distance, array==0, noData)

# Create raster file and write information
rasterFile = 'nz-coast-distance.tif'
rasterData = rasterDriver.Create(rasterFile, nCol, nRow, 1, gdal.GDT_Float32, options=['COMPRESS=LZW'])
rasterData.SetGeoTransform((xMin, cellSize, 0, yMax, 0, -cellSize))
rasterData.SetProjection(vectorSRS.ExportToWkt())
band = rasterData.GetRasterBand(1)
band.WriteArray(distance)
band.SetNoDataValue(noData)
del(rasterData)

#------------------------------------------------------------------------------

endTime = time.perf_counter()

processTime = endTime - startTime

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