Розщеплення растра на менші шматки за допомогою GDAL?


18

У мене є растр (насправді USGS DEM), і мені потрібно розділити його на менші шматки, як показано на малюнку нижче. Це було досягнуто в ArcGIS 10.0 за допомогою інструмента Split Raster. Я хотів би це зробити методом FOSS. Я дивився на GDAL, думаючи, що це зроблять це (якось із gdal_translate), але нічого не можу знайти. Зрештою, я хотів би мати змогу взяти растр і сказати, наскільки великі (4 км на 4 км куски) я хотів би, щоб він розділився.

введіть тут опис зображення


У мене є утиліта, яка використовує subprocess.Popen одночасно запускати кілька перекладів gdal, які я використовую для вилучення великого растра до плиток за допомогою риболовної мережі, особливо корисно, якщо введення та / або вихід сильно стиснуті (наприклад, LZW або дефляція GeoTiff ), якщо жоден не сильно стискається, максимум процесу отримує доступ до жорсткого диска і не набагато швидший, ніж запуск одного за одним. На жаль, це не є загальним для спільного використання через жорсткі конвенції про називання, але їжа для роздумів у будь-якому випадку. Опція -multi для GDALWarp часто спричиняє проблеми і використовує лише 2 потоки (один читання, один запис), не всі доступні.
Майкл Стимсон

Відповіді:


18

gdal_translate буде працювати за допомогою параметрів -srcwin або -projwin.

-srcwin xoff yoff xsize ysize: Вибирає підвікно з вихідного зображення для копіювання на основі розташування пікселів / рядків.

-projwin ulx uly lrx lry: Вибирає підвікно з вихідного зображення для копіювання (як -srcwin), але з кутами, заданими в геореферендированних координатах.

Вам потрібно буде придумати місце розташування пікселів / ліній або кутові координати, а потім перевести значення через gdal_translate. Щось на кшталт швидкого і брудного пітона нижче буде працювати, якщо використання значень пікселів і -srcwin підходить для вас, буде трохи більше роботи над упорядкуванням координат.

import os, gdal
from gdalconst import *

width = 512
height = 512
tilesize = 64

for i in range(0, width, tilesize):
    for j in range(0, height, tilesize):
        gdaltranString = "gdal_translate -of GTIFF -srcwin "+str(i)+", "+str(j)+", "+str(tilesize)+", " \
            +str(tilesize)+" utm.tif utm_"+str(i)+"_"+str(j)+".tif"
        os.system(gdaltranString)

1
Привіт, коли я спробую -projwin варіант із зображенням геотифа, я отримую попередження: "Попередження: Обчислено -srcwin -3005000 1879300 50 650 повністю випадає за рамки растру. Продовжуючи все ж" Я не впевнений, де я роблю неправильно, схоже, що це не так за допомогою геореференційних координат.
ncelik

@ncelik, можливо, тому, що ви використовуєте координати комірок у своєму projwin, і замість цього слід використовувати srcwin. Якщо у вас виникли труднощі, будь ласка, опублікуйте нове запитання з усією відповідною інформацією, щоб ми могли зробити пропозиції щодо вашої конкретної проблеми.
Майкл Стімсон

15

Моє рішення на основі рішення від @wwnick зчитує розміри растру з самого файлу і охоплює все зображення, зменшуючи крайні плитки за потреби:

import os, sys
from osgeo import gdal

dset = gdal.Open(sys.argv[1])

width = dset.RasterXSize
height = dset.RasterYSize

print width, 'x', height

tilesize = 5000

for i in range(0, width, tilesize):
    for j in range(0, height, tilesize):
        w = min(i+tilesize, width) - i
        h = min(j+tilesize, height) - j
        gdaltranString = "gdal_translate -of GTIFF -srcwin "+str(i)+", "+str(j)+", "+str(w)+", " \
            +str(h)+" " + sys.argv[1] + " " + sys.argv[2] + "_"+str(i)+"_"+str(j)+".tif"
        os.system(gdaltranString)

Я думаю, що це має бути sys.argv [1], де написано sys.argv [2], правда?
оскарлін

