แบ่งแรสเตอร์เป็นชิ้นเล็ก ๆ โดยใช้ GDAL หรือไม่


18

ฉันมีแรสเตอร์ (USGS DEM จริง ๆ ) และฉันต้องแยกมันออกเป็นชิ้นเล็ก ๆ เหมือนภาพด้านล่างแสดง ซึ่งสำเร็จใน ArcGIS 10.0 โดยใช้เครื่องมือ Split Raster ฉันต้องการวิธีการ FOSS เพื่อทำสิ่งนี้ ฉันดูที่ GDAL แล้วคิดว่าจะทำอย่างนั้น (อย่างใดกับ gdal_translate) แต่หาอะไรไม่เจอ ในที่สุดฉันต้องการที่จะใช้แรสเตอร์และพูดว่าชิ้นใหญ่ (4KM โดย 4KM ชิ้น) ฉันต้องการแยกออกเป็น

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


ฉันมีโปรแกรมอรรถประโยชน์ที่ใช้ subprocess.Popen ทำงานหลาย gdal แปลในเวลาเดียวกันซึ่งฉันใช้สำหรับการแยกแรสเตอร์ขนาดใหญ่เพื่อกระเบื้องโดยใช้แหอวนโดยเฉพาะอย่างยิ่งมีประโยชน์ถ้าอินพุตและ / หรือเอาท์พุทถูกบีบอัดสูง (เช่น LZW หรือย่อ GeoTiff ) หากไม่มีการบีบอัดอย่างมากกระบวนการจะถึงจุดสูงสุดในการเข้าถึง HDD และไม่เร็วกว่าการใช้งานครั้งละมาก น่าเสียดายที่มันไม่ธรรมดาพอที่จะแบ่งปันเนื่องจากข้อตกลงการตั้งชื่อที่เข้มงวด แต่อาหารสำหรับความคิดอยู่แล้ว ตัวเลือก -multi สำหรับ GDALWarp มักทำให้เกิดปัญหาและใช้ 2 เธรดเท่านั้น (อ่านหนึ่งครั้งหนึ่งเขียน) ไม่สามารถใช้งานได้ทั้งหมด
Michael Stimson

คำตอบ:


18

gdal_translateจะทำงานโดยใช้ตัวเลือก -srcwin หรือ -projwin

-srcwin xoff yoff xsize ysize: เลือก subwindow จากอิมเมจต้นทางสำหรับการคัดลอกตามตำแหน่งพิกเซล / บรรทัด

-projwin ulx uly lrx lry: เลือก subwindow จากอิมเมจต้นทางสำหรับการคัดลอก (เช่น -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 พร้อมด้วยรูป geotiff ฉันได้รับคำเตือนว่า "คำเตือน: คำนวณ -srcwin -3005000 1879300 50 650 อยู่นอกขอบเขตแรสเตอร์อย่างสมบูรณ์อย่างไรก็ตามฉันไม่แน่ใจว่าที่ฉันทำอะไรผิดดูเหมือนว่าไม่ ใช้พิกัดทางภูมิศาสตร์ของมัน
ncelik

@ncelik อาจเป็นเพราะคุณกำลังใช้พิกัดเซลล์ใน projwin ของคุณและควรใช้ srcwin แทน หากคุณประสบปัญหาโปรดโพสต์คำถามใหม่พร้อมข้อมูลที่เกี่ยวข้องทั้งหมดเพื่อให้เราสามารถให้คำแนะนำเกี่ยวกับปัญหาเฉพาะของคุณ
Michael Stimson

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] ใช่ไหม?
oskarlin

3
ฉันเชื่อว่า sys.argv [2] ใช้เป็นคำนำหน้าสำหรับไฟล์เอาต์พุต สุดยอดประโยชน์ - ขอบคุณ @Ries!
Charlie Hofmann

4

มีสคริปต์ python ที่ให้มาโดยเฉพาะสำหรับการรวบรวม rasters, 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 ที่ถามว่า:

ฉันหวังว่าจะพบคำตอบของ @wwnick รุ่น gdalwarp ที่ใช้ตัวเลือก -multi สำหรับการดำเนินการมัลติคอร์และมัลติเธรดที่ได้รับการปรับปรุง

ข้อจำกัดความรับผิดชอบเล็กน้อย

การใช้งานนี้gdalwarpแม้ว่าฉันจะไม่เชื่ออย่างเต็มที่ว่าจะได้รับประสิทธิภาพมากขึ้น จนถึงตอนนี้ฉันถูกผูกไว้กับ I / O แล้ว - การรันสคริปต์นี้บนแรสเตอร์ขนาดใหญ่ที่ตัดเป็นส่วนเล็ก ๆ หลาย ๆ อันดูเหมือนจะไม่ได้ใช้ซีพียูมากนักดังนั้นฉันจึงคิดว่าคอขวดกำลังเขียนลงดิสก์ หากคุณวางแผนที่จะฉายแผ่นกระเบื้องหรือสิ่งอื่นที่คล้ายกันพร้อมกันสิ่งนี้อาจเปลี่ยนไป มีเคล็ดลับการปรับแต่งเป็นที่นี่ การเล่นสั้น ๆ นั้นไม่ได้ปรับปรุงอะไรสำหรับฉันและ CPU ก็ไม่เคยเป็นปัจจัย จำกัด

ข้อสงวนสิทธิ์กันนี่คือสคริปต์ที่จะใช้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 สร้างแผนที่แรสเตอร์แยกต่างหากสำหรับแต่ละไทล์ที่มีชื่อแผนที่เป็นตัวเลขตามคำนำหน้าที่ผู้ใช้กำหนด สามารถกำหนดความกว้างของไทล์ (คอลัมน์) และความสูงของไทล์ (แถว)

การใช้Python API ของgrass-sessionเพียงไม่กี่บรรทัดของรหัส Python จำเป็นต้องเรียกใช้ฟังก์ชัน r.tile จากภายนอกเช่นการเขียนสคริปต์แบบสแตนด์อโลน การใช้r.externalและr.external.out จะไม่มีการทำซ้ำข้อมูลเกิดขึ้นในระหว่างขั้นตอนการประมวลผล GRASS GIS

รหัสหลอก:

  1. เริ่มต้นเซสชันหญ้า
  2. กำหนดรูปแบบเอาต์พุตด้วย r.external.out
  3. ไฟล์อินพุตลิงก์ด้วย r.external
  4. รัน r.tile ซึ่งสร้างไทล์ในรูปแบบที่กำหนดไว้ด้านบน
  5. ยกเลิกการเชื่อมโยง r.external.out
  6. ปิดหญ้าเซสชั่น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.