Rasterdifferenz: Wie kann überprüft werden, ob Bilder identische Werte haben?

10

Gibt es eine Möglichkeit zu überprüfen, ob zwei bestimmte Rasterebenen identischen Inhalt haben ?

Wir haben ein Problem mit unserem gemeinsam genutzten Unternehmensspeichervolumen: Es ist jetzt so groß, dass die Durchführung einer vollständigen Sicherung über 3 Tage dauert. Voruntersuchungen haben ergeben, dass On / Off-Raster einer der größten platzraubenden Schuldigen sind, die wirklich als 1-Bit-Layer mit CCITT-Komprimierung gespeichert werden sollten.

ein typisches vorhandenes / nicht vorhandenes Raster

Dieses Beispielbild ist derzeit 2 Bit (also 3 mögliche Werte) und wird als LZW-komprimiertes TIFF mit 11 MB im Dateisystem gespeichert. Nach der Konvertierung in 1 Bit (also 2 mögliche Werte) und der Anwendung der CCITT Group 4-Komprimierung wird diese auf 1,3 MB reduziert, was fast einer Größenordnung der Einsparungen entspricht.

(Dies ist eigentlich ein sehr gut erzogener Bürger, es gibt andere, die als 32-Bit-Float gespeichert sind!)

Das sind fantastische Neuigkeiten! Es gibt jedoch fast 7.000 Bilder, um dies auch anzuwenden. Es wäre einfach, ein Skript zu schreiben, um sie zu komprimieren:

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

... aber es fehlt ein wichtiger Test: Ist die neu komprimierte Version inhaltsidentisch?

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

Gibt es ein Werkzeug oder eine Methode, mit der automatisch nachgewiesen werden kann, dass der Inhalt von Bild-A mit dem Inhalt von Bild-B identisch ist?

Ich habe Zugriff auf ArcGIS 10.2 und QGIS, bin aber auch für fast alles andere offen, als die Notwendigkeit zu vermeiden, alle diese Bilder manuell zu überprüfen, um die Richtigkeit vor dem Überschreiben sicherzustellen. Es würde fälschlicherweise convert schrecklich sein und ein Bild überschreiben , dass wirklich haben mehr haben als Ein / Aus - Werte drin. Die meisten kosten Tausende von Dollar, um sie zu sammeln und zu generieren.

ein sehr schlechtes Ergebnis

Update: Die größten Straftäter sind 32-Bit-Floats, die bis zu 100.000 Pixel pro Seite reichen, also ~ 30 GB unkomprimiert.

matt wilkie
quelle
1
Eine Möglichkeit zur Implementierung besteht raster_diff(old_img, new_img) == "Identical"darin, zu überprüfen, ob das zonale Maximum des Absolutwerts der Differenz gleich 0 ist, wobei die Zone über die gesamte Gitterausdehnung genommen wird. Ist dies die Art von Lösung, nach der Sie suchen? (Wenn ja, müsste es verfeinert werden, um zu überprüfen, ob alle NoData-Werte auch konsistent sind.)
whuber
1
@whuber danke für die richtige NoDataHandhabung bleibt im Gespräch.
Matt Wilkie
Wenn Sie dies überprüfen können len(numpy.unique(yourraster)) == 2, wissen Sie, dass es zwei eindeutige Werte hat, und Sie können dies sicher tun.
RemcoGerlich
@Remco Der zugrunde liegende Algorithmus numpy.uniquewird rechenintensiver (sowohl zeitlich als auch räumlich) als die meisten anderen Methoden, um zu überprüfen, ob der Unterschied eine Konstante ist. Bei einem Unterschied zwischen zwei sehr großen Gleitkomma-Rastern, die viele Unterschiede aufweisen (z. B. beim Vergleich eines Originals mit einer verlustbehafteten komprimierten Version), würde es wahrscheinlich für immer festsitzen oder vollständig versagen.
whuber
1
@ Aaron, ich wurde vom Projekt abgezogen, um andere Dinge zu tun. Ein Teil davon war, dass die Entwicklungszeit weiter zunahm: Zu viele Randfälle, um automatisch behandelt zu werden. Daher wurde die Entscheidung getroffen, das Problem wieder auf die Personen zu werfen, die die Bilder generieren, anstatt sie zu beheben. (zB "Ihr Festplattenkontingent ist X. Sie lernen, wie man darin arbeitet.") Allerdings gdalcompare.pyzeigte sich
vielversprechend

