ラスターはpython、gdal、numpyを使用して再分類します


9

pyhton、gdal、および/またはnumpyを使用して、10クラスのラスターから8クラスのラスターにラスターファイルを再分類したいと思います。クラスは整数として表されます。この投稿の手順に従って、GDALとPython、numpy.equal doc、およびgdal_calc doc を使用してラスタを再分類しました。しかし、役に立たない。

再分類されるラスターファイルには、0〜11の範囲の整数値が含まれ、値100および255も含まれます。次に、再分類(from value:to value)を示します。

nodata:4、0:4、1:1、2:2、3:3、4:3、5:4、6:5、7:5、8:6、9:7、10:8、100: nodata、255:nodata、

私ができることは、tkinter.FileDialogを使用して再分類するラスターファイルを選択し、retrans = gdal.Open(raster、GA_ReadOnly)でgeotransformやピクセルサイズなどのラスター情報を取得することです。

上記を解決するにはどうすればよいですか?

場合によっては、再分類されるラスターがかなり大きくなる可能性がある(500MBから5GB)ことに注意してください。



@bennos、ブログでスクリプトを試しましたが、配列を解凍するとメモリエラーが返されます。
PyMapr 2015

私は彼がより良い私よりも彼のコードを知っているかもしれない問題を解決する方法を知っているとして、あなたは、ロジャーVeciana私ロビラ、ポストの著者でこの問題を議論示唆
bennos

入力ラスターを16ビット符号なしから8ビット符号なしに変更すると、メモリの問題が解決しました。ただし、以下のdmh126スクリプトと再分類するには、ほぼ同じ時間がかかります。
PyMapr 2015

回答:


6

ここに再分類のための単純なpythonスクリプトがあり、私はそれを書いて私のために動作します:

from osgeo import gdal

driver = gdal.GetDriverByName('GTiff')
file = gdal.Open('/home/user/workspace/raster.tif')
band = file.GetRasterBand(1)
lista = band.ReadAsArray()

# reclassification
for j in  range(file.RasterXSize):
    for i in  range(file.RasterYSize):
        if lista[i,j] < 200:
            lista[i,j] = 1
        elif 200 < lista[i,j] < 400:
            lista[i,j] = 2
        elif 400 < lista[i,j] < 600:
            lista[i,j] = 3
        elif 600 < lista[i,j] < 800:
            lista[i,j] = 4
        else:
            lista[i,j] = 5

# create new file
file2 = driver.Create( 'raster2.tif', file.RasterXSize , file.RasterYSize , 1)
file2.GetRasterBand(1).WriteArray(lista)

# spatial ref system
proj = file.GetProjection()
georef = file.GetGeoTransform()
file2.SetProjection(proj)
file2.SetGeoTransform(georef)
file2.FlushCache()

範囲を変更するだけです。

お役に立てば幸いです。


3
またはで閉じてfile2、ディスクに書き込まれることを確認してください。GDALの内部タイルキャッシュのみに影響します。del file2file2 = None.FlushCache()
ケルステン

@ dmh126、私は範囲を変更し、スクリプトは動作します。ただし、それほど迅速ではありません(議論の余地があります)。入力ラスターは約120MBで、完了するまでに約15分かかりました。市販のリモートセンシングパッケージを使用すると、数秒で完了します。処理時間の短縮に関する推奨事項はありますか?
PyMapr 2015

マルチスレッドが役立つと思います。すべてのコアを使用してみることができます。gis.stackexchange.com
…の

double forループを使用しても意味がありません。以下の回答を参照してください
Mattijn

そうです、二重ループと要素ごとの再分類は、これを行うためのすべての可能な方法の中で最も遅いものです。ufuncsのようなnumpyの強力な部分を使用します:docs.scipy.org/doc/numpy-1.10.1/reference/ufuncs.html
sgillies

16

dmh126で記述されているdouble forループとして再分類を行う代わりに、次を使用してそれを行いますnp.where

# reclassification    
lista[np.where( lista < 200 )] = 1
lista[np.where((200 < lista) & (lista < 400)) ] = 2
lista[np.where((400 < lista) & (lista < 600)) ] = 3
lista[np.where((600 < lista) & (lista < 800)) ] = 4
lista[np.where( lista > 800 )] = 5

6163 x 3537ピクセル(41.6mb)の配列では、分類は1.59秒で行われ、double forループを使用すると12分41秒かかります。合計で478倍のスピードアップです。

結論として、double forループを使用しないでください numpy


ヒントをありがとうございましたが、入力クラスが出力クラスと重なると問題が発生すると思います。次のルールで新しい値を変更したくない。
etrimaille 2016年

@Gustry-ここで問題が発生しました。
relima

そこで、以下の私の答えをチェック:gis.stackexchange.com/questions/163007/...を
etrimaille

6

次に、rasterioとnumpy を使用した基本的な例を示します。

import rasterio as rio
import numpy as np


