需要一个高性能的图片相似度计算方案 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
laoooo
V2EX    问与答

需要一个高性能的图片相似度计算方案

  •  
  • /div>   laoooo 2023-03-31 11:56:20 +08:00 3768 次点击
    这是一个创建于 933 天前的主题,其中的信息可能已经有所发展或是发生改变。
    需求如下:

    1. 我有一个文件夹,里面有九千多张大小不一的图片,我需要对每张图进行相似度计算。
    2. 我希望通过我给定一个阈值,计算哪些图的相似度大于此阈值,复制至 result 目录中以“基准图”文件名命名的文件夹中。
    3. 高性能运行,多线程 /其他方案。要求计算一万张图片的耗时在一分钟左右。
    4. 要求以 Python 实现

    尝试了通过多线程计算哈希的方式来实现,效果还不错,但是一万张图的耗时在 3000 秒左右。求更高效的方案。
    20 条回复    2023-03-31 19:26:56 +08:00
    kop1989smurf
        1
    kop1989smurf  
       2023-03-31 11:57:55 +08:00
    一万张图的总大小是多大?
    laoooo
        2
    laoooo  
    OP
       2023-03-31 11:59:11 +08:00
    @kop1989smurf 40MB 左右,都是小图,分辨率在 128*128 的样子
    frankmdong
        3
    frankmdong  
       2023-03-31 12:56:58 +08:00
    首先要定义相似度具体是怎么计算,如果是单纯的比较相同位置的像素颜色是否相同,那可以多线程跑 compute shader ,在 gpu 对比两张图片对应的像素是否相同。可以参考 https://zhuanlan.zhihu.com/p/392448858 这篇文章中提到的资源优化工具,但是一分钟内几乎不可能跑完一万张图。
    oylinv
        4
    oylinv  
       2023-03-31 13:19:39 +08:00 via Android
    qq565425677
        5
    qq565425677  
       2023-03-31 13:39:44 +08:00
    我提供一个思路,不过具体我也不是太清楚

    有没有可能计算图片的奇异值分解,128*128 应该很快,然后基于奇异值定义距离来判断
    kzzhr
        6
    kzzhr  
       2023-03-31 13:44:50 +08:00
    我把这个问题丢给了 GPT ,以下是他的回答(还给了个代码,太长了不贴了。。。)

    要实现一个高性能的图片相似度计算方案,可以使用以下方法:

    1. 使用深度学习模型:使用预训练的深度学习模型,如 VGG, ResNet 等,可以更高效地提取图像特征。这些特征可以用于计算相似度。
    2. 特征向量降维:使用 PCA 或 t-SNE 等方法对特征向量进行降维,这样可以减少计算量,提高相似度计算速度。
    3. 近似最近邻搜索:对于相似度计算,可以使用近似最近邻搜索( Approximate Nearest Neighbors ,ANN )算法,如 Annoy 、Faiss 等库。它们可以在保持搜索质量的同时大大提高搜索速度
    4. 多线程 /多进程:使用 Python 的 multiprocessing 或 concurrent.futures 模块来实现多线程 /多进程并行计算。
    kop1989smurf
        7
    kop1989smurf  
       2023-03-31 13:50:45 +08:00
    @laoooo #2 40MB ,一万张图,“基准图”有几张?也就是需要支持几个分组?
    需要抗翻转、裁切、偏移么?相似度的阈值大概是多少?

    如果需要抗偏移,感觉 1 分钟基本上做不到。
    horizon
        8
    horizon  
       2023-03-31 13:56:44 +08:00
    准备开始学深度学习了。。
    Donahue
        9
    Donahue  
       2023-03-31 14:19:45 +08:00
    可以问问 chatGPT
    NoOneNoBody
        10
    NoOneNoBody  
       2023-03-31 15:51:13 +08:00   2
    小图很快的,不需要 3000s ,但 1m 又基本不行
    不知道你的参照有多少,我 1000 vs 1000 ,5~10MB/pic ,也就 30 分钟内
    如果参照已经缓存了计算值,时间减半,小图(<1MB/pic),时间减 2/3

    方案 1. pyvips
    def viMse(vim, refvim)->float:
    '''计算 MSE 差异值,vim/refvim 都是 pyvips.Image 类型'''
    return ((vim - refvim) ** 2).avg()
    然后你按 mse 比较,网上有
    opencv 也有 mse 计算,但比 pyvips 慢

    方案 2 pyvips|opencv
    有些图片字节数相同或极度接近,但 md5/crc32 不同,它们可能只是 exif 或者文件头不同,图片内容是完全相同的
    可以用
    np.isclose((vim1-vim2).max(), 0, rtol=1e-9)

    cvim1.shape==cvim2.shape and not (numpy.bitwise_xor(cvim1, cvim2).any())
    vim 为 pyvips.Image 格式,cvim 为 opencv/numpy 格式,vips 较快且耗内存小,但大图有可能有未知错误,全自动的话 opencv 在保证内存足够的情况下比较保险

    方案 3 opencv.imgHash
    target 和 refer 分别计算 imgHash ,opencv 的 imgHash 有七八种,阙值是自定的,但网上有参考,自己选择

    无论哪种方案,应该做预匹配,不然就是 10000 * 10000 ,计算量大
    预匹配就是从字节、文件名相似、exif 日期时间一致,长宽比……这些很少计算能快速排除“完全不可能相似”
    如果很难做预匹配,例如上述参数都没有规律,那就只能硬着头皮按组合双循环计算了

    还有其他方案,但此题好像不适用,我主要目标是找有没有裁切水印把图变小了,和你需求略有不同

    PS: 如果 refer 经常使用的话,建议把上述计算的中间值保存,以后使用跳过计算,省时间,我是入库的
    NoOneNoBody
        11
    NoOneNoBody  
       2023-03-31 15:57:31 +08:00
    PS: 上述时间是 intel 12700 使用 16 个并发(因为我要留 CPU 做其他事情,用尽的话其他 app 会没响应,无奈)
    orangie
        12
    orangie  
       2023-03-31 16:31:39 +08:00
    插一句,python 的多线程还是单核性能,不能用来并行、提高计算速度,只能用来做异步、并发。
    faithid
        13
    faithid  
       2023-03-31 16:33:16 +08:00   1
    用深度学习模型提取 embedding ,用 milvus 计算相似度
    NoOneNoBody
        14
    NoOneNoBody  
       2023-03-31 16:46:45 +08:00
    再补充一个经验,做图片比较,耗时最大是生成上述各种中间值,因为不仅计算,还有 IO
    但如果已经有中间值,并发计算是很快的,如 imgHash ,千万对(就是两张)并发计算只是几分钟( i7 12700 16 并发)
    另一个好处是“离线”,不需要挂载 refer 图片所在硬盘就能比较
    这就是我把这些中间值入库的原因
    qiayue
        15
    qiayue  
    PRO
       2023-03-31 16:53:00 +08:00
    基于 #13 @faithid 的回答,我补充下,使用 OpenAI 的 https://github.com/openai/CLIP 为每一张图片计算向量,之后存储到文本文件里。
    再写个程序,把所有图片的向量载入到内存中,循环计算任意一张图片的向量与其它图片的向量的距离,欧几里得距离( Euclidean distance )和余弦距离( cosine distance )都行,对于所得到的距离从小到大排序,就得到了每一张图片和其它所有图片的相似度。
    你再取一个阈值,如距离小于多少,就算你定义的很像近图片。把所有小于这个阈值的图片放一起。
    LuffyWong
        16
    LuffyWong  
       2023-03-31 17:34:27 +08:00   1
    如果相似度算法 ok 了的话, python 调用 pytorch 实现直接 cuda 跑更快
    yousabuk
        17
    yousabuk  
       2023-03-31 18:41:17 +08:00 via iPhone
    帖子内容和格式像极了甲方对楼主提的需求
    laoooo
        18
    laoooo  
    OP
       2023-03-31 19:21:15 +08:00
    @NoOneNoBody 谢谢,我之前问过 GPT ,尝试过第三种方案,和你说的一样,这些小图片没法做预匹配,现在就是卡在了计算量上。第二种方案有所启发,非常感谢。
    laoooo
        19
    laoooo  
    OP
       2023-03-31 19:24:25 +08:00
    @kop1989smurf 每一张图都需要作为基准图与其他图进行对比,你说的这些情况理论上都要考虑。阈值的范围需要通过参数指定,并不是固定值。
    laoooo
        20
    laoooo  
    OP
       2023-03-31 19:26:56 +08:00
    @LuffyWong 对,目前相似度算法部分已经解决,效果还不错,但是目前没想到怎么去优化计算量,想通过 GPU 来跑,看看能不能快一点。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2528 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 11:20 PVG 19:20 LAX 04:20 JFK 07:20
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86