在python中将url中的图像与文件系统中的图像进行比较 [英] Comparing image in url to image in filesystem in python

查看:17
本文介绍了在python中将url中的图像与文件系统中的图像进行比较的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我从 stackoverflow 中发现了很少的图像比较问题,但没有一个实际上证明了这个问题的答案.

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

def equal(im1, im2):返回 ImageChops.difference(im1, im2).getbbox() 是 None

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

我的代码目前如下:.度量 SSIM (Structural SIMilarity) 涉及更多,您可以在前面包含的链接中找到详细信息.要轻松应用指标,请考虑以下代码:

导入numpy从 scipy.signal 导入 fftconvolvedef ssim(im1, im2, window, k=(0.01, 0.03), l=255):"""见 https://ece.uwaterloo.ca/~z70wang/research/ssim/"""# 检查窗口是否小于图像.对于 a, b in zip(window.shape, im1.shape):如果 a >乙:返回无,无# 根据基本实现,k 中的值必须为正.对于 ki in k:如果 ki <0:返回无,无c1 = (k[0] * l) ** 2c2 = (k[1] * l) ** 2窗口 = 窗口/numpy.sum(窗口)mu1 = fftconvolve(im1, window, mode='valid')mu2 = fftconvolve(im2, window, mode='valid')mu1_sq = mu1 * mu1mu2_sq = mu2 * mu2mu1_mu2 = mu1 * mu2sigma1_sq = fftconvolve(im1 * im1, window, mode='valid') - mu1_sqsigma2_sq = fftconvolve(im2 * im2, window, mode='valid') - mu2_sqsigma12 = fftconvolve(im1 * im2, window, mode='valid') - mu1_mu2如果 c1 >0 和 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别的:num1 = 2 * mu1_mu2 + c1num2 = 2 * sigma12 + c2den1 = mu1_sq + mu2_sq + c1den2 = sigma1_sq + sigma2_sq + c2ssim_map = numpy.ones(numpy.shape(mu1))索引 = (den1 * den2) >0ssim_map[index] = (num1[index] * num2[index])/(den1[index] * den2[index])索引 = (den1 != 0) &(den2 == 0)ssim_map[index] = num1[index]/den1[index]mssim = ssim_map.mean()返回 mssim, ssim_mapdef nrmse(im1, im2):a, b = im1.shapermse = 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))返回 1 - (rmse/(max_val - min_val))如果 __name__ == "__main__":导入系统从 scipy.signal 导入高斯从 PIL 导入图像img1 = Image.open(sys.argv[1])img2 = Image.open(sys.argv[2])如果 img1.size != img2.size:打印错误:图像大小不同"提高系统退出# 为窗口参数创建一个二维高斯win = numpy.array([gaussian(11, 1.5)])win2d = 赢 * (win.T)num_metrics = 2sim_index = [2 for _ in xrange(num_metrics)]对于 zip(img1.split(), img2.split()) 中的 band1、band2:b1 = numpy.asarray(band1, dtype=numpy.double)b2 = numpy.asarray(band2, dtype=numpy.double)# SSIMres, smap = ssim(b1, b2, win2d)m = [res, nrmse(b1, b2)]对于 xrange(num_metrics) 中的 i:sim_index[i] = min(m[i], sim_index[i])打印结果:",sim_index

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

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

I've found few image compare questions from stackoverflow 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:

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).

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

解决方案

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.

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.

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.

Results (rounded):

  • 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

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).

  • NRMSE(f, g) = 0.92
  • 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:

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.

这篇关于在python中将url中的图像与文件系统中的图像进行比较的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