如何按 "bursts?" 对图像进行分组

How to group images by "bursts?"

我认为这需要一些解释,所以请耐心等待...

我一次拍摄了 2000 多张亚秒级连拍图像,每张 4-6 张。它们都被扔在了同一个地方,所以我需要对它们进行分类。我需要按突发对它们进行排序,但 EXIF 数据仅提供一分钟的分辨率。连发应该是几乎一模一样的东西,不同的连发被设计成明显不同。

我需要查看每张图片,将其与下一张进行比较,看看是否相似。如果相差太大,则一定是另一次连拍,需要将其放入新文件夹,以及以下任何与其相似的图像,依此类推。

我的想法是将当前图像的每个像素与下一个像素之间的差异的绝对值相加。一旦这个总和达到一个阈值,那么这一定意味着它们来自不同的突发(我可以做一些测试来找出一个好的阈值是多少)。

最大的问题是如何? PIL/Pillow 支持这样的东西吗?有没有更好的方法来查看一张图片是否 "mostly" 与另一张图片相同?

与使用任何特定技术相比,我对快速排序它们更感兴趣,因此欢迎使用其他方法。

...而且几乎必须是 Python。

编辑: 这是一对样本图像,它们应该放在同一个文件夹中:

这是来自以下连拍的两张图片,应该放在另一个文件夹中:

如果您想进行基于内容的匹配而不是上面好人建议的基于时间戳的排序,OpenCV 库是一个不错的选择。查看此 post,了解如何将 OpenCV 库用于图像相似性匹配的不同技术:Checking images for similarity with OpenCV

关于同一主题有大量 SO 问题,因此通读它们会给您一个更好的主意。

根据上面的时间思路,当我只绘制您的照片拍摄时间时,我得到的是这样的图:

不同的颜色代表不同的文件夹(应该使用不同的颜色图以获得更好的可见性,但是哦......)。

仅根据这些时间,您的集群间时间似乎确实比集群内时间明显更明显。

我还在下面的输出中计算了一些集群内和集群间指标:

folder: ImageBurstsDataset/001
Total image files in folder: 6
Total intra-cluster time: 1.0
Average intra-cluster time: 0.166666666667
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/002
Total image files in folder: 7
Total intra-cluster time: 1.0
Average intra-cluster time: 0.142857142857
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/003
Total image files in folder: 6
Total intra-cluster time: 1.0
Average intra-cluster time: 0.166666666667
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/004
Total image files in folder: 6
Total intra-cluster time: 2.0
Average intra-cluster time: 0.333333333333
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/005
Total image files in folder: 6
Total intra-cluster time: 2.0
Average intra-cluster time: 0.333333333333
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/006
Total image files in folder: 6
Total intra-cluster time: 1.0
Average intra-cluster time: 0.166666666667
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/007
Total image files in folder: 6
Total intra-cluster time: 2.0
Average intra-cluster time: 0.333333333333
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/008
Total image files in folder: 5
Total intra-cluster time: 2.0
Average intra-cluster time: 0.4
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/009
Total image files in folder: 6
Total intra-cluster time: 1.0
Average intra-cluster time: 0.166666666667
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/010
Total image files in folder: 6
Total intra-cluster time: 2.0
Average intra-cluster time: 0.333333333333
Max: 1.0, Min: 0.0


Inter-cluster times: [10.0, 8.0, 7.0, 5.0, 6.0, 6.0, 5.0, 10.0, 6.0]

免责声明:匆忙写了这个脚本,只需要返回并确保所有边缘情况都是正确的。但除此之外……我从您上传的数据集中得出的结论是:

  1. 在一个簇内,一张图片与前一张的间隔不会超过1秒。

  2. 下一组中的第一张图片与上一组中的最后一张图片至少相隔5秒。

两张图片有多相似是一个开放的研究问题。但是,鉴于您的图像是快速连拍拍摄的,使用绝对差异是合理的。另一种可能性是使用相关性,例如,乘以像素值并接受高于阈值的结果。

问题将出在速度上。根据您对准确性的要求,您可能能够非常显着地对图像进行子采样。可能是比较 100 或 1000 个均匀分布的像素的值——每幅图像中的相同像素——会给你一个足够准确的统计数据来满足你的目的。

PIL可以给出图像的RGB数据,理论上可以用于图像的对比。要衡量两幅图像的接近程度,您可能必须计算两幅图像的差异或者甚至更多的误差计算统计方法。您可以使用

获取 RGB 数据
import Image
pic  = Image.open('/path/to/file')
rgbdata = pic.load()
width, height = pic.size

您可以纯粹根据 rgbdata[i,j] 中第 ij 个像素的 RGB 值来查看数据。

希望对您有所帮助。

[编辑] 此方法仅在假设所有照片都在同一帧中拍摄时有效...如果相机移动一点,则此方法无效。

如果它们来自三脚架上的相机(静止)并且物体在移动,那么我们甚至可以追踪物体的运动(像素值差异更高的地方)。

否则必须像在人脸识别类应用程序中那样定义跟踪点。 (我不是图像处理方面的专家,但很少看到以这种方式工作的应用程序)

另一种比较两幅图像的方法是在傅立叶域中。但不确定它对您的效果如何。

抱歉,原来是 EXIF 数据。看起来爆发之间有 10-15 秒的时间,所以应该很容易分辨一次结束和另一次开始。

PIL/Pillow 有足够的工具来查看创建日期:

from PIL.ExifTags import TAGS

def get_exif(fn):
    ret = {}
    i = Image.open(fn)
    info = i._getexif()
    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        ret[decoded] = value
    return ret

...或类似的东西。