Chia raster thành các phần nhỏ hơn bằng cách sử dụng GDAL?


18

Tôi có một raster (USGS DEM thực sự) và tôi cần chia nó thành các phần nhỏ hơn như hình ảnh dưới đây cho thấy. Điều đó đã được thực hiện trong ArcGIS 10.0 bằng công cụ Split Raster. Tôi muốn một phương pháp FOSS để làm điều này. Tôi đã xem GDAL, nghĩ rằng chắc chắn nó sẽ làm điều đó (bằng cách nào đó với gdal_translate), nhưng không thể tìm thấy bất cứ điều gì. Cuối cùng, tôi muốn có thể lấy raster và nói mức độ lớn (4KM x 4KM) tôi muốn nó tách ra thành bao nhiêu.

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


Tôi có một tiện ích sử dụng quy trình con.Popen để chạy nhiều bản dịch gdal cùng lúc mà tôi sử dụng để trích xuất một raster lớn để xếp gạch bằng fishnet, đặc biệt hữu ích nếu đầu vào và / hoặc đầu ra được nén cao (ví dụ LZW hoặc khử định vị GeoTiff ), nếu không được nén nhiều thì đỉnh xử lý khi truy cập vào ổ cứng và không nhanh hơn nhiều so với chạy một lần. Thật không may, nó không đủ chung chung để chia sẻ do các quy ước đặt tên cứng nhắc nhưng dù sao cũng là thức ăn. Tùy chọn -multi cho GDALWarp thường gây rắc rối và chỉ sử dụng 2 luồng (một đọc, một viết) không có sẵn.
Michael Promotionson

Câu trả lời:


18

gdal_translate sẽ hoạt động bằng cách sử dụng các tùy chọn -srcwin hoặc -projwin.

-srcwin xoff yoff xsize ysize: Chọn một luồng con từ hình ảnh nguồn để sao chép dựa trên vị trí pixel / dòng.

-projwin ulx uly lrx lry: Chọn một luồng con từ hình ảnh nguồn để sao chép (như -srcwin) nhưng với các góc được cho trong tọa độ tham chiếu địa lý.

Bạn sẽ cần phải đưa ra các vị trí pixel / dòng hoặc tọa độ góc và sau đó lặp qua các giá trị bằng gdal_translate. Một cái gì đó giống như con trăn nhanh và bẩn dưới đây sẽ hoạt động nếu sử dụng các giá trị pixel và -srcwin phù hợp với bạn, sẽ tốn công hơn một chút để sắp xếp theo tọa độ.

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
Xin chào khi tôi thử tùy chọn -projwin với hình ảnh địa lý, tôi nhận được cảnh báo "Cảnh báo: Đã tính -srcwin -3005000 1879300 50 650 rơi hoàn toàn bên ngoài phạm vi raster. Tuy nhiên" Tôi không chắc là mình đang làm sai ở đâu sử dụng tọa độ tham chiếu địa lý của nó.
ncelik

@ncelik có lẽ là do bạn đang sử dụng tọa độ ô trong projwin của mình và nên sử dụng srcwin thay thế. Nếu bạn đang gặp khó khăn xin vui lòng gửi một câu hỏi mới với tất cả các thông tin liên quan để chúng tôi có thể đưa ra đề xuất về vấn đề cụ thể của bạn.
Michael Promotionson

15

Giải pháp của tôi, dựa trên một từ @wwnick đọc kích thước raster từ chính tệp và bao phủ toàn bộ hình ảnh bằng cách làm cho các cạnh cạnh nhỏ hơn nếu cần:

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)

Tôi nghĩ nó nên là sys.argv [1] trong đó nó nói sys.argv [2], phải không?
oskarlin

3
sys.argv [2] được sử dụng làm tiền tố cho các tệp đầu ra, tôi tin thế. Siêu hữu ích-- cảm ơn @Ries!
Charlie Hofmann

4

Có một tập lệnh python được gói đặc biệt để thử lại các trình quét , 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

ví dụ:

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


4

Dành cho @Aaron, người đã hỏi:

Tôi hy vọng tìm thấy phiên bản gdalwarp của câu trả lời của @ wwnick sử dụng tùy chọn -multi cho các hoạt động đa lõi và đa luồng nâng cao

Tuyên bố từ chối trách nhiệm

Điều này sử dụng gdalwarp, mặc dù tôi không hoàn toàn tin rằng sẽ có nhiều hiệu suất đạt được. Cho đến nay tôi đã bị ràng buộc I / O - chạy tập lệnh này trên một raster lớn, cắt nó thành nhiều phần nhỏ hơn có vẻ không cần nhiều CPU, vì vậy tôi cho rằng nút cổ chai đang ghi vào đĩa. Nếu bạn đang dự định đồng thời chiếu lại các ô hoặc một cái gì đó tương tự, thì điều này có thể thay đổi. Có lời khuyên điều chỉnh ở đây . Một cuộc chơi ngắn không mang lại bất kỳ cải thiện nào cho tôi và CPU dường như không bao giờ là yếu tố hạn chế.

Từ chối trách nhiệm sang một bên, đây là một tập lệnh sẽ sử dụng gdalwarpđể chia raster thành nhiều ô nhỏ hơn. Có thể có một số mất mát do phân chia sàn nhưng điều này có thể được chăm sóc bằng cách chọn số lượng gạch bạn muốn. Nó sẽ là n+1nơi nsố bạn chia cho để lấy tile_widthtile_heightbiến.

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

Bạn có thể sử dụng r.tile của GRASS GIS. r.tile tạo ra một bản đồ raster riêng cho mỗi ô có tên bản đồ được đánh số dựa trên tiền tố do người dùng xác định. Chiều rộng của gạch (cột) và chiều cao của gạch (hàng) có thể được xác định.

Sử dụng API Python phiên chỉ cần một vài dòng mã Python để gọi chức năng r.tile từ bên ngoài, tức là để viết một tập lệnh độc lập. Sử dụng r.externalr.external.out cũng không xảy ra sự trùng lặp dữ liệu trong bước xử lý GRASS GIS.

Mã giả:

  1. khởi tạo phiên cỏ
  2. xác định định dạng đầu ra với r.external.out
  3. liên kết tập tin đầu vào với r.external
  4. chạy r.tile để tạo các ô theo định dạng được xác định ở trên
  5. hủy liên kết r.external.out
  6. đóng cửa phiên cỏ
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.