Raster diff: bagaimana cara memeriksa apakah gambar memiliki nilai yang identik?

10

Apakah ada cara untuk memeriksa untuk melihat apakah ada 2 layer raster yang diberikan memiliki konten yang identik ?

Kami memiliki masalah pada volume penyimpanan bersama perusahaan kami: sekarang sangat besar sehingga diperlukan lebih dari 3 hari untuk melakukan pencadangan penuh. Penyelidikan awal mengungkapkan salah satu biang kerok memakan ruang terbesar adalah raster on / off yang benar-benar harus disimpan sebagai lapisan 1-bit dengan kompresi CCITT.

raster sekarang / tidak-sekarang yang khas

Gambar sampel ini saat ini 2bit (jadi 3 nilai yang mungkin) dan disimpan sebagai LZW kompresi file, 11 MB dalam sistem file. Setelah mengonversi ke 1bit (jadi 2 nilai yang memungkinkan) dan menerapkan kompresi CCITT Group 4, kami mendapatkannya menjadi 1,3 MB, hampir seluruh urutan besarnya penghematan.

(Ini sebenarnya adalah warga negara yang berperilaku sangat baik, ada yang lain disimpan sebagai float 32bit!)

Ini berita fantastis! Namun ada hampir 7.000 gambar untuk menerapkan ini juga. Akan mudah untuk menulis naskah untuk mengompres mereka:

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

... tetapi tidak ada tes penting: apakah konten versi yang baru dikompresi-identik?

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

Apakah ada alat atau metode yang dapat (otomatis) membuktikan konten Gambar-A bernilai identik dengan konten Gambar-B?

Saya memiliki akses ke ArcGIS 10.2 dan QGIS, tetapi saya juga terbuka untuk hampir semua hal selain yang dapat meniadakan kebutuhan untuk memeriksa semua gambar ini secara manual untuk memastikan kebenaran sebelum menimpa. Akan mengerikan untuk secara keliru mengkonversi dan menimpa gambar yang benar - benar memiliki lebih dari nilai on / off di dalamnya. Sebagian besar biaya ribuan dolar untuk mengumpulkan dan menghasilkan.

hasil yang sangat buruk

pembaruan: Pelanggar terbesar adalah float 32bit yang berkisar hingga 100.000px ke satu sisi, jadi ~ 30GB terkompresi.

matt wilkie
sumber
1
Salah satu cara untuk mengimplementasikannya raster_diff(old_img, new_img) == "Identical"adalah dengan mengecek bahwa zonal max dari nilai absolut dari selisihnya sama dengan 0, di mana zona tersebut diambil dari seluruh luas kisi. Apakah ini semacam solusi yang Anda cari? (Jika demikian, perlu disempurnakan untuk memeriksa apakah nilai-nilai NoData konsisten juga.)
whuber
1
@whuber, terima kasih telah memastikan NoDatapenanganan yang benar tetap dalam percakapan.
matt wilkie
jika Anda dapat memeriksanya len(numpy.unique(yourraster)) == 2, maka Anda tahu bahwa ia memiliki 2 nilai unik dan Anda dapat melakukannya dengan aman.
RemcoGerlich
@Remco Algoritma yang mendasarinya numpy.uniqueakan menjadi lebih mahal secara komputasi (baik dari segi waktu dan ruang) daripada kebanyakan cara lain untuk memeriksa bahwa perbedaannya adalah konstan. Ketika dihadapkan dengan perbedaan antara dua raster floating point yang sangat besar yang menunjukkan banyak perbedaan (seperti membandingkan yang asli dengan versi kompresi yang lossy) kemungkinan akan macet selamanya atau gagal sepenuhnya.
whuber
1
@ Harun, saya ditarik dari proyek untuk melakukan hal-hal lain. Sebagian dari itu adalah karena waktu pengembangan terus bertambah: terlalu banyak kasus tepi untuk ditangani secara otomatis, sehingga keputusan dibuat untuk melempar masalah kembali pada orang yang menghasilkan gambar daripada memperbaikinya. (mis. "Kuota disk Anda adalah X. Anda belajar cara bekerja di dalamnya.") Namun gdalcompare.pymenunjukkan janji besar ( lihat jawaban )
matt wilkie

Jawaban:

8

Coba konversi raster Anda ke array numpy dan kemudian periksa untuk melihat apakah mereka memiliki bentuk dan elemen yang sama dengan array_equal . Jika sama, hasilnya harus 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"
Harun
sumber
Itu terlihat manis dan sederhana. Saya ingin tahu tentang dua detail (yang, meskipun teknis, bisa sangat penting). Pertama, apakah solusi ini menangani nilai-nilai NoData dengan benar? Kedua, bagaimana kecepatannya dibandingkan dengan menggunakan fungsi bawaan yang dimaksudkan untuk perbandingan kisi, seperti ringkasan zona?
whuber
1
Poin bagus @whuber. Saya membuat penyesuaian cepat pada naskah yang harus memperhitungkan bentuk dan elemennya. Saya akan memeriksa poin yang Anda kemukakan dan melaporkan temuannya.
Aaron
1
@whuber Mengenai NoDatapenanganannya, RasterToNumPyArraymenetapkan secara default nilai NoData input raster ke array. Pengguna dapat menentukan nilai yang berbeda, meskipun itu tidak berlaku dalam kasus Matt. Mengenai kecepatan, butuh 4,5 detik untuk skrip untuk membandingkan 2 raster 4-bit dengan 6210 kolom dan 7650 baris (sejauh DOQQ). Saya belum membandingkan metode ini dengan ringkasan zona apa pun.
Aaron
1
Saya melipat di gdal setara, diadaptasi dari gis.stackexchange.com/questions/32995/…
matt wilkie
4

