视觉词袋

数据挖掘 Python 聚类 图像分类 k-均值
2021-09-14 13:00:59

我正在尝试做的事情:

我正在尝试使用本地和全局特征对一些图像进行分类。

到目前为止我做了什么:

我已经为每个图像提取了筛选描述符,并将其用作 k-means 的输入,以从每个图像的所有特征中创建我的词汇表。从这里开始,我通过将图像筛选特征传递给 k-means 中的预测方法,为每个图像创建一个直方图,为我提供聚类的标签。从这里我通过计算每个 bin 的标签数量来创建直方图。现在我有一个 nxm 矩阵,其中 n 是图像的数量,m 是每个图像的聚类(特征/单词)的数量。

我会将这个矩阵提供给分类器以获取我的图像分类。

简而言之,步骤:

  1. 提取筛选特征描述符,为每个图像提供一个 nx128 矩阵

  2. 将所有特征描述符堆叠成一个大列表

  3. 将所有这些特征拟合到 kmeans 算法设置 k=100

  4. 对于每个图像,使用其筛选特征来使用相同的训练 kmeans 模型预测集群的标签

  5. 使用 k 作为 bin 数从集群创建直方图,模型中每个标签的 bin 加 1。(如果一张图片有 10 个来自 sift 的特征,它将给我们 10 个标签,这 10 个标签将在 k 的范围内,因此对于每个标签,我们将其添加到直方图的相应 bin 中)。

  6. 我们现在有一个 nxk 矩阵,其中 n 是图像的数量,k 是集群的数量。

  7. 我们现在将直方图输入分类器,并要求它对测试数据进行预测。

问题:

我是否正确地执行了视觉词袋?

这是我的代码:

def extract_features(df):
    IF = imageFeatures()
    global_features = []
    sift_features = []
    labels = []
    for i, (index, sample) in enumerate(df.iterrows()):
        image = cv2.imread(sample["location"])
        image = cv2.resize(image, shape)
        hist = IF.fd_histogram(image)
        haralick = IF.fd_haralick(image)
        hu = IF.fd_hu_moments(image)
        lbp = IF.LocalBinaryPatterns(image, 24, 8)
        kp, des = IF.SIFT(image)
        if len(kp) == 0:
            #print (i)
            #print (index)
            #print (sample)
            #return 0
            des = np.zeros(128)
        sift_features.append(des)
        global_feature = np.hstack([hist, haralick, hu, lbp])
        global_features.append(global_feature)
        labels.append(sample["class_id"])
    scaler = MinMaxScaler(feature_range=(0, 1))
    rescaled = scaler.fit_transform(global_features)
    return sift_features, rescaled, labels

def BOVW(feature_descriptors, n_clusters = 100):
    print("Bag of visual words with {} clusters".format(n_clusters))
    #take all features and put it into a giant list
    combined_features = np.vstack(np.array(feature_descriptors))
    #train kmeans on giant list
    print("Starting K-means training")
    kmeans = MiniBatchKMeans(n_clusters=n_clusters, random_state=0).fit(combined_features)
    print("Finished K-means training, moving on to prediction")
    bovw_vector = np.zeros([len(feature_descriptors), n_clusters])#number of images x number of clusters. initiate matrix of histograms
    for index, features in enumerate(feature_descriptors):#sift descriptors in each image
        try:
            for i in kmeans.predict(features):#get label for each centroid
                bovw_vector[index, i] += 1#create individual histogram vector
        except:
            pass
    return bovw_vector#this should be our histogram

if __name__ == '__main__':
    n_clusters = 100
    #set model
    model = GaussianNB()
    image_list = pd.read_csv("image_list.csv")
    image_list_subset = image_list.groupby('class_id').head(80)#image_list.loc[(image_list["class_id"] == 0) | (image_list["class_id"] == 19)]
    shape = (330,230)
    train, test = train_test_split(image_list_subset, test_size=0.1, random_state=42)

    train_sift_features, train_global_features, y_train = extract_features(train)
    train_histogram = BOVW(train_sift_features, n_clusters)
    import matplotlib.pyplot as plt
    plt.plot(train_histogram[100], 'o')
    plt.ylabel('frequency');
    plt.xlabel('features');

    test_sift_features, test_global_features, y_test = extract_features(test)
    test_histogram = BOVW(test_sift_features, n_clusters)

    '''Naive Bays'''
    y_hat = model.fit(train_histogram, y_train).predict(test_histogram)
    print("Number of correctly labeled points out of a total {} points : {}. An accuracy of {}"
          .format(len(y_hat), sum(np.equal(y_hat,np.array(y_test))), 
                  sum(np.equal(y_hat,np.array(y_test)))/len(y_hat)))
1个回答

回答您的问题的最佳方法是查看介绍该方法的原始论文:

“带有关键点袋的视觉分类”(2004 年)

文章不长,通俗易懂。对于您的问题,您只能阅读前 6 页。

摘自文章“Visual Categorization with Bags of Keypoints”:

我们方法的主要步骤是:

• 图像补丁的检测和描述

• 使用矢量量化算法将补丁描述符分配给一组预先确定的集群(词汇表)

• 构造一个关键点包,计算分配给每个集群的补丁数量

• 应用多类分类器,将关键点包作为特征向量,从而确定分配给图像的类别。