【问题标题】:Converting OpenCV SURF features to float32 arrays in Python在 Python 中将 OpenCV SURF 特征转换为 float32 数组
【发布时间】:2018-04-03 16:07:23
【问题描述】:

我使用compute() 函数提取特征并将它们添加到列表中。然后我尝试使用 NumPy 将所有特征转换为float32,以便它们可以与 OpenCV 一起用于分类。我得到的错误是:

ValueError: setting an array element with a sequence. 

不太确定我能做些什么。我正在关注一本书并执行相同的步骤,只是他们使用 HOS 来提取特征。我正在提取特征并取回大小不一致的矩阵,但不确定如何使它们全部相等。相关代码(可能有轻微的语法错误,因为我从原始代码中截断了它):

    def get_SURF_feature_vector(area_of_interest, surf):
            # Detect the key points in the image
            key_points = surf.detect(area_of_interest);
            # Create array of zeros with the same shape and type as a given array
            image_key_points = np.zeros_like(area_of_interest);
            # Draw key points on the image
            image_key_points = cv2.drawKeypoints(area_of_interest, key_points, image_key_points, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
            # Create feature discriptors
            key_points, feature_descriptors = surf.compute(area_of_interest, key_points);
            # Plot Image and descriptors
            # plt.imshow(image_key_points);
            # Return computed feature description matrix
            return feature_descriptors;

    for x in range(0, len(data)):
            feature_list.append(get_SURF_feature_vector(area_of_interest[x], surf));
list_of_features = np.array(list_of_features, dtype = np.float32);

【问题讨论】:

标签: python numpy opencv surf


【解决方案1】:

这个错误根本不是 OpenCV 特有的,只是 numpy。

您的列表feature_list 包含不同长度的数组。您不能用不同大小的数组制作二维数组。

例如您可以非常简单地重现错误:

>>> np.array([[1], [2, 3]], dtype=np.float32)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: setting an array element with a sequence.

我假设您对操作的期望是输入 [1], [1, 2] 并返回 np.array([1, 2, 3]),即连接(实际上这不是 OP 想要的,请参阅这篇文章下的 cmets)。您可以使用np.hstack()np.vstack() 进行这些操作,具体取决于输入的形状。您也可以将 np.concatenate()axis 参数一起使用,但堆叠操作对于 2D/3D 数组更为明确。

>>> a = np.array([1], dtype=np.float32)
>>> b = np.array([2, 3, 4], dtype=np.float32)
>>> np.hstack([a, b])
array([1., 2., 3., 4.], dtype=float32)

虽然描述符是垂直列出的,所以它们应该垂直堆叠,而不是像上面那样水平堆叠。因此,您可以简单地这样做:

list_of_features = np.vstack(list_of_features)

您不需要指定dtype=np.float32,因为默认情况下描述符为np.float32(另外,vstack 没有dtype 参数,因此您必须在堆叠操作后对其进行转换) .


如果您想要一个 3D 数组,那么您需要在所有图像中使用相同数量的特征,以便它是一个均匀填充的 3D 数组。您可以使用占位符值(例如 0 或 np.nan)填充特征向量,使它们的长度相同,然后您可以像最初一样将它们组合在一起。

>>> des1 = np.random.rand(500, 64).astype(np.float32)
>>> des2 = np.random.rand(200, 64).astype(np.float32)
>>> des3 = np.random.rand(400, 64).astype(np.float32)
>>> feature_descriptors = [des1, des2, des3]

所以这里每个图像的特征描述符都有不同数量的特征。你可以找到最大的:

>>> max_des_length = max([len(d) for d in feature_descriptors])
>>> max_des_length
500

您可以使用np.pad() 来填充每个特征数组,但它需要与最大大小描述符集的大小相同。

现在,在一行中完成所有操作有点不必要,但无论如何。

>>> feature_descriptors = [np.pad(d, ((0, (max_des_length - len(d))), (0, 0)), 'constant', constant_values=np.nan) for d in feature_descriptors]

这里((0, (max_des_length - len(d))), (0, 0))的烦人论点只是说要在顶部填充0个元素,在底部填充max_des_length - len(des)元素,左侧为0,右侧为0。

正如您在此处看到的,我将np.nan 值添加到数组中。如果您遗漏了constant_values 参数,则默认为0。最后你要做的就是转换成一个 numpy 数组:

>>> feature_descriptors = np.array(feature_descriptors)
>>> feature_descriptors.shape
(3, 500, 64)

【讨论】:

  • 嗨,亚历克斯,感谢您的回复。问题可能是我每次都没有提取等量的特征吗?当我执行 print(feature_descriptors.shape) 时,它给了我一个 [x, 64] 的矩阵,x 的数量取决于从样本中提取了多少特征。如果我理解正确,每次解决我的问题时都会使 x 成为相同的值吗?
  • 没错,但只需将np.vstack() 放在一起也可以解决您的问题——无论如何,这就是您可能想要实现的目标(只是一个形状数组(total_n_features, 64))。
  • 嗯,我似乎不再得到错误,但我也没有得到我想要的特征数组 - 它应该是 [nr_of_images, nr_of_features, 64] 我相信,而不仅仅是 [ nr_of_features,64]。有什么你可能知道的可以帮助我吗?否则我只会将其标记为正确,因为它确实绕过了错误...
  • 哦!在那种情况下,是的——你在过去的评论中提出的就是你想做的事情。图像不会具有相同数量的特征,但您可以用虚拟 val(如 np.nan 或其他东西)填充其余部分,以便获得均匀的 3d 数组。我会更新的。
  • @Borzi 添加了一个示例,说明如何实现所需的形状。
猜你喜欢
  • 1970-01-01
  • 2014-05-07
  • 2023-03-21
  • 2011-09-04
  • 2019-05-21
  • 2016-01-26
  • 2021-07-22
  • 2017-10-14
  • 1970-01-01
相关资源
最近更新 更多