OpenCV特征提取与图像检索实现(附代码)

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

OpenCV特征提取与图像检索实现(附代码)“拍立淘”“一键识花”“街景匹配”……不知道大家在使用这些神奇的功能的时候,有没有好奇过它们背后的技术原理?其实这些技术都离不开最基本的图像检索技术。本篇文章我们就将对这一技术的原理进行介绍,并通过一个简单的Python脚本来实现一个最基本的图像检索demo。▌图像特征首先我们需要明白图像特征是什么以及它的使用方法。图像特征是一种简单的图像模式,基于这种模式我们可以描述我们在图像上所看到的内容。例如,在一张跟猫有关的图片中,猫咪的眼睛就可以作为这幅图像的特征。特征在(包括但不限于)计算机视觉中的主要作用是将视觉信息转换为向量空间表示。这种向量空间表示让我们可以利用数学运算对其进行处理,例如通过计算寻找相似向量(这可以用来寻找相似图像或图像中的相似目标)。▌如何从图像中获取特征?从图像中获取特征的方法有两种,第一种是通过提取图像描述符实现(白盒算法);第二种通过基于神经网络的方法实现(黑盒算法)。本文主要介绍第一种方法。特征提取的算法有很多,最常用的有:SURF、ORB、SIFT、BRIEF等。这些算法大多是基于图像梯度的。为了简化安装需求,本教程使用的是KAZE描述符,因为其他描述符在python的基础OpenCV库中没有提供。下面是特征提取器的实现代码:importcv2importnumpyasnpimportscipyfromscipy.miscimportimreadimportcPickleaspickleimportrandomimportosimportmatplotlib.pyplotasplt#Featureextractor#特征提取器defextract_features(image_path,vector_size=32):image=imread(image_path,mode='RGB')try:#UsingKAZE,causeSIFT,ORBandotherwasmovedtoadditionalmodule#whichisaddingaddtionalpainduringinstall#此处为了简化安装步骤,使用KAZE,因为SIFT/ORB以及其他特征算子需要安#装额外的模块alg=cv2.KAZE_create()#Findingimagekeypoints#寻找图像关键点kps=alg.detect(image)#Gettingfirst32ofthem.#计算前32个#Numberofkeypointsisvariesdependonimagesizeandcolorpallet#关键点的数量取决于图像大小以及彩色调色板#Sortingthembasedonkeypointresponsevalue(biggerisbetter)#根据关键点的返回值进行排序(越大越好)kps=sorted(kps,key=lambdax:-x.response)[:vector_size]#computingdescriptorsvector#计算描述符向量kps,dsc=alg.compute(image,kps)#Flattenalloftheminonebigvector-ourfeaturevector#将其放在一个大的向量中,作为我们的特征向量dsc=dsc.flatten()#Makingdescriptorofsamesize#使描述符的大小一致#Descriptorvectorsizeis64#描述符向量的大小为64needed_size=(vector_size*64)ifdsc.size#ifwehavelessthe32descriptorsthenjustaddingzeros#attheendofourfeaturevector#如果少于32个描述符,则在特征向量后面补零dsc=np.concatenate([dsc,np.zeros(needed_size-dsc.size)])exceptcv2.errorase:print'Error:',ereturnNonereturndscdefbatch_extractor(images_path,pickled_db_path='features.pck'):files=[os.path.join(images_path,p)forpinsorted(os.listdir(images_path))]result={}forfinfiles:print'Extractingfeaturesfromimage%s'%fname=f.split('/')[-1].lower()result[name]=extract_features(f)#savingallourfeaturevectorsinpickledfile#将特征向量存于pickled文件withopen(pickled_db_path,'w')asfp:pickle.dump(result,fp)OpenCV中的大多数特征提取算法的python接口都相同,所以如果你想要使用SIFT特征,只需要用SIFT_create替换KAZE_create就行。首先,程序会用extract_features检测图像上的关键点(局部模式的中心点)。因为关键点数量随图像的不同有所不同,因此我们需要添加一些规则,以确保所得到的特征向量大小始终相同(这是因为在计算时,我们无法对维度不同的向量进行比较,所以必须保证相同的大小)。然后是根据关键点构建向量描述符,每个描述符的大小为64,我们有32个这样的描述符,所以我们的特征向量是2048维。batch_extractor是在所有的图像中批量运行特征提取器,并将特征向量保存在pickled文件中以供后续使用。现在我们来建立类Matcher,它会将待搜索图像和数据库中的图像进行匹配。classMatcher(object):def__init__(self,pickled_db_path='features.pck'):withopen(pickled_db_path)asfp:self.data=pickle.load(fp)self.names=[]self.matrix=[]fork,vinself.data.iteritems():self.names.append(k)self.matrix.append(v)self.matrix=np.array(self.matrix)self.names=np.array(self.names)defcos_cdist(self,vector):#gettingcosinedistancebetweensearchimageandimagesdatabase#计算待搜索图像与数据库图像的余弦距离v=vector.reshape(1,-1)returnscipy.spatial.distance.cdist(self.matrix,v,'cosine').reshape(-1)defmatch(self,image_path,topn=5):features=extract_features(image_path)img_distances=self.cos_cdist(features)#gettingtop5records#获得前5个记录nearest_ids=np.argsort(img_distances)[:topn].tolist()nearest_img_paths=self.names[nearest_ids].tolist()returnnearest_img_paths,img_distances[nearest_ids].tolist()这里要加载前一步得到的特征向量,并从它们中创建一个大矩阵,然后计算待搜索图像的特征向量和特征向量数据库之间的余弦距离,然后输出最近的前N个结果。当然,这仅仅是一个demo,在实际计算中,还可以用一些算法来快速计算数百万图像间的余弦距离。你可以使用简单且运行速度相当快的AnnoyIndex(在1M图像中搜索约需2ms)。现在把它们放在一起运行一下:defshow_img(path):img=imread(path,mode='RGB')plt.imshow(img)plt.show()defrun():images_path='resources/images/'files=[os.path.join(images_path,p)forpinsorted(os.listdir(images_path))]#getting3randomimages#随机获取3张图sample=random.sample(files,3)batch_extractor(images_path)ma=Matcher('features.pck')forsinsample:print'Queryimage=========================================='show_img(s)names,match=ma.match(s,topn=3)print'Resultimages========================================'foriinrange(3):#wegotcosinedistance,lesscosinedistancebetweenvectors#moretheysimilar,thuswesubtructitfrom1togetmatchvalue#我们得到了余弦距离,向量之间的余弦距离越小表示它们越相似,因此我们从1中减去它以得到匹配值print'Match%s'%(1-match[i])show_img(os.path.join(images_path,names[i]))run()大家可以在我的github上下载源码,或者在GoogleColab上运行(GoogleColab是一种提供GPU在线计算的免费服务):▌总结在运行上述代码的过程中,你可能会发现搜索到的相似图像并不总能达到我们想象中的那种相似程度。这是因为我们所用的这种算法是上下文无关(context-unaware)的,所以该算法在寻找相同(即使是被修改过的)图像方面表现更好,而不是在相似图像方面。如果是要寻找上下文相关的相似图像,那就要使用卷积神经网络了,我的下一篇文章会对这方面的知识进行详细介绍。作者:AndreyNikishaev

1 / 9
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功