Antworten:

8

Versuchen Sie, Ihre Raster in numpy Arrays zu konvertieren, und überprüfen Sie dann, ob sie dieselbe Form und dieselben Elemente wie array_equal haben . Wenn sie gleich sind, sollte das Ergebnis sein 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"
Aaron
quelle
Das sieht süß und einfach aus. Ich bin neugierig auf zwei Details (die, obwohl technisch, entscheidend sein könnten). Behandelt diese Lösung NoData-Werte korrekt? Zweitens, wie ist die Geschwindigkeit im Vergleich zur Verwendung integrierter Funktionen für Gittervergleiche wie z. B. zonale Zusammenfassungen?
whuber
1
Gute Punkte @whuber. Ich habe eine schnelle Anpassung am Skript vorgenommen, die die Form und die Elemente berücksichtigen sollte. Ich werde die von Ihnen angesprochenen Punkte überprüfen und die Ergebnisse melden.
Aaron
1
@whuber Hinsichtlich der NoDataHandhabung, RasterToNumPyArrayAbtretungsempfänger der Standardeinstellung Eingabe - Raster des NoData Wert auf dem Array. Der Benutzer kann einen anderen Wert angeben, obwohl dies in Matts Fall nicht zutreffen würde. In Bezug auf die Geschwindigkeit dauerte es 4,5 Sekunden, bis das Skript 2 4-Bit-Raster mit 6210 Spalten und 7650 Zeilen (DOQQ-Umfang) verglichen hatte. Ich habe die Methode nicht mit zonalen Zusammenfassungen verglichen.
Aaron
1
Ich faltete das gdal-Äquivalent ein, angepasst von gis.stackexchange.com/questions/32995/…
matt wilkie
4

Sie können es mit dem Skript gdalcompare.py http://www.gdal.org/gdalcompare.html versuchen . Der Quellcode des Skripts befindet sich unter http://trac.osgeo.org/gdal/browser/trunk/gdal/swig/python/scripts/gdalcompare.py. Da es sich um ein Python-Skript handelt, sollte es einfach sein, das Unnötige zu entfernen Tests und fügen Sie neue hinzu, um Ihren aktuellen Anforderungen zu entsprechen. Das Skript scheint einen Pixel-für-Pixel-Vergleich durchzuführen, indem Bilddaten aus den beiden Bildern Band für Band gelesen werden, und das ist wahrscheinlich eine recht schnelle und wiederverwendbare Methode.

user30184
quelle
1
faszinierend, ich liebe gdal, wusste nichts über dieses Skript. Dokumente zur Interpretation der Ergebnisse sind jedoch spärlich bis gar nicht vorhanden ;-). Bei meinen ersten Tests werden Unterschiede in der Farbinterpretation und den Paletten gemeldet, was bedeutet, dass es möglicherweise zu spezifisch für meine aktuellen Anforderungen ist. Ich erforsche es trotzdem. (Hinweis: Diese Antwort ist zu kurz, um hier gut zu passen. Antworten nur auf Links werden nicht empfohlen. Bitte überlegen Sie, sie zu konkretisieren.)
Matt Wilkie
1

Ich würde vorschlagen, dass Sie Ihre Rasterattributtabelle für jedes Bild erstellen und dann die Tabellen vergleichen. Dies ist keine vollständige Überprüfung (wie die Berechnung der Differenz zwischen den beiden), aber die Wahrscheinlichkeit, dass sich Ihre Bilder bei gleichen Histogrammwerten unterscheiden, ist sehr, sehr gering. Außerdem erhalten Sie die Anzahl der eindeutigen Werte ohne NoData (aus der Anzahl der Zeilen in der Tabelle). Wenn Ihre Gesamtzahl kleiner als die Bildgröße ist, wissen Sie, dass Sie NoData-Pixel haben.

