如果需要处理的原图及代码,请移步小编的GitHub地址
传送门:请点击我
如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice
最近一段时间学习并做的都是对图像进行处理,其实自己也是新手,各种尝试,所以我这个门外汉想总结一下自己学习的东西,图像处理的流程。但是动起笔来想总结,一下却不知道自己要写什么,那就把自己做过的相似图片搜索的流程整理一下,想到什么说什么吧。
一:图片相似度算法(对像素求方差并比对)的学习
1.1 算法逻辑
1.1.1 缩放图片
将需要处理的图片所放到指定尺寸,缩放后图片大小由图片的信息量和复杂度决定。譬如,一些简单的图标之类图像包含的信息量少,复杂度低,可以缩放小一点。风景等复杂场景信息量大,复杂度高就不能缩放太小,容易丢失重要信息。根据自己需求,弹性的缩放。在效率和准确度之间维持平衡。
1.1.2 灰度处理
通常对比图像相似度和颜色关系不是很大,所以处理为灰度图,减少后期计算的复杂度。如果有特殊需求则保留图像色彩。
1.1.3 计算平均值
此处开始,与传统的哈希算法不同:分别依次计算图像每行像素点的平均值,记录每行像素点的平均值。每一个平均值对应着一行的特征。
1.1.4 计算方差
对得到的所有平均值进行计算方差,得到的方差就是图像的特征值。方差可以很好的反应每行像素特征的波动,既记录了图片的主要信息。
1.1.5 比较方差
经过上面的计算之后,每张图都会生成一个特征值(方差)。到此,比较图像相似度就是比较图像生成方差的接近成程度。
一组数据方差的大小可以判断稳定性,多组数据方差的接近程度可以反应数据波动的接近程度。我们不关注方差的大小,只关注两个方差的差值的大小。方差差值越小图像越相似!
1.2 代码:
import cv2
import matplotlib.pyplot as plt
#计算方差
def getss(list):
#计算平均值
avg=sum(list)/len(list)
#定义方差变量ss,初值为0
ss=0
#计算方差
for l in list:
ss+=(l-avg)*(l-avg)/len(list)
#返回方差
return ss
#获取每行像素平均值
def getdiff(img):
#定义边长
Sidelength=30
#缩放图像
img=cv2.resize(img,(Sidelength,Sidelength),interpolation=cv2.INTER_CUBIC)
#灰度处理
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#avglist列表保存每行像素平均值
avglist=[]
#计算每行均值,保存到avglist列表
for i in range(Sidelength):
avg=sum(gray[i])/len(gray[i])
avglist.append(avg)
#返回avglist平均值
return avglist
#读取测试图片
img1=cv2.imread("james.jpg")
diff1=getdiff(img1)
print('img1:',getss(diff1))
#读取测试图片
img11=cv2.imread("durant.jpg")
diff11=getdiff(img11)
print('img11:',getss(diff11))
ss1=getss(diff1)
ss2=getss(diff11)
print("两张照片的方差为:%s"%(abs(ss1-ss2)))
x=range(30)
plt.figure("avg")
plt.plot(x,diff1,marker="*",label="$jiames$")
plt.plot(x,diff11,marker="*",label="$durant$")
plt.title("avg")
plt.legend()
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()
两张原图:
图像结果如下:
img1: 357.03162469135805
img11: 202.56193703703704
两张照片的方差为:154.469687654321
实验环境开始设置了图片像素值,而且进行灰度化处理,此方法比对图像相似对不同的图片方差很大,结果很明显,但是对比比较相似,特别相似的图片不适应。
二:图片相似度算法(感知哈希算法)的学习
"感知哈希算法"(Perceptual hash algorithm),它的作用是对每张图片生成一个"指纹"(fingerprint)字符串,然后比较不同图片的指纹。结果越接近,就说明图片越相似。
2.1 算法步骤
2.1.1 缩小尺寸
将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。
2.1.2 简化色彩
将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。
2.1.3 计算平均值
计算所有64个像素的灰度平均值
2.1.4 比较像素的灰度平均值
将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。
2.1.5 计算哈希值
将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。
得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hamming distance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。
此算法参考博客:http://www.ruanyifeng.com/blog/2011/07
/principle_of_similar_image_search.html
但是未实现代码,代码如下:
#!/usr/bin/python
import glob
import os
import sys
from PIL import Image
EXTS = 'jpg', 'jpeg', 'JPG', 'JPEG', 'gif', 'GIF', 'png', 'PNG'
def avhash(im):
if not isinstance(im, Image.Image):
im = Image.open(im)
im = im.resize((8, 8), Image.ANTIALIAS).convert('L')
avg = reduce(lambda x, y: x + y, im.getdata()) / 64.
return reduce(lambda x, (y, z): x | (z << y),
enumerate(map(lambda i: 0 if i < avg else 1, im.getdata())),
0)
def hamming(h1, h2):
h, d = 0, h1 ^ h2
while d:
h += 1
d &= d - 1
return h
if __name__ == '__main__':
if len(sys.argv) <= 1 or len(sys.argv) > 3:
print "Usage: %s image.jpg [dir]" % sys.argv[0]
else:
im, wd = sys.argv[1], '.' if len(sys.argv) < 3 else sys.argv[2]
h = avhash(im)
os.chdir(wd)
images = []
for ext in EXTS:
images.extend(glob.glob('*.%s' % ext))
seq = []
prog = int(len(images) > 50 and sys.stdout.isatty())
for f in images:
seq.append((f, hamming(avhash(f), h)))
if prog:
perc = 100. * prog / len(images)
x = int(2 * perc / 5)
print '\rCalculating... [' + '#' * x + ' ' * (40 - x) + ']',