图像比较算法

发布于 2024-08-13 07:33:06 字数 777 浏览 3 评论 0原文

我试图将图像相互比较以找出它们是否不同。首先,我尝试对 RGB 值进行皮尔逊相关,除非图片有一点偏移,否则效果也相当好。因此,如果一张图像 100% 相同,但其中一张稍微移动了一点,我会得到一个很差的相关值。

对于更好的算法有什么建议吗?

顺便说一句,我正在谈论比较数千张图像......

编辑: 这是我的图片示例(微观):

im1:

在此处输入图像描述

im2:

在此处输入图像描述

im3:

在此处输入图像描述

im1 和 im2 相同,但有一点移位/剪切,im3 应该被认为是完全不同的...

编辑: 根据Peter Hansen的建议问题已经解决了!效果很好!感谢所有答案!一些结果可以在这里找到 http://labtools.ipk-gatersleben.de/image%20comparison/image %20comparison.pdf

I'm trying to compare images to each other to find out whether they are different. First I tried to make a Pearson correleation of the RGB values, which works also quite good unless the pictures are a litte bit shifted. So if a have a 100% identical images but one is a little bit moved, I get a bad correlation value.

Any suggestions for a better algorithm?

BTW, I'm talking about to compare thousand of imgages...

Edit:
Here is an example of my pictures (microscopic):

im1:

enter image description here

im2:

enter image description here

im3:

enter image description here

im1 and im2 are the same but a little bit shifted/cutted, im3 should be recognized as completly different...

Edit:
Problem is solved with the suggestions of Peter Hansen! Works very well! Thanks to all answers! Some results can be found here
http://labtools.ipk-gatersleben.de/image%20comparison/image%20comparision.pdf

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

Saygoodbye 2024-08-20 07:33:06

一年前曾提出过一个类似问题,并得到了众多回复,包括关于图像像素化的一项,我建议这至少作为资格预审步骤(因为它会很快排除非常不相似的图像)。

那里还有一些更早的问题的链接,这些问题有更多的参考资料和很好的答案。

这是使用 Scipy 的一些想法的实现,使用上面的三个图像(分别保存为 im1.jpg、im2.jpg、im3.jpg)。最终输出显示 im1 与其自身进行比较(作为基线),然后将每个图像与其他图像进行比较。

>>> import scipy as sp
>>> from scipy.misc import imread
>>> from scipy.signal.signaltools import correlate2d as c2d
>>>
>>> def get(i):
...     # get JPG image as Scipy array, RGB (3 layer)
...     data = imread('im%s.jpg' % i)
...     # convert to grey-scale using W3C luminance calc
...     data = sp.inner(data, [299, 587, 114]) / 1000.0
...     # normalize per http://en.wikipedia.org/wiki/Cross-correlation
...     return (data - data.mean()) / data.std()
...
>>> im1 = get(1)
>>> im2 = get(2)
>>> im3 = get(3)
>>> im1.shape
(105, 401)
>>> im2.shape
(109, 373)
>>> im3.shape
(121, 457)
>>> c11 = c2d(im1, im1, mode='same')  # baseline
>>> c12 = c2d(im1, im2, mode='same')
>>> c13 = c2d(im1, im3, mode='same')
>>> c23 = c2d(im2, im3, mode='same')
>>> c11.max(), c12.max(), c13.max(), c23.max()
(42105.00000000259, 39898.103896795357, 16482.883608327804, 15873.465425120798)

因此请注意,im1 与其自身相比给出的分数为 42105,im2 与 im1 相比相差不远,但 im3 与其他任何一个相比给出的分数远低于该值的一半。您必须尝试其他图像才能了解其效果如何以及如何改进它。

运行时间很长......在我的机器上需要几分钟。我会尝试一些预过滤,以避免浪费时间比较非常不同的图像,也许使用在回答其他问题时提到的“比较 jpg 文件大小”技巧,或者使用像素化。事实上,你拥有不同尺寸的图像,这让事情变得复杂,但你没有提供足够的信息来说明人们可能期望的屠杀程度,因此很难给出考虑到这一点的具体答案。

