title: ValueError: need at least one array to concatenate
body: <p>I am having issues with </p>
  
  <blockquote>
    <p>ValueError: need at least one array to concatenate</p>
  </blockquote>
  
  <p>Below is the whole error message. </p>
  
  <pre><code>    Training mode
  Traceback (most recent call last):
    File "bcf.py", line 342, in &lt;module&gt;
      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
  </code></pre>
  
  <p>Below is the area of the problem.</p>
  
  <pre><code>    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] &gt; 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
  </code></pre>
  
  <p>Below is the complete CLASS</p>
  
  <pre><code>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 &gt; 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] &gt; 50
          trimmed = trimmed.astype('uint8')
          trimmed[trimmed &gt; 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] &gt; 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
  </code></pre>
  
  <p>I have read through the various posts on ValueError already described, but I am not having much luck on figuring it out. I have now attached the CLASS and full error message information. </p>
  
  <p>Please, can someone point out what I am missing? </p>
  
  <p>Thank you</p>