如何量化两幅图像之间的差异?

225

以下是我想做的事情:

我想定期使用网络摄像头拍照片。有点像时间流逝的东西。但是,如果没有真正发生改变,也就是说,图片基本上看起来相同,我不想存储最新的快照。

我想象有一种量化差异的方法,我将不得不凭经验确定阈值。

我寻求简单而非完美。 我正在使用Python。


相关:https://dev59.com/EnVD5IYBdhLWcg3wTJvF - Anoyz
25个回答

3

如果回复晚了,我很抱歉。由于我做过类似的事情,所以我想我可以做出一些贡献。

也许您可以使用OpenCV进行模板匹配。假设您正在使用网络摄像头:

  1. 简化图像(可以使用阈值处理)
  2. 应用模板匹配并检查max_val,使用minMaxLoc确定最大值

提示:max_val(或min_val,具体取决于所使用的方法)将给您一些大数字。要获取百分比差异,请使用相同图像的模板匹配-结果将是100%。

伪代码如下:

previous_screenshot = ...
current_screenshot = ...

# simplify both images somehow

# get the 100% corresponding value
res = matchTemplate(previous_screenshot, previous_screenshot, TM_CCOEFF)
_, hundred_p_val, _, _ = minMaxLoc(res)

# hundred_p_val is now the 100%

res = matchTemplate(previous_screenshot, current_screenshot, TM_CCOEFF)
_, max_val, _, _ = minMaxLoc(res)

difference_percentage = max_val / hundred_p_val

# the tolerance is now up to you

希望这有所帮助。

3
我遇到了同样的问题,并编写了一个简单的Python模块,使用Pillow的ImageChops比较两个大小相同的图像,创建出一个黑/白差异图像并求出直方图值之和。您可以直接获取这个分数,或者与全黑对全白差异进行比较得出一个百分比值。该模块还包含一个简单的is_equal功能,可以提供一个模糊阈值,在(包括)该阈值以下的情况下,图像被视为相等。此方法不是非常复杂,但也许对其他遇到同样问题的人有所帮助。请参考https://pypi.python.org/pypi/imgcompare/

2
import os
from PIL import Image
from PIL import ImageFile
import imagehash
  
#just use to the size diferent picture
def compare_image(img_file1, img_file2):
    if img_file1 == img_file2:
        return True
    fp1 = open(img_file1, 'rb')
    fp2 = open(img_file2, 'rb')

    img1 = Image.open(fp1)
    img2 = Image.open(fp2)

    ImageFile.LOAD_TRUNCATED_IMAGES = True
    b = img1 == img2

    fp1.close()
    fp2.close()

    return b





#through picturu hash to compare
def get_hash_dict(dir):
    hash_dict = {}
    image_quantity = 0
    for _, _, files in os.walk(dir):
        for i, fileName in enumerate(files):
            with open(dir + fileName, 'rb') as fp:
                hash_dict[dir + fileName] = imagehash.average_hash(Image.open(fp))
                image_quantity += 1

    return hash_dict, image_quantity

