Tạo raster nơi mỗi ô ghi lại khoảng cách với biển?


10

Tôi muốn tạo một raster với độ phân giải 25 mét × 25 mét, trong đó mỗi ô chứa khoảng cách đến đường bờ biển gần nhất, như được tính từ tâm của ô. Để làm điều này, tất cả những gì tôi có là một hình dạng của đường bờ biển của New Zealand .

Tôi đã thử làm theo hướng dẫn của Dominic Roye để thực hiện nó trong R hoạt động ... loại. Sẽ giảm xuống độ phân giải khoảng 1 km × 1 km nhưng nếu tôi cố gắng tăng thêm RAM thì nó yêu cầu vượt quá mức có sẵn trên PC của tôi (~ 70 gb RAM yêu cầu) hoặc bất kỳ loại nào khác mà tôi cũng có quyền truy cập. Nói như vậy, tôi nghĩ rằng đây là một hạn chế của R và tôi nghi ngờ rằng QGIS có thể có cách tạo raster hiệu quả hơn về mặt tính toán này, nhưng tôi chưa quen với nó và tôi không thể tìm ra cách thực hiện.

Tôi đã thử làm theo raster với khoảng cách đến tính năng bằng cách sử dụng QGIS? để tạo nó trong QGIS nhưng nó trả về lỗi này:

_core.QssProcessingException: Không thể tải lớp nguồn cho INPUT: C: /..../ Coastline / nz-Coastlines-and-Islands-polygons-topo-150k.shp không tìm thấy

và tôi không chắc tại sao.

Có ai có bất kỳ đề nghị về những gì có thể đi sai hoặc một cách khác để làm điều này?

Biên tập:

Chiếc raster mà tôi hy vọng sản xuất sẽ có khoảng 59684 hàng và 40827 cột để nó trùng với raster thiếu nước hàng năm từ LINZ. Nếu raster được sản xuất lớn hơn raster thiếu nước hàng năm, tôi có thể bắn nó trong R mặc dù ...

Một điều mà tôi nghĩ có thể là một vấn đề tiềm năng là shapefile của bờ biển New Zealand có một lượng lớn biển giữa các đảo và tôi không quan tâm đến việc tính toán khoảng cách đến bờ biển cho các tế bào này. Tôi thực sự chỉ muốn tính toán các giá trị cho các ô bao gồm một vài mảnh đất. Tôi không chắc chắn làm thế nào để làm điều này, hoặc nếu nó thực sự là một vấn đề.


1
Bạn đang chạy một kịch bản để làm điều này? Hay bạn đang sử dụng các công cụ trong QGIS? Một cái gì đó để kiểm tra, mặc dù nghe có vẻ như vậy - hãy kiểm tra tệp thực sự tồn tại ở nơi bạn nói nó ... cũng kiểm tra xem bạn đã đọc và ghi quyền truy cập vào thư mục cụ thể đó chưa.
Keagan Allan

Hiện đang sử dụng các công cụ nhưng tôi khá ham học kịch bản, chỉ không biết bắt đầu từ đâu. Tôi chắc chắn rằng tệp tồn tại, vì tôi đã tải tệp .shp vào QGIS và nó bật lên dưới dạng hình ảnh. Tôi cũng nên có quyền truy cập đọc / ghi vì tôi là quản trị viên trên máy và nó chỉ nằm trong dropbox của tôi.
André.B

Hãy thử di chuyển nó ra khỏi Dropbox vào một ổ đĩa cục bộ. Có thể có một vấn đề với đường dẫn khiến QGIS từ chối nó. Những gì bạn đang tìm kiếm nên khá đơn giản trong QGIS. Phiên bản nào của QGIS bạn đang sử dụng?
Keagan Allan

1
Ok, hãy thử chuyển đổi đa tuyến thành raster. Công cụ tiệm cận trong QGIS cần một đầu vào raster. Chơi xung quanh với các cài đặt theo trợ giúp của công cụ: docs.qgis.org/2.8/en/docs/user_manual/ Processing_algs/gdalogr/ . Hãy lưu ý, đây vẫn là một quá trình chuyên sâu, hiện tại tôi đang thử nghiệm nó cho vui và nó đã chạy được 30 phút và vẫn tiếp tục ...
Keagan Allan

1
Kích thước của raster đầu ra về mặt hàng và cột bạn đang cố gắng tạo là gì? Bạn có thực sự sẽ có thể làm việc với raster đó một khi bạn tạo nó không? Nếu kích thước tệp của toàn bộ sự cố là một vấn đề, bạn có thể tạo các ô nhỏ hơn không, đây cũng là điều bạn có thể làm song song trên một cụm hoặc đám mây để tăng tốc.
Spainedman

Câu trả lời:


9

Với thư viện python PyQGISGDAL không khó để làm điều đó. Bạn cần các tham số biến đổi địa lý (độ phân giải x trên cùng bên trái, độ phân giải pixel, xoay, y trên cùng bên trái, xoay, độ phân giải pixel ns) và số hàng và số cột để tạo raster kết quả. Để tính khoảng cách đến đường bờ biển gần nhất, cần có một lớp vectơ để biểu diễn đường bờ biển.

Với PyQGIS , mỗi điểm raster là trung tâm của ô được tính toán và khoảng cách của nó đến đường bờ biển được đo bằng cách sử dụng phương pháp 'nearSegmentWithContext' từ lớp QssGeometry . Thư viện python GDAL được sử dụng để tạo raster với các giá trị khoảng cách này trong mảng hàng x cột.

