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

时间:2021-12-07 06:09:40

Is there a quick and easy way to do such comparison?

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

I've found few image compare questions from * but none of those actually proved answer for this question.

我发现很少有来自*的图像比较问题,但实际上没有一个问题可以回答这个问题。

I have images files in my filesystem and a script that fetches images from urls. I want to check if the image in url is already the same that is on disk. Normally I would load the image in disk and url to a PIL object and use following function I found:

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

def equal(im1, im2):
    return ImageChops.difference(im1, im2).getbbox() is None

but this doesn't work if you have a image saved to disk with PIL as it gets compressed even if you turn the quality to 100 im1.save(outfile,quality=100).

但是,如果将图像保存到磁盘并使用PIL进行压缩,即使将质量转换为100 im1.save(outfile,quality = 100),这也不起作用。

My code is currently following: http://pastebin.com/295kDMsp but the image always ends up re-saved.

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

3 个解决方案

#1


12  

The question's title suggests you have two exact images to compare, and that is trivially done. Now, if you have similar images to compare then that explains why you didn't find a fully satisfactory answer: there is no metric applicable to every problem that gives the expected results (note that expected results varies between applications). One of the problems is that it is hard -- in the sense that there is no common agreement -- to compare images with multiple bands, like color images. To handle that, I will consider the application of a given metric in each band, and the result of that metric will be the lowest resulting value. This assumes the metric has a well established range, like [0, 1], and the maximum value in this range means the images are identical (by the given metric). Conversely, the minimum value means the images are totally different.

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

So, all I will do here is give you two metrics. One of them is SSIM and the other one I will call as NRMSE (a normalization of the root of the mean squared error). I choose to present the second one because it is a very simple method, and it may be enough for your problem.

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

Let us get started with examples. The images are in this order: f = original image in PNG, g1 = JPEG at 50% quality of f (made with convert f -quality 50 g), g2 = JPEG 1% quality of f, h = "lightened" g2.

让我们开始举例。图像按此顺序排列:f = PNG中的原始图像,g1 = 50%质量f(用转换f质量50 g制成),g2 = JPEG 1%质量f,h =“亮”g2。

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

Results (rounded):

结果(四舍五入):

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

In a way, both metrics handled well the modifications but SSIM showed to be a more sensible by reporting lower similarities when images were in fact visually distinct, and by reporting a higher value when the images were visually very similar. The next example considers a color image (f = original image, and g = JPEG at 5% quality).

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

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

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

So, it is up to you to determine what is the metric you prefer and a threshold value for it.

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

Now, the metrics. What I denominated as NRMSE is simply 1 - [RMSE / (maxval - minval)]. Where maxval is the maximum intensity from the two images being compared, and respectively the same for minval. RMSE is given by the square root of MSE: sqrt[(sum(A - B) ** 2) / |A|], where |A| means the number of elements in A. By doing this, the maximum value given by RMSE is maxval. If you want to further understand the meaning of MSE in images, see, for example, https://ece.uwaterloo.ca/~z70wang/publications/SPM09.pdf. The metric SSIM (Structural SIMilarity) is more involved, and you can find details in the earlier included link. To easily apply the metrics, consider the following code:

现在,指标。我称之为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

Note that ssim refuses to compare images when the given window is larger than them. The window is typically very small, default is 11x11, so if your images are smaller than that, there is no much "structure" (from the name of the metric) to compare and you should use something else (like the other function nrmse). Probably there is a better way to implement ssim, since in Matlab this run much faster.

请注意,当给定窗口大于它们时,ssim拒绝比较图像。窗口通常非常小,默认为11x11,因此如果您的图像小于该值,则没有太多“结构”(来自度量标准的名称)进行比较,您应该使用其他东西(如其他函数nrmse) 。可能有更好的方法来实现ssim,因为在Matlab中运行速度要快得多。

#2


1  

You can make your own comparison - using square difference. You will then set up a threshold, like 95% and if they are that similar, then you don't have to download it. It eliminates the problem of compression

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

#3


0  

