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 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) """Keep the top n features (default: 5)


Approach: Approach:
- for range in 0-n - for range in 0-n
+ expand the nth top feature to min duration + expand the nth top feature to min duration
(move start back by 0.5*min_duration, end forward by 0.5*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 - return the top n features


Each feature is a Feature object, with an Interval object 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) features = sorted(features, key=lambda x: x.score, reverse=True)
for i in range(num): for i in range(num):
current_feature = features.pop(0) 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) keep_features.append(current_feature)
# drop any features that are now in that feature's range (plus margin) # 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 return keep_features


@@ -305,8 +311,12 @@ class LoudAudioFeatureExtractor(FeatureExtractor):
features.append(Feature(interval=Interval(start=time, duration=0.500), features.append(Feature(interval=Interval(start=time, duration=0.500),
source=file, feature_extractor="loudness", source=file, feature_extractor="loudness",
score=loudness)) score=loudness))

# prune features list to keep self.num_features # 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): class VideoActivityFeatureExtractor(FeatureExtractor):
@@ -383,14 +393,14 @@ class VideoActivityFeatureExtractor(FeatureExtractor):
scores = sorted(scores, key=lambda x: x[1], reverse=True) scores = sorted(scores, key=lambda x: x[1], reverse=True)
return scores[:int(len(scores) * (percent / 100))] 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) """Keep the top n features (default: 5)


Approach: Approach:
- for range in 0-n - for range in 0-n
+ expand the nth top feature to min duration + expand the nth top feature to min duration
(move start back by 0.5*min_duration, end forward by 0.5*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 - return the top n features


Each feature is a Feature object, with an Interval object 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) features = sorted(features, key=lambda x: x.score, reverse=True)
for i in range(num): for i in range(num):
current_feature = features.pop(0) 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) keep_features.append(current_feature)
# drop any features that are now in that feature's range (plus margin) # 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 return keep_features



def setup(self): def setup(self):
pass pass


@@ -427,7 +442,10 @@ class VideoActivityFeatureExtractor(FeatureExtractor):
score=score)) score=score))


# prune features list to keep self.num_features # 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): def teardown(self):
pass pass


Loading…
Cancel
Save