Radouxju
quelle
Würde dies mit 32-Bit-Floats funktionieren? Wäre das Erstellen und Vergleichen von zwei Tabellen tatsächlich schneller (oder einfacher) als das Untersuchen der Differenzwerte der beiden Raster (die im Prinzip nur Null und NoData sein sollten)?
whuber
Sie haben Recht, dass es mit 32-Bit-Float nicht funktionieren würde, und ich habe nicht nach der Geschwindigkeit gesucht. Das Erstellen der Attributtabelle muss die Daten jedoch nur einmal lesen und kann dazu beitragen, die 1-Bit-Komprimierung zu vermeiden, wenn Sie wissen, dass sie fehlschlagen wird. Ich kenne auch die Größe der Bilder nicht, aber manchmal kann man sie nicht im Speicher speichern.
Radouxju
@radouxju die Bilder reichen bis zu 100.000px zu einer Seite, also ~ 30GB unkomprimiert. Wir haben keine Maschine mit so viel RAM (obwohl vielleicht mit virtuellen ...)
Matt Wilkie
Es ist wahrscheinlich, dass RAM kein Problem darstellt, vorausgesetzt, Sie bleiben bei nativen ArcGIS-Vorgängen. Die RAM-Auslastung bei der Verarbeitung von Rastern ist ziemlich gut: Intern kann die Verarbeitung zeilenweise, nach Gruppen von Zeilen und nach rechteckigen Fenstern erfolgen. Lokale Operationen wie das Subtrahieren eines Gitters von einem anderen können im Wesentlichen mit der Geschwindigkeit der Eingabe und Ausgabe arbeiten, wobei nur ein (relativ kleiner) Puffer für jeden Eingabedatensatz erforderlich ist. Für die Erstellung einer Attributtabelle ist eine zusätzliche Hash-Tabelle erforderlich. Dies wäre winzig, wenn nur ein oder zwei Werte angezeigt werden, könnte jedoch für beliebige Raster enorm sein.
whuber
numpy wird viel mit 2 * 30Go-Arrays tauschen, dies ist nicht mehr ArcGIS. Basierend auf dem Druckbildschirm habe ich angenommen, dass die Bilder klassifizierte Bilder sind (die meisten mit nur wenigen Werten), sodass Sie nicht so viele Klassen erwarten.
Radouxju
0

Die einfachste Lösung, die ich gefunden habe, besteht darin, einige zusammenfassende Statistiken zu den Rastern zu berechnen und diese zu vergleichen. Normalerweise verwende ich Standardabweichung und Mittelwert, die für die meisten Änderungen robust sind, obwohl es möglich ist, sie durch absichtliche Manipulation der Daten zu täuschen.

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
quelle
2
Eine große Möglichkeit, diese Statistiken zu täuschen, besteht darin, den Zellinhalt zu permutieren (was passieren kann und tut, wenn die Bilddimensionen nicht ganz richtig sind). Bei sehr großen Rastern würden weder die SD noch der Mittelwert zuverlässig einige kleine Änderungen erkennen, die verstreut sind (insbesondere wenn nur ein paar Pixel entfernt wurden). Möglicherweise würden sie auch keine umfassende Neuabtastung des Gitters feststellen, vorausgesetzt, es wurde eine kubische Faltung verwendet (die den Mittelwert und die SD erhalten soll). Es erscheint stattdessen ratsam, die SD der Differenz der Gitter mit Null zu vergleichen.
whuber
0

Am einfachsten ist es, ein Raster vom anderen zu subtrahieren. Wenn das Ergebnis 0 ist, sind beide Bilder gleich. Sie können auch das Histogramm oder den Plot nach Farbe des Ergebnisses sehen.

Pau
quelle
Subtraktion scheint ein guter Weg zu sein, um einen Vergleich durchzuführen. Ich glaube jedoch, dass das Histogramm beim Erkennen von Problemen mit NoData-Werten nicht sehr nützlich wäre. Nehmen wir zum Beispiel an, dass durch die Komprimierungsprozedur ein Ein-Pixel-Rand um das Raster entfernt wurde (dies kann passieren!), Ansonsten aber genau war: Alle Unterschiede wären immer noch Null. Haben Sie auch bemerkt, dass das OP dies mit 7000 Raster-Datensätzen tun muss? Ich bin mir nicht sicher, ob er es genießen würde, 7000 Grundstücke zu untersuchen.
whuber