diff --git a/pipeline/feature_extractors.py b/pipeline/feature_extractors.py index dadaa0a..b3089f1 100644 --- a/pipeline/feature_extractors.py +++ b/pipeline/feature_extractors.py @@ -254,14 +254,14 @@ class LoudAudioFeatureExtractor(FeatureExtractor): return loudness_features - def _keep_num(self, features, num=_CONFIG_DEFAULT_NUM_FEATURES, margin=10.0) -> list: + def _keep_num(self, features, num=_CONFIG_DEFAULT_NUM_FEATURES, trim_overlap=False) -> list: """Keep the top n features (default: 5) Approach: - for range in 0-n + expand the nth top feature to min duration (move start back by 0.5*min_duration, end forward by 0.5*min_duration) - + drop any features that are now in that feature's range (plus margin) + + drop any features that are now in that feature's range (optional) - return the top n features Each feature is a Feature object, with an Interval object @@ -271,14 +271,20 @@ class LoudAudioFeatureExtractor(FeatureExtractor): features = sorted(features, key=lambda x: x.score, reverse=True) for i in range(num): current_feature = features.pop(0) - # expand the feature to min_duration - current_feature.interval.move_start(-0.5*self._min_duration, relative=True) - current_feature.interval.move_end(0.5*self._min_duration, relative=True) + # expand the feature to min_duration - try and keep centered at current start + if self._min_duration > current_feature.interval.duration: + current_feature.interval.move_start(-0.5*self._min_duration, relative=True) + if current_feature.interval.duration < self._min_duration: + current_feature.interval.update_duration(self._min_duration) keep_features.append(current_feature) # drop any features that are now in that feature's range (plus margin) - features = [f for f in features if - (f.interval.end < current_feature.interval.start-margin or - f.interval.start > current_feature.interval.end+margin)] + # features = [f for f in features if + # (f.interval.start < current_feature.interval.start-margin and + # f.interval.end > current_feature.interval.start-margin) or + # (f.interval.end > current_feature.interval.end+margin and + # f.interval.start < current_feature.interval.end+margin)] + if trim_overlap: + features = [f for f in features if f.interval.overlaps(current_feature.interval)] return keep_features @@ -305,8 +311,12 @@ class LoudAudioFeatureExtractor(FeatureExtractor): features.append(Feature(interval=Interval(start=time, duration=0.500), source=file, feature_extractor="loudness", score=loudness)) + # prune features list to keep self.num_features - self.features = self._keep_num(features, self._num_features) + if len(features) > self._num_features: + self.features = self._keep_num(features, self._num_features) + else: + self.features = features class VideoActivityFeatureExtractor(FeatureExtractor): @@ -383,14 +393,14 @@ class VideoActivityFeatureExtractor(FeatureExtractor): scores = sorted(scores, key=lambda x: x[1], reverse=True) return scores[:int(len(scores) * (percent / 100))] - def _keep_num(self, features, num=_CONFIG_DEFAULT_NUM_FEATURES, margin=10.0) -> list: + def _keep_num(self, features, num=_CONFIG_DEFAULT_NUM_FEATURES, trim_overlap=False) -> list: """Keep the top n features (default: 5) Approach: - for range in 0-n + expand the nth top feature to min duration (move start back by 0.5*min_duration, end forward by 0.5*min_duration) - + drop any features that are now in that feature's range (plus margin) + + drop any features that are now in that feature's range (optional) - return the top n features Each feature is a Feature object, with an Interval object @@ -400,18 +410,23 @@ class VideoActivityFeatureExtractor(FeatureExtractor): features = sorted(features, key=lambda x: x.score, reverse=True) for i in range(num): current_feature = features.pop(0) - # expand the feature to min_duration - current_feature.interval.move_start(-0.5*self._min_duration, relative=True) - current_feature.interval.move_end(0.5*self._min_duration, relative=True) + # expand the feature to min_duration - try and keep centered at current start + if self._min_duration > current_feature.interval.duration: + current_feature.interval.move_start(-0.5*self._min_duration, relative=True) + if current_feature.interval.duration < self._min_duration: + current_feature.interval.update_duration(self._min_duration) keep_features.append(current_feature) # drop any features that are now in that feature's range (plus margin) - features = [f for f in features if - (f.interval.end < current_feature.interval.start-margin or - f.interval.start > current_feature.interval.end+margin)] + # features = [f for f in features if + # (f.interval.start < current_feature.interval.start-margin and + # f.interval.end > current_feature.interval.start-margin) or + # (f.interval.end > current_feature.interval.end+margin and + # f.interval.start < current_feature.interval.end+margin)] + if trim_overlap: + features = [f for f in features if f.interval.overlaps(current_feature.interval)] return keep_features - def setup(self): pass @@ -427,7 +442,10 @@ class VideoActivityFeatureExtractor(FeatureExtractor): score=score)) # prune features list to keep self.num_features - self.features = self._keep_num(features, self._num_features) + if len(self.features) > self._num_features: + self.features = self._keep_num(features, self._num_features) + else: + self.features = features def teardown(self): pass