ラスター差分:画像が同じ値を持っているかどうかを確認する方法?


10

指定された2つのラスターレイヤーのコンテンツが同じかどうかを確認する手段はありますか?

企業の共有ストレージボリュームに問題があります。非常に大きいため、フルバックアップを実行するには3日以上かかります。予備調査の結果、スペースを消費する最大の原因の1つは、オン/オフラスターであり、CCITT圧縮を使用して1ビットレイヤーとして保存する必要があることが判明しました。

典型的な存在/非存在ラスター

このサンプル画像は現在2ビット(可能な3つの値)であり、LZW圧縮tiff、ファイルシステムに11 MBとして保存されています。1ビット(2つの可能な値)に変換し、CCITT Group 4圧縮を適用した後、1.3 MBまで削減しました。これは、ほぼ完全な節約です。

(これは実際には非常に行儀の良い市民です。他にも32ビット浮動小数点数として格納されているものがあります!)

これは素晴らしいニュースです!ただし、これを適用する画像は約7,000枚あります。それらを圧縮するスクリプトを書くのは簡単です。

for old_img in [list of images]:
    convert_to_1bit_and_compress(old_img)
    remove(old_img)
    replace_with_new(old_img, new_img)

...しかし、重要なテストが欠落しています:新しく圧縮されたバージョンはコンテンツ同一ですか?

  if raster_diff(old_img, new_img) == "Identical":
      remove(old_img)
      rename(new_img, old_img)

Image-AのコンテンツをImage-Bのコンテンツと同じように自動的に(非)証明できるツールまたは方法はありますか?

私はArcGIS 10.2とQGISにアクセスできますが、上書きする前にこれらのすべての画像を手動で検査して正確性を確認する必要をなくすことができるもの以外にもほとんど何でも開いています。それは誤って変換するために、恐ろしいことや、実際に画像上書きしてしまいましたより多くのそれの値のオン/オフよりも持っているし。ほとんどの場合、収集と生成に数千ドルの費用がかかります。

非常に悪い結果

更新:最大の違反者は、1辺が最大100,000pxの32ビットフロートであるため、圧縮されていない状態で最大30GBです。


1
実装raster_diff(old_img, new_img) == "Identical"する1つの方法は、差の絶対値のゾーン最大値が0に等しいことを確認することです。この場合、ゾーンはグリッド範囲全体にわたって取得されます。これはあなたが探しているソリューションの種類ですか?(もしそうなら、NoData値も一貫していることを確認するために
調整

1
@whuber NoDataは、会話の中で適切な処理が維持されるように感謝します。
マットウィルキー2014

これを確認できればlen(numpy.unique(yourraster)) == 2、2つの一意の値があり、安全にこれを実行できることがわかります。
RemcoGerlich 2014

@Remco基になるアルゴリズムnumpy.uniqueは、差が一定であることを確認する他のほとんどの方法よりも(時間とスペースの両方の点で)計算コストが高くなります。2つの非常に大きな浮動小数点ラスターの違いに直面すると、多くの違い(オリジナルと非可逆圧縮バージョンの比較など)が発生し、永久に停止するか、完全に失敗する可能性があります。
whuber

1
@Aaron、私は他のことをするためにプロジェクトを中止しました。その理由の1つは、開発時間が増え続けたためです。エッジケースが多すぎて自動的に処理できないため、画像を修正するのではなく、画像を生成している人に問題を投げ戻すことにしました。(たとえば、「ディスククォータはXです。内部で作業する方法を学びます。」)しかし、gdalcompare.py大きな期待(回答を参照)を示しました
マットウィルキー

回答:


8

ラスタをnumpy配列に変換してから、array_equalを使用してそれらの形状と要素が同じかどうかを確認してください。それらが同じ場合、結果は次のようになりますTrue

ArcGIS:

import arcpy, numpy

raster1 = r'C:\path\to\raster.tif'
raster2 = r'C:\path\to\raster.tif'

r1 = arcpy.RasterToNumPyArray(raster1)
r2 = arcpy.RasterToNumPyArray(raster2)

d = numpy.array_equal(r1,r2)

if d == False:
    print "They differ"

else:
    print "They are the same"

GDAL:

import numpy
from osgeo import gdal        

raster1 = r'C:\path\to\raster.tif'
raster2 = r'C:\path\to\raster.tif'

ds1 = gdal.Open(raster1)
ds2 = gdal.Open(raster2)

r1 = numpy.array(ds1.ReadAsArray())
r2 = numpy.array(ds2.ReadAsArray())

d = numpy.array_equal(r1,r2)

if d == False:
    print "They differ"

else:
    print "They are the same"

それは甘くてシンプルに見えます。私は2つの詳細に興味があります(これは技術的ですが、非常に重要な場合があります)。まず、このソリューションはNoData値を正しく処理しますか?次に、その速度は、ゾーン集計などのグリッド比較を目的とした組み込み関数を使用する場合とどのように比較されますか?
whuber

1
良い点@whuber。形状と要素を考慮に入れるべきスクリプトをすばやく調整しました。ご指摘いただいた内容を確認し、報告いたします。
アーロン

1
@whuber処理に関してはNoDataRasterToNumPyArrayデフォルトで入力ラスターのNoData値を配列に割り当てます。ユーザーは別の値を指定できますが、Mattの場合は適用されません。速度については、スクリプトが2つの4ビットラスターを6210列と7650行(DOQQエクステント)で比較するのに4.5秒かかりました。この方法をゾーンサマリーと比較していません。
アーロン

1
私は、GDAL同等に折らから適応gis.stackexchange.com/questions/32995/...
マットウィルキー

4

gdalcompare.pyスクリプトhttp://www.gdal.org/gdalcompare.htmlを試すことができます。スクリプトのソースコードはhttp://trac.osgeo.org/gdal/browser/trunk/gdal/swig/python/scripts/gdalcompare.pyにあります。これはPythonスクリプトなので、不要なものを簡単に削除できます。現在のニーズに合わせて新しいものをテストして追加します。スクリプトは、2つの画像からバンドごとに画像データを読み取ることにより、ピクセルごとの比較を行うようであり、これはおそらく非常に高速で再利用可能な方法です。


1
興味深いことに、私はgdalが大好きで、このスクリプトについては知りませんでした。結果を解釈するためのドキュメントは存在しませんが、まばらです;-)。私の最初のテストでは、色の解釈とパレットの違いを報告します。つまり、私の現在のニーズにはあまりにも具体的すぎる可能性があります。私はまだそれを探究しています。(注:この回答は短すぎてここに収まりません。リンクのみの回答はお勧めしません。具体化することを検討してください)。
マットウィルキー2014

