首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在python中比较url中的图像与文件系统中的图像

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

Stack Overflow用户
提问于 2012-12-14 17:36:39
回答 3查看 7K关注 0票数 5

有没有一种快速简单的方法来做这样的比较?

我在stackoverflow中发现了很少的图像比较问题,但这些问题都没有真正证明对这个问题的答案。

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

代码语言:javascript
复制
def equal(im1, im2):
    return ImageChops.difference(im1, im2).getbbox() is None

但是,即使你将图像质量调到100 im1.save(outfile,quality=100),如果你在压缩时用PIL将图像保存到磁盘上,这种方法也不起作用。

我的代码目前如下:http://pastebin.com/295kDMsp,但图像总是会被重新保存。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-12-15 03:18:19

这个问题的标题表明你有两个确切的图像要比较,这是微不足道的。现在,如果您有相似的图像要比较,那么这就解释了为什么您没有找到完全令人满意的答案:没有适用于每个问题的度量标准,这些问题给出了预期的结果(请注意,预期的结果因应用程序而异)。其中一个问题是,很难比较具有多个波段的图像,比如彩色图像,因为在某种意义上没有共同的共识。为了处理这一问题,我将考虑在每个频段中应用给定的度量,该度量的结果将是最低的结果值。这假设度量有一个很好的范围,如0,1,并且这个范围中的最大值意味着图像是相同的(通过给定的度量)。相反,最小值表示图像完全不同。

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

让我们从示例开始。图像的顺序如下:f=原始图像为PNG,g1 = 50%质量的f (用convert f -quality 50 g制作)的JPEG,g2 = 1%质量的f的JPEG,h=“加亮的”g2。

结果(舍入):

0.96

  • NRMSE(f,0.88

  • NRMSE(f,(f,g2) =0.96

  • NRMSE(f,g2) = 0.63

  • SSIM(f,g1) = 0.98

  • SSIM(f,g2)= 0.81

  • SSIM(f,h) = 0.55

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

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

因此,您可以决定您喜欢的指标以及它的阈值。

现在,指标。我命名为NRMSE的是简单的1- RMSE / (maxval - minval)。其中,maxval是来自被比较的两个图像的最大强度,对于minval分别相同。均方根由MSE的平方根给出: sqrt(sum(A - B) ** 2) / | A |,其中|A|表示A中的元素数。通过这样做,RMSE给出的最大值是maxval。如果您想进一步了解图像中MSE的含义,例如,请参阅https://ece.uwaterloo.ca/~z70wang/publications/SPM09.pdf。指标SSIM (Structural SIMilarity)涉及更多,您可以在前面包含的链接中找到详细信息。要轻松应用这些指标,请考虑以下代码:

代码语言:javascript
复制
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

请注意,当给定的window大于图像时,ssim拒绝比较图像。window通常非常小,默认为11x11,因此如果您的图像小于11x11,则没有太多的“结构”(来自度量的名称)可供比较,您应该使用其他函数(如另一个函数nrmse)。也许有一种更好的方法来实现ssim,因为在Matlab中运行起来要快得多。

票数 15
EN

Stack Overflow用户

发布于 2012-12-14 17:44:33

您可以进行自己的比较-使用平方差。然后你将设置一个阈值,比如95%,如果它们是如此相似,那么你就不需要下载它。它消除了压缩的问题

票数 1
EN

Stack Overflow用户

发布于 2012-12-14 17:55:50

按照Bartlomiej Lewandowski的建议,我建议比较直方图熵,它很容易计算,而且相对快速:

代码语言:javascript
复制
def histogram_entropy(im):
    """ Calculate the entropy of an images' histogram.
    Used for "smart cropping" in easy-thumbnails;
    see also https://raw.github.com/SmileyChris/easy-thumbnails/master/easy_thumbnails/utils.py
    """
    if not isinstance(im, Image.Image):
        return 0  # Fall back to a constant entropy.

    histogram = im.histogram()
    hist_ceil = float(sum(histogram))
    histonorm = [histocol / hist_ceil for histocol in histogram]

..。此函数是我在构建的auto-square-crop filter中使用的函数-但您可以使用熵值来比较任何两个图像(即使大小不同)。

我还有其他应用这种想法的例子,如果你想让我以你的方式发送一个具体的例子,请在评论中告诉我。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13875989

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档