with rio.open('~/rasterio/tests/data/rgb1.tif') as src:
    # Read the raster into a (rows, cols, depth) array,
    # dstack this into a (depth, rows, cols) array,
    # the sum along the last axis (~= grayscale)
    grey = np.mean(np.dstack(src.read()), axis=2)

    # Read the file profile
    srcprof = src.profile.copy()

classes = 5
# Breaks is an array of the class breaks: [   0.   51.  102.  153.  204.]
breaks = (np.arange(classes) / float(classes)) * grey.max()

# classify the raster
classified = np.sum(np.dstack([(grey < b) for b in breaks]), axis=2).reshape(1, 400, 400).astype(np.int32)

# Update the file opts to one band
srcprof.update(count=1, nodata=None, dtype=classified.dtype)

with rio.open('/tmp/output.tif', 'w', **srcprof) as dst:
    # Write the output
    dst.write(classified)

2

@Mattijnからの回答を完了するために、入力クラスが出力クラスと重複する場合、問題が発生すると思います。次のルールで新しい値が変更されないようにしたい。

速度が落ちたかどうかはわかりませんが、深いコピーを行う必要があります。

list_dest = lista.copy()

list_dest[np.where( lista < 0 )] = 0
list_dest[np.where((0 <= lista) & (lista <= 1)) ] = 1
list_dest[np.where((1 < lista) & (lista <= 5)) ] = 2
list_dest[np.where( 5 < lista )] = 3

1

これは、Rasterioクックブックと@Mattijnの答えを使用してハッキングした別のRasterioアプローチです。

import rasterio
import numpy as np

with rasterio.open('input_raster.tif') as src:    
    # Read as numpy array
    array = src.read()
    profile = src.profile

    # Reclassify
    array[np.where(array == 0)] = 4 
    array[np.where(array == 2)] = 1
    # and so on ...  

with rasterio.open('output_raster.tif', 'w', **profile) as dst:
    # Write to disk
    dst.write(array)

0

いくつかのケースでは、numpyのデジタイズはすぐにゴミ箱に範囲から行くのに便利です。

import rasterio
import numpy as np

with rasterio.open('my_raster.tif') as src:    
    array = src.read()
    profile = src.profile
    bins = np.array([-1.,-0.7,-0.4, 0.2, 1]) 
    inds = np.digitize(array, bins)

with rasterio.open('output_raster.tif', 'w', **profile) as dst:
    dst.write(inds)

0

ラスターRGBカラーテーブルをサポート:

import numpy as np
from osgeo import gdal

path_inDs = "/data/OCS_2016.extract.tif"
path_outDs = "/data/OCS_2016.postpython.tif"

driver = gdal.GetDriverByName('GTiff')
file = gdal.Open(path_inDs)

if file is None:
  print ('Could not open image file')
  sys.exit(1)

band = file.GetRasterBand(1)
lista = band.ReadAsArray()


# reclassification
lista[np.where(lista == 31)] = 16

# create new file
file2 = driver.Create(path_outDs, file.RasterXSize , file.RasterYSize , 1, gdal.GPI_RGB)
file2.GetRasterBand(1).WriteArray(lista)

# spatial ref system
proj = file.GetProjection()
georef = file.GetGeoTransform()
meta = file.GetMetadata()
colors = file.GetRasterBand(1).GetRasterColorTable()

file2.SetProjection(proj)
file2.SetGeoTransform(georef)
file2.SetMetadata(meta)
file2.GetRasterBand(1).SetRasterColorTable(colors)

file2.FlushCache()
del file2


0

少し異なる代替策は次のようになります:

import numpy as np
from osgeo import gdal

original = gdal.Open('**PATH**\\origianl_raster.tif')



# read the original file

band = original.GetRasterBand(1) # assuming that the file has only one band
band_array = band.ReadAsArray()



#create a new array with reclassified values

new_array = np.where(band_array == np.nan, 4, 
                np.where(band_array == 0, 4,
                    np.where(band_array == 1, 1,
                        np.where(band_array == 2, 2,
                            np.where(band_array == 3, 3,
                                np.where(band_array == 4, 3, 
                                    np.where(band_array == 5, 4,
                                        np.where(band_array == 6, 5,
                                            np.where(band_array == 7, 5,
                                                np.where(band_array == 8, 6, 
                                                    np.where(band_array == 9, 7,
                                                       np.where(band_array == 10, 8,
                                                            np.where(band_array == 100, np.nan, np.nan))))))))))))) 
                                # the last line also includes values equal to 255, as they are the only ones left



# create and save reclassified raster as a new file

outDs = gdal.GetDriverByName('GTiff').Create("**PATH**\\reclassified_raster.tif", original.RasterXSize, original.RasterYSize, 1, gdal.GDT_Float32)

outBand = outDs.GetRasterBand(1)
outBand.WriteArray(new_array)

outDs.SetGeoTransform(original.GetGeoTransform())
outDs.SetProjection(original.GetProjection())


# flush cache

outDs.FlushCache()

このスクリプトはnumpy.where(https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html)で再生されます。最後のステップ以外のすべてのステップで、条件が満たされない場合、別のnp.whereが返されます。そして、ラスターのすべての可能な値が考慮されるまで、それは続きます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.