Raster diff: come verificare se le immagini hanno valori identici?


10

Esiste un modo per verificare se uno qualsiasi dei 2 livelli raster ha un contenuto identico ?

Abbiamo un problema con il nostro volume di archiviazione condiviso aziendale: ora è così grande che ci vogliono più di 3 giorni per eseguire un backup completo. L'indagine preliminare rivela che uno dei maggiori colpevoli che consumano spazio sono i raster on / off che dovrebbero essere archiviati come layer a 1 bit con compressione CCITT.

un tipico raster presente / non presente

Questa immagine di esempio è attualmente a 2 bit (quindi 3 possibili valori) e salvata come tiff compresso LZW, 11 MB nel file system. Dopo aver convertito in 1 bit (quindi 2 possibili valori) e aver applicato la compressione CCITT Group 4, lo portiamo a 1,3 MB, quasi un intero ordine di grandezza dei risparmi.

(Questo è in realtà un cittadino molto ben educato, ce ne sono altri memorizzati come float a 32 bit!)

Questa è una notizia fantastica! Tuttavia, ci sono quasi 7.000 immagini per applicare anche questo. Sarebbe semplice scrivere uno script per comprimerli:

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

... ma manca un test vitale: la versione appena compressa è identica al contenuto?

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

Esiste uno strumento o un metodo che può automaticamente (dis) dimostrare che il contenuto di Image-A è identico al valore di Image-B?

Ho accesso ad ArcGIS 10.2 e QGIS, ma sono anche aperto a quasi tutto ciò che può ovviare alla necessità di ispezionare tutte queste immagini manualmente per garantire la correttezza prima di sovrascrivere. Sarebbe orribile convertire e sovrascrivere erroneamente un'immagine che in realtà conteneva più di valori on / off. La maggior parte costa migliaia di dollari da raccogliere e generare.

un pessimo risultato

aggiornamento: i più grandi delinquenti sono float a 32 bit che vanno fino a 100.000 px su un lato, quindi ~ 30 GB non compressi.


1
Un modo di implementare raster_diff(old_img, new_img) == "Identical"sarebbe verificare che il massimo zonale del valore assoluto della differenza sia uguale a 0, in cui la zona viene presa per l'intera estensione della griglia. È questo il tipo di soluzione che stai cercando? (In tal caso, dovrebbe essere perfezionato per verificare che anche i valori NoData siano coerenti.)
whuber

1
@whuber grazie per aver assicurato una corretta NoDatagestione durante la conversazione.
Matt Wilkie,

se riesci a verificarlo len(numpy.unique(yourraster)) == 2, allora sai che ha 2 valori univoci e puoi farlo tranquillamente.
Remco Gerlich,

@Remco L'algoritmo sottostante numpy.uniquesarà più costoso dal punto di vista computazionale (sia in termini di tempo che di spazio) rispetto alla maggior parte degli altri modi per verificare che la differenza sia costante. Se confrontato con una differenza tra due raster in virgola mobile molto grandi che presentano molte differenze (come il confronto tra un originale e una versione compressa con perdita di dati) probabilmente si impantanerebbe per sempre o fallire completamente.
whuber

1
@Aaron, sono stato tirato fuori dal progetto per fare altre cose. In parte ciò è dovuto al fatto che il tempo di sviluppo ha continuato a crescere: troppi casi limite da gestire automaticamente, quindi è stata presa la decisione di restituire il problema alle persone che generavano le immagini piuttosto che risolverle. (ad es. "La tua quota del disco è X. Imparerai a lavorare al suo interno.") Tuttavia ha gdalcompare.pymostrato una grande promessa ( vedi risposta )
matt wilkie

Risposte:


8

Prova a convertire i tuoi raster in array intorpiditi e poi controlla per vedere se hanno la stessa forma ed elementi con array_equal . Se sono uguali, il risultato dovrebbe essere 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"

Sembra dolce e semplice. Sono curioso di sapere due dettagli (che, per quanto tecnici, potrebbero essere cruciali). Innanzitutto, questa soluzione gestisce correttamente i valori NoData? In secondo luogo, come si confronta la sua velocità con l'utilizzo di funzioni integrate destinate ai confronti di reti, come i riepiloghi zonali?
whuber

1
Aspetti positivi @whuber. Ho apportato una rapida modifica alla sceneggiatura che dovrebbe tener conto della forma e degli elementi. Controllerò i punti che hai sollevato e riferirò i risultati.
Aaron

1
@whuber Per quanto riguarda la NoDatagestione, RasterToNumPyArrayassegna di default il valore NoData dell'input raster all'array. L'utente può specificare un valore diverso, sebbene ciò non si applichi nel caso di Matt. Per quanto riguarda la velocità, lo script ha impiegato 4,5 secondi per confrontare 2 raster a 4 bit con 6210 colonne e 7650 righe (estensione DOQQ). Non ho confrontato il metodo con nessun riassunto zonale.
Aaron

1
Ho piegato nell'equivalente gdal, adattato da gis.stackexchange.com/questions/32995/…
matt wilkie

4

