【问题标题】:Bag Of Visual Words Implementation in Python is giving terrible accuracy用 Python 实现的视觉词袋的实现给出了可怕的准确性
【发布时间】:2018-12-12 14:42:57
【问题描述】:

我正在尝试自己实现一个词袋分类器来对我拥有的数据集进行分类。为了确定我的实现是正确的,我只使用了加州理工学院数据集 (http://www.vision.caltech.edu/Image_Datasets/Caltech101/) 中的两个类来测试我的实现:大象和电吉他。由于它们在视觉上完全不同,我相信正确实施视觉词袋 (BOVW) 分类可以准确地对这些图像进行分类。

根据我的理解(如果我错了请纠正我),正确的 BOVW 分类发生在三个步骤中:

  1. 从训练图像中检测 SIFT 128 维描述符并使用 k-means 对它们进行聚类。

  2. 在 k-means 分类器(在步骤 1 中训练)中测试训练和测试图像 SIFT 描述符,并制作分类结果的直方图。

  3. 将这些直方图用作 SVM 分类的特征向量

正如我之前解释的,我试图解决一个非常简单的问题,即对两个截然不同的类进行分类。我正在从文本文件中读取训练和测试文件,我使用训练图像 SIFT 描述符来训练 k-means 分类器,使用训练和测试图像来获取分类的直方图,最后将它们用作分类的特征向量。

我的解决方案的源代码如下:

import numpy as np
from sklearn import svm
from sklearn.metrics import accuracy_score

#this function will get SIFT descriptors from training images and 
#train a k-means classifier    
def read_and_clusterize(file_images, num_cluster):

    sift_keypoints = []

    with open(file_images) as f:
        images_names = f.readlines()
        images_names = [a.strip() for a in images_names]

        for line in images_names:
        print(line)
        #read image
        image = cv2.imread(line,1)
        # Convert them to grayscale
        image =cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
        # SIFT extraction
        sift = cv2.xfeatures2d.SIFT_create()
        kp, descriptors = sift.detectAndCompute(image,None)
        #append the descriptors to a list of descriptors
        sift_keypoints.append(descriptors)

    sift_keypoints=np.asarray(sift_keypoints)
    sift_keypoints=np.concatenate(sift_keypoints, axis=0)
    #with the descriptors detected, lets clusterize them
    print("Training kmeans")    
    kmeans = MiniBatchKMeans(n_clusters=num_cluster, random_state=0).fit(sift_keypoints)
    #return the learned model
    return kmeans

#with the k-means model found, this code generates the feature vectors 
#by building an histogram of classified keypoints in the kmeans classifier 
def calculate_centroids_histogram(file_images, model):

    feature_vectors=[]
    class_vectors=[]

    with open(file_images) as f:
        images_names = f.readlines()
        images_names = [a.strip() for a in images_names]

        for line in images_names:
        print(line)
        #read image
        image = cv2.imread(line,1)
        #Convert them to grayscale
        image =cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
        #SIFT extraction
        sift = cv2.xfeatures2d.SIFT_create()
        kp, descriptors = sift.detectAndCompute(image,None)
        #classification of all descriptors in the model
        predict_kmeans=model.predict(descriptors)
        #calculates the histogram
        hist, bin_edges=np.histogram(predict_kmeans)
        #histogram is the feature vector
        feature_vectors.append(hist)
        #define the class of the image (elephant or electric guitar)
        class_sample=define_class(line)
        class_vectors.append(class_sample)

    feature_vectors=np.asarray(feature_vectors)
    class_vectors=np.asarray(class_vectors)
    #return vectors and classes we want to classify
    return class_vectors, feature_vectors


def define_class(img_patchname):

    #print(img_patchname)
    print(img_patchname.split('/')[4])

    if img_patchname.split('/')[4]=="electric_guitar":
        class_image=0

    if img_patchname.split('/')[4]=="elephant":
    class_image=1

    return class_image

def main(train_images_list, test_images_list, num_clusters):
    #step 1: read and detect SURF keypoints over the input image (train images) and clusterize them via k-means 
    print("Step 1: Calculating Kmeans classifier")
    model= bovw.read_and_clusterize(train_images_list, num_clusters)

    print("Step 2: Extracting histograms of training and testing images")
    print("Training")
    [train_class,train_featvec]=bovw.calculate_centroids_histogram(train_images_list,model)
    print("Testing")
    [test_class,test_featvec]=bovw.calculate_centroids_histogram(test_images_list,model)

    #vamos usar os vetores de treino para treinar o classificador
    print("Step 3: Training the SVM classifier")
    clf = svm.SVC()
    clf.fit(train_featvec, train_class)

    print("Step 4: Testing the SVM classifier")  
    predict=clf.predict(test_featvec)

    score=accuracy_score(np.asarray(test_class), predict)

    file_object  = open("results.txt", "a")
    file_object.write("%f\n" % score)
    file_object.close()

    print("Accuracy:" +str(score))

if __name__ == "__main__":
    main("train.txt", "test.txt", 1000)
    main("train.txt", "test.txt", 2000)
    main("train.txt", "test.txt", 3000)
    main("train.txt", "test.txt", 4000)
    main("train.txt", "test.txt", 5000)

如您所见,我尝试在 kmeans 分类器中改变很多簇的数量。但是,无论我尝试什么,准确率始终是 53.62%,考虑到图像类非常不同,这太糟糕了。

那么,我对 BOVW 的理解或实施有什么问题吗?我在这里弄错了什么?

【问题讨论】:

    标签: python image-processing machine-learning computer-vision


    【解决方案1】:

    解决方案比我想象的要简单。

    在这一行:

      hist, bin_edges=np.histogram(predict_kmeans)
    

    bin 的数量是来自 numpy 的标准 bin 数量(我相信它是 10)。通过这样做:

       hist, bin_edges=np.histogram(predict_kmeans, bins=num_clusters)
    

    使用 1000 个聚类,因此使用 1000 个维度向量,准确度从我报告的 53.62% 提高到 78.26%。

    【讨论】:

    • 仅供参考:在github.com/shackenberg/… 中,他们使用sqrt 的筛选特征数作为集群数。
    • @Framester 根据您的建议,我使用 RBF 内核 SVM 分类器对成本和 gamma 参数进行网格搜索,准确率达到 84.05%。非常感谢您的建议。
    【解决方案2】:

    看起来您正在为每个图像创建集群和直方图。但是为了让它工作,你必须聚合所有图像的筛选特征,然后对这些图像进行聚类,并使用这些常见的聚类来创建直方图。也可以查看https://github.com/shackenberg/Minimal-Bag-of-Visual-Words-Image-Classifier

    【讨论】:

    • 我正在从所有训练图像中提取 SIFT 描述符并将它们聚合到同一个矩阵中。该矩阵用于 k 均值聚类。您是否建议我也考虑在 k-means 聚类中测试图像时使用 SIFT 描述符?
    • > 我正在从所有训练图像中提取 SIFT 描述符并将它们聚合到同一个矩阵中。啊,比我忽略了。 > 你是否建议我也考虑在 k-means 聚类中测试图像的 SIFT 描述符?不,这不合理并会导致过度拟合,因为会使用(隐式)来自测试集的信息。
    • 聚合筛选特征是什么意思?我已经在使用所有训练图像中的所有 SIFT 特征将它们聚集在 k-means 中。在您建议我检查的代码中,作者说“为每个转换图像聚合视觉词的直方图”,这对我来说很模棱两可。在我的理解中,我们不会聚合直方图,我们所做的是考虑来自同一图像的所有点(聚合它的点)来计算它的直方图。我在这里不明白什么?谢谢。
    • 我认为这意味着,为每张图像计算直方图,所有这些直方图都“聚合”或更好地“收集”在一个“数据结构”中,并用作训练的特征。
    猜你喜欢
    • 2013-11-02
    • 1970-01-01
    • 2015-10-22
    • 2018-06-15
    • 2018-08-05
    • 1970-01-01
    • 2012-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多