Растрова різниця: як перевірити, чи мають зображення однакові значення?


10

Чи є засіб перевірити, чи є якісь два задані растрові шари однаковим вмістом ?

У нас є проблема з нашим корпоративним обсягом спільного зберігання: він зараз настільки великий, що потрібно повне резервне копіювання. Попереднє дослідження виявляє, що один з найбільших винуватців місця, що займає місце, є растрами вмикання / вимкнення, які дійсно повинні зберігатися як 1-бітні шари при стисненні CCITT.

типовий растр теперішнього / немає

На даний момент зразок зображення є 2-бітовим (тому 3 можливі значення) і зберігається як стислий тиф LZW, 11 Мб у файловій системі. Після перетворення на 1 біт (тобто 2 можливих значення) та застосування стиснення CCITT Group 4 ми зменшуємо його до 1,3 Мб, майже на повний порядок економії.

(Це насправді дуже добре поводиться громадянин, є й інші, які зберігаються як 32-бітний поплавок!)

Це фантастична новина! Однак є майже 7000 зображень, щоб застосувати і це. Було б просто написати сценарій для їх стиснення:

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, але я також відкритий для більшості всього іншого, ніж може усунути необхідність перевіряти всі ці зображення вручну, щоб забезпечити правильність перед перезаписом. Було б жахливо помилково перетворити і перезаписати зображення , яке дійсно було мати більше , ніж на / від значень в ньому. Більшість коштує тисяч доларів, щоб зібрати та генерувати.

дуже поганий результат

оновлення: Найбільшими правопорушниками є 32-бітові поплавці, що мають діапазон до 100 000 пікселів в сторону, тому ~ 30 ГБ не стискається.


1
Одним із способів здійснення raster_diff(old_img, new_img) == "Identical"було б перевірити, що зональний макс абсолютного значення різниці дорівнює 0, де зона взята на весь обсяг сітки. Це таке рішення, яке ви шукаєте? (Якщо так, то його потрібно буде уточнити, щоб перевірити, чи будь-які значення NoData відповідають.)
whuber

1
@whuber спасибі за те, що ви забезпечили належне NoDataповодження з роботою в розмові.
matt wilkie

якщо ви можете це перевірити len(numpy.unique(yourraster)) == 2, то ви знаєте, що він має 2 унікальних значення, і ви можете сміливо це робити.
RemcoGerlich

@Remco Алгоритм, що лежить numpy.uniqueв основі , буде більш обчислювально дорогим (як у часі, так і в просторі), ніж більшість інших способів перевірити, чи різниця є постійною. Якщо зіткнутися з різницею між двома дуже великими растрами з плаваючою точкою, які виявляють багато відмінностей (наприклад, порівняння оригіналу зі стислим версією з втратою), воно, ймовірно, зависне назавжди або повністю вийде з ладу.
whuber

1
@Aaron, я взяв проект, щоб зайнятися іншими справами. Частина цього полягала в тому, що час розробки продовжував зростати: занадто багато крайових випадків для автоматичної обробки, тому було прийнято рішення повернути проблему людям, що генерують зображення, а не виправляти їх. (напр., "Ваша дискова квота - X. Ви навчитесь працювати всередині неї".) Однак gdalcompare.pyпоказала велику обіцянку ( див. відповідь )
matt wilkie

Відповіді:


8

Спробуйте перетворити ваші растри в нумеровані масиви, а потім перевірте, чи вони мають однакову форму та елементи з 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"

Це виглядає мило і просто. Мені цікаво дві деталі (які, хоча вони є технічними, можуть бути вирішальними). По-перше, чи правильно вирішує це рішення значення NoData? По-друге, як його швидкість порівнюється з використанням вбудованих функцій, призначених для порівняння сітки, таких як зональні підсумки?
whuber

1
Хороші бали @whuber. Я зробив швидке пристосування до сценарію, який повинен враховувати форму та елементи. Я перевірю підсумки, які ви підняли, і повідомлю про результати.
Аарон

1
@whuber Що стосується NoDataкерованості, массив RasterToNumPyArrayпризначає за замовчуванням значення NoData растра вхідного растру. Користувач може вказати інше значення, хоча це не стосується випадку Метта. Що стосується швидкості, сценарію знадобилося 4,5 секунди, щоб порівняти 2 4-бітні растри з 6210 стовпцями та 7650 рядками (ступінь DOQQ). Я не порівнював метод із жодними зональними підсумками.
Аарон

1
Я склав еквівалент gdal, адаптований з gis.stackexchange.com/questions/32995/…
matt wilkie

4