1

画像ごとにラスター属性テーブルを作成してから、テーブルを比較することをお勧めします。これは完全なチェック(2つの間の差の計算など)ではありませんが、同じヒストグラム値で画像が異なる確率は非常に小さくなります。また、(テーブルの行数から)NoDataなしの一意の値の数も得られます。合計数が画像サイズより小さい場合、NoDataピクセルがあることがわかります。


これは32ビットfloatで動作しますか?2つのテーブルの作成と比較は、2つのラスターの差の値(原則としてゼロとNoDataのみ)を調べるよりも実際に高速(または簡単)でしょうか。
whuber

あなたはそれが32ビットの浮動小数点で動作しないだろうというのは正しいです、そして私は速度をチェックしませんでした。ただし、属性テーブルの作成はデータを1回だけ読み取る必要があり、失敗することがわかっている場合に1ビット圧縮を回避するのに役立ちます。また、画像のサイズはわかりませんが、メモリに保存できない場合があります。
radouxju 2014

@radouxju画像のサイズは一辺が最大100,000pxなので、圧縮されていない場合は最大30GBです。それほど多くのRAMを備えたマシンはありません(おそらく仮想マシンを備えていますが)
マットウィルキー2014

おそらく、ArcGISのネイティブ操作を使用している限り、RAMは問題ではないようです。グリッドを処理するときのRAM使用量はかなり良いです。内部的には、行ごと、行のグループごと、および長方形のウィンドウによって処理できます。あるグリッドを別のグリッドから減算するようなローカル操作は、本質的に入力と出力の速度で動作でき、各入力データセットに対して1つの(比較的小さな)バッファーのみを必要とします。属性テーブルを作成するには、追加のハッシュテーブルが必要です。1つまたは2つの値しか表示されない場合は非常に小さくなりますが、任意のグリッドでは巨大になる可能性があります。
whuber

numpyは2 * 30Go配列で多くのスワッピングを行いますが、これはもはやArcGISではありません。printscreenに基づいて、画像は分類された画像(ほとんどが値がほとんどない)であると想定したので、それほど多くのクラスを期待することはできません。
radouxju 2014

0

私が見つけた最も簡単な解決策は、ラスターのいくつかの要約統計量を計算し、それらを比較することです。私は通常、標準偏差と平均を使用します。これらはほとんどの変更に対してロバストですが、意図的にデータを操作することでそれらをだますことができます。

mean_obj = arcpy.GetRasterProperties(input_raster, 'MEAN')
mean = float(mean_obj.getOutput(0))
if round(mean, 4) != 0.2010:
    print("raster differs from expected mean.")

std_obj = arcpy.GetRasterProperties(input_raster, 'STD')
std = float(std_obj.getOutput(0))
if round(std, 4) != 0.0161:
    print("raster differs from expected standard deviation.")

2
これらの統計をだますための巨大な方法の1つは、セルの内容を並べ替えることです(これは、画像の寸法が正しくない場合に発生する可能性があります)。非常に大きなラスターでは、SDも平均も、散在するいくつかの小さな変化を確実に検出しません(特に、いくつかのピクセルが単にドロップされた場合)。立方畳み込みを使用した場合、グリッドの大規模なリサンプリングも検出されない可能性があります(平均とSDを保持することを目的としています)。代わりに、グリッドの差のSDをゼロに比較するのが賢明に思えます。
whuber

0

最も簡単な方法は、一方のラスタをもう一方のラスタから差し引くことです。結果が0の場合、両方の画像は同じです。また、ヒストグラムを表示したり、結果を色でプロットしたりすることもできます。


減算は、比較を行うための良い方法のようです。ただし、NoData値の問題を検出する場合、ヒストグラムはあまり役に立ちません。たとえば、圧縮手順によってグリッドの周りの1ピクセルの境界が削除されたとします(これが発生する可能性があります)。また、OPが7000ラスターデータセットでこれを行う必要があることに気付きましたか?彼が7000のプロットを検討するのを楽しんでいるかどうかはわかりません。
whuber
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.