在Python中将OpenCV SURF功能转换为float32数组

时间:2018-04-03 16:07:24

标签: python numpy opencv surf

我使用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);

1 个答案:

答案 0 :(得分: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想要的,请参阅这篇文章的评论)。您可以使用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。最后,你所要做的就是演员阵容:

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