基于传统CV实现图片分类(以图搜图)
Posted mini梁翊洲MAX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于传统CV实现图片分类(以图搜图)相关的知识,希望对你有一定的参考价值。
图片分类在计算机领域并不是一个新鲜的话题了,相对于传统计算机视觉(CV)方法解决这类问题,深度学习的效果反而更好。但是我们依然需要了解传统做法,说不定在未来研究时可以提供不一样的灵感。
图像描述符
要实现图像分类,首先我们需要提取我们图像库里已有图像的特征,这个过程称为描述图像。图像描述符定义了我们如何量化图像,而其输出可以看作图像本身的抽象。图像描述符的选取可以有很多,可以以颜色,形状为基准或者质地为基准。关于图像描述符更多更详细的介绍将在后面的文章中说明。在本文中,我们使用颜色中的颜色直方图作为图像描述符。
相似度指标
如何判断目标图像和图像库里的某一个图像是否是一类?我们可以通过比较二者的图像描述符来判断。而这个比较方法我们称之为相似度指标,即用来判断两者是否相似的标准。关于相似度指标更多更详细的介绍将在后面的文章中说明。
代码及简单解释
导入必要的库,如果导入失败可以pip安装或者自行搜索导入教程。
import imutils
import cv2
from imutils.paths import list_images
import argparse
import numpy as np
import os
这个是颜色直方图的类,在这里简单介绍一下颜色直方图calcHist()。颜色直方图可以将显示图片中各像素数值区间内像素的数量。例如,我们将bin设为2,那么意味着我们将像素范围[0,255]等比例分为2份[0,127];[128,255]。然后计算图片里属于[0,127]的像素的个数和属于[128,255]的像素的个数。像素数值的大小反映了亮暗程度,各个通道RGB的像素又分别代表了颜色的深浅。于是两幅整体颜色相近的图片的颜色直方图是类似的。
在实际应用时我们也应该注意一点,不同图像的像素数量可能不同,于是我们可以使用归一化normalize(),将数量换成比例。例如[100,300],经过归一化后变为[0.25,0.75]。这样就可以比较不同大小的图像的颜色直方图。
class ColorHistogram:
def __init__(self,bins):
self.bins=bins
def describe(self,image):
hist=cv2.calcHist([image],[0,1,2],None,self.bins,
[0,256,0,256,0,256])
hist=cv2.normalize(hist,hist)
return hist.flatten()
初始化,bin选择32。我们要注意bin的选择会影响数据量的多少,对于小数据集来说,bin选取较大时构建颜色直方图的时间似乎并没有增长太多。但是对于后续比较相似度时,bin的大小将会明显影响计算的时间。而且可以肯定的是,bin选取越大对于分类的准确性是有提升的。但是提升的幅度可能在到达某一点后就大幅减少,此时再通过堆计算量来提升那一两个百分点其实是没有必要的,尤其是对于专注于应用的同学。
ap=argparse.ArgumentParser()
ap.add_argument("-d","--dataset",required=True)
ap.add_argument("-i","--image",required=True)
args=vars(ap.parse_args())
index=
desc=ColorHistogram([32,32,32])
for imagePath in list_images(args["dataset"]):
k=imagePath[imagePath.rfind("/")+1:]
image=cv2.imread(imagePath)
features=desc.describe(image)
index[k]=features
读取我们的图像库,我的图像库里有从网上下载的20张图片,分别包括海洋,树林和沙漠。
定义我们的分类的类,这里面chi2_distance()就是本文使用的相似度指标。我们在这里面对目标图像的图像描述符和图像库的各个图像的图像描述符基于相似度指标来计算相似度,并将其按小到大的顺序排列。
class Classif:
def __init__(self,index):
self.index=index
def classif(self,iFeature):
results=
for (k,features) in self.index.items():
d=self.chi2_distance(features,iFeature)
results[k]=d
results=sorted([(v,k) for (k,v) in results.items()])
return results
def chi2_distance(self,histA,histB,eps=1e-10):
d=0.5*np.sum([((a-b)**2)/(a+b+eps) for (a,b) in zip(histA,histB)])
return d
读取我们的目标图片,提取图像描述符并进行分类。分类结束后,我们提取图像库中相似度最高的五张图像进行展示。
image=cv2.imread(args["image"])
cv2.imshow("Image",image)
Features=desc.describe(image)
clas=Classif(index)
results=clas.classif(Features)
montage=np.zeros((100*5,200,3),dtype="uint8")
for j in range(0,5):
(score,imageName)=results[j]
path=os.path.join(args["dataset"],imageName)
result=cv2.imread(path)
result=cv2.resize(result,(200,100))
if j<5:
montage[j*100:(j+1)*100,:]=result
cv2.imshow("Result",montage)
cv2.waitKey(0)
结果
看起来不错,但很明显这个分类器对颜色很敏感,并不完全符合我们对于分类器的需求。我们也可以根据我们想要分类图片的特征来选取图像描述符,例如有些图片里物体的形状特征很明显。当然,后期我们也会介绍神经网络,深度学习的方法,这个是目前的主流。
“本站所有文章均为原创,欢迎转载,请注明文章出处:https://blog.csdn.net/kasami_/article/details/123834951。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。”
以上是关于基于传统CV实现图片分类(以图搜图)的主要内容,如果未能解决你的问题,请参考以下文章
以图搜图 最佳实践阿里云 Elasticsearch 向量检索4步搭建“以图搜图”搜索引擎,