A similar question was asked a year ago and has numerous responses, including one regarding pixelizing the images, which I was going to suggest as at least a pre-qualification step (as it would exclude very non-similar images quite quickly).

There are also links there to still-earlier questions which have even more references and good answers.

Here's an implementation using some of the ideas with Scipy, using your above three images (saved as im1.jpg, im2.jpg, im3.jpg, respectively). The final output shows im1 compared with itself, as a baseline, and then each image compared with the others.

>>> import scipy as sp
>>> from scipy.misc import imread
>>> from scipy.signal.signaltools import correlate2d as c2d
>>>
>>> def get(i):
...     # get JPG image as Scipy array, RGB (3 layer)
...     data = imread('im%s.jpg' % i)
...     # convert to grey-scale using W3C luminance calc
...     data = sp.inner(data, [299, 587, 114]) / 1000.0
...     # normalize per http://en.wikipedia.org/wiki/Cross-correlation
...     return (data - data.mean()) / data.std()
...
>>> im1 = get(1)
>>> im2 = get(2)
>>> im3 = get(3)
>>> im1.shape
(105, 401)
>>> im2.shape
(109, 373)
>>> im3.shape
(121, 457)
>>> c11 = c2d(im1, im1, mode='same')  # baseline
>>> c12 = c2d(im1, im2, mode='same')
>>> c13 = c2d(im1, im3, mode='same')
>>> c23 = c2d(im2, im3, mode='same')
>>> c11.max(), c12.max(), c13.max(), c23.max()
(42105.00000000259, 39898.103896795357, 16482.883608327804, 15873.465425120798)

So note that im1 compared with itself gives a score of 42105, im2 compared with im1 is not far off that, but im3 compared with either of the others gives well under half that value. You'd have to experiment with other images to see how well this might perform and how you might improve it.

Run time is long... several minutes on my machine. I would try some pre-filtering to avoid wasting time comparing very dissimilar images, maybe with the "compare jpg file size" trick mentioned in responses to the other question, or with pixelization. The fact that you have images of different sizes complicates things, but you didn't give enough information about the extent of butchering one might expect, so it's hard to give a specific answer that takes that into account.

噩梦成真你也成魔 2024-08-20 07:33:06

我已经通过图像直方图比较来完成此操作。我的基本算法是这样的:

  1. 将图像分割为红色、绿色和蓝色
  2. 为红色、绿色和蓝色通道创建标准化直方图,并将它们连接成向量 (r0...rn, g0...gn, b0... bn) 其中 n 是“桶”的数量,256 应该足够
  3. 从另一张图像的直方图中减去该直方图并计算距离,

这里是一些使用 numpy的代码pil

r = numpy.asarray(im.convert( "RGB", (1,0,0,0, 1,0,0,0, 1,0,0,0) ))
g = numpy.asarray(im.convert( "RGB", (0,1,0,0, 0,1,0,0, 0,1,0,0) ))
b = numpy.asarray(im.convert( "RGB", (0,0,1,0, 0,0,1,0, 0,0,1,0) ))
hr, h_bins = numpy.histogram(r, bins=256, new=True, normed=True)
hg, h_bins = numpy.histogram(g, bins=256, new=True, normed=True)
hb, h_bins = numpy.histogram(b, bins=256, new=True, normed=True)
hist = numpy.array([hr, hg, hb]).ravel()

如果你有两个直方图,你可以这样得到距离:

diff = hist1 - hist2
distance = numpy.sqrt(numpy.dot(diff, diff))

如果两个图像相同,距离为0,它们越发散,距离越大。

它对我来说对于照片来说效果很好,但对于文本和徽标等图形却失败了。

