相关推荐
Python基于Imagehash及OpenCV的图像视频数据媒资检索
2024-11-11 01:59

        前段时间参加了一个关于图像视频检索的比赛,抽空总结一下思路,并在结尾附上参赛代码以及对应数据集。

Python基于Imagehash及OpenCV的图像视频数据媒资检索

        链接:       

        截至目前只公布了Top10,复赛参加后暂无更多的消息,可能主办方也鸽了(不是)。

         结果出来了,被榜上的大佬们反复蹂躏

1.1  数据集介绍 

         提供数据集为

  • db

        包含3186个长度为10秒左右的随机视频,模拟视频数据库。

  • image

        从db中截取的图片,并进行相应处理,处理方式包括

         原始视频中某一帧,用于图像查询视频,变换类型说明如下:                 - black_pad:   基于原图片上下添加黑边                 - bw:               颜色变换-黑白                 - color:            颜色变换-彩色                 - crop:             图片裁减                 - cut:               子片段(对于图片无效)                 - logo:             随机位置增加logo                 - mohu:           变得模糊                 - ori:                无变换,可以理解为原切图                 - shuiyin:         增加全屏的水印                 - zimu:            下方增加字幕

        分为训练集(每种类1000个图片)和测试集(每种类200个图片)

  • video

        基于db视频采取与image相同处理方式的视频,训练集与测试集相同。

