【问题标题】:ValueError: need at least one array to concatenateValueError:需要至少一个数组来连接
【发布时间】:2019-07-24 20:20:17
【问题描述】:

我遇到了问题

ValueError: 需要至少一个数组来连接

以下是整个错误消息。

    Training mode
Traceback (most recent call last):
  File "bcf.py", line 342, in <module>
    bcf.train()
  File "bcf.py", line 321, in train
    self._learn_codebook()
  File "bcf.py", line 142, in _learn_codebook
    feats_sc = np.concatenate(feats_sc, axis=1).transpose()
ValueError: need at least one array to concatenate

以下是问题所在。

    def _learn_codebook(self):
    MAX_CFS = 800 # max number of contour fragments per image; if above, sample randomly
    CLUSTERING_CENTERS = 1500
    feats_sc = []
    for image in self.data.values():
        feats = image['cfs']
        feat_sc = feats[1]
        if feat_sc.shape[1] > MAX_CFS:
            # Sample MAX_CFS from contour fragments
            rand_indices = np.random.permutation(feat_sc.shape[1])
            feat_sc = feat_sc[:, rand_indices[:MAX_CFS]]
        feats_sc.append(feat_sc)
    feats_sc = np.concatenate(feats_sc, axis=1).transpose()
    print("Running KMeans...")
    self.kmeans = sklearn.cluster.KMeans(min(CLUSTERING_CENTERS, feats_sc.shape[0]), n_jobs=-1, algorithm='elkan').fit(feats_sc)
    print("Saving codebook...")
    self._save_kmeans(self.kmeans)
    return self.kmeans

下面是完整的类

class BCF():
def __init__(self):
    self.DATA_DIR = "/Users/minniemouse/TRAIN/bcf-master5/data/cuauv/"
    self.PERC_TRAINING_PER_CLASS = 0.5
    self.CODEBOOK_FILE = "codebook.data"
    self.CLASSIFIER_FILE = "classifier"
    self.LABEL_TO_CLASS_MAPPING_FILE = "labels_to_classes.data"
    self.classes = defaultdict(list)
    self.data = defaultdict(dict)
    self.counter = defaultdict(int)
    self.kmeans = None
    self.clf = None
    self.label_to_class_mapping = None

def _load_classes(self):
    for dir_name, subdir_list, file_list in os.walk(self.DATA_DIR):
        if subdir_list:
            continue
        for f in sorted(file_list, key=hash):
            self.classes[dir_name.split('/')[-1]].append(os.path.join(dir_name, f))

def _load_training(self):
    for cls in self.classes:
        images = self.classes[cls]
        for image in images[:int(len(images) * self.PERC_TRAINING_PER_CLASS)]:
            image_id = self._get_image_identifier(cls)
            self.data[image_id]['image'] = cv2.imread(image, cv2.IMREAD_GRAYSCALE)
            if self.data[image_id]['image'] is None:
                print("Failed to load " + image)

def _load_testing(self):
    for cls in self.classes:
        images = self.classes[cls]
        for image in images[int(len(images) * self.PERC_TRAINING_PER_CLASS):]:
            image_id = self._get_image_identifier(cls)
            self.data[image_id]['image'] = cv2.imread(image, cv2.IMREAD_GRAYSCALE)
            if self.data[image_id]['image'] is None:
                print("Failed to load " + image)

def _load_single(self, image):
    # Load single image data
    self.data.clear()
    image_id = self._get_image_identifier(None)
    self.data[image_id]['image'] = image

def _save_label_to_class_mapping(self):
    self.label_to_class_mapping = {hash(cls): cls for cls in self.classes}
    with open(self.LABEL_TO_CLASS_MAPPING_FILE, 'wb') as out_file:
        pickle.dump(self.label_to_class_mapping, out_file, -1)

def _load_label_to_class_mapping(self):
    if self.label_to_class_mapping is None:
        with open(self.LABEL_TO_CLASS_MAPPING_FILE, 'rb') as in_file:
            self.label_to_class_mapping = pickle.load(in_file)
    return self.label_to_class_mapping

def _normalize_shapes(self):
    for (cls, idx) in self.data.keys():
        image = self.data[(cls, idx)]['image']
        # Remove void space
        y, x = np.where(image > 50)
        max_y = y.max()
        min_y = y.min()
        max_x = x.max()
        min_x = x.min()
        trimmed = image[min_y:max_y, min_x:max_x] > 50
        trimmed = trimmed.astype('uint8')
        trimmed[trimmed > 0] = 255
        self.data[(cls, idx)]['normalized_image'] = trimmed