I have one done this with an image histogram comparison. My basic algorithm was this:

  1. Split image into red, green and blue
  2. Create normalized histograms for red, green and blue channel and concatenate them into a vector (r0...rn, g0...gn, b0...bn) where n is the number of "buckets", 256 should be enough
  3. subtract this histogram from the histogram of another image and calculate the distance

here is some code with numpy and pil

r = numpy.asarray(im.convert( "RGB", (1,0,0,0, 1,0,0,0, 1,0,0,0) ))
g = numpy.asarray(im.convert( "RGB", (0,1,0,0, 0,1,0,0, 0,1,0,0) ))
b = numpy.asarray(im.convert( "RGB", (0,0,1,0, 0,0,1,0, 0,0,1,0) ))
hr, h_bins = numpy.histogram(r, bins=256, new=True, normed=True)
hg, h_bins = numpy.histogram(g, bins=256, new=True, normed=True)
hb, h_bins = numpy.histogram(b, bins=256, new=True, normed=True)
hist = numpy.array([hr, hg, hb]).ravel()

if you have two histograms, you can get the distance like this:

diff = hist1 - hist2
distance = numpy.sqrt(numpy.dot(diff, diff))

If the two images are identical, the distance is 0, the more they diverge, the greater the distance.

It worked quite well for photos for me but failed on graphics like texts and logos.

蓝海 2024-08-20 07:33:06

你确实需要更好地具体说明问题,但是,看看这 5 张图像,生物体似乎都以相同的方式定向。如果总是这种情况,您可以尝试进行归一化互相关< /a> 比较两幅图像,取峰值作为你的相似度。我不知道Python中的归一化互相关函数,但有一个类似的 fftconvolve() 函数,您可以自己进行循环互相关:

a = asarray(Image.open('c603225337.jpg').convert('L'))
b = asarray(Image.open('9b78f22f42.jpg').convert('L'))
f1 = rfftn(a)
f2 = rfftn(b)
g =  f1 * f2
c = irfftn(g)

这不会像编写的那样工作,因为图像大小不同,并且输出根本没有加权或标准化。

输出峰值的位置表示两幅图像之间的偏移,峰值的大小表示相似度。应该有一种方法对其进行加权/标准化,以便您可以区分良好的匹配和不良的匹配。

这并不是我想要的那么好的答案,因为我还没有弄清楚如何规范化它,但如果我弄清楚了,我会更新它,它会给你一个研究的想法。

You really need to specify the question better, but, looking at those 5 images, the organisms all seem to be oriented the same way. If this is always the case, you can try doing a normalized cross-correlation between the two images and taking the peak value as your degree of similarity. I don't know of a normalized cross-correlation function in Python, but there is a similar fftconvolve() function and you can do the circular cross-correlation yourself:

a = asarray(Image.open('c603225337.jpg').convert('L'))
b = asarray(Image.open('9b78f22f42.jpg').convert('L'))
f1 = rfftn(a)
f2 = rfftn(b)
g =  f1 * f2
c = irfftn(g)

This won't work as written since the images are different sizes, and the output isn't weighted or normalized at all.

The location of the peak value of the output indicates the offset between the two images, and the magnitude of the peak indicates the similarity. There should be a way to weight/normalize it so that you can tell the difference between a good match and a poor match.

This isn't as good of an answer as I want, since I haven't figured out how to normalize it yet, but I'll update it if I figure it out, and it will give you an idea to look into.

絕版丫頭 2024-08-20 07:33:06

如果您的问题与移位像素有关,也许您应该与频率变换进行比较。

FFT 应该没问题(numpy有一个二维矩阵的实现),但我总是听说小波更适合这种任务^_^

关于性能,如果所有图像都具有相同的大小,如果我没记错的话, FFTW 包为每个 FFT 输入大小创建了一个专门的函数,因此您可以重用相同的代码获得很好的性能提升...我不知道 numpy 是否基于 FFTW,但如果不是,也许您可​​以尝试调查一个那里有一点点。

