def test_metrics(): """ Test StatsManager metric registration/setting/getting with a set of pre-defined key-value pairs (metric_dict). """ metric_dict = {'some_metric': 1.2345, 'another_metric': 6.7890} metric_keys = list(metric_dict.keys()) stats = StatsManager() frame_key = 100 assert not stats.is_save_required() stats.register_metrics(metric_keys) assert not stats.is_save_required() with pytest.raises(FrameMetricRegistered): stats.register_metrics(metric_keys) assert not stats.metrics_exist(frame_key, metric_keys) assert stats.get_metrics(frame_key, metric_keys) == [None] * len(metric_keys) stats.set_metrics(frame_key, metric_dict) assert stats.is_save_required() assert stats.metrics_exist(frame_key, metric_keys) assert stats.metrics_exist(frame_key, metric_keys[1:]) assert stats.get_metrics(frame_key, metric_keys) == [ metric_dict[metric_key] for metric_key in metric_keys]
def test_metrics(): """ Test StatsManager metric registration/setting/getting with a set of pre-defined key-value pairs (metric_dict). """ metric_dict = {'some_metric': 1.2345, 'another_metric': 6.7890} metric_keys = list(metric_dict.keys()) stats = StatsManager() frame_key = 100 assert not stats.is_save_required() stats.register_metrics(metric_keys) assert not stats.is_save_required() with pytest.raises(FrameMetricRegistered): stats.register_metrics(metric_keys) assert not stats.metrics_exist(frame_key, metric_keys) assert stats.get_metrics(frame_key, metric_keys) == [None] * len(metric_keys) stats.set_metrics(frame_key, metric_dict) assert stats.is_save_required() assert stats.metrics_exist(frame_key, metric_keys) assert stats.metrics_exist(frame_key, metric_keys[1:]) assert stats.get_metrics(frame_key, metric_keys) == [ metric_dict[metric_key] for metric_key in metric_keys]
def test_load_hardcoded_file(): """ Test loading a stats file with some hard-coded data generated by this test case. """ stats_manager = StatsManager() with open(TEST_STATS_FILES[0], 'w') as stats_file: stats_writer = get_csv_writer(stats_file) some_metric_key = 'some_metric' some_metric_value = 1.2 some_frame_key = 100 base_timecode = FrameTimecode(0, 29.97) some_frame_timecode = base_timecode + some_frame_key # Write out a valid file. stats_writer.writerow( [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key]) stats_writer.writerow([ some_frame_key, some_frame_timecode.get_timecode(), str(some_metric_value) ]) stats_file.close() stats_file = open(TEST_STATS_FILES[0], 'r') stats_manager.load_from_csv(csv_file=stats_file) # Check that we decoded the correct values. assert stats_manager.metrics_exist(some_frame_key, [some_metric_key]) assert stats_manager.get_metrics( some_frame_key, [some_metric_key])[0] == pytest.approx(some_metric_value)
def test_save_load_from_video(test_video_file): """ Test generating and saving some frame metrics from TEST_VIDEO_FILE to a file on disk, and loading the file back to ensure the loaded frame metrics agree with those that were saved. """ video_manager = VideoManager([test_video_file]) stats_manager = StatsManager() scene_manager = SceneManager(stats_manager) base_timecode = video_manager.get_base_timecode() scene_manager.add_detector(ContentDetector()) try: video_fps = video_manager.get_framerate() start_time = FrameTimecode('00:00:00', video_fps) duration = FrameTimecode('00:00:20', video_fps) video_manager.set_duration(start_time=start_time, end_time=duration) video_manager.set_downscale_factor() video_manager.start() scene_manager.detect_scenes(frame_source=video_manager) with open(TEST_STATS_FILES[0], 'w') as stats_file: stats_manager.save_to_csv(stats_file, base_timecode) stats_manager_new = StatsManager() with open(TEST_STATS_FILES[0], 'r') as stats_file: stats_manager_new.load_from_csv(stats_file, base_timecode) # Choose the first available frame key and compare all metrics in both. frame_key = min(stats_manager._frame_metrics.keys()) metric_keys = list(stats_manager._registered_metrics) assert stats_manager.metrics_exist(frame_key, metric_keys) orig_metrics = stats_manager.get_metrics(frame_key, metric_keys) new_metrics = stats_manager_new.get_metrics(frame_key, metric_keys) for i, metric_val in enumerate(orig_metrics): assert metric_val == pytest.approx(new_metrics[i]) finally: os.remove(TEST_STATS_FILES[0]) video_manager.release()
def test_save_load_from_video(test_video_file): """ Test generating and saving some frame metrics from TEST_VIDEO_FILE to a file on disk, and loading the file back to ensure the loaded frame metrics agree with those that were saved. """ video_manager = VideoManager([test_video_file]) stats_manager = StatsManager() scene_manager = SceneManager(stats_manager) base_timecode = video_manager.get_base_timecode() scene_manager.add_detector(ContentDetector()) try: video_fps = video_manager.get_framerate() start_time = FrameTimecode('00:00:00', video_fps) duration = FrameTimecode('00:00:20', video_fps) video_manager.set_duration(start_time=start_time, end_time=duration) video_manager.set_downscale_factor() video_manager.start() scene_manager.detect_scenes(frame_source=video_manager) with open(TEST_STATS_FILES[0], 'w') as stats_file: stats_manager.save_to_csv(stats_file, base_timecode) stats_manager_new = StatsManager() with open(TEST_STATS_FILES[0], 'r') as stats_file: stats_manager_new.load_from_csv(stats_file, base_timecode) # Choose the first available frame key and compare all metrics in both. frame_key = min(stats_manager._frame_metrics.keys()) metric_keys = list(stats_manager._registered_metrics) assert stats_manager.metrics_exist(frame_key, metric_keys) orig_metrics = stats_manager.get_metrics(frame_key, metric_keys) new_metrics = stats_manager_new.get_metrics(frame_key, metric_keys) for i, metric_val in enumerate(orig_metrics): assert metric_val == pytest.approx(new_metrics[i]) finally: os.remove(TEST_STATS_FILES[0]) video_manager.release()
def test_detector_metrics(test_video_file): """ Test passing StatsManager to a SceneManager and using it for storing the frame metrics from a ContentDetector. """ video_manager = VideoManager([test_video_file]) stats_manager = StatsManager() scene_manager = SceneManager(stats_manager) #base_timecode = video_manager.get_base_timecode() assert not stats_manager._registered_metrics scene_manager.add_detector(ContentDetector()) # add_detector should trigger register_metrics in the StatsManager. assert stats_manager._registered_metrics try: video_fps = video_manager.get_framerate() start_time = FrameTimecode('00:00:00', video_fps) duration = FrameTimecode('00:00:20', video_fps) video_manager.set_duration(start_time=start_time, end_time=duration) video_manager.set_downscale_factor() video_manager.start() scene_manager.detect_scenes(frame_source=video_manager) # Check that metrics were written to the StatsManager. assert stats_manager._frame_metrics frame_key = min(stats_manager._frame_metrics.keys()) assert stats_manager._frame_metrics[frame_key] assert stats_manager.metrics_exist( frame_key, list(stats_manager._registered_metrics)) # Since we only added 1 detector, the number of metrics from get_metrics # should equal the number of metric keys in _registered_metrics. assert len( stats_manager.get_metrics( frame_key, list(stats_manager._registered_metrics))) == len( stats_manager._registered_metrics) finally: video_manager.release()
def test_load_hardcoded_file(test_video_file): """ Test loading a stats file with some hard-coded data generated by this test case. """ from scenedetect.stats_manager import COLUMN_NAME_FPS from scenedetect.stats_manager import COLUMN_NAME_FRAME_NUMBER from scenedetect.stats_manager import COLUMN_NAME_TIMECODE stats_manager = StatsManager() stats_file = open(TEST_STATS_FILES[0], 'w') try: stats_writer = get_csv_writer(stats_file) some_metric_key = 'some_metric' some_metric_value = 1.2 some_frame_key = 100 base_timecode = FrameTimecode(0, 29.97) some_frame_timecode = base_timecode + some_frame_key # Write out a valid file. stats_writer.writerow([COLUMN_NAME_FPS, '%.10f' % base_timecode.get_framerate()]) stats_writer.writerow( [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key]) stats_writer.writerow( [some_frame_key, some_frame_timecode.get_timecode(), str(some_metric_value)]) stats_file.close() stats_file = open(TEST_STATS_FILES[0], 'r') stats_manager.load_from_csv(csv_file=stats_file, base_timecode=base_timecode) # Check that we decoded the correct values. assert stats_manager.metrics_exist(some_frame_key, [some_metric_key]) assert stats_manager.get_metrics( some_frame_key, [some_metric_key])[0] == pytest.approx(some_metric_value) finally: stats_file.close() os.remove(TEST_STATS_FILES[0])
def test_detector_metrics(test_video_file): """ Test passing StatsManager to a SceneManager and using it for storing the frame metrics from a ContentDetector. """ video_manager = VideoManager([test_video_file]) stats_manager = StatsManager() scene_manager = SceneManager(stats_manager) #base_timecode = video_manager.get_base_timecode() assert not stats_manager._registered_metrics scene_manager.add_detector(ContentDetector()) # add_detector should trigger register_metrics in the StatsManager. assert stats_manager._registered_metrics try: video_fps = video_manager.get_framerate() start_time = FrameTimecode('00:00:00', video_fps) duration = FrameTimecode('00:00:20', video_fps) video_manager.set_duration(start_time=start_time, end_time=duration) video_manager.set_downscale_factor() video_manager.start() scene_manager.detect_scenes(frame_source=video_manager) # Check that metrics were written to the StatsManager. assert stats_manager._frame_metrics frame_key = min(stats_manager._frame_metrics.keys()) assert stats_manager._frame_metrics[frame_key] assert stats_manager.metrics_exist(frame_key, list(stats_manager._registered_metrics)) # Since we only added 1 detector, the number of metrics from get_metrics # should equal the number of metric keys in _registered_metrics. assert len(stats_manager.get_metrics( frame_key, list(stats_manager._registered_metrics))) == len( stats_manager._registered_metrics) finally: video_manager.release()
def test_load_hardcoded_file_backwards_compat(): """ Test loading a stats file with some hard-coded data generated by this test case. Ensures backwards compatibility with old statsfiles which included an addional header. """ stats_manager = StatsManager() with open(TEST_STATS_FILES[0], 'w') as stats_file: stats_writer = get_csv_writer(stats_file) some_metric_key = 'some_metric' some_metric_value = 1.2 some_frame_key = 100 base_timecode = FrameTimecode(0, 29.97) some_frame_timecode = base_timecode + some_frame_key # Write out a valid file as per PySceneDetect v0.5.4 and prior. stats_writer.writerow(['Video Framerate', '23.976']) stats_writer.writerow( [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key]) stats_writer.writerow([ some_frame_key, some_frame_timecode.get_timecode(), str(some_metric_value) ]) stats_file.close() stats_file = open(TEST_STATS_FILES[0], 'r') stats_manager.load_from_csv(csv_file=stats_file) # Check that we decoded the correct values. assert stats_manager.metrics_exist(some_frame_key, [some_metric_key]) assert stats_manager.get_metrics( some_frame_key, [some_metric_key])[0] == pytest.approx(some_metric_value)
def make_dataset(video_path, video_name, timecodes, save_dir): # type: (str) -> List[Tuple[FrameTimecode, FrameTimecode]] video_manager = VideoManager([video_path]) stats_manager = StatsManager() # Construct our SceneManager and pass it our StatsManager. scene_manager = SceneManager(stats_manager) # Add ContentDetector algorithm (each detector's constructor # takes detector options, e.g. threshold). scene_manager.add_detector(ContentDetector()) base_timecode = video_manager.get_base_timecode() # We save our stats file to {VIDEO_PATH}.stats.csv. stats_file_path = 'stats/%s.stats.csv' % video_name scene_list = [] try: # If stats file exists, load it. if os.path.exists(stats_file_path): # Read stats from CSV file opened in read mode: with open(stats_file_path, 'r') as stats_file: stats_manager.load_from_csv(stats_file, base_timecode) # Set downscale factor to improve processing speed. video_manager.set_downscale_factor() # Start video_manager. video_manager.start() # Perform scene detection on video_manager. scene_manager.detect_scenes(frame_source=video_manager) # We only write to the stats file if a save is required: if stats_manager.is_save_required(): with open(stats_file_path, 'w') as stats_file: stats_manager.save_to_csv(stats_file, base_timecode) start_timecode = "" start_content_val = 0 end_timecode = "" end_content_val = 0 metric_keys = sorted( list( stats_manager._registered_metrics.union( stats_manager._loaded_metrics))) frame_keys = sorted(stats_manager._frame_metrics.keys()) for frame_key in frame_keys: frame_timecode = base_timecode + frame_key timecode = frame_timecode.get_timecode() if timecode > timecodes[0] and timecode < timecodes[1]: content_val = stats_manager.get_metrics( frame_key, metric_keys)[0] if start_content_val < content_val: start_content_val = content_val start_timecode = timecode if timecode > timecodes[2] and timecode < timecodes[3]: content_val = stats_manager.get_metrics( frame_key, metric_keys)[0] if end_content_val < content_val: end_content_val = content_val end_timecode = timecode threshold = min(start_content_val, end_content_val) print(f"Start Time: {start_timecode}, End Time: {end_timecode}") finally: video_manager.release() video_manager = VideoManager([video_path]) stats_manager = StatsManager() scene_manager = SceneManager(stats_manager) scene_manager.add_detector(ContentDetector(threshold=threshold)) base_timecode = video_manager.get_base_timecode() scene_list = [] try: # If stats file exists, load it. if os.path.exists(stats_file_path): # Read stats from CSV file opened in read mode: with open(stats_file_path, 'r') as stats_file: stats_manager.load_from_csv(stats_file, base_timecode) # Set downscale factor to improve processing speed. video_manager.set_downscale_factor() # Start video_manager. video_manager.start() # Perform scene detection on video_manager. scene_manager.detect_scenes(frame_source=video_manager) # Obtain list of detected scenes. scene_list = scene_manager.get_scene_list(base_timecode) # Each scene is a tuple of (start, end) FrameTimecodes. start_video_num = 0 end_video_num = 0 for i, scene in enumerate(scene_list): if scene[0].get_timecode( ) >= start_timecode and start_video_num == 0: start_video_num = i print(f"start video: {start_video_num}") if scene[1].get_timecode() >= end_timecode and end_video_num == 0: end_video_num = i print(f"end video: {end_video_num}") finally: video_manager.release() video_dir = os.path.join(save_dir, video_name) if not os.path.exists(video_dir): os.makedirs(video_dir) split_video_ffmpeg([video_path], scene_list, os.path.join(video_dir, "${VIDEO_NAME}-${SCENE_NUMBER}.mp4"), video_name) return start_video_num, end_video_num, len(scene_list)