def compare_image_with_hash(image_file_name_1, image_file_name_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.
    recommend to use
    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_1 = None
    hash_2 = None
    with open(image_file_name_1, 'rb') as fp:
        hash_1 = imagehash.average_hash(Image.open(fp))
    with open(image_file_name_2, 'rb') as fp:
        hash_2 = imagehash.average_hash(Image.open(fp))
    dif = hash_1 - hash_2
    if dif < 0:
        dif = -dif
    if dif <= max_dif:
        return True
    else:
        return False


def compare_image_dir_with_hash(dir_1, dir_2, max_dif=0):
    """
    max_dif: The maximum hash difference is allowed, the smaller and more accurate, the minimum is 0.

    """
    ImageFile.LOAD_TRUNCATED_IMAGES = True
    hash_dict_1, image_quantity_1 = get_hash_dict(dir_1)
    hash_dict_2, image_quantity_2 = get_hash_dict(dir_2)

    if image_quantity_1 > image_quantity_2:
        tmp = image_quantity_1
        image_quantity_1 = image_quantity_2
        image_quantity_2 = tmp

        tmp = hash_dict_1
        hash_dict_1 = hash_dict_2
        hash_dict_2 = tmp

    result_dict = {}

    for k in hash_dict_1.keys():
        result_dict[k] = None

    for dif_i in range(0, max_dif + 1):
        have_none = False

        for k_1 in result_dict.keys():
            if result_dict.get(k_1) is None:
                have_none = True

        if not have_none:
            return result_dict

        for k_1, v_1 in hash_dict_1.items():
            for k_2, v_2 in hash_dict_2.items():
                sub = (v_1 - v_2)
                if sub < 0:
                    sub = -sub
                if sub == dif_i and result_dict.get(k_1) is None:
                    result_dict[k_1] = k_2
                    break
    return result_dict


def main():
    print(compare_image('image1\\815.jpg', 'image2\\5.jpg'))
    print(compare_image_with_hash('image1\\815.jpg', 'image2\\5.jpg', 7))
    r = compare_image_dir_with_hash('image1\\', 'image2\\', 10)
    for k in r.keys():
        print(k, r.get(k))


if __name__ == '__main__':
    main()
  • 输出结果:

    False
    True
    image2\5.jpg image1\815.jpg
    image2\6.jpg image1\819.jpg
    image2\7.jpg image1\900.jpg
    image2\8.jpg image1\998.jpg
    image2\9.jpg image1\1012.jpg

  • 示例图片:

    • 815.jpg
      815.jpg

    • 5.jpg
      5.jpg


1

我一直在使用同一台相机上三脚架拍摄的jpg图像,运用以下方法取得了很好的效果:

  1. 大幅简化(例如将3000像素宽的图像缩小至100像素宽或更少)
  2. 将每个jpg数组压缩成单个向量
  3. 使用简单的相关算法对连续图像进行成对相关,以获取相关系数
  4. 将相关系数平方以获取r-square(即一个图像中可变性的一部分由下一个图像中的变化所解释的比例)
  5. 通常情况下,如果r-square<0.9,则表示两个图像不同,并且之间发生了某些变化。

在我的实现中(Mathematica 7),这种方法非常稳健和快速。

值得注意的是,应该尝试裁剪所有图像到感兴趣的图像部分并专注于该部分,否则可能会错过远离相机但重要的变化。

我不知道如何使用Python,但我确信它也可以进行相关性计算,不是吗?


1

你可以计算两张图片的直方图,然后计算Bhattacharyya系数,这是一个非常快速的算法,我曾经在使用openCV(用C语言)检测板球视频中的镜头变化时使用过它。


你能计算图像本身的系数吗? - endolith
您需要计算图像的直方图(直方图的箱子大小根据要求确定)。 - vishalv2050

1

地球移动距离可能正是你所需要的。 不过实时实现可能会有些困难


我觉得这个回答并没有很好地解决问题:“我更注重简单而非完美。我正在使用Python。” - PilouPili
我认为,由于这个问题线程的流量很大,而且吸引大多数观众的标题是关于如何量化两个图像之间的差异,因此它在这里具有价值。 - Danoram

1

计算两个图像的曼哈顿距离怎么样?这会给你n*n个值。然后你可以做一些行平均来减少到n个值,再通过一个函数得到一个单一的值。


1
这是我写的一个函数,它接受两个图像文件路径作为参数,并返回两个图像像素分量之间平均差异。对于确定视觉上“相等”的图像(当它们不是 == 相等时),这对我非常有效。 < p> (我发现8是确定图像是否基本相同的好限制。) < p> (如果您不添加任何预处理,则图像必须具有相同的尺寸。)
from PIL import Image

def imagesDifference( imageA, imageB ):
    A = list(Image.open(imageA, r'r').convert(r'RGB').getdata())
    B = list(Image.open(imageB, r'r').convert(r'RGB').getdata())
    if (len(A) != len(B)): return -1
    diff = []
    for i in range(0, len(A)):
        diff += [abs(A[i][0] - B[i][0]), abs(A[i][1] - B[i][1]), abs(A[i][2] - B[i][2])]
    return (sum(diff) / len(diff))

1

看看isk-daemon如何实现Haar小波。您可以使用它的imgdb C++代码实时计算图像之间的差异:

isk-daemon是一个开源数据库服务器,能够为任何与图像相关的网站或软件添加基于内容(视觉)的图像搜索功能。

这项技术允许任何与图像相关的网站或软件的用户在小部件上草绘他们想要查找的图像,并让网站回复他们最相似的图像,或者仅在每个图像详细页面请求更多相似的照片。


1
一种更有原则的方法是使用全局描述符来比较图像,例如GIST或CENTRIST。如此处所述,哈希函数也提供了类似的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接