1.2 要求介绍

        这里不做比赛简介的复述了,采用大白话的方式进行说明

        设计一种算法,官方测试时指定新的db文件夹,以及随机混合10种类型的图片和视频文件夹,以路径作为参数传入指定脚本中,经过处理运算后得到一个匹配对照文件以及耗时文件。运行时提供必要的显卡和cuda环境作为支持。为避免环境问题,参赛方以docker镜像的方式提供算法模型。

        代码按照要求应分为三个py文件,build.py、query_image.py、query_video.py

  • build.py:进行你想要的预处理,不计入时间
  • query_image.py:db和image文件夹路径作为参数传入,生成匹配文档和耗时文档
  • query_video.py:db和video文件夹路径作为参数传入,生成匹配文档和耗时文档

         主要难度:     

        混合类型的图像或音频,算法泛用性难度大大增加;官方测试时仅一张T4显卡作为运算主力,耗时问题;还有一个CV和深度学习处理能力为0的本人(我是菜狗)。

        2.1 选取方法

        既然提供了显卡和cuda环境,本能的想到了什么目标识别、聚类、相似度匹配巴拉巴拉的一大堆,感觉要狠狠的torch起来,但是查阅了很多论文和开源项目代码,发现我能找到的或者我能理解并复现的一些技术,并不适合当前数据集的要求,进而在选择技术方法方面花费了较长时间。

        最终采取了图像相似度的方式,也就是基于图像hash值对比的方式进行图片检索,在本次数据集的数量级范围内理论可行。Imagehash官方的库中有各种hash值计算的函数,包括但不限于ahash、dhash、phash、whash等,其中我们根据实验数据进行测试,排除了ahash、dhash等简单数值运算的方式,选取了whash基于小波变换的方式。

        2.2 WHash原理及实现

        whash算法核心思路

  • 灰度化 
  • Resize=>8*8,平滑 (在最终提交版本选取了16*16的大小,提高了精度,但降低了效率
  • 小波变换获取不同的低频特征
  • 二值化获得二值图
  • 合并得到 fingerprint
  • 比较不同图片的 fingerprint(ImageHash 格式
  • 比较海明距(同为 ImageHash 格式可以直接与或运算得到计算结果

                小波变换中会进行多次迭代,对whash原理想要详细了解的同学可以看以下的源码,但是感觉一些底层函数在这部分源码中也没有讲清楚,这里更像是判断并计算,感兴趣的小伙伴们可以深入了解一下。

 

2.3 宏观思路

        我们现在手里的武器

        掌握了一种叫Whash的函数,把图片传入函数,返回一个可以描述一张图片的“特征码”,凭借对比“特征码”的异同之处来判断是不是同一张图片或者相似图片。

        我们需要解决的问题

        给你一个图片或者视频,说出这是数据库的哪一个视频。

        2.3.1 思路描述

        将db数据库的视频切帧,每隔10帧左右保存一张图片,然后根据图片生成对应的“特征码”,全部处理后,我们会获得3186个视频中出现过的事物的全部信息,也就是“特征码”,大概60000个“特征码”,采用十六进制存储为csv格式,大小为13M左右。这部分预处理交给build.py去做

         判断图片来自哪个视频

        加载处理过的60000个特征码,把目标图片传入Whash函数,获得特征码,进行比较,选取差别(汉明距最小)的目标“特征值”,返回该“特征值”来自的db数据视频id。

        判断视频是db中哪个视频

        比图片多一步预处理,将待查找视频切取某一帧,后续简化为图片查找。

        2.3.2 面临的问题

        1)不同种类的泛用性

        测试时需要传入各种处理过的不同类型,尽管Whash的鲁棒性较强,抗干扰能力也还可以,但是某些类型,如“黑边”“裁切”图片准确率极低。

        2)遍历的复杂度

        查询每一张图片都需要进行遍历获得所有汉明距离,而“特征码”不同点的随机性,以及“非存在性”使得索引或者传统查找方式难以使用。

        “非存在性”人话版

        假设待查找特征码为10001,我们当然想要寻找标号为10001的特征码,然而因为切帧并不一定就正好切到原图,就算切到原图,经过变换后也基本不可能是10001。

        假设我们站在上帝视角,最相近的图片特征码为“10004”,汉名距离为3,事实便是:我们要查的数据不存在数据库中,我们只能找最相近的某一个值,而这个“最”怎么避免遍历查找便是问题,而且不同图片查找后汉明距离这一数据不能得到有效利用,只能废弃。

        “特征码不同点的随机性”人话版

        此时我们想到能否让数据库数据排好队,我们从第一位赶着来,但是问题又来了,这个图片特征码为10001,而上帝视角的我们又知道了,最相似的图片是20101,距离为3。我们不知道哪一位是变的,因此从哪一位开始对比似乎都显得不合适。

        经过小组讨论(一共就两个人,我们探讨了似乎可行的方案,但并未实施落地,原理如下

         PS:1、采用size=16的whash值长度位256位0或1,但存储时采用16进制。

                  2、汉明距离大于20基本不可能是原图。

        我们不关心0和1的具体位置,允许你是0我是1的情况存在,只不过这样我们的“汉明距离”便会增加1。基于以上理论,我们将256位数据分段,统计每段0和1的个数,比如说分了四段,1的个数分别为 20,38,54,19(0~64取值,现在我们拿到了一个带查找特征码,他的分段数据为:17,12,52,22。那我们便可以根据第二段差距过大的原因,直接否决他们是原图的可能性。

        有同学可能要问了,这不还是比较吗,但请注意,分段数据是可以排序的,我们建立类似树状的结构,1,1,1,1->1,1,1,2---->>>>64,64,64,64

        拿到一个图片,我们计算每段01个数,假如为30,30,30,30,那我们进行遍历查找的数据可能只需要是20,20,20,20到40,40,40,40这部分的数据。

        但是在实际操作中还是存在一定的技术难度,比如构建数据结构,每段容错只给10是否合理,截至提交时依旧采用遍历方式(太菜了)。

        3)该方式无法使用GPU加速

        暂时没有研究过“汉明距离”遍历计算以及生成hash值如何使用gpu加速的问题。

 2.4 准确率优化

        2.4.1种类判断

        1. 非敏感类型

        WHash 算法对黑白、颜色反转、Logo、模糊、水印、字幕这几类不敏感,原因如下:黑白、颜色反转因为统一转换为灰度图的原因,颜色信息会被丢弃,因此来自颜色的干扰不会产生影响

        Logo、模糊、水印因为在获取低频信息以及迭代时会丢弃掉这些影响,放大了部分低频信息;字幕会对图片特征值获取产生部分影响,但是从实际结果来看,海明距仅增加 1 到 2,可以忽略。

        2. 敏感类型

        只需要处理 Crop,black-pad 两种类型的图片或视频,思路步骤如下

         2.4.2 后续处理

        1. 黑边类型

        扫描黑边采用像素扫描的方式,从左上和左下的第一个像素点进行扫描,并向中心渐进。默认存在黑边,记录黑边的“宽度”,直到发现某一行出现大量非黑色像素点停止记录,观察“黑边”宽度(即已经扫描过的行数,若小于某临界值,则认为不存在黑边。若在临界值之上,则判定存在黑边。

        黑边图片可以直接根据记录的“黑边宽度”,使用 OpenCV 的裁切函数删除黑边区域。

        2. 裁切类型

        这部分处理花费了很多心思,困难有二

        1)主要难以判断是否是裁切类图片或者视频

        2)裁切视频或图片该如何在3000个视频正确匹配,基于像素遍历扫描还是基于深度学习

        当时并没有很好的方案能够进行适配。但注意到所有的测试集与 DB 样本集中,除了竖屏视频,其余视频样本长宽比均维持在1280*720 类似的比例,裁切类型则会生成比例不定的任意类型图片,且大小不会过小,借助这一特点, 可以尝试判断图片比例,按照图片比例进行筛选,从而分离出裁切类型。

        2.4.3 裁切图片预处理

        裁切图片需要进行补全操作 OpenCV 库中提供了这几个常见的补全方式

  • Original:原裁切图
  • REPLICATE: 复制边缘上的像素颗粒,所有的维度都使用当前的点
  • REFLECT: 进行以边界为对称轴的翻转,即 4321|123456|6543 的方式
  • REFLECT_101: 按行进行中间值翻转 即 543|1234567|345 的方式
  • WRAP: 外包装法即 123|123456|456 的方式,相当于进行了边缘部分的复制
  • CONSTANT: 进行常数的补全操作, 例如参数 value=0,表示使用颜色 0 进行补全操作

 

        根据扩充效果,首先排除 ConSTANT 方法,单一的色块堆叠(无论什么颜色)会对 Whash 算法造成巨 大误差(先前去除黑边就是为了避免该误差)。

        接下来则是运行测试样例,统计不同扩充方式对图片匹配准确率提升的大小。测试时挑选了原本无法正确匹配的裁剪类图片100 张,分别使用 REPLICATE、REFLECT、REFLECT_101、WRAP 四种算法进行边界填充,REPLICATE 算法表现最好,再次成功识别了42张(裁切类型直接匹配准确率不足30%,这还是裁切部分不算太多的情况下,相当惨淡),其余算法均在35张左右。

        因为详细代码过长,此处不进行全部粘贴,文末会附上代码和数据集的下载链接

        3.1 build.py

 
 

 build.py运行时需要传入db文件夹位置,并指定cache文件夹,用来存放切图和hash值文件

 

3.2 query_image.py

 
 
 
 

         query_image.py执行时需要传入先前的cache参数,指定结果输出文件位置result,指定待查找图片位置img

 

3.3 query_video.py

        与query_image.py极为相似,多出一步待测视频切帧的步骤

 

4.1 运行 build.py

  • --db: db 样本池的完全路径
  • --cache: 指定一个文件夹存放预处理相关数据,同样需要输入完全路径

        jupyter或linux请执行

        python build.py --db /data/db --cache /data/cache cache

        文件夹会自动创建,事先手动创建也可,下同

4.2 运行 query_image.py

  • --cache: build 中指定的 cache 完全路径
  • --result: 运行结果存放路径,从中查询匹配结果 result.csv 及时间花费 time_cost.txt
  • --img: 指定待查找图片文件夹的完全路径

       jupyter或linux请执行

        python query_image.py --cache /data/cache --result /data/result --img /data/image

4.3:运行 query_video.py 

  • --cache: build 中指定的 cache 完全路径
  • --result: 运行结果存放路径,从中查询匹配结果 result.csv 及时间花费 time_cost.txt
  • --video: 指定待查找视频文件夹的完全路径

        jupyter或linux请执行

        python query_video.py --cache /data/cache --result /data/result --img /data/video

4.4pycharm传参方式

 

 4.5 build执行如下

        此时正在切图

        此时正在生成对应hash值

        处理完毕

 4.6 query_image.py执行如下

        第一行的预处理可能会持续稍久一点,因为此时会判断是否存在黑边和裁切类型,并且尝试除去黑边和补全裁切。

         匹配完毕并保存匹配文件到指定目录。

  4.6 query_image.py执行如下

         此时正在视频切帧

         此时正在匹配

         匹配完成并保存匹配文件到指定目录

 4.7 观察结果

 

5.1 数据集方面 

        数据集分为

  •         总数据集(分卷压缩
  •         tiny数据集(200个db、200个image、video

5.2 代码方面

        代码分为

  •         for_windows建议在pycharm中按指定传参方式运行
  •         for_docker根据镜像和dockerfile搭建环境并挂载外部数据

        额外提供一个创建数据库及对应image、video的代码方式,首先随意手动创建一个db,然后填入3186个视频的总数据地址,会根据名称自动建库,代码不在赘述,相信应该较为浅显易懂。

        额外提供一个检测准确率的代码方式,指定csv文件地址,调整好正确的列名,即可计算准确率。 

代码及数据集链接

提取码:3b51 

    以上就是本篇文章【Python基于Imagehash及OpenCV的图像视频数据媒资检索】的全部内容了,欢迎阅览 ! 文章地址:http://yejunbin01.xhstdz.com/quote/76764.html 
     栏目首页      相关文章      动态      同类文章      热门文章      网站地图      返回首页 物流园资讯移动站 http://yejunbin01.xhstdz.com/mobile/ , 查看更多   
发表评论
0评