如何量化两幅图像之间的差异?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (19)

我想做的是:

我定期用摄像头拍照。有点像时间流逝的事。但是,如果没有什么真正的改变,那就是,这幅画差不多了。相貌同样,我不想存储最新的快照。

我想有一些方法可以量化这种差异,我需要用经验来确定一个阈值。

提问于
用户回答回答于

一般观念

选项1:将两个图像作为数组加载(scipy.misc.imread)并计算一个元素级(逐像素)的差值。计算差额的范数。

选项2:加载两个图像。计算每个特征向量(如直方图)。计算特征向量之间的距离,而不是图像之间的距离。

然而,有一些决定要首先作出。

问题

你应该先回答以下问题:

  • 图像的形状和尺寸是否相同? 如果没有,可能需要调整大小或裁剪它们。PIL库将有助于在Python中完成此操作。 如果它们是用相同的设置和相同的设备拍摄的,它们可能是相同的。
  • 图像是否对齐? 如果不是,可能希望先运行互相关,以找到最佳的对齐第一。SciPy有做这件事的功能。 如果相机和场景仍然存在,图像很可能会很好地对齐。
  • 图像的曝光总是一样的吗?(轻盈/对比是否相同?)
  • 颜色信息重要吗? 如果想要注意颜色的变化,您将有一个颜色值的向量每点,而不是一个标量值,如在灰度图像。在编写这样的代码时,需要更多的注意。
  • 图像中有清晰的边缘吗?他们有可能搬走吗? 如果是的话,可以先应用边缘检测算法(例如,用Sobel或Prewitt变换计算梯度,应用一些阈值),然后比较第一幅图像上的边缘和第二幅图像上的边缘。
  • 图像中有噪音吗? 所有传感器都会对图像造成一定程度的噪声。低成本传感器有更多的噪音。在比较图像之前,可能希望应用一些降噪方法。模糊是这里最简单(但不是最好)的方法。
  • 你想注意什么变化? 这可能会影响对图像之间的差异所使用的规范的选择。 考虑使用曼哈顿范数(绝对值之和)或零范数(不等于零的元素数)来衡量图像变化的程度。前者会告诉你图像有多差,后者只会告诉你多少像素差。

我想你的照片是对齐的,大小和形状都一样,可能有不同的曝光。为了简单起见,我将它们转换为灰度,即使它们是彩色(RGB)图像。

将需要这些进口品:

import sys

from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average

主要功能,读取两幅图像,转换为灰度,比较打印结果:

def main():
    file1, file2 = sys.argv[1:1+2]
    # read images as 2D arrays (convert to grayscale for simplicity)
    img1 = to_grayscale(imread(file1).astype(float))
    img2 = to_grayscale(imread(file2).astype(float))
    # compare
    n_m, n_0 = compare_images(img1, img2)
    print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
    print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size

如何比较。img1img2这里是2D SciPy数组:

def compare_images(img1, img2):
    # normalize to compensate for exposure difference, this may be unnecessary
    # consider disabling it
    img1 = normalize(img1)
    img2 = normalize(img2)
    # calculate the difference and its norms
    diff = img1 - img2  # elementwise for scipy arrays
    m_norm = sum(abs(diff))  # Manhattan norm
    z_norm = norm(diff.ravel(), 0)  # Zero norm
    return (m_norm, z_norm)

如果文件是彩色图像,imread返回一个3D数组,平均RGB通道(最后一个阵列轴)以获得强度。不需要对灰度图像进行处理。.pgm)):

def to_grayscale(arr):
    "If arr is a color image (3D array), convert it to grayscale (2D array)."
    if len(arr.shape) == 3:
        return average(arr, -1)  # average over the last axis (color channels)
    else:
        return arr

规范化是微不足道的,您可以选择将其规范化为0,1而不是0,255。arr这里是一个SciPy数组,所以所有操作都是元素级的:

def normalize(arr):
    rng = arr.max()-arr.min()
    amin = arr.min()
    return (arr-amin)*255/rng

运行main职能:

if __name__ == "__main__":
    main()

现在,您可以将所有这些放在一个脚本中,并针对两个图像运行。如果我们将图像与自身进行比较,就没有什么区别:

$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0

如果我们模糊图像并与原始图像进行比较,就会有一些不同:

$ python compare.py one.jpg one-blurred.jpg 
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0

用户回答回答于

一个简单的解决方案:

将图像编码为JPEG寻找一个重大的改变文件大小

我用视频缩略图实现了类似的东西,并且取得了很大的成功和可伸缩性。

扫码关注云+社区