#python #gis #gdal #shapefile
Вопрос:
У меня есть шейп-файл береговой линии пяти великих озер и привязанная к географической привязке фотография озера Онтарио. Я хочу наложить шейп-файл береговой линии на фотографию tiff в качестве нового растрового слоя. В частности, я хочу сопоставить пиксели шейп-файла и фотографии tiff с одинаковыми координатами. Результатом будет растровый слой m x n (размер одного канала фотографии tiff), где значения равны 1, если координата совпадает с файлом tiff, и 0, если не совпадает. Что мне делать после прочтения этих файлов, как показано ниже? Я могу использовать базовые gdal, растерио и геопанды в Python. Я искал существующие ответы в течение недели, но не смог найти ни одного.
# read tiff file
ds = gdal.Open(path)
band = ds.GetRasterBand(1)
array = band.ReadAsArray()
# read shapefile
shoreline_delineation = gpd.read_file(shoreline_path)
Ниже приведены два изображения, о которых я упоминал. Большое спасибо!
Файлы Geotiff шейп
-файлов
Комментарии:
1. Что вы подразумеваете под «соответствием»? Вы можете растеризировать шейп
gdal.Rasterize
-файл, например, с помощью и проанализировать выходные географические свойства из вашего растра.2. Я имею в виду добавить шейп-файл береговой линии в качестве нового растрового слоя к фотографии в формате tiff. значения равны 1, где координаты файла tiff совпадают с шейп-файлом, и 0, если они не совпадают.
Ответ №1:
Добавление растеризованной версии шейп-файла можно выполнить с помощью кода, приведенного ниже.
Предположим, у вас есть два входных файла, растр и вектор, и предполагается, что ваш вектор уже имеет тип linestring (не полигоны).
from osgeo import gdal
shp_file = 'D:/Temp/input_vector.shp'
ras_file = 'D:/Temp/input_raster.tif'
ras_file_overlay = 'D:/Temp/output_raster_overlay.tif'
Прочитайте свойства входного растра:
ds = gdal.Open(ras_file)
gt = ds.GetGeoTransform()
proj = ds.GetProjection()
n_bands = ds.RasterCount
xsize = ds.RasterXSize
ysize = ds.RasterYSize
ds = None
Вычислите экстент растра:
ulx, xres, _, uly, _, yres = gt
lrx = ulx xres * xsize
lry = uly yres * ysize
Растрируйте вектор в геотиф в памяти и считайте его как массив Numpy:
opts = gdal.RasterizeOptions(
outputType=gdal.GDT_Byte,
outputBounds=[ulx, lry, lrx, uly],
outputSRS=proj,
xRes=xres,
yRes=yres,
allTouched=False,
initValues=0,
burnValues=1,
)
tmp_file = '/vsimem/tmp'
ds_overlay = gdal.Rasterize(tmp_file, shp_file, options=opts)
overlay = ds_overlay.ReadAsArray()
ds_overlay = None
gdal.Unlink(tmp_file)
Вы можете изменить tmp_file
местоположение на диске, чтобы записать его в качестве промежуточного вывода (однослойный). Это может быть удобно для отладки.
При необходимости вы можете добавить буфер к береговой линии, чтобы создать большую/более широкую границу на выходе, добавив что-то вроде этого к gdal.RasterizeOptions
вышесказанному:
SQLStatement="SELECT ST_Buffer(geometry, 0.1) FROM <layer_name>",
SQLDialect="sqlite",
Драйвер Geotiff не поддерживает метод «AddBand», поэтому вы не можете напрямую добавить его во входной растр. Но добавить его в копию можно с помощью:
ds = gdal.Open(ras_file)
tmp_ds = gdal.GetDriverByName('MEM').CreateCopy('', ds, 0)
tmp_ds.AddBand()
tmp_ds.GetRasterBand(tmp_ds.RasterCount).WriteArray(overlay)
dst_ds = gdal.GetDriverByName('GTIFF').CreateCopy(ras_file_overlay, tmp_ds, 0)
dst_ds = None
ds = None
В качестве альтернативы вы можете записать растрированный слой непосредственно на диск в формате tiff, а затем использовать что-то вроде gdal.BuildVRT
их объединения.
Комментарии:
1. Ваш код ОЧЕНЬ подробный и понятный! Но когда я добавляю
SQLStatement="SELECT ST_Buffer(geometry, 0.1) FROM <layer_name>", SQLDialect="sqlite",
в gdal.RasterizeOptions, я получаю ошибку « Трассировка ошибки атрибута (последний последний вызов) 16 ds_overlay = gdal.Растеризация(tmp_file, shp_file, параметры=опции) —> 17 наложение = ds_overlay. ReadAsArray() 18 ds_overlay = Нет 19 gdal. Ошибка атрибута Unlink(tmp_file): объект ‘NoneType’ не имеет атрибута ‘ReadAsArray’ « Код хорошо работает без добавления инструкции SQL.2. @Chloe, ты изменила
<layer_name>
часть на свое настоящее имя слоя? Обычно имя слоя шейп-файла равно имени файла без расширения (и пути). Ошибка, которую вы получаете, находится ниже по течению, GDAL, вероятно, напечатал ошибку в используемой вами командной строке/терминале, намекая на проблему с именем этого слоя.3. В моем примере выше имя слоя будет
input_vector
следующим . Вы могли бы подумать о том, чтобы сделать это автоматически, используя форматирование строк Python в сочетании сos.path.basename(shp_file)
.4. Имя файла без расширения работает! Я использовал имя пути к шейп-файлу, поэтому это не сработало.
5. Рад, что это сработало! Теперь я понимаю, что мой последний комментарий должен был быть:
os.path.splitext(os.path.basename(shp_file))[0]
. Для того, чтобы также удалить расширение из имени файла.