这里你有一个原型......你可以稍微玩一下它,看看哪个阈值适合你的图像。

import Image
import numpy
import sys

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

    if img1.size != img2.size or img1.getbands() != img2.getbands():
        return -1

    s = 0
    for band_index, band in enumerate(img1.getbands()):
        m1 = numpy.fft.fft2(numpy.array([p[band_index] for p in img1.getdata()]).reshape(*img1.size))
        m2 = numpy.fft.fft2(numpy.array([p[band_index] for p in img2.getdata()]).reshape(*img2.size))
        s += numpy.sum(numpy.abs(m1-m2))
    print s

if __name__ == "__main__":
    sys.exit(main())

另一种方法可能是模糊图像,然后从两个图像中减去像素值。如果差异不为零,则可以将其中一个图像在每个方向上移动1 px并再次比较,如果差异小于上一步,则可以在梯度方向上重复移动并减去,直到差异低于某个阈值或再次增加。如果模糊核的半径大于图像的偏移,那么这应该有效。

此外,您还可以尝试使用摄影工作流程中常用的一些工具来混合多个曝光或制作全景图,例如 全景工具

If your problem is about shifted pixels, maybe you should compare against a frequency transform.

The FFT should be OK (numpy has an implementation for 2D matrices), but I'm always hearing that Wavelets are better for this kind of tasks ^_^

About the performance, if all the images are of the same size, if I remember well, the FFTW package created an specialised function for each FFT input size, so you can get a nice performance boost reusing the same code... I don't know if numpy is based on FFTW, but if it's not maybe you could try to investigate a little bit there.

Here you have a prototype... you can play a little bit with it to see which threshold fits with your images.

import Image
import numpy
import sys

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

    if img1.size != img2.size or img1.getbands() != img2.getbands():
        return -1

    s = 0
    for band_index, band in enumerate(img1.getbands()):
        m1 = numpy.fft.fft2(numpy.array([p[band_index] for p in img1.getdata()]).reshape(*img1.size))
        m2 = numpy.fft.fft2(numpy.array([p[band_index] for p in img2.getdata()]).reshape(*img2.size))
        s += numpy.sum(numpy.abs(m1-m2))
    print s

if __name__ == "__main__":
    sys.exit(main())

Another way to proceed might be blurring the images, then subtracting the pixel values from the two images. If the difference is non nil, then you can shift one of the images 1 px in each direction and compare again, if the difference is lower than in the previous step, you can repeat shifting in the direction of the gradient and subtracting until the difference is lower than a certain threshold or increases again. That should work if the radius of the blurring kernel is larger than the shift of the images.

Also, you can try with some of the tools that are commonly used in the photography workflow for blending multiple expositions or doing panoramas, like the Pano Tools.

最笨的告白 2024-08-20 07:33:06

我很久以前就学过一些图像处理课程,记得在匹配时我通常从制作图像灰度开始,然后锐化图像的边缘,这样你就只能看到边缘。然后,您(软件)可以移动并减去图像,直到差异最小。

如果该差异大于您设置的阈值,则图像不相等,您可以继续处理下一个图像。接下来可以分析具有较小阈值的图像。

我确实认为您最多可以从根本上减少可能的匹配,但需要亲自比较可能的匹配以确定它们确实相等。

我无法真正展示代码,因为那是很久以前的事了,我在那门课程中使用了 Khoros/Cantata。

I have done some image processing course long ago, and remember that when matching I normally started with making the image grayscale, and then sharpening the edges of the image so you only see edges. You (the software) can then shift and subtract the images until the difference is minimal.

If that difference is larger than the treshold you set, the images are not equal and you can move on to the next. Images with a smaller treshold can then be analyzed next.

I do think that at best you can radically thin out possible matches, but will need to personally compare possible matches to determine they're really equal.

I can't really show code as it was a long time ago, and I used Khoros/Cantata for that course.

心头的小情儿 2024-08-20 07:33:06