Ви можете спробувати скрипт gdalcompare.py http://www.gdal.org/gdalcompare.html . Вихідний код сценарію знаходиться на веб-сторінці http://trac.osgeo.org/gdal/browser/trunk/gdal/swig/python/scripts/gdalcompare.py, і оскільки це сценарій python, слід видалити непотрібне тести та додайте нові, щоб відповідати вашим поточним потребам. Сценарій, схоже, робить порівняння пікселів за пікселями, читаючи дані зображення з двох діапазонів зображень за діапазоном, і це, мабуть, досить швидкий і багаторазовий метод.


1
інтригуючий, я люблю gdal, не знав про цей сценарій. Документи для інтерпретації результатів рідкісні до неіснуючих ;-). Під час мого початкового тестування він повідомляє про відмінності в інтерпретації кольорів та піддонах, тобто це може бути занадто специфічним для моїх поточних потреб. Я все ще досліджую це, хоча. (зауважте: ця відповідь занадто коротка, щоб бути добре придатною тут, лише відповіді на посилання не відволікають, будь ласка, розгляньте їх детальну)
matt wilkie

1

Я б запропонував вам створити свою таблицю атрибутів растру для кожного зображення, а потім можна порівняти таблиці. Це не повна перевірка (як, наприклад, обчислення різниці між ними), але ймовірність того, що ваші зображення відрізняються з однаковими значеннями гістограми, дуже мала. Також він дає вам кількість унікальних значень без NoData (від кількості рядків у таблиці). Якщо ваша загальна кількість менше розміру зображення, ви знаєте, що у вас є пікселі NoData.


Чи буде це працювати з 32-бітовими плавцями? Хіба побудова та порівняння двох таблиць насправді буде швидше (або простіше), ніж вивчення значень різниці двох растрових (які в принципі повинні бути лише нульовими та NoData)?
whuber

Ви маєте рацію, що це не буде працювати з 32-бітовим плаванням, і я не перевіряв швидкість. Однак, будуючи таблицю атрибутів, потрібно прочитати дані лише один раз, і це допоможе уникнути 1-бітового стиснення, коли ви знаєте, що це не вдасться. Також не знаю розмір зображень, але іноді ви не можете зберегти їх у пам'яті.
radouxju

@radouxju зображення мають діапазон до 100 000 пікселів в сторону, тому ~ 30 Гб нестиснений. У нас немає машини з такою великою кількістю барана (хоча, можливо, і з віртуальною ...)
matt wilkie

Схоже, що оперативна пам'ять не буде проблемою, якщо ви дотримуєтесь власних операцій ArcGIS. Це досить добре з використанням оперативної пам’яті при обробці сіток: внутрішньо вона може виконувати обробку по черзі, за групами рядків та прямокутними вікнами. Локальні операції, такі як віднімання однієї сітки від іншої, можуть працювати по суті зі швидкістю введення та виведення, вимагаючи лише одного (відносно крихітного) буфера для кожного вводу даних. Для побудови таблиці атрибутів потрібна додаткова хеш-таблиця - що було б незначно, коли з’являються лише одне або два значення, але може бути величезним для довільних сіток.
whuber

numpy зробить багато заміни з масивами 2 * 30Go, це вже не ArcGIS. Я вважав, що виходячи з екрану друку, що зображення є класифікованими зображеннями (більшість з лише afew значеннями), тому ви не очікуєте так багато класів.
radouxju

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
Один з величезних способів обдурити цю статистику - перестановка вмісту комірки (що може статися, і коли це не зовсім правильно). На дуже великих растрах ані SD, ані середнє значення не може надійно виявити кілька невеликих змін, розкиданих навколо (особливо, якщо просто було скинуто кілька пікселів). Імовірно, вони також не виявлять оптового перекомплектування сітки, за умови використання кубічної згортки (яка призначена для збереження середнього рівня та SD). Замість цього, здавалося б, доцільно порівнювати значення SD різниці сіток до нуля.
whuber

0

Найпростіший спосіб - відняти один растр від іншого, якщо результат дорівнює 0, то обидва зображення однакові. Також ви можете побачити гістограму або графік за кольором результату.


Віднімання здається хорошим способом проведення порівняння. Однак я вважаю, що гістограма не була б дуже корисною для виявлення проблем зі значеннями NoData. Припустимо, наприклад, що процедура стиснення усунула однопіксельну межу навколо сітки (це може статися!), Але в іншому випадку було точно: всі різниці все одно будуть нульовими. Також ви помітили, що ОП потребує цього для 7000 растрових наборів даних? Я не впевнений, що він із задоволенням вивчить 7000 сюжетів.
whuber
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.