OpenCV - Python字典(BoW)从字典

时间:2017-03-29 21:02:07

标签: python opencv

我一直在尝试使用关键点和单词技术包在Python OpenCV 3.2.0中创建一个图像分类器。经过一番阅读后,我发现我可以按照以下方式执行此操作

  1. 使用AKAZE提取图像描述符
  2. 对描述符执行k-means聚类以生成字典
  3. 基于字典生成图像的直方图
  4. 使用直方图训练SVM
  5. 我设法做了第1步和第2步,但却陷入了第3步和第4步。

    我通过使用k-means聚类返回的标签成功生成了直方图(我认为)。但是,当我想使用未用于生成字典的新测试数据时,我得到了一些意想不到的结果。我尝试使用像tutorial这样的FLANN匹配器,但是从标签数据生成直方图得到的结果与FLANN匹配返回的数据不匹配。

    我加载图片:

    dictionary_size = 512
    # Loading images
    imgs_data = []
    # imreads returns a list of all images in that directory
    imgs = imreads(imgs_path)
    for i in xrange(len(imgs)):
        # create a numpy to hold the histogram for each image
        imgs_data.insert(i, np.zeros((dictionary_size, 1)))
    
    然后我创建了一个描述符数组(desc):

    def get_descriptors(img, detector):
        # returns descriptors of an image
        return detector.detectAndCompute(img, None)[1]
    
    # Extracting descriptors
    detector = cv2.AKAZE_create()
    
    desc = np.array([])
    # desc_src_img is a list which says which image a descriptor belongs to
    desc_src_img = []
    for i in xrange(len(imgs)):
        img = imgs[i]
        descriptors = get_descriptors(img, detector)
        if len(desc) == 0:
            desc = np.array(descriptors)
        else:
            desc = np.vstack((desc, descriptors))
        # Keep track of which image a descriptor belongs to
        for j in range(len(descriptors)):
            desc_src_img.append(i)
    # important, cv2.kmeans only accepts type32 descriptors
    desc = np.float32(desc)
    

    然后使用k-means对描述符进行聚类:

    # Clustering
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 0.01)
    flags = cv2.KMEANS_PP_CENTERS
    # desc is a type32 numpy array of vstacked descriptors
    compactness, labels, dictionary = cv2.kmeans(desc, dictionary_size, None, criteria, 1, flags)
    

    然后我使用从k-means返回的标签为每个图像创建直方图:

    # Getting histograms from labels
    size = labels.shape[0] * labels.shape[1]
    for i in xrange(size):
        label = labels[i]
        # Get this descriptors image id
        img_id = desc_src_img[i]
        # imgs_data is a list of the same size as the number of images
        data = imgs_data[img_id]
        # data is a numpy array of size (dictionary_size, 1) filled with zeros
        data[label] += 1
    
    ax = plt.subplot(311)
    ax.set_title("Histogram from labels")
    ax.set_xlabel("Visual words")
    ax.set_ylabel("Frequency")
    ax.plot(imgs_data[0].ravel())
    

    这会输出像Label Histogram这样的直方图,它的分布非常均匀,符合我的期望。

    然后我尝试在同一图像上做同样的事情,但使用FLANN:

    matcher = cv2.FlannBasedMatcher_create()
    matcher.add(dictionary)
    matcher.train()
    
    descriptors = get_descriptors(imgs[0], detector)
    
    result = np.zeros((dictionary_size, 1), np.float32)
    # flan matcher needs descriptors to be type32
    matches = matcher.match(np.float32(descriptors))
    for match in matches:
        visual_word = match.trainIdx
        result[visual_word] += 1
    
    ax = plt.subplot(313)
    ax.set_title("Histogram from FLANN")
    ax.set_xlabel("Visual words")
    ax.set_ylabel("Frequency")
    ax.plot(result.ravel())
    

    这会输出像FLANN Histogram这样的直方图,它的分布非常不均匀,与第一个直方图不匹配。

    您可以在GitHub上查看完整的代码和图片。改变" imgs_path" (第20行)在运行之前带有图像的目录。

    我哪里错了?为什么直方图如此不同?如何使用字典生成新数据的直方图?

    作为附注,我尝试使用OpenCV BOW实现,但发现了另一个问题,它给出了错误:" _queryDescriptors.type()== trainDescType in function cv :: BFMatcher :: knnMatchImpl "这就是为什么我自己试图实现它。如果有人可以使用Python OpenCV BOW和AKAZE提供一个工作示例那么那就好了。

1 个答案:

答案 0 :(得分:1)

似乎你无法使用字典训练FlannBasedMatcher,如下图所示:

matcher = cv2.FlannBasedMatcher_create()
matcher.add(dictionary)
matcher.train()

但是,您可以在匹配时传递dictionary

matcher = cv2.FlannBasedMatcher_create()

...

matches = matcher.match(np.float32(descriptors), dictionary)

我不完全确定为什么会这样。或许train方法只是由match方法使用,如post中暗示的那样。

同样根据opencv docsmatch的参数为:

  
      
  • queryDescriptors - 查询描述符集。
  •   
  • trainDescriptors - 训练描述符集。此集不会添加到存储在类对象中的train描述符集合中。
  •   
  • 匹配 - 匹配。如果在掩码中屏蔽了查询描述符,则不会为此描述符添加匹配项。因此,匹配大小可能小于查询描述符计数。
  •   

所以我猜你应该将dictionary作为trainDescriptors传递,因为它就是这样。

如果有人能够对此有所了解,我们将不胜感激。

以下是使用上述方法后的结果:

The two histograms; one generated from labels and one generated from the flann matches

您可以看到完整更新的代码here