Puoi provare con lo script gdalcompare.py http://www.gdal.org/gdalcompare.html . Il codice sorgente dello script è su http://trac.osgeo.org/gdal/browser/trunk/gdal/swig/python/scripts/gdalcompare.py e poiché si tratta di uno script Python dovrebbe essere facile rimuovere l'inutile test e aggiungine di nuovi per soddisfare le tue attuali esigenze. Lo script sembra fare un confronto pixel per pixel leggendo i dati immagine dalle due immagini banda per banda e questo è probabilmente un metodo abbastanza veloce e riutilizzabile.


1
intrigante, adoro gdal, non sapevo di questa sceneggiatura. I documenti per l'interpretazione dei risultati sono scarsi per inesistenti ;-). Nel mio test iniziale riporta differenze nell'interpretazione dei colori e nelle palette, il che significa che potrebbe essere troppo specifico per le mie esigenze attuali. Lo sto ancora esplorando. (nota: questa risposta è troppo breve per essere una buona scelta qui, solo le risposte al link sono sconsigliate, si prega di prendere in considerazione l'idea di farlo).
Matt Wilkie,

1

Suggerirei di creare la tabella degli attributi raster per ogni immagine, quindi puoi confrontare le tabelle. Questo non è un controllo completo (come calcolare la differenza tra i due), ma la probabilità che le tue immagini siano diverse con gli stessi valori dell'istogramma è molto piccola. Inoltre ti dà il numero di valori univoci senza NoData (dal numero di righe nella tabella). Se il conteggio totale è inferiore alla dimensione dell'immagine, sai di avere pixel NoData.


Funzionerebbe con float a 32 bit? Costruire e confrontare due tabelle sarebbe effettivamente più veloce (o più semplice) che esaminare i valori della differenza dei due raster (che in linea di principio dovrebbero essere solo zero e NoData)?
whuber

Hai ragione sul fatto che non funzionerebbe con float a 32 bit e non ho verificato la velocità. Tuttavia, la creazione della tabella degli attributi deve leggere i dati una sola volta e può aiutare a evitare la compressione a 1 bit quando si sa che fallirà. Inoltre non conosco la dimensione delle immagini, ma a volte non è possibile memorizzarle.
Radouxju,

@radouxju le immagini vanno fino a 100.000 px su un lato, quindi ~ 30 GB non compressi. Non abbiamo una macchina con così tanto ariete (anche se forse con virtuale ...)
matt wilkie,

Sembra probabile che la RAM non sia un problema a condizione che tu ti attacchi alle operazioni native di ArcGIS. È abbastanza buono con l'utilizzo della RAM durante l'elaborazione delle griglie: internamente può eseguire l'elaborazione riga per riga, per gruppi di righe e per finestre rettangolari. Operazioni locali come la sottrazione di una griglia da un'altra possono operare essenzialmente alla velocità di input e output, richiedendo solo un buffer (relativamente piccolo) per ciascun set di dati di input. La costruzione di una tabella degli attributi richiede una tabella hash aggiuntiva, che sarebbe minuscola quando si presentavano solo uno o due valori, ma potrebbe essere enorme per le griglie arbitrarie.
whuber

numpy eseguirà molti scambi con array 2 * 30Go, questo non è più ArcGIS. Ho ipotizzato in base allo schermo di stampa che le immagini sono classificate (la maggior parte con solo valori afew), quindi non ti aspetti così tante classi.
Radouxju,

0

La soluzione più semplice che ho trovato è calcolare alcune statistiche riassuntive sui raster e confrontarle. Di solito uso la deviazione standard e la media, che sono robuste per la maggior parte delle modifiche, sebbene sia possibile ingannarle manipolando intenzionalmente i dati.

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
Un modo enorme per ingannare queste statistiche sarebbe quello di permutare il contenuto della cella (cosa che può accadere, e lo fa, quando le dimensioni dell'immagine non sono del tutto giuste). Su raster molto grandi, né la SD né la media rileverebbero in modo affidabile alcune piccole modifiche sparse (specialmente se alcuni pixel fossero stati eliminati). Concepibilmente, non avrebbero neppure rilevato un ricampionamento all'ingrosso della griglia, purché fosse utilizzata una convoluzione cubica (che ha lo scopo di preservare la media e la DS). Sembrerebbe invece prudente confrontare lo SD della differenza delle griglie con zero.
whuber

0

Il modo più semplice è sottrarre un raster dall'altro, se il risultato è 0, entrambe le immagini sono uguali. Inoltre puoi vedere l'istogramma o tracciare per colore il risultato.


La sottrazione sembra un buon modo per condurre un confronto. Tuttavia, credo che l'istogramma non sarebbe molto utile per rilevare problemi con i valori NoData. Supponiamo, ad esempio, che la procedura di compressione abbia eliminato un bordo di un pixel attorno alla griglia (questo può accadere!) Ma per il resto era accurata: tutte le differenze sarebbero comunque zero. Inoltre, hai notato che l'OP deve fare questo con 7000 set di dati raster? Non sono sicuro che apprezzerebbe l'esame di 7000 trame.
whuber
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.