Mã sau được sử dụng để tạo raster khoảng cách (độ phân giải 25 m × 25 m và 1000 hàng x 1000 cột) bắt đầu tại điểm (397106.7689872353, 4499634.06675821); gần bờ biển phía tây của Hoa Kỳ.

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

Sau khi chạy mã trên, kết quả raster đã được tải trong QGIS và nó trông giống như trong hình ảnh sau (pseudocolor với 5 lớp và đường nối Spectral). Chiếu là UTM 10 N (EPSG: 32610)

nhập mô tả hình ảnh ở đây


Điều này có thể không phải là một vấn đề nhưng một điều tôi hơi lo lắng là đa giác là của New Zealand và các đảo xung quanh có nghĩa là nó bao gồm một lượng lớn biển xung quanh. Tôi đang cố gắng tìm hiểu về mã, nhưng với ví dụ của bạn, tôi có thể đặt giá trị cho tất cả các ô trên biển thành NA không? Tôi thực sự chỉ quan tâm đến khoảng cách ra biển từ các điểm trên đất liền.
André.B

Xin lỗi trước nếu đây là một câu hỏi ngớ ngẩn nhưng làm cách nào để tôi chọn điểm bắt đầu mới ở New Zealand theo cách bạn đặt tọa độ cho các tiểu bang? Ngoài ra, làm cách nào để giữ nó trong EPSG: 2193?
André.B

7

Có thể là một giải pháp để thử:

  1. Tạo lưới (Loại "điểm", thuật toán "Tạo lưới")
  2. Tính khoảng cách gần nhất giữa các điểm của bạn (lưới) và đường thẳng (bờ biển) của bạn với thuật toán "thuộc tính tham gia gần nhất". Hãy cẩn thận chỉ chọn tối đa 1 hàng xóm gần nhất.

Bây giờ bạn nên có một lớp điểm mới với khoảng cách đến bờ biển như trong ví dụ này nhập mô tả hình ảnh ở đây

  1. Nếu cần, bạn có thể chuyển đổi lớp điểm mới của mình sang raster (thuật toán "rasterize")

nhập mô tả hình ảnh ở đây


2

Trong QGIS, bạn có thể thử plugin GRASS. Theo như tôi biết thì nó quản lý bộ nhớ tốt hơn R và tôi hy vọng giải pháp khác sẽ thất bại trên các khu vực rộng lớn.

lệnh GRASS được gọi là r.grow.distance, mà bạn có thể tìm thấy trong thanh công cụ xử lý. Lưu ý rằng bạn cần chuyển đổi dòng của bạn thành raster lúc đầu.

nhập mô tả hình ảnh ở đây

Một trong những vấn đề của bạn có thể là kích thước của đầu ra, vì vậy bạn có thể thêm một số tùy chọn tạo hữu ích như (đối với tệp tif) BIGTIFF = YES, TILED = YES, COMPRESS = LZW, PREDICTOR = 3


Có cách nào để tôi có thể loại bỏ bất kỳ vùng biển nào để giảm thời gian tính toán / kích thước không?
André.B

về lý thuyết, nếu bạn sử dụng khoảng cách từ nhìn (tất cả đều thấy các pixel có cùng giá trị, đó là đa giác) thay vì từ đường bờ biển, bạn nên tiết kiệm thời gian tính toán. Kích thước không nén của raster nên giống nhau, nhưng nén sẽ hiệu quả hơn, do đó bạn cũng nên giảm kích thước cuối cùng.
radouxju

0

Tôi sẽ thử cách khác. Nếu bạn đang sử dụng poligon của New Zealand thì chuyển đổi các cạnh đa giác thành dòng. Sau đó, tạo bộ đệm trên ranh giới cho mỗi 25 mét khoảng cách từ ranh giới (có thể centorid có thể giúp xác định khi nào nên dừng lại). Sau đó cắt bộ đệm ra với đa giác và sau đó chuyển đổi đa giác đó thành raster. Tôi không chắc điều này sẽ hoạt động nhưng chắc chắn bạn sẽ cần ít RAM hơn. Và PostGiS là tuyệt vời khi bạn có vấn đề về hiệu suất.

Hy vọng nó có thể giúp ít nhất một chút :)


0

Ban đầu tôi sẽ không trả lời câu hỏi của riêng tôi, nhưng một đồng nghiệp của tôi (người không sử dụng trang này), đã viết cho tôi một loạt mã trăn để làm những gì tôi đang theo đuổi; bao gồm việc giới hạn các tế bào để có khoảng cách đến bờ biển chỉ cho các tế bào trên mặt đất và để lại các tế bào trên biển dưới dạng NA. Đoạn mã sau sẽ có thể chạy từ bất kỳ bảng điều khiển python nào, với điều duy nhất cần thay đổi là:

1) Đặt tệp tập lệnh vào cùng thư mục với tệp hình dạng quan tâm;

2) thay đổi tên của shapefile trong tập lệnh python thành tên của shapefile của bạn là gì;

3) đặt độ phân giải mong muốn và;

4) thay đổi phạm vi để phù hợp với các raster khác.

Các shapefile lớn hơn những gì tôi đang sử dụng sẽ cần một lượng RAM lớn nhưng nếu không thì script chạy nhanh (khoảng ba phút để tạo ra raster độ phân giải 50m và mười phút cho raster độ phân giải 25m).

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

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