Anda dapat mencoba skrip gdalcompare.py http://www.gdal.org/gdalcompare.html . Kode sumber skrip ada di http://trac.osgeo.org/gdal/browser/trunk/gdal/swig/python/scripts/gdalcompare.py dan karena ini adalah skrip python seharusnya mudah untuk menghapus yang tidak perlu menguji dan menambahkan yang baru sesuai dengan kebutuhan Anda saat ini. Script tampaknya melakukan perbandingan piksel dengan piksel dengan membaca data gambar dari dua gambar band demi band dan itu mungkin metode yang cukup cepat dan dapat digunakan kembali.

pengguna30184
sumber
1
menarik, saya suka gdal, tidak tahu tentang skrip ini. Dokumen untuk menafsirkan hasilnya jarang atau tidak ada ;-). Dalam pengujian awal saya melaporkan perbedaan dalam interpretasi warna dan palet, artinya mungkin terlalu spesifik untuk kebutuhan saya saat ini. Saya masih menjelajahinya. (catatan: jawaban ini terlalu pendek untuk cocok di sini, hanya tautan jawaban yang tidak disarankan, harap pertimbangkan untuk menyempurnakannya).
matt wilkie
1

Saya menyarankan agar Anda membangun tabel atribut raster untuk setiap gambar, lalu Anda dapat membandingkan tabel. Ini bukan pemeriksaan lengkap (seperti menghitung perbedaan antara keduanya), tetapi probabilitas bahwa gambar Anda berbeda dengan nilai histogram yang sama sangat kecil. Juga memberi Anda jumlah nilai unik tanpa NoData (dari jumlah baris dalam tabel). Jika jumlah total Anda kurang dari ukuran gambar, Anda tahu bahwa Anda memiliki piksel NoData.

radouxju
sumber
Apakah ini bekerja dengan float 32-bit? Apakah membangun dan membandingkan dua tabel sebenarnya lebih cepat (atau lebih mudah) daripada memeriksa nilai-nilai perbedaan dua raster (yang pada prinsipnya hanya nol dan NoData)?
whuber
Anda benar bahwa itu tidak akan berfungsi dengan float 32-bit dan saya tidak memeriksa kecepatannya. Namun, membangun tabel atribut perlu membaca data hanya sekali dan dapat membantu menghindari kompresi 1-bit ketika Anda tahu bahwa itu akan gagal. Saya juga tidak tahu ukuran gambar, tetapi kadang-kadang Anda tidak dapat menyimpannya di memori.
radouxju
@radouxju kisaran gambar hingga 100.000px ke satu sisi, jadi ~ 30GB tidak terkompresi. Kami tidak memiliki mesin dengan ram sebanyak itu (meskipun mungkin dengan virtual ...)
matt wilkie
Sepertinya RAM tidak akan menjadi masalah asalkan Anda tetap menggunakan operasi asli ArcGIS. Ini cukup baik dengan penggunaan RAM ketika memproses grid: secara internal dapat melakukan pemrosesan baris-demi-baris, oleh kelompok baris, dan oleh jendela persegi panjang. Operasi lokal seperti mengurangi satu grid dari yang lain dapat beroperasi pada dasarnya dengan kecepatan input dan output, hanya membutuhkan satu (relatif kecil) buffer untuk setiap dataset input. Membangun tabel atribut memerlukan tabel hash tambahan - yang akan sangat kecil ketika hanya satu atau dua nilai muncul, tetapi bisa sangat besar untuk grid sewenang-wenang.
whuber
numpy akan melakukan banyak pertukaran dengan array 2 * 30Go, ini bukan ArcGIS lagi. Saya berasumsi berdasarkan pada printscreen bahwa gambar tersebut adalah gambar rahasia (sebagian besar hanya dengan nilai baru), jadi Anda tidak berharap banyak kelas.
radouxju
0

Solusi paling sederhana yang saya temukan adalah menghitung beberapa statistik ringkasan pada raster, dan membandingkannya. Saya biasanya menggunakan standar deviasi dan rata-rata, yang kuat untuk sebagian besar perubahan, meskipun dimungkinkan untuk mengelabui mereka dengan secara sengaja memanipulasi data.

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.")
scw
sumber
2
Salah satu cara besar untuk mengelabui statistik ini adalah dengan mengubah urutan konten sel (yang dapat terjadi, dan memang, ketika dimensi gambar tidak tepat). Pada raster yang sangat besar baik SD maupun rerata tidak akan dapat mendeteksi beberapa perubahan kecil yang tersebar (terutama jika beberapa piksel dijatuhkan). Dapat dibayangkan mereka tidak akan mendeteksi resampling grosir grid, baik, asalkan konvolusi kubik digunakan (yang dimaksudkan untuk mempertahankan mean dan SD). Tampaknya lebih bijaksana untuk membandingkan SD dari perbedaan grid ke nol.
whuber
0

Cara termudah adalah dengan mengurangi satu raster dari yang lain, jika hasilnya 0, maka kedua gambar itu sama. Anda juga dapat melihat histogram atau plot berdasarkan warna hasilnya.

Pau
sumber
Pengurangan sepertinya cara yang baik untuk melakukan perbandingan. Namun, saya percaya histogram tidak akan sangat berguna dalam mendeteksi masalah dengan nilai-nilai NoData. Misalkan, misalnya, bahwa prosedur kompresi menghilangkan batas satu-pixel di sekitar grid (ini bisa terjadi!) Tetapi sebaliknya akurat: semua perbedaan masih nol. Juga, apakah Anda memperhatikan bahwa OP perlu melakukan ini dengan 7000 set data raster? Saya tidak yakin dia akan senang memeriksa 7000 plot.
whuber