Scene Recognition with Bag of Words(python实现)

6 篇文章 2 订阅
该博客介绍了基于BOW(Bag of Words)、SVM(Support Vector Machine)和K-means聚类的图像分类方法。首先,通过SIFT特征提取和K-means聚类构建视觉词汇字典,接着利用BOW模型将图像特征向量化,最后通过SVM进行猫狗分类。数据集包含25000张图片,已预处理为猫和狗两个子目录。代码实现包括数据集划分、特征提取、聚类和分类器训练等步骤。
摘要由CSDN通过智能技术生成

目录

一、题目

二、原理

三、数据集的处理

四、代码


一、题目

二、原理

(BOW+SVM+K-means)

我们把图像的特征当做单词,把图像“文字化”之后,有助于大规模的图像检索。

(1)BOW基本步骤

特征提取:提取数据集中每幅图像的特征点,然后提取特征描述符,利用sift方法形成特征数据。

学习词袋:把处理好的特征数据全部合并,利用聚类把特征词分为若干类,此若干类的数目由自己设定,每一类相当于一个视觉词汇;

利用视觉词袋量化图像特征:每一张图像由很多视觉词汇组成,我们利用统计的词频直方图,可以表示图像属于哪一类;

这个过程需要获取视觉词汇(visual word)字典,从一定程度上来说,词汇越多越好,因此我们需要的数据集也相应的越大越好;

(2)K-means

利用sift方法形成特征数据后,我们将这些特征数据进行分类,形成40个类,每一个类均是一个视觉词汇。

(3)SVM

将40个特征词汇再次进行分类,通过SVM将其分为两个类别:cat & dog。

三、数据集的处理

25000张图片(12500狗+12500猫)

处理前的数据:

猫和狗的图片在homework3/data一个文件夹中(部分截图)

     

处理后的数据:

split_dataset.py文件的功能,是在homework3/data文件中建立了两个文件,分别是cat、dog,存储猫和狗的图片,进行copy,防止分类过程中出现错误。

将猫的图片放进homework3/data/cat文件中(部分截图),

将狗的图片放进homework3/data/dog文件中(部分截图)

     

四、代码

1、split_dataset.py

import os
import os.path as osp
import shutil

#图片路径
IMAGE_PATH = 'E:/Pycharm_project/homework3/data'

#将数据中的猫、狗按照文件名进行分类
DOG_DIR = 'E:/Pycharm_project/homework3/data/dog'
CAT_DIR = 'E:/Pycharm_project/homework3/data/cat'

if not osp.exists(DOG_DIR):
    os.makedirs(DOG_DIR)
if not osp.exists(CAT_DIR):
os.makedirs(CAT_DIR)

# dog
dog_fnames = ['dog.{}.jpg'.format(i) for i in range(12500)]
i = 0
for dog_fname in dog_fnames:
    src = osp.join(IMAGE_PATH, dog_fname)
    dat = osp.join(DOG_DIR, dog_fname)
    shutil.copy(src, dat)
    i += 1
    print("dog {} has been coped.".format(i))

# cat
cat_fnames = ['cat.{}.jpg'.format(i) for i in range(12500)]
i = 0
for cat_fname in cat_fnames:
    src = osp.join(IMAGE_PATH, cat_fname)
    dat = osp.join(CAT_DIR, cat_fname)
    shutil.copy(src, dat)
    i += 1
    print("cat{} has been coped.".format(i))

 2、demo.py

import numpy as np
import cv2
import argparse
import os

parser = argparse.ArgumentParser()
parser.add_argument('--train_test_pair', type=str, default='2000_100', help="\'400_100\' or \'500_100\'")
args = parser.parse_args()

class BOW(object):

    def __init__(self, train_sample_num):
        self.train_sample_num = train_sample_num
        # 创建一个SIFT对象  用于关键点提取
        self.feature_detector = cv2.xfeatures2d.SIFT_create()
        # 创建一个SIFT对象  用于关键点描述符提取
        self.descriptor_extractor = cv2.xfeatures2d.SIFT_create()

    def path(self, cls, i):
        '''
        用于获取图片的全路径
        '''
        # print('%s/%s/%s.%d.jpg' % (self.train_path, cls, cls, i + 1))
        return '%s/%s/%s.%d.jpg' % (self.train_path, cls, cls, i + 1)

    def fit(self, train_path, k):
        self.train_path = train_path

        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(self.train_sample_num):  # 这里取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 = str(args.train_test_pair).split("_")[1]
    print("test samples:", test_samples)
    test_samples = int(test_samples)
    test_results = np.zeros(test_samples, dtype=np.bool)

    # 训练集图片路径  狗和猫两类  进行训练
    train_path = 'E:/Pycharm_project/homework3/data'
    train_samples = str(args.train_test_pair).split("_")[0]
    train_samples = int(train_samples)
    print("train samples:", train_samples)
    bow = BOW(train_sample_num=train_samples)
    bow.fit(train_path, 40)

    acc_dir = "./" + str(train_samples) + "_" + str(test_samples)
    if not os.path.exists(acc_dir):
        os.makedirs(acc_dir)
        print("acc_path has been created:", acc_dir)
    acc_path = acc_dir + "/acc.txt"
    with open(acc_path, "w") as acc_f:
        # 指定测试图像路径
        for index in range(12400,12500):
            dog = 'E:/Pycharm_project/homework3/data/dog/dog.{0}.jpg'.format(index)
            print(dog)
            dog_img = cv2.imread(dog)

            # 预测
            dog_predict = bow.predict(dog)
            test_results[index - 12400] = dog_predict

        # 计算准确率
        accuracy = np.mean(test_results.astype(dtype=np.float32))
        print('测试准确率为:', accuracy)
        acc_f.write("测试准确率为: {}".format(accuracy))
        acc_f.write('\n')
        acc_f.flush()
    acc_f.close()

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值