栅格差异:如何检查图像是否具有相同的值?


10

是否可以检查给定的2个栅格图层是否具有相同的内容

我们的公司共享存储量有一个问题:它太大了,需要三天以上的时间才能进行完整备份。初步调查显示,占用空间最大的罪魁祸首之一是应使用CCITT压缩将开/关栅格真正存储为1位图层。

典型的当前/不存在栅格

该示例图像当前为2位(因此有3个可能的值),并保存为文件系统中11 MB的LZW压缩tiff。转换为1bit(所以有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,但是除了可以避免手动检查所有这些图像以确保覆盖之前的正确性之外,其他所有功能都可以使用。错误地转换和覆盖确实具有超过开/关值的图像将是可怕的。其中大多数会花费数千美元来收集和生成。

一个非常糟糕的结果

更新:最大的违规者是32位浮点数,每边最大可达100,000px,因此约30GB未压缩。


1
一种实现raster_diff(old_img, new_img) == "Identical"方式是检查差的绝对值的区域最大值等于0,其中该区域在整个网格范围内进行。这是您要找的解决方案吗?(如果是这样,则还需要完善以检查所有NoData值是否也是一致的。)
whuber

1
@whuber感谢您确保NoData在对话中保持适当的处理。
马特·威尔基

如果您可以检查len(numpy.unique(yourraster)) == 2,则说明它具有2个唯一值,您可以放心地执行此操作。
RemcoGerlich 2014年

@Remco numpy.unique与检查差异是否为常数的大多数其他方法相比,底层的算法在计算上(在时间和空间上)将更加昂贵。当面对表现出许多差异的两个非常大的浮点栅格之间的差异时(例如将原始版本与有损压缩版本进行比较),它可能会永远陷入困境或完全失败。
ub

1
@Aaron,我退出该项目去做其他事情。部分原因是开发时间持续增长:太多的边缘案例无法自动处理,因此决定将问题归咎于生成图像的人,而不是修复它们。(例如,“您的磁盘配额为X。您将学习如何在其中使用磁盘。”)但是gdalcompare.py显示出了很大的希望(请参阅答案
matt wilkie 2015年

Answers:


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"

看起来很简单。我对两个细节感到好奇(尽管它们是技术性的,但可能很关键)。首先,此解决方案是否正确处理NoData值?其次,与使用用于网格比较的内置功能(例如区域汇总)相比,其速度如何?
whuber

1
好点@whuber。我对脚本进行了快速调整,应考虑形状和元素。我将检查您提出的要点并报告调查结果。
亚伦

1
@whuber关于NoData处理,RasterToNumPyArray默认情况下将输入栅格的NoData值分配给数组。用户可以指定其他值,尽管这不适用于Matt的情况。关于速度,脚本花了4.5秒时间比较了2个具有6210列和7650行(DOQQ范围)的4位栅格。我没有将该方法与任何区域摘要进行比较。
亚伦

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脚本,因此应该很容易删除不必要的内容测试并添加新的内容以适合您当前的需求。该脚本似乎通过逐条读取两个图像中的图像数据来进行逐像素比较,这可能是一种快速且可重用的方法。


1
有趣的是,我爱gdal,不知道这个脚本。虽然,解释结果的文档很少;-)。在我的初始测试中,它报告了颜色解释和调色板的差异,这意味着它可能太适合我当前的需求。我仍然在探索它。(请注意:此答案太短,不足以适合此处,不建议仅链接答案,请考虑充实它)。
马特·威尔基

1

我建议您为每个图像构建栅格属性表,然后可以比较这些表。这不是一个完整的检查(例如计算两者之间的差异),但是在相同的直方图值下图像不同的可能性非常小。此外,它还为您提供不带NoData的唯一值的数量(根据表中的行数)。如果您的总数小于图像大小,则说明您有NoData像素。


可以使用32位浮点数吗?与检查两个栅格的差值(原则上应该只是零和NoData)相比,建立和比较两个表实际上会更快(或更容易)吗?
ub

没错,它不适用于32位浮点,并且我没有检查速度。但是,构建属性表只需要读取一次数据,当您知道它将失败时,可以帮助避免1位压缩。我也不知道图像的大小,但是有时您无法将它们存储在内存中。
radouxju 2014年

@radouxju图像的一侧最多可容纳100,000像素,因此约30GB未压缩。我们没有配备那么多内存的机器(尽管也许有虚拟机……)
马特·威尔基

如果您坚持使用ArcGIS本机操作,似乎RAM不会成为问题。处理网格时,RAM使用情况非常好:在内部,它可以逐行,按行组和按矩形窗口进行处理。像从另一个网格中减去一个网格之类的本地操作基本上可以以输入和输出的速度进行操作,每个输入数据集仅需要一个(相对较小的)缓冲区。构造属性表需要一个附加的哈希表-当仅显示一个或两个值时,该表很小,但对于任意网格来说可能是巨大的。
ub

numpy将与2 * 30Go数组进行大量交换,这不再是ArcGIS。基于打印屏幕,我假设图像是分类图像(大多数图像只有少量值),因此您不会期望这么多的类。
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
愚弄这些统计信息的一种重要方法是对单元格内容进行置换(当图像尺寸不太正确时,可能会发生并且确实会发生)。在非常大的栅格上,SD和均值均无法可靠地检测到一些零散的微小变化(尤其是如果只是掉落了几个像素)。可以想象,如果使用三次卷积(其目的是保留均值和SD),它们也不会检测到整个网格的重采样。相反,将网格差异的SD比较为零似乎是审慎的做法。
ub

0

最简单的方法是从另一个栅格中减去一个栅格,如果结果为0,则两个图像都相同。您也可以查看直方图或按颜色绘制结果。


减法似乎是进行比较的好方法。但是,我相信直方图对检测NoData值的问题不是很有用。例如,假设压缩过程消除了网格周围的一个像素边界(这可能发生!),但否则是准确的:所有差异仍然为零。另外,您是否注意到OP需要使用7000个栅格数据集来执行此操作?我不确定他会喜欢检查7000个地块。
ub
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.