python简单代码图⽚-利⽤Python实现简单的相似图⽚搜索的
教程
⼤概五年前吧,我那时还在为⼀家约会⽹站做开发⼯作。他们是早期创业公司,但他们也开始拥有了⼀些稳定⽤户量。不像其他约会⽹站,这家公司向来以洁⾝⾃好为主要市场形象。它不是⼀个供你⿁混的⽹站——是让你能到忠实伴侣的地⽅。
由于投⼊了数以百万计的风险资本(在US⼤萧条之前),他们关于真爱并寻灵魂伴侣的在线⼴告势如破⽵。Forbes(福布斯,美国著名财经杂志)采访了他们。全国性电视节⽬也对他们进⾏了专访。早期的成功促成了事业起步时让⼈垂涎的指数级增长现象——他们的⽤户数量以每⽉加倍的速度增长。对他们⽽⾔,⼀切都似乎顺风顺⽔。
但他们有⼀个严重的问题——⾊情问题。
该约会⽹站的⽤户中会有⼀些⼈上传⾊情图⽚,然后设置为其个⼈头像。这种⾏为破坏了很多其他⽤户的体验——导致很多⽤户取消了会员。
可能对于现在的⼀些约会⽹站随处可见⼏张⾊情图⽚也许并不能称之为是问题。或者可以说是习以为常甚⾄有些期待,只是⼀个被接受然后被⽆视的在线约会的副产品。
然⽽,这样的⾏为既不应该被接受也应该被忽视。
别忘了,这次创业可是将⾃⼰定位在优秀的约会天堂,免于⽤户受到困扰其他约会⽹站的污秽和垃圾的烦扰。简⽽⾔之,他们拥有很实在的以风险资本作为背后⽀撑的名声,⽽这也正是他们需要保持的风格。
该约会⽹站为了能迅速阻⽌⾊情图⽚的爆发可以说是不顾⼀切了。他们雇佣了图⽚论坛版主团队,真是不做其他事只是每天盯着监管页⾯8个⼩时以上,然后移除任何被上传到社交⽹络的⾊情图⽚。
毫不夸张的说,他们投⼊了数万美元(更不⽤说数不清的⼈⼯⼩时)来解决这个问题,然⽽也仅仅只是缓解,控制情况不变严重⽽不是在源头上阻⽌。
⾊情图⽚的爆发在2009年的七⽉达到了临界⽔平。8个⽉来第⼀次⽤户量没能翻倍(甚⾄已经开始减少了)。更糟糕的是,投资者声称若该公司不能解决这个问题将会撤资。事实上,污秽的潮汐早已开始冲击这座象⽛塔了,将它推翻流⼊⼤海也不过是时间问题。
正在这个约会⽹站巨头快要撑不住时,我提出了⼀个更鲁棒的长期解决⽅案:如果我们使⽤图⽚指纹来与⾊情图⽚的爆发⽃争呢?
你看,每张图⽚都有⼀个指纹。正如⼈的指纹可以识别⼈,图⽚的指纹能识别图⽚。
这促使了⼀个三阶段算法的实现:
1. 为不雅图⽚建⽴指纹,然后将图⽚指纹存储在⼀个数据库中。
2. 当⼀个⽤户上传⼀份新的头像时,我们会将它与数据库中的图⽚指纹对⽐。如果上传图⽚的指纹与数据库任意⼀个不雅图⽚指纹相符,我们就阻⽌⽤户将该图⽚设置为个⼈头像。
3. 当图⽚监管⼈标记新的⾊情图⽚时,这些图⽚也被赋予指纹并存⼊我们的数据库,建⽴⼀个能⽤于阻⽌⾮法上传且不断进化的数据库。
我们的⽅法,尽管不⼗分完美,但是也卓有成效。慢慢地,⾊情图⽚爆发的情况有所减慢。它永远不会消失——但这个算法让我们成功将⾮法上传的数量减少了80%以上。
这也挽回了投资者的⼼。他们继续为我们提供资⾦⽀持——直到萧条到来,我们都失业了。
回顾过去时,我不禁笑了。我的⼯作并没持续太久。这个公司也没有坚持太久。甚⾄还有⼏个投资者卷铺盖⾛⼈了。
但有⼀样确实存活了下来。提取图⽚指纹的算法。⼏年之后,我把这个算法的基本内容分享出来,期望你们可以将它应⽤到你们⾃⼰的项⽬中。
但最⼤的问题是,我们怎么才能建⽴图⽚指纹呢?
继续读下去⼀探究竟吧。
即将要做的事情
我们打算⽤图⽚指纹进⾏相似图⽚的检测。这种技术通常被称为"感知图像hash”或是简单的"图⽚hash”。
什么是图⽚指纹/图⽚哈希
图⽚hash是检测⼀张图⽚的内容然后根据检测的内容为图⽚建⽴⼀个唯⼀值的过程。
⽐如,看看本⽂最上⾯的那张图⽚。给定⼀张图⽚作为输⼊,应⽤⼀个hash函数,然后基于图⽚的视觉计算出⼀个图⽚hash。相似的图⽚也应当有相似的hash值。图⽚hash算法的应⽤使得相似图⽚的检测变得相当简单了。
特别地,我们将会使⽤"差别Hash”或简单的DHash算法计算图⽚指纹。简单来说,DHash算法着眼于两个相邻像素之间的差值。然后,基于这样的差值,就建⽴起⼀个hash值了。
为什么不使⽤md5,sha-1等算法?
不幸的是,我们不能在实现中使⽤加密hash算法。由于加密hash算法的本质使然,输⼊⽂件中⾮常微⼩的差别也能造成差异极⼤的hash 值。⽽在图⽚指纹的案例中,我们实际上希望相似的输⼊可以有相似的hash输出值。
图⽚指纹可以⽤在哪⾥?
正如我上⾯举的例⼦,你可以使⽤图⽚指纹来维护⼀个保存不雅图⽚的数据库——当⽤户尝试上传类似图⽚时可以发出警告。
你可以建⽴⼀个图⽚的逆向搜索引擎,⽐如TinEye,它可以记录图⽚以及它们出现的相关⽹页。
你还可以使⽤图⽚指纹帮助管理你个⼈的照⽚收集。假设你有⼀个硬盘,上⾯有你照⽚库的⼀些局部备份,但需要⼀个⽅法删除局部备份,⼀张图⽚仅保留⼀份唯⼀的备份——图⽚指纹可以帮你做到。
简单来说,你⼏乎可以将图⽚指纹/哈希⽤于任何需要你检测图⽚的相似副本的场景中。
需要的库有哪些?
为了建⽴图⽚指纹⽅案,我们打算使⽤三个主要的Python包:
ImageHash,包括DHash的实现
以及NumPy/SciPy,ImageHash的依赖包
你可以使⽤下列命令⼀键安装所需要的必备库:
1
$ pipinstall
pillow imagehash
第⼀步:为⼀个图⽚集建⽴指纹
第⼀步就是为我们的图⽚集建⽴指纹。
也许你会问,但我们不会,我们不会使⽤那些我为那家约会⽹站⼯作时的⾊情图⽚。相反,我创建了⼀个可供使⽤的⼈⼯数据集。
对计算机视觉的研究⼈员⽽⾔,数据集CALTECH-101是⼀个传奇般的存在。它包含来⾃101个不同分类中的⾄少7500张图⽚,内容分别有⼈物,摩托车和飞机。
从这7500多张图⽚中,我随机的挑选了17张。
然后,从这17张随机挑选的图⽚中,以⼏个百分点的⽐例随机放⼤/缩⼩并创建N张新图⽚。这⾥我们的⽬标是到这些近似副本的图⽚——有点⼤海捞针的感觉。
你也想创建⼀个类似的数据集⽤于⼯作吗?那就下载CALTECH-101数据集,抽取⼤概17张图⽚即可,然后运⾏repo下的脚本⽂件gather.py。
回归正题,这些图⽚除了宽度和⾼度,其他各⽅⾯都是⼀样的。⽽且因为他们没有相同的形状,我们不能依赖简单的md5校验和。最重要的是,有相似内容的图⽚可能有完全不相同的md5哈希。然⽽,采取图⽚哈希,相似内容的图⽚也有相似的哈希指纹。
所以赶紧开始写代码为数据集建⽴指纹吧。创建⼀个新⽂件,命名为index.py,然后开始⼯作:
1
2
3
4
5
python怎么读取py文件
6
7
8
9
10
11
12
13
14
15
16
17
# import the necessary packages
from PILimport Image
import imagehash
import argparse
import shelve
import glob
# construct the argument parse and parse the arguments ap=
argparse.ArgumentParser()
ap.add_argument("-d","--dataset", required= True,
help = "path to input dataset of images")
ap.add_argument("-s","--shelve", required= True,
help = "output shelve database")
args=
vars(ap.parse_args())
# open the shelve database
db=
shelve.open(args["shelve"], writeback= True)
要做的第⼀件事就是引⼊我们需要的包。我们将使⽤PIL或Pillow中的Image类载⼊硬盘上的图⽚。这个imagehash库可以被⽤于构建哈希算法。
Argparse库⽤于解析命令⾏参数,shelve库⽤作⼀个存储在硬盘上的简单键值对数据库(Python字典)。glob库能很容易的获取图⽚路径。
然后传递命令⾏参数。第⼀个,—dataset是输⼊图⽚库的路径。第⼆个,—shelve是shelve数据库的
输出路径。
下⼀步,打开shelve数据库以写数据。这个db数据库存储图⽚哈希。更多的如下所⽰:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# loop over the image dataset
for imagePathin glob.glob(args["dataset"]+ "/*.jpg"):
# load the image and compute the difference hash
image= Image.open(imagePath)
h= str(imagehash.dhash(image))
# extract the filename from the path and update the database
# using the hash as the key and the filename append to the
# list of values
filename= imagePath[imagePath.rfind("/")+ 1:]
db[h]= db.get(h, [])
+ [filename]
# close the shelf database
db.close()
以上就是⼤部分⼯作的内容了。开始循环从硬盘读取图⽚,创建图⽚指纹并存⼊数据库。
现在,来看看整个范例中最重要的两⾏代码:
1
2
filename=
imagePath[imagePath.rfind("/")+ 1:]
db[h]=
<(h, [])+ [filename]
正如本⽂早些时候提到的,有相同指纹的图⽚被认为是⼀样的。
因此,如果我们的⽬标是到近似图⽚,那就需要维护⼀个有相同指纹值的图⽚列表。
⽽这也正是这⼏⾏代码做的事情。
前⼀个代码段提取了图⽚的⽂件名。⽽后⼀个代码⽚段维护了⼀个有相同指纹值的图⽚列表。
为了从我们的数据库中提取图⽚指纹并建⽴哈希数据库,运⾏下列命令:
1
$ python index.py —dataset images —shelve db.shelve
这个脚本会运⾏⼏秒钟,完成后,就会出现⼀个名为db.shelve的⽂件,包含了图⽚指纹和⽂件名的键值对。
这个基本算法正是⼏年前我为这家约会创业公司⼯作时使⽤的算法。我们获得了⼀个不雅图⽚集,为其中的每张图⽚构建⼀个图⽚指纹并将其存⼊数据库。当来⼀张新图⽚时,我只需简单地计算它的哈希值,检测数据库查看是否上传图⽚已被标识为⾮法内容。
下⼀步中,我将展⽰实际如何执⾏查询,判定数据库中是否存在与所给图⽚具有相同哈希值的图⽚。
第⼆步:查询数据集
既然已经建⽴了⼀个图⽚指纹的数据库,那么现在就该搜索我们的数据集了。
打开⼀个新⽂件,命名为search.py,然后开始写代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论