def _extract_cf(self):
    for (cls, idx) in self.data.keys():
        image = self.data[(cls, idx)]['normalized_image']
        images,contours, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        contour = sorted(contours, key=len)[-1]
        mat = np.zeros(image.shape, np.int8)
        cv2.drawContours(mat, [contour], -1, (255, 255, 255))
        #self.show(mat)
        MAX_CURVATURE = 1.5
        N_CONTSAMP = 50
        N_PNTSAMP = 10
        C = None
        for pnt in contour:
            if C is None:
                C = np.array([[pnt[0][0], pnt[0][1]]])
            else:
                C = np.append(C, [[pnt[0][0], pnt[0][1]]], axis=0)
        cfs = self._extr_raw_points(C, MAX_CURVATURE, N_CONTSAMP, N_PNTSAMP)
        tmp = mat.copy()
        for cf in cfs:
            for pnt in cf:
                cv2.circle(tmp, (pnt[0], pnt[1]), 2, (255, 0, 0))
            #self.show(tmp)
        num_cfs = len(cfs)
        print("Extracted %s points" % (num_cfs))
        feat_sc = np.zeros((300, num_cfs))
        xy = np.zeros((num_cfs, 2))

        for i in range(num_cfs):
            cf = cfs[i]
            sc, _, _, _ = shape_context(cf)
            # shape context is 60x5 (60 bins at 5 reference points)
            sc = sc.flatten(order='F')
            sc /= np.sum(sc) # normalize
            feat_sc[:, i] = sc
            # shape context descriptor sc for each cf is 300x1
            # save a point at the midpoint of the contour fragment
            xy[i, 0:2] = cf[np.round(len(cf) / 2. - 1).astype('int32'), :]
        sz = image.shape
        self.data[(cls, idx)]['cfs'] = (cfs, feat_sc, xy, sz)

def _learn_codebook(self):
    MAX_CFS = 800 # max number of contour fragments per image; if above, sample randomly
    CLUSTERING_CENTERS = 1500
    feats_sc = []
    for image in self.data.values():
        feats = image['cfs']
        feat_sc = feats[1]
        if feat_sc.shape[1] > MAX_CFS:
            # Sample MAX_CFS from contour fragments
            rand_indices = np.random.permutation(feat_sc.shape[1])
            feat_sc = feat_sc[:, rand_indices[:MAX_CFS]]
        feats_sc.append(feat_sc)
    feats_sc = np.concatenate(feats_sc, axis=1).transpose()
    print("Running KMeans...")
    self.kmeans = sklearn.cluster.KMeans(min(CLUSTERING_CENTERS,  feats_sc.shape[0]), n_jobs=-1, algorithm='elkan').fit(feats_sc)
    print("Saving codebook...")
    self._save_kmeans(self.kmeans)
    return self.kmeans

我已经阅读了已经描述过的有关 ValueError 的各种帖子,但我没有太多运气来弄清楚它。我现在附上了 CLASS 和完整的错误消息信息。

请,有人可以指出我缺少什么吗?

谢谢

【问题讨论】:

  • (1) 请提供minimal reproducible example。您的代码看起来像是一个类的一部分,但尚未提供其实现和调用。尝试减少代码以重现相同的问题。 (2) 通常错误消息跨越多行(称为回溯)。请将整个回溯复制粘贴到您的问题中 - 它们包含重要信息(例如发生错误的行号)。
  • 没用过这个模块,不过猜测是feats_sc是一个列表,而不是一个数组的问题?
  • 因此,在回答“请提供足够的代码以触发相同的结果”的问题时,该脚本的长度为多个页面,涵盖各种文件。这是我可以发布到 StackOverflow 上的东西吗?原始文件github.com/ChesleyTan/bcf.git>

标签: python valueerror


【解决方案1】:

问题来自阵列的长度。检查您的数组/列表是否长于 0 print(len(feats_sc))

别忘了查看文档numpy.concatenate — NumPy v1.16 Manual

【讨论】:

    【解决方案2】:

    问题似乎出在np.concatenate 中,它需要一个数组数组,但它没有收到。

    参考:Scipy docs

    numpy.concatenate((a1, a2, ...), axis=0, out=None)
    

    沿现有轴加入一系列数组。

    参数:
    a1, a2, ... : array_like 的序列 数组必须有 相同的形状,除了对应于轴的尺寸( 首先,默认情况下)。

    axis : int, optional 数组将沿其连接的轴。 如果axis为None,则数组在使用前会被展平。默认为 0。

    out : ndarray,可选如果提供,则放置 结果。形状必须正确,与连接的形状相匹配 如果没有指定 out 参数,将会返回。

    返回: res : ndarray 串联的数组。

    在您的情况下,检查 feats_sc 包含的内容。

    您可以使用pdb进行调试

    python -m pdb <your-code>.py
    (pdb) b fullpath/to/your-code.py:line-number-to-break
    (pdb) c
    
    • c 会一直持续到遇到断点
    • n 将移至下一行
    • b是设置断点
    • q是退出

    【讨论】:

      猜你喜欢
      • 2021-08-07
      • 2023-02-10
      • 2020-12-22
      • 2021-04-23
      • 2020-04-11
      • 1970-01-01
      • 2022-12-18
      • 1970-01-01
      • 2011-07-21
      相关资源
      最近更新 更多