首先,相关性是一种非常消耗 CPU 资源的相似性度量,而且并不准确。如果各个像素之间存在差异,为什么不直接求平方和呢?

如果最大移位受到限制,一种简单的解决方案是:生成所有可能的移位图像并找到最佳匹配的图像。确保仅在所有移位图像中可以匹配的像素子集上计算匹配变量(即相关性)。此外,您的最大移位应该明显小于图像的尺寸。

如果你想使用一些更先进的图像处理技术,我建议你看看 SIFT 这个是一种非常强大的方法,(无论如何理论上)可以正确匹配图像中的项目,而与平移、旋转和缩放无关。

First off, correlation is a very CPU intensive rather inaccurate measure for similarity. Why not just go for the sum of the squares if differences between individual pixels?

A simple solution, if the maximum shift is limited: generate all possible shifted images and find the one that is the best match. Make sure you calculate your match variable (i.e. correllation) only over the subset of pixels that can be matched in all shifted images. Also, your maximum shift should be significantly smaller than the size of your images.

If you want to use some more advances image processing techniques I suggest you look at SIFT this is a very powerfull method that (theoretically anyway) can properly match items in images independent of translation, rotation and scale.

半葬歌 2024-08-20 07:33:06

为了让导入在我的 Ubuntu 16.04(截至 2017 年 4 月)上正常工作,我安装了 python 2.7 和这些:

sudo apt-get install python-dev
sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk
sudo apt-get install python-scipy
sudo pip install pillow

然后我将 Snowflake 的导入更改为这些:

import scipy as sp
from scipy.ndimage import imread
from scipy.signal.signaltools import correlate2d as c2d

8 年后 Snowflake 的脚本对我来说太棒了!

To get the imports to work correctly on my Ubuntu 16.04 (as of April 2017), I installed python 2.7 and these:

sudo apt-get install python-dev
sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk
sudo apt-get install python-scipy
sudo pip install pillow

Then I changed Snowflake's imports to these:

import scipy as sp
from scipy.ndimage import imread
from scipy.signal.signaltools import correlate2d as c2d

How awesome that Snowflake's scripted worked for me 8 years later!

软的没边 2024-08-20 07:33:06

我想你可以这样做:

  • 估计参考图像与比较图像的垂直/水平位移。一个
    带有运动矢量的简单 SAD(绝对差之和)就可以了。

  • 相应地移动比较图像

  • 计算您尝试进行的皮尔逊相关性

移动测量并不困难。

  • 在比较图像中选取一个区域(例如大约 32x32)。
  • 将其水平移动 x 像素,垂直方向移动 y 像素。
  • 计算原始图像的 SAD(绝对差之和)
  • 对小范围 (-10, +10) 内的 x 和 y 的多个值执行此操作
  • 找到差异最小的位置
  • 选择该值作为移位运动向量

注意:

如果所有 x 和 y 值的 SAD 都非常高,那么您无论如何都可以假设图像非常不相似,并且不需要进行偏移测量。

I guess you could do something like this:

  • estimate vertical / horizontal displacement of reference image vs the comparison image. a
    simple SAD (sum of absolute difference) with motion vectors would do to.

  • shift the comparison image accordingly

  • compute the pearson correlation you were trying to do

Shift measurement is not difficult.

  • Take a region (say about 32x32) in comparison image.
  • Shift it by x pixels in horizontal and y pixels in vertical direction.
  • Compute the SAD (sum of absolute difference) w.r.t. original image
  • Do this for several values of x and y in a small range (-10, +10)
  • Find the place where the difference is minimum
  • Pick that value as the shift motion vector

Note:

If the SAD is coming very high for all values of x and y then you can anyway assume that the images are highly dissimilar and shift measurement is not necessary.

╭ゆ眷念 2024-08-20 07:33:06

我提出了一种基于图像直方图相似度的杰卡德指数的解决方案。 参阅:https://en.wikipedia.org/wiki/Jaccard_index#Weighted_Jaccard_similarity_and_distance