3
sys.argv [2], я вважаю, використовується як префікс для вихідних файлів. Супер корисно-- дякую @Ries!
Чарлі Хофманн

4

Існує пакетний python-скрипт, спеціально для вилучення растрових файлів, gdal_retile :

gdal_retile.py [-v] [-co NAME=VALUE]* [-of out_format] [-ps pixelWidth pixelHeight]
               [-overlap val_in_pixel]
               [-ot  {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/
                      CInt16/CInt32/CFloat32/CFloat64}]'
               [ -tileIndex tileIndexName [-tileIndexField tileIndexFieldName]]
               [ -csv fileName [-csvDelim delimiter]]
               [-s_srs srs_def]  [-pyramidOnly]
               [-r {near/bilinear/cubic/cubicspline/lanczos}]
               -levels numberoflevels
               [-useDirForEachRow]
               -targetDir TileDirectory input_files

наприклад:

gdal_retile.py -ps 512 512 -targetDir C:\example\dir some_dem.tif


4

Для @Aaron, який запитав:

Я сподіваюся знайти версію gdalwarp відповіді @ wwnick, яка використовує опцію -multi для розширених багатоядерних та багатопотокових операцій.

Невелика відмова від відповідальності

Це використовує gdalwarp, хоча я не зовсім впевнений, що буде багато прибутків. Поки що я був пов'язаний введенням-виведенням - запуск цього сценарію на великому растрі розрізання його на багато менших частин не здається процесорним процесом, тому я припускаю, що вузьке місце записується на диск. Якщо ви плануєте одночасно перепроектувати плитку чи щось подібне, це може змінитися. Є налаштування поради тут . Коротка гра не принесла жодного покращення для мене, і процесор ніколи не здавався обмежуючим фактором.

Відмову відмови, ось сценарій, який використовуватиме gdalwarpдля розділення растру на кілька менших плиток. Можуть бути певні втрати через поділ підлоги, але це можна переконатись, вибравши кількість плиток, яку ви хочете. Це буде місце, n+1де nє число, на яке ви поділите, щоб отримати tile_widthі tile_heightзмінні.

import subprocess
import gdal
import sys


def gdalwarp(*args):
    return subprocess.check_call(['gdalwarp'] + list(args))


src_path = sys.argv[1]
ds = gdal.Open(src_path)

try:
    out_base = sys.argv[2]
except IndexError:
    out_base = '/tmp/test_'

gt = ds.GetGeoTransform()

width_px = ds.RasterXSize
height_px = ds.RasterYSize

# Get coords for lower left corner
xmin = int(gt[0])
xmax = int(gt[0] + (gt[1] * width_px))

# get coords for upper right corner
if gt[5] > 0:
    ymin = int(gt[3] - (gt[5] * height_px))
else:
    ymin = int(gt[3] + (gt[5] * height_px))

ymax = int(gt[3])

# split height and width into four - i.e. this will produce 25 tiles
tile_width = (xmax - xmin) // 4
tile_height = (ymax - ymin) // 4

for x in range(xmin, xmax, tile_width):
    for y in range(ymin, ymax, tile_height):
        gdalwarp('-te', str(x), str(y), str(x + tile_width),
                 str(y + tile_height), '-multi', '-wo', 'NUM_THREADS=ALL_CPUS',
                 '-wm', '500', src_path, out_base + '{}_{}.tif'.format(x, y))

3

Ви можете використовувати r.tile GRASS GIS. r.tile створює окрему растрову карту для кожної плитки з нумерованими іменами карт на основі визначеного користувачем префікса. Можна визначити ширину плиток (стовпців) та висоту плиток (рядків).

Використовуючи API Python для трав'яної сесії, для виклику функціональності r.tile потрібно лише кілька рядків коду Python, тобто для написання окремого сценарію. Використання r.external та r.external.out також не відбувається дублювання даних під час кроку обробки GRIS GIS.

Псевдокод:

  1. ініціалізувати трав'яну сесію
  2. визначити формат виводу за допомогою r.external.out
  3. посилання вхідного файлу з r.external
  4. запустіть r.tile, який генерує плитки у форматі, визначеному вище
  5. від’єднати r.external.out
  6. закрити траву сесії
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.