比较url中的图像与python中文件系统中的图像

Osk*_*emi 4 python diff image-comparison image-processing python-imaging-library

有没有一种快速简便的方法来进行这种比较?

我发现很少有来自stackoverflow的图像比较问题,但没有一个真正证明了这个问题的答案.

我的文件系统中有图像文件,还有一个从URL中获取图像的脚本.我想检查url中的图像是否与磁盘上的图像相同.通常我会将磁盘和url中的图像加载到PIL对象并使用我发现的以下函数:

def equal(im1, im2):
    return ImageChops.difference(im1, im2).getbbox() is None
Run Code Online (Sandbox Code Playgroud)

但是,如果使用PIL将图像保存到磁盘,即使将质量设置为100,它也会被压缩,但这不起作用im1.save(outfile,quality=100).

我的代码目前正在关注:http: //pastebin.com/295kDMsp 但图像总是最终重新保存.

mmg*_*mgp 14

问题的标题表明你有两个精确的图像可供比较,而这很简单.现在,如果您有相似的图像进行比较,那么这就解释了为什么您没有找到一个完全令人满意的答案:没有适用于给出预期结果的每个问题的指标(请注意,预期结果因应用程序而异).其中一个问题是很难 - 在没有共同协议的意义上 - 将图像与多个波段(如彩色图像)进行比较.为了解决这个问题,我将考虑在每个频段中应用给定的度量,并且该度量的结果将是最低的结果值.这假设度量具有良好建立的范围,如[0,1],并且此范围中的最大值意味着图像相同(通过给定度量).相反,最小值意味着图像完全不同.

所以,我在这里要做的就是给你两个指标.其中一个是SSIM,另一个是我称之为NRMSE(均方误差的根的归一化).我选择提出第二个,因为它是一个非常简单的方法,它可能足以解决您的问题.

让我们开始举例.图像按此顺序排列:f = PNG中的原始图像,g1 = 50%质量f(制作convert f -quality 50 g),g2 = JPEG 1%质量f,h ="亮"g2.

在此输入图像描述 在此输入图像描述 在此输入图像描述 在此输入图像描述

结果(四舍五入):

  • NRMSE(f,g1)= 0.96
  • NRMSE(f,g2)= 0.88
  • NRMSE(f,h)= 0.63
  • SSIM(f,g1)= 0.98
  • SSIM(f,g2)= 0.81
  • SSIM(f,h)= 0.55

在某种程度上,这两个指标都很好地处理了修改,但是SSIM当图像实际上在视觉上不同时,通过报告较低的相似性,以及当图像在视觉上非常相似时报告更高的值,显示更加明智.下一个示例考虑彩色图像(f =原始图像,g = JPEG,质量为5%).

在此输入图像描述 在此输入图像描述

  • NRMSE(f,g)= 0.92
  • SSIM(f,g)= 0.61

因此,您需要确定自己喜欢的指标和阈值.

现在,指标.我称之为NRMSE的只是1 - [RMSE /(maxval- minval)].maxval来自两个图像的最大强度在哪里被比较,并且分别相同minval.RMSE由MSE的平方根给出:sqrt [(sum(A - B)**2)/ | A |],其中| A | 表示A中元素的数量.通过这样做,RMSE给出的最大值是maxval.如果您想进一步了解MSE在图像中的含义,请参阅https://ece.uwaterloo.ca/~z70wang/publications/SPM09.pdf.度量标准SSIM(结构类似性)更复杂,您可以在之前包含的链接中找到详细信息.要轻松应用指标,请考虑以下代码:

import numpy
from scipy.signal import fftconvolve

def ssim(im1, im2, window, k=(0.01, 0.03), l=255):
    """See https://ece.uwaterloo.ca/~z70wang/research/ssim/"""
    # Check if the window is smaller than the images.
    for a, b in zip(window.shape, im1.shape):
        if a > b:
            return None, None
    # Values in k must be positive according to the base implementation.
    for ki in k:
        if ki < 0:
            return None, None

    c1 = (k[0] * l) ** 2
    c2 = (k[1] * l) ** 2
    window = window/numpy.sum(window)

    mu1 = fftconvolve(im1, window, mode='valid')
    mu2 = fftconvolve(im2, window, mode='valid')
    mu1_sq = mu1 * mu1
    mu2_sq = mu2 * mu2
    mu1_mu2 = mu1 * mu2
    sigma1_sq = fftconvolve(im1 * im1, window, mode='valid') - mu1_sq
    sigma2_sq = fftconvolve(im2 * im2, window, mode='valid') - mu2_sq
    sigma12 = fftconvolve(im1 * im2, window, mode='valid') - mu1_mu2

    if c1 > 0 and c2 > 0:
        num = (2 * mu1_mu2 + c1) * (2 * sigma12 + c2)
        den = (mu1_sq + mu2_sq + c1) * (sigma1_sq + sigma2_sq + c2)
        ssim_map = num / den
    else:
        num1 = 2 * mu1_mu2 + c1
        num2 = 2 * sigma12 + c2
        den1 = mu1_sq + mu2_sq + c1
        den2 = sigma1_sq + sigma2_sq + c2
        ssim_map = numpy.ones(numpy.shape(mu1))
        index = (den1 * den2) > 0
        ssim_map[index] = (num1[index] * num2[index]) / (den1[index] * den2[index])
        index = (den1 != 0) & (den2 == 0)
        ssim_map[index] = num1[index] / den1[index]

    mssim = ssim_map.mean()
    return mssim, ssim_map


def nrmse(im1, im2):
    a, b = im1.shape
    rmse = numpy.sqrt(numpy.sum((im2 - im1) ** 2) / float(a * b))
    max_val = max(numpy.max(im1), numpy.max(im2))
    min_val = min(numpy.min(im1), numpy.min(im2))
    return 1 - (rmse / (max_val - min_val))


if __name__ == "__main__":
    import sys
    from scipy.signal import gaussian
    from PIL import Image

    img1 = Image.open(sys.argv[1])
    img2 = Image.open(sys.argv[2])

    if img1.size != img2.size:
        print "Error: images size differ"
        raise SystemExit

    # Create a 2d gaussian for the window parameter
    win = numpy.array([gaussian(11, 1.5)])
    win2d = win * (win.T)

    num_metrics = 2
    sim_index = [2 for _ in xrange(num_metrics)]
    for band1, band2 in zip(img1.split(), img2.split()):
        b1 = numpy.asarray(band1, dtype=numpy.double)
        b2 = numpy.asarray(band2, dtype=numpy.double)
        # SSIM
        res, smap = ssim(b1, b2, win2d)

        m = [res, nrmse(b1, b2)]
        for i in xrange(num_metrics):
            sim_index[i] = min(m[i], sim_index[i])

    print "Result:", sim_index
Run Code Online (Sandbox Code Playgroud)

请注意,ssim当给定window值大于它们时,拒绝比较图像.在window通常是非常小的,默认为11×11,因此,如果您的图片小于,没有什么太大的"结构"(从指标的名称)来比较,你应该用别的东西(像其他功能nrmse).可能有一种更好的实现方式ssim,因为在Matlab中运行速度要快得多.