Sample `nsamples` points form raster

        :param raster: Input 2D or single-channel 3D label image
        :type raster: uint8 numpy array
        :param n_samples: Number of points to sample in total
        :type n_samples: uint32
        :return: List of row indices of samples, list of column indices of samples
        :rtype: numpy.array, numpy.array

def sample(self, raster, n_samples=1000):
        """ Sample `nsamples` points form raster

        :param raster: Input 2D or single-channel 3D label image
        :type raster: uint8 numpy array
        :param n_samples: Number of points to sample in total
        :type n_samples: uint32
        :return: List of row indices of samples, list of column indices of samples
        :rtype: numpy.array, numpy.array
        """
        # Check dimensionality and reshape to 2D
        raster = raster.copy()
        if raster.ndim == 3 and raster.shape[-1] == 1:
            raster = raster.squeeze()
        elif raster.ndim != 2:
            raise ValueError('Class operates on 2D or 3D single-channel raster images')

        # Calculate mask of all pixels which can be sampled
        mask = np.zeros(raster.shape, dtype=np.bool)
        for label in self.labels:
            label_mask = (raster == label)
            mask |= label_mask

        unique_labels, label_count = np.unique(raster[mask], return_counts=True)
        if not unique_labels.size:
            LOGGER.warning('No samples matching given parameters found in EOPatch')
            return np.empty((0,), dtype=np.uint32), np.empty((0,), dtype=np.uint32)

        if self.even_sampling:
            # Valid labels have the same (or off by one) number of samples
            n_samples_per_label = np.diff(np.round(np.linspace(0, n_samples,
                                                               num=label_count.size + 1))).astype(np.uint32)
        else:
            # Number of samples per label is proportional to label frequency
            label_ratio = label_count / np.sum(label_count)
            n_samples_per_label = (np.ceil(n_samples * label_ratio)).astype(np.uint32)

        # Apply mask to raster
        unknown_value = self._get_unknown_value()
        raster[~mask] = unknown_value
        if not np.array_equal(~mask, raster == unknown_value):
            raise ValueError('Failed to set unknown value. Too many labels for sampling reference mask of type '
                             '{}'.format(raster.dtype))

        # Sample raster
        samples = np.concatenate([self._binary_sample(raster, label, n_sample_label, label_count)
                                  for label, n_sample_label, label_count in zip(unique_labels, n_samples_per_label,
                                                                                label_count)], axis=1).T

        # Shuffle to mix labels in case they are fed directly to train a ML model
        np.random.shuffle(samples)

        # Return row index and col index. Return exactly `n_sample` values
        return samples[:n_samples, 0], samples[:n_samples, 1]