Along the lines of Bartlomiej Lewandowski's suggestion, I would recommend comparing histogram entropy, which is easy and relatively quick to calculate:

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

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]

... This function is one that I use in a auto-square-crop filter I built — but you can use the entropy value to compare any two images (even of disparate size).

...这个函数是我在我构建的自动方形裁剪滤镜中使用的 - 但你可以使用熵值来比较任何两个图像(甚至是不同大小)。

I have other examples of the application of this sort of idea, let me know with a comment if you'd like me to send a specific example your way.

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

#1


12  

The question's title suggests you have two exact images to compare, and that is trivially done. Now, if you have similar images to compare then that explains why you didn't find a fully satisfactory answer: there is no metric applicable to every problem that gives the expected results (note that expected results varies between applications). One of the problems is that it is hard -- in the sense that there is no common agreement -- to compare images with multiple bands, like color images. To handle that, I will consider the application of a given metric in each band, and the result of that metric will be the lowest resulting value. This assumes the metric has a well established range, like [0, 1], and the maximum value in this range means the images are identical (by the given metric). Conversely, the minimum value means the images are totally different.

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

So, all I will do here is give you two metrics. One of them is SSIM and the other one I will call as NRMSE (a normalization of the root of the mean squared error). I choose to present the second one because it is a very simple method, and it may be enough for your problem.

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

Let us get started with examples. The images are in this order: f = original image in PNG, g1 = JPEG at 50% quality of f (made with convert f -quality 50 g), g2 = JPEG 1% quality of f, h = "lightened" g2.

让我们开始举例。图像按此顺序排列:f = PNG中的原始图像,g1 = 50%质量f(用转换f质量50 g制成),g2 = JPEG 1%质量f,h =“亮”g2。

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

Results (rounded):

结果(四舍五入):

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

In a way, both metrics handled well the modifications but SSIM showed to be a more sensible by reporting lower similarities when images were in fact visually distinct, and by reporting a higher value when the images were visually very similar. The next example considers a color image (f = original image, and g = JPEG at 5% quality).

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

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

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

So, it is up to you to determine what is the metric you prefer and a threshold value for it.

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

Now, the metrics. What I denominated as NRMSE is simply 1 - [RMSE / (maxval - minval)]. Where maxval is the maximum intensity from the two images being compared, and respectively the same for minval. RMSE is given by the square root of MSE: sqrt[(sum(A - B) ** 2) / |A|], where |A| means the number of elements in A. By doing this, the maximum value given by RMSE is maxval. If you want to further understand the meaning of MSE in images, see, for example, https://ece.uwaterloo.ca/~z70wang/publications/SPM09.pdf. The metric SSIM (Structural SIMilarity) is more involved, and you can find details in the earlier included link. To easily apply the metrics, consider the following code:

现在,指标。我称之为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

Note that ssim refuses to compare images when the given window is larger than them. The window is typically very small, default is 11x11, so if your images are smaller than that, there is no much "structure" (from the name of the metric) to compare and you should use something else (like the other function nrmse). Probably there is a better way to implement ssim, since in Matlab this run much faster.

请注意,当给定窗口大于它们时,ssim拒绝比较图像。窗口通常非常小,默认为11x11,因此如果您的图像小于该值,则没有太多“结构”(来自度量标准的名称)进行比较,您应该使用其他东西(如其他函数nrmse) 。可能有更好的方法来实现ssim,因为在Matlab中运行速度要快得多。

#2


1  

You can make your own comparison - using square difference. You will then set up a threshold, like 95% and if they are that similar, then you don't have to download it. It eliminates the problem of compression

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

#3


0  

Along the lines of Bartlomiej Lewandowski's suggestion, I would recommend comparing histogram entropy, which is easy and relatively quick to calculate:

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

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]

... This function is one that I use in a auto-square-crop filter I built — but you can use the entropy value to compare any two images (even of disparate size).

...这个函数是我在我构建的自动方形裁剪滤镜中使用的 - 但你可以使用熵值来比较任何两个图像(甚至是不同大小)。

I have other examples of the application of this sort of idea, let me know with a comment if you'd like me to send a specific example your way.

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