Browse Source

fix: stop FEs incorrectly dropping some Features

_keep_num() was incorrectly detecting overlaps
main
Rob Hallam 1 month ago
parent
commit
4bec7a8ecc
1 changed files with 37 additions and 19 deletions
  1. +37
    -19
      pipeline/feature_extractors.py

+ 37
- 19
pipeline/feature_extractors.py View File

@@ -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


Loading…
Cancel
Save