第二十节、基于传统图像处理的目标检测与识别(词袋模型BOW+SVM附代码)
在上一节、我们已经介绍了使用HOG和SVM实现目标检测和识别,这一节我们将介绍使用词袋模型BOW和SVM实现目标检测和识别。
一 词袋介绍
词袋模型(Bag-Of-Word)的概念最初不是针对计算机视觉的,但计算机视觉会使用该概念的升级。词袋最早出现在神经语言程序学(NLP)和信息检索(IR)领域,该模型忽略掉文本的语法和语序,用一组无序的单词来表达一段文字或者一个文档。
我们使用BOW在一系列文档中构建一个字典,然后使用字典中每个单词次数构成向量来表示每一个文档。比如:
- 文档1:I like OpenCV and I like Python;
- 文档2:I like C++ and Python;
- 文档3:I don't like artichokes;
对于这三个文档,我们建立如下的字典:
dic = {1:'I', 2:'like', 3:'OpenCV', 4:'and', 5:'Python', 6:'C++', 7:'don\'t', 8:'artichokes'}
该字典一共有8项。使用这8项构成的向量来表示每个文档,每个向量包含字典中的所有单词,向量的每个元素表示文档中每个单词出现的次数。则上面三个文档可以使用如下向量来表示:
[2,2,1,1,1,0,0,0]
[1,1,0,1,1,1,0,0]
[1,1,0,0,0,0,1,1]
每一个向量都可以看做是一个文档的直方图表示或被当做特征,这些特征可以用来训练分类器。在实际中,也有许多有效地应用,比如垃圾邮箱过滤。
二 计算机视觉中的BOW
与应用到文本的BOW模型类比,我们可以把BOW模型应用到计算机视觉,我们把图像的特征当做单词,把图像“文字化”之后,有助于大规模的图像检索。
1、BOW基本步骤
- 特征提取:提取数据集中每幅图像的特征点,然后提取特征描述符,形成特征数据(如:SIFT或者SURF方法);
- 学习词袋:把处理好的特征数据全部合并,利用聚类把特征词分为若干类,此若干类的数目由自己设定,每一类相当于一个视觉词汇;
- 利用视觉词袋量化图像特征:每一张图像由很多视觉词汇组成,我们利用统计的词频直方图,可以表示图像属于哪一类;
这个过程需要获取视觉词汇(visual word)字典,从一定程度上来说,词汇越多越好,因此我们需要的数据集也相应的越大越好;
2、BOW可视化
下面我们来对BOW过程进行可视化,
- 假设我们有三个目标类,分别是人脸、自行车和吉他。首先从图像中提取出相互独立的视觉词汇(假设使用SIFT方法):
通过观察会发现,同一类目标的不同实例之间虽然存在差异,但我们仍然可以找到它们之间的一些共同的地方,比如说人脸,虽然说不同人的脸差别比较大,但眼睛,嘴,鼻子等一些比较细小的部位,却观察不到太大差别,我们可以把这些不同实例之间共同的部位提取出来,作为识别这一类目标的视觉词汇。
- 将所有的视觉词汇集合在一起:
- 利用K-means算法构造词汇字典。K-means算法是一种基于样本间相似性度量的间接聚类方法,此算法以为参数,把个对象分为个簇,以使簇内具有较高的相似度,而簇间相似度较低。SIFT算法提取的视觉词汇向量之间根据距离的远近,可以利用K-Means算法将词义相近的词汇合并,作为词汇字典中的基础词汇,假定我们将设为4,那么词汇字典的构建过程如下:
- 利用词汇字典的中词汇表示图像。利用SIFT算法,可以从每幅图像中提取很多个特征点,这些特征点都可以用词汇字典中的词汇近似代替,通过统计词汇字典中每个词汇在图像中出现的次数,可以将图像表示成为一个$k=4$维数值向量:
上图中,我们从人脸、自行车和吉他三个目标类图像中提取出的不同视觉词汇,而构造的词汇字典中,会把词义相近的视觉词汇合并为同一类,经过合并,词汇表中只包含了四个视觉词汇,分别按索引值标记为1,2,3,4。通过观察可以看到,它们分别属于自行车、人脸、吉他、人脸类。统计这些词汇在不同目标类中出现的次数可以得到每幅图像的直方图表示(我们假定存在误差,实际情况亦不外如此):
人脸: [3,30,3,20] 自行车:[20,3,3,2] 吉他: [8,12,32,7]
其实这个过程非常简单,就是针对人脸、自行车和吉他这三个文档,抽取出相似的部分(或者词义相近的视觉词汇合并为同一类),构造一个字典,字典中包含4个视觉单词,即:
dic = {1:'自行车', 2:'人脸', 3:'吉他', 4:'人脸类'}
最终人脸、自行车和吉他这三个文档皆可以用一个4维向量表示,最后根据三个文档相应部分出现的次数绘制对应的直方图。
需要说明的是,以上过程只是针对三个目标类非常简单的一个示例,实际应用中,为了达到较好的效果,单词表中的词汇数量往往非常庞大,并且目标类数目越多,对应的值也越大,一般情况下,的取值在几百到上千,在这里取仅仅是为了方便说明。
三 目标识别
对于图像和视频检测中的目标类型没有具体限制,但是为了使结果的准确度在可以接收的范围内,需要一个足够大的数据集,包括训练图像的大小尽量也一样。
如果自己构建数据集将会花费较长的时间,因此,在这里我们利用现成的数据集,在网上可以下载这样的数据集,这里我们使用猫和狗的数据集:
https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data
训练集一共包含25000张照片,其中一半是狗(正样本),一半是猫(负样本),在这里我们就使用其中的部分数据集,训练一个二分类器;
- 首先我们选取一定数量的正负样本(这里选择的为10,没有选择全部样本是因为数据量大,计算速度就会很慢,而且该数值小一些有时候效果会更好),然后使用SIFT算法提取特征数据,并使用聚类分类(k=40),形成词汇字典;
- 选取更多正负样本数据集(这里选择的是400),利用视觉词袋(即词汇字典)量化每一个样本特征,并使用SVM进行训练;
- 对100个样本进行测试;
代码如下:
# -*- coding: utf-8 -*- """ Created on Wed Oct 17 09:38:26 2018 @author: zy """ ''' 词袋模型BOW+SVM 目标识别 以狗和猫数据集二分类为例 如果是狗 返回True 如果是猫 返回False ''' import numpy as np import cv2 class BOW(object): def __init__(self,): #创建一个SIFT对象 用于关键点提取 self.feature_detector = cv2.xfeatures2d.SIFT_create() #创建一个SIFT对象 用于关键点描述符提取 self.descriptor_extractor = cv2.xfeatures2d.SIFT_create() def path(self,cls,i): ''' 用于获取图片的全路径 ''' return '%s/%s/%s.%d.jpg'%(self.train_path,cls,cls,i+1) def fit(self,train_path,k): ''' 开始训练 args: train_path:训练集图片路径 我们使用的数据格式为 train_path/dog/dog.i.jpg train_path/cat/cat.i.jpg k:k-means参数k ''' self.train_path = train_path #FLANN匹配 参数algorithm用来指定匹配所使用的算法,可以选择的有LinearIndex、KTreeIndex、KMeansIndex、CompositeIndex和AutotuneIndex,这里选择的是KTreeIndex(使用kd树实现最近邻搜索) flann_params = dict(algorithm=1,tree=5) flann = cv2.FlannBasedMatcher(flann_params,{}) #创建BOW训练器,指定k-means参数k 把处理好的特征数据全部合并,利用聚类把特征词分为若干类,此若干类的数目由自己设定,每一类相当于一个视觉词汇 bow_kmeans_trainer = cv2.BOWKMeansTrainer(k) pos = 'dog' neg = 'cat' #指定用于提取词汇字典的样本数 length = 10 #合并特征数据 每个类从数据集中读取length张图片(length个狗,length个猫),通过聚类创建视觉词汇 for i in range(length): bow_kmeans_trainer.add(self.sift_descriptor_extractor(self.path(pos,i))) bow_kmeans_trainer.add(self.sift_descriptor_extractor(self.path(neg,i))) #进行k-means聚类,返回词汇字典 也就是聚类中心 voc = bow_kmeans_trainer.cluster() #输出词汇字典 <class 'numpy.ndarray'> (40, 128) print(type(voc),voc.shape) #初始化bow提取器(设置词汇字典),用于提取每一张图像的BOW特征描述 self.bow_img_descriptor_extractor = cv2.BOWImgDescriptorExtractor(self.descriptor_extractor,flann) self.bow_img_descriptor_extractor.setVocabulary(voc) #创建两个数组,分别对应训练数据和标签,并用BOWImgDescriptorExtractor产生的描述符填充 #按照下面的方法生成相应的正负样本图片的标签 1:正匹配 -1:负匹配 traindata,trainlabels = [],[] for i in range(400): #这里取200张图像做训练 traindata.extend(self.bow_descriptor_extractor(self.path(pos,i))) trainlabels.append(1) traindata.extend(self.bow_descriptor_extractor(self.path(neg,i))) trainlabels.append(-1) #创建一个SVM对象 self.svm = cv2.ml.SVM_create() #使用训练数据和标签进行训练 self.svm.train(np.array(traindata),cv2.ml.ROW_SAMPLE,np.array(trainlabels)) def predict(self,img_path): ''' 进行预测样本 ''' #提取图片的BOW特征描述 data = self.bow_descriptor_extractor(img_path) res = self.svm.predict(data) print(img_path,'\t',res[1][0][0]) #如果是狗 返回True if res[1][0][0] == 1.0: return True #如果是猫,返回False else: return False def sift_descriptor_extractor(self,img_path): ''' 特征提取:提取数据集中每幅图像的特征点,然后提取特征描述符,形成特征数据(如:SIFT或者SURF方法); ''' im = cv2.imread(img_path,0) return self.descriptor_extractor.compute(im,self.feature_detector.detect(im))[1] def bow_descriptor_extractor(self,img_path): ''' 提取图像的BOW特征描述(即利用视觉词袋量化图像特征) ''' im = cv2.imread(img_path,0) return self.bow_img_descriptor_extractor.compute(im,self.feature_detector.detect(im)) if __name__ == '__main__': #测试样本数量,测试结果 test_samples = 100 test_results = np.zeros(test_samples,dtype=np.bool) #训练集图片路径 狗和猫两类 进行训练 train_path = './data/cat_and_dog/data/train' bow = BOW() bow.fit(train_path,40) #指定测试图像路径 for index in range(test_samples): dog = './data/cat_and_dog/data/train/dog/dog.{0}.jpg'.format(index) dog_img = cv2.imread(dog) #预测 dog_predict = bow.predict(dog) test_results[index] = dog_predict #计算准确率 accuracy = np.mean(test_results.astype(dtype=np.float32)) print('测试准确率为:',accuracy) #可视化最后一个 font = cv2.FONT_HERSHEY_SIMPLEX if test_results[0]: cv2.putText(dog_img,'Dog Detected',(10,30),font,1,(0,255,0),2,cv2.LINE_AA) cv2.imshow('dog_img',dog_img) cv2.waitKey(0) cv2.destroyAllWindows()
运行结果如下:
四 目标检测
在上面我们已经初步完成了目标识别,但是还有个问题我们没有解决,假设一张图中有多个目标,我们有时候需要定位到每个目标的具体位置。要想做到这一点,我们需要使用滑动窗口的方法,对每一个候选区域进行目标识别,具体步骤如下:
- 给定一张图像28×28×3 的图片应用滑动窗口操作,以 14×14 区域滑动窗口,从左到右移动,从上到下移动,对于每得到的一个滑动区域,使用BOW训练很好的SVM进行分类;
- 把每个滑动区域的预测结果保存下来;
- 完成整个图像的分类后,缩放图像并重复整个滑动窗口的过程;
- 继续对图像进行缩放和分类,直至缩放到最小尺寸才停止;
在这个阶段,已经收集了图像内容的重要信息。然而,还有一个问题:很可能检测是以许多评分为正数的重叠块结束。这意味着图像中可能包含被检测四五次的对象,如果将这些作为检测结果,那么这个结果是相当不准确的,因此需要使用非极大值抑制解决这个问题。
以人脸检测为例,我们从网上搜集到10000张大小为96×96的人脸图片,以及从一些图片中随机裁切到的10000张大小为96×96非人脸图片:
有了训练集之后,要想训练一个人脸检测的检测器,还需要包含以下步骤:
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了