def extract_parts(self, edges, edges_unspread, settings={}):
        #print 'strides', self.settings.get('strides', 1)
        if 'indices' in self.extra:
            feats = ag.features.code_parts_as_features_INDICES(edges, 
                                                       edges_unspread,
                                                       self._log_parts, self._log_invparts, 
                                                       self.extra['indices'],
                                                       self.threshold_in_counts(self.settings['threshold'], edges.shape[-1]), self.settings['patch_frame'], 
                                                       strides=self.settings.get('strides', 1), 
                                                       tau=self.settings.get('tau', 0.0),
                                                       max_threshold=self.threshold_in_counts(self.settings.get('max_threshold', 1.0), edges.shape[-1]))
        else:
            feats = ag.features.code_parts_as_features(edges, 
                                                       edges_unspread,
                                                       self._log_parts, self._log_invparts, 
                                                       self.threshold_in_counts(self.settings['threshold'], edges.shape[-1]), self.settings['patch_frame'], 
                                                       strides=self.settings.get('strides', 1), 
                                                       tau=self.settings.get('tau', 0.0),
                                                       max_threshold=self.threshold_in_counts(self.settings.get('max_threshold', 1.0), edges.shape[-1]))

        # Pad with background (TODO: maybe incorporate as an option to code_parts?)
        # This just makes things a lot easier, and we don't have to match for instance the
        # support which will be bigger if we don't do this.
        # TODO: If we're not using a support, this could be extremely detrimental!

        if settings.get('preserve_size'):
            # TODO: Create a function called pad_to_size that handles this better
            feats = ag.util.zeropad(feats, (self._log_parts.shape[1]//2, self._log_parts.shape[2]//2, 0))

            # TODO: This is a bit of a hack. This makes it handle even-sized parts
            if self._log_parts.shape[1] % 2 == 0:
                feats = feats[:-1]
            if self._log_parts.shape[2] % 2 == 0:
                feats = feats[:,:-1]

        sett = self.settings.copy()
        sett.update(settings)

        # Do spreading
        radii = sett.get('spread_radii', (0, 0))

        assert radii[0] == radii[1], 'Supports only axis symmetric radii spreading at this point'
        from amitgroup.features.features import array_bspread_new
        
        feats = array_bspread_new(feats, spread='box', radius=radii[0])

        cb = sett.get('crop_border')
        if cb:
            # Due to spreading, the area of influence can be greater
            # than what we're cutting off. That's why it's good to have
            # a cut_border property if you're training on real images.
            feats = feats[cb:-cb, cb:-cb]

        return feats 
    def extract_parts(self, edges, edges_unspread, settings={}):
        #print 'strides', self.settings.get('strides', 1)
        if 'indices' in self.extra:
            feats = ag.features.code_parts_as_features_INDICES(
                edges,
                edges_unspread,
                self._log_parts,
                self._log_invparts,
                self.extra['indices'],
                self.threshold_in_counts(self.settings['threshold'],
                                         edges.shape[-1]),
                self.settings['patch_frame'],
                strides=self.settings.get('strides', 1),
                tau=self.settings.get('tau', 0.0),
                max_threshold=self.threshold_in_counts(
                    self.settings.get('max_threshold', 1.0), edges.shape[-1]))
        else:
            feats = ag.features.code_parts_as_features(
                edges,
                edges_unspread,
                self._log_parts,
                self._log_invparts,
                self.threshold_in_counts(self.settings['threshold'],
                                         edges.shape[-1]),
                self.settings['patch_frame'],
                strides=self.settings.get('strides', 1),
                tau=self.settings.get('tau', 0.0),
                max_threshold=self.threshold_in_counts(
                    self.settings.get('max_threshold', 1.0), edges.shape[-1]))

        # Pad with background (TODO: maybe incorporate as an option to code_parts?)
        # This just makes things a lot easier, and we don't have to match for instance the
        # support which will be bigger if we don't do this.
        # TODO: If we're not using a support, this could be extremely detrimental!

        if settings.get('preserve_size'):
            # TODO: Create a function called pad_to_size that handles this better
            feats = ag.util.zeropad(feats, (self._log_parts.shape[1] // 2,
                                            self._log_parts.shape[2] // 2, 0))

            # TODO: This is a bit of a hack. This makes it handle even-sized parts
            if self._log_parts.shape[1] % 2 == 0:
                feats = feats[:-1]
            if self._log_parts.shape[2] % 2 == 0:
                feats = feats[:, :-1]

        sett = self.settings.copy()
        sett.update(settings)

        # Do spreading
        radii = sett.get('spread_radii', (0, 0))

        assert radii[0] == radii[
            1], 'Supports only axis symmetric radii spreading at this point'
        from amitgroup.features.features import array_bspread_new

        feats = array_bspread_new(feats, spread='box', radius=radii[0])

        cb = sett.get('crop_border')
        if cb:
            # Due to spreading, the area of influence can be greater
            # than what we're cutting off. That's why it's good to have
            # a cut_border property if you're training on real images.
            feats = feats[cb:-cb, cb:-cb]

        return feats
    def extract_parts(self, edges, edges_unspread, settings={}, dropout=None):
        bsett = self.bedges_settings()
        if 'indices' in self.extra:
            feats = ag.features.code_parts_as_features_INDICES(
                edges,
                edges_unspread,
                self._log_parts,
                self._log_invparts,
                self.extra['indices'],
                self.threshold_in_counts(self.settings['threshold'],
                                         edges.shape[-1],
                                         bsett['contrast_insensitive']),
                self.settings['patch_frame'],
                strides=self.settings.get('strides', 1),
                tau=self.settings.get('tau', 0.0),
                max_threshold=self.threshold_in_counts(
                    self.settings.get('max_threshold', 1.0), edges.shape[-1],
                    bsett['contrast_insensitive']))
        elif 0:
            feats = ag.features.code_parts_as_features(
                edges,
                edges_unspread,
                self._log_parts,
                self._log_invparts,
                self.threshold_in_counts(self.settings['threshold'],
                                         edges.shape[-1]),
                self.settings['patch_frame'],
                strides=self.settings.get('strides', 1),
                tau=self.settings.get('tau', 0.0),
                max_threshold=self.threshold_in_counts(
                    self.settings.get('max_threshold', 1.0), edges.shape[-1]))
        else:
            print("THIS IS THE ONE")
            partprobs = ag.features.code_parts(
                edges,
                edges_unspread,
                self._log_parts,
                self._log_invparts,
                self.threshold_in_counts(self.settings['threshold'],
                                         edges.shape[-1]),
                self.settings['patch_frame'],
                strides=self.settings.get('strides', 1),
                max_threshold=self.threshold_in_counts(
                    self.settings.get('max_threshold', 1.0), edges.shape[-1]))

            if dropout is not None:
                II = np.arange(self.num_features)
                np.random.shuffle(II)
                II = II[:int(dropout * self.num_features)]
                IJ = np.sort(np.concatenate([II * 2, (II * 2 + 1)]))
                yesno = np.concatenate([[0],
                                        np.bincount(IJ,
                                                    minlength=self.num_parts *
                                                    2)]).astype(bool)

                partprobs[:, :, yesno] = -np.inf

            # Sort out low-probability ones

            if 0:
                L = -np.ones(partprobs.shape[-1]) * np.inf
                L[0] = 0

                max2 = scipy.stats.scoreatpercentile(partprobs, 98, axis=-1)

                partprobs[max2 < -195] = L

                #feats = ag.features.convert_partprobs_to_feature_vector(partprobs.astype(np.float32), 2.0)
                feats = ag.features.convert_part_to_feature_vector(
                    partprobs.argmax(axis=-1).astype(np.uint32),
                    self.num_parts * 2)
            else:
                #feats = ag.features.convert_part_to_feature_vector(partprobs.argmax(axis=-1).astype(np.uint32), self.num_parts*2)
                #feats = convert_partprobs_to_feature_vector(partprobs.astype(np.float32), 0.0)
                feats = ag.features.convert_partprobs_to_feature_vector(
                    partprobs.astype(np.float32), self.settings.get('tau', 0))

        # Pad with background (TODO: maybe incorporate as an option to code_parts?)
        # This just makes things a lot easier, and we don't have to match for instance the
        # support which will be bigger if we don't do this.
        # TODO: If we're not using a support, this could be extremely detrimental!

        if settings.get('preserve_size'):
            # TODO: Create a function called pad_to_size that handles this better
            feats = ag.util.zeropad(feats, (self._log_parts.shape[1] // 2,
                                            self._log_parts.shape[2] // 2, 0))

            # TODO: This is a bit of a hack. This makes it handle even-sized parts
            if self._log_parts.shape[1] % 2 == 0:
                feats = feats[:-1]
            if self._log_parts.shape[2] % 2 == 0:
                feats = feats[:, :-1]

        sett = self.settings.copy()
        sett.update(settings)

        # Do spreading
        radii = sett.get('spread_radii', (0, 0))

        assert radii[0] == radii[
            1], 'Supports only axis symmetric radii spreading at this point'
        from amitgroup.features.features import array_bspread_new

        feats = array_bspread_new(feats, spread='box', radius=radii[0])

        cb = sett.get('crop_border')
        if cb:
            # Due to spreading, the area of influence can be greater
            # than what we're cutting off. That's why it's good to have
            # a cut_border property if you're training on real images.
            feats = feats[cb:-cb, cb:-cb]

        return feats
    def extract_parts(self, edges, edges_unspread, settings={}, dropout=None):
        #print 'strides', self.settings.get('strides', 1)
        if 'indices' in self.extra:
            feats = ag.features.code_parts_as_features_INDICES(edges, 
                                                       edges_unspread,
                                                       self._log_parts, self._log_invparts, 
                                                       self.extra['indices'],
                                                       self.threshold_in_counts(self.settings['threshold'], edges.shape[-1]), self.settings['patch_frame'], 
                                                       strides=self.settings.get('strides', 1), 
                                                       tau=self.settings.get('tau', 0.0),
                                                       max_threshold=self.threshold_in_counts(self.settings.get('max_threshold', 1.0), edges.shape[-1]))
        elif 0:
            feats = ag.features.code_parts_as_features(edges, 
                                                       edges_unspread,
                                                       self._log_parts, self._log_invparts, 
                                                       self.threshold_in_counts(self.settings['threshold'], edges.shape[-1]), self.settings['patch_frame'], 
                                                       strides=self.settings.get('strides', 1), 
                                                       tau=self.settings.get('tau', 0.0),
                                                       max_threshold=self.threshold_in_counts(self.settings.get('max_threshold', 1.0), edges.shape[-1]))
        else:
            partprobs = ag.features.code_parts(edges,
                                               edges_unspread,
                                               self._log_parts, self._log_invparts, 
                                               self.threshold_in_counts(self.settings['threshold'], edges.shape[-1]), self.settings['patch_frame'], 
                                               strides=self.settings.get('strides', 1), 
                                               max_threshold=self.threshold_in_counts(self.settings.get('max_threshold', 1.0), edges.shape[-1]))

            if dropout is not None:
                II = np.arange(self.num_features)
                np.random.shuffle(II)
                II = II[:int(dropout*self.num_features)]
                IJ = np.sort(np.concatenate([II*2, (II*2+1)]))
                yesno = np.concatenate([[0], np.bincount(IJ, minlength=self.num_parts*2)]).astype(bool)

                partprobs[:,:,yesno] = -np.inf

            # Sort out low-probability ones

            if 0:
                L = -np.ones(partprobs.shape[-1]) * np.inf
                L[0] = 0
                
                max2 = scipy.stats.scoreatpercentile(partprobs, 98, axis=-1)

                partprobs[max2 < -195] = L

               #feats = ag.features.convert_partprobs_to_feature_vector(partprobs.astype(np.float32), 2.0)
                feats = ag.features.convert_part_to_feature_vector(partprobs.argmax(axis=-1).astype(np.uint32), self.num_parts*2)
            else:
                #feats = ag.features.convert_part_to_feature_vector(partprobs.argmax(axis=-1).astype(np.uint32), self.num_parts*2)
                #feats = convert_partprobs_to_feature_vector(partprobs.astype(np.float32), 0.0)
                feats = ag.features.convert_partprobs_to_feature_vector(partprobs.astype(np.float32), self.settings.get('tau', 0))


        # Pad with background (TODO: maybe incorporate as an option to code_parts?)
        # This just makes things a lot easier, and we don't have to match for instance the
        # support which will be bigger if we don't do this.
        # TODO: If we're not using a support, this could be extremely detrimental!

        if settings.get('preserve_size'):
            # TODO: Create a function called pad_to_size that handles this better
            feats = ag.util.zeropad(feats, (self._log_parts.shape[1]//2, self._log_parts.shape[2]//2, 0))

            # TODO: This is a bit of a hack. This makes it handle even-sized parts
            if self._log_parts.shape[1] % 2 == 0:
                feats = feats[:-1]
            if self._log_parts.shape[2] % 2 == 0:
                feats = feats[:,:-1]

        sett = self.settings.copy()
        sett.update(settings)

        # Do spreading
        radii = sett.get('spread_radii', (0, 0))

        assert radii[0] == radii[1], 'Supports only axis symmetric radii spreading at this point'
        from amitgroup.features.features import array_bspread_new
        
        feats = array_bspread_new(feats, spread='box', radius=radii[0])

        cb = sett.get('crop_border')
        if cb:
            # Due to spreading, the area of influence can be greater
            # than what we're cutting off. That's why it's good to have
            # a cut_border property if you're training on real images.
            feats = feats[cb:-cb, cb:-cb]

        return feats