请 可以计算像素颜色分布的差异。这对于翻译来说确实是相当不变的。

from PIL.Image import Image
from typing import List

def jaccard_similarity(im1: Image, im2: Image) -> float:
    """Compute the similarity between two images.
    First, for each image an histogram of the pixels distribution is extracted.
    Then, the similarity between the histograms is compared using the weighted Jaccard index of similarity, defined as:
    Jsimilarity = sum(min(b1_i, b2_i)) / sum(max(b1_i, b2_i)
    where b1_i, and b2_i are the ith histogram bin of images 1 and 2, respectively.

    The two images must have same resolution and number of channels (depth).

    See: https://en.wikipedia.org/wiki/Jaccard_index
    Where it is also called Ruzicka similarity."""

    if im1.size != im2.size:
        raise Exception("Images must have the same size. Found {} and {}".format(im1.size, im2.size))

    n_channels_1 = len(im1.getbands())
    n_channels_2 = len(im2.getbands())
    if n_channels_1 != n_channels_2:
        raise Exception("Images must have the same number of channels. Found {} and {}".format(n_channels_1, n_channels_2))

    assert n_channels_1 == n_channels_2

    sum_mins = 0
    sum_maxs = 0

    hi1 = im1.histogram()  # type: List[int]
    hi2 = im2.histogram()  # type: List[int]

    # Since the two images have the same amount of channels, they must have the same amount of bins in the histogram.
    assert len(hi1) == len(hi2)

    for b1, b2 in zip(hi1, hi2):
        min_b = min(b1, b2)
        sum_mins += min_b
        max_b = max(b1, b2)
        sum_maxs += max_b

    jaccard_index = sum_mins / sum_maxs

    return jaccard_index

就均方误差而言,杰卡德指数始终位于 [0,1] 范围内,因此可以在不同图像尺寸之间进行比较。

然后,您可以比较两个图像,但在重新缩放到相同大小之后!或者像素计数必须以某种方式标准化。我使用了这个:

import sys

from skincare.common.utils import jaccard_similarity

import PIL.Image
from PIL.Image import Image

file1 = sys.argv[1]
file2 = sys.argv[2]

im1 = PIL.Image.open(file1)  # type: Image
im2 = PIL.Image.open(file2)  # type: Image

print("Image 1: mode={}, size={}".format(im1.mode, im1.size))
print("Image 2: mode={}, size={}".format(im2.mode, im2.size))

if im1.size != im2.size:
    print("Resizing image 2 to {}".format(im1.size))
    im2 = im2.resize(im1.size, resample=PIL.Image.BILINEAR)

j = jaccard_similarity(im1, im2)
print("Jaccard similarity index = {}".format(j))

测试你的图像:

$ python CompareTwoImages.py im1.jpg im2.jpg
Image 1: mode=RGB, size=(401, 105)
Image 2: mode=RGB, size=(373, 109)
Resizing image 2 to (401, 105)
Jaccard similarity index = 0.7238955686269157
$ python CompareTwoImages.py im1.jpg im3.jpg 
Image 1: mode=RGB, size=(401, 105)
Image 2: mode=RGB, size=(457, 121)
Resizing image 2 to (401, 105)
Jaccard similarity index = 0.22785529941822316
$ python CompareTwoImages.py im2.jpg im3.jpg 
Image 1: mode=RGB, size=(373, 109)
Image 2: mode=RGB, size=(457, 121)
Resizing image 2 to (373, 109)
Jaccard similarity index = 0.29066426814105445

你也可以考虑尝试不同的重采样过滤器(如 NEAREST 或 LANCZOS),因为它们当然会在调整大小时改变颜色分布。

此外,请考虑交换图像会改变结果,因为第二个图像可能会被下采样而不是上采样(毕竟,裁剪可能比重新缩放更适合您的情况。)

I propose a solution based on the Jaccard index of similarity on the image histograms. See: https://en.wikipedia.org/wiki/Jaccard_index#Weighted_Jaccard_similarity_and_distance

You can compute the difference in the distribution of the pixel colors. This is indeed pretty invariant to translations.

from PIL.Image import Image
from typing import List

def jaccard_similarity(im1: Image, im2: Image) -> float:
    """Compute the similarity between two images.
    First, for each image an histogram of the pixels distribution is extracted.
    Then, the similarity between the histograms is compared using the weighted Jaccard index of similarity, defined as:
    Jsimilarity = sum(min(b1_i, b2_i)) / sum(max(b1_i, b2_i)
    where b1_i, and b2_i are the ith histogram bin of images 1 and 2, respectively.

    The two images must have same resolution and number of channels (depth).

    See: https://en.wikipedia.org/wiki/Jaccard_index
    Where it is also called Ruzicka similarity."""

    if im1.size != im2.size:
        raise Exception("Images must have the same size. Found {} and {}".format(im1.size, im2.size))

    n_channels_1 = len(im1.getbands())
    n_channels_2 = len(im2.getbands())
    if n_channels_1 != n_channels_2:
        raise Exception("Images must have the same number of channels. Found {} and {}".format(n_channels_1, n_channels_2))

    assert n_channels_1 == n_channels_2

    sum_mins = 0
    sum_maxs = 0

    hi1 = im1.histogram()  # type: List[int]
    hi2 = im2.histogram()  # type: List[int]

    # Since the two images have the same amount of channels, they must have the same amount of bins in the histogram.
    assert len(hi1) == len(hi2)

    for b1, b2 in zip(hi1, hi2):
        min_b = min(b1, b2)
        sum_mins += min_b
        max_b = max(b1, b2)
        sum_maxs += max_b

    jaccard_index = sum_mins / sum_maxs

    return jaccard_index

With respect to mean squared error, the Jaccard index lies always in the range [0,1], thus allowing for comparisons among different image sizes.

Then, you can compare the two images, but after rescaling to the same size! Or pixel counts will have to be somehow normalized. I used this:

import sys

from skincare.common.utils import jaccard_similarity

import PIL.Image
from PIL.Image import Image

file1 = sys.argv[1]
file2 = sys.argv[2]

im1 = PIL.Image.open(file1)  # type: Image
im2 = PIL.Image.open(file2)  # type: Image

print("Image 1: mode={}, size={}".format(im1.mode, im1.size))
print("Image 2: mode={}, size={}".format(im2.mode, im2.size))

if im1.size != im2.size:
    print("Resizing image 2 to {}".format(im1.size))
    im2 = im2.resize(im1.size, resample=PIL.Image.BILINEAR)

j = jaccard_similarity(im1, im2)
print("Jaccard similarity index = {}".format(j))

Testing on your images:

$ python CompareTwoImages.py im1.jpg im2.jpg
Image 1: mode=RGB, size=(401, 105)
Image 2: mode=RGB, size=(373, 109)
Resizing image 2 to (401, 105)
Jaccard similarity index = 0.7238955686269157
$ python CompareTwoImages.py im1.jpg im3.jpg 
Image 1: mode=RGB, size=(401, 105)
Image 2: mode=RGB, size=(457, 121)
Resizing image 2 to (401, 105)
Jaccard similarity index = 0.22785529941822316
$ python CompareTwoImages.py im2.jpg im3.jpg 
Image 1: mode=RGB, size=(373, 109)
Image 2: mode=RGB, size=(457, 121)
Resizing image 2 to (373, 109)
Jaccard similarity index = 0.29066426814105445

You might also consider experimenting with different resampling filters (like NEAREST or LANCZOS), as they, of course, alter the color distribution when resizing.

Additionally, consider that swapping images change the results, as the second image might be downsampled instead of upsampled (After all, cropping might better suit your case rather than rescaling.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文