def write_scene_list(output_csv_file, scene_list, cut_list=None):
    """ Writes the given list of scenes to an output file handle in CSV format.

    Arguments:
        output_csv_file: Handle to open file in write mode.
        scene_list: List of pairs of FrameTimecodes denoting each scene's start/end FrameTimecode.
        cut_list: Optional list of FrameTimecode objects denoting the cut list (i.e. the frames
            in the video that need to be split to generate individual scenes). If not passed,
            the start times of each scene (besides the 0th scene) is used instead.
    """
    # type: (File, List[Tuple[FrameTimecode, FrameTimecode]], Optional[List[FrameTimecode]]) -> None
    csv_writer = get_csv_writer(output_csv_file)
    # Output Timecode List
    csv_writer.writerow(
        ["Timecode List:"] +
        cut_list if cut_list else [start.get_timecode() for start, _ in scene_list[1:]])
    csv_writer.writerow([
        "Scene Number",
        "Start Frame", "Start Timecode", "Start Time (seconds)",
        "End Frame", "End Timecode", "End Time (seconds)",
        "Length (frames)", "Length (timecode)", "Length (seconds)"])
    for i, (start, end) in enumerate(scene_list):
        duration = end - start
        csv_writer.writerow([
            '%d' % (i+1),
            '%d' % start.get_frames(), start.get_timecode(), '%.3f' % start.get_seconds(),
            '%d' % end.get_frames(), end.get_timecode(), '%.3f' % end.get_seconds(),
            '%d' % duration.get_frames(), duration.get_timecode(), '%.3f' % duration.get_seconds()])
Beispiel #2
0
def write_scene_list(output_csv_file, scene_list, include_cut_list=True, cut_list=None):
    # type: (File, List[Tuple[FrameTimecode, FrameTimecode]],
    #        Optional[bool], Optional[List[FrameTimecode]]) -> None
    """ Writes the given list of scenes to an output file handle in CSV format.

    Arguments:
        output_csv_file: Handle to open file in write mode.
        scene_list: List of pairs of FrameTimecodes denoting each scene's start/end FrameTimecode.
        include_cut_list: Bool indicating if the first row should include the timecodes where
            each scene starts.  Current default is True, but will be moving to False eventually
            as part of #136 (https://github.com/Breakthrough/PySceneDetect/issues/136).
        cut_list: Optional list of FrameTimecode objects denoting the cut list (i.e. the frames
            in the video that need to be split to generate individual scenes). If not passed,
            the start times of each scene (besides the 0th scene) is used instead.
    """
    csv_writer = get_csv_writer(output_csv_file)
    # If required, output the cutting list as the first row (i.e. before the header row).
    if include_cut_list:
        csv_writer.writerow(
            ["Timecode List:"] +
            cut_list if cut_list else [start.get_timecode() for start, _ in scene_list[1:]])
    csv_writer.writerow([
        "Scene Number",
        "Start Frame", "Start Timecode", "Start Time (seconds)",
        "End Frame", "End Timecode", "End Time (seconds)",
        "Length (frames)", "Length (timecode)", "Length (seconds)"])
    for i, (start, end) in enumerate(scene_list):
        duration = end - start
        csv_writer.writerow([
            '%d' % (i+1),
            '%d' % start.get_frames(), start.get_timecode(), '%.3f' % start.get_seconds(),
            '%d' % end.get_frames(), end.get_timecode(), '%.3f' % end.get_seconds(),
            '%d' % duration.get_frames(), duration.get_timecode(), '%.3f' % duration.get_seconds()])
Beispiel #3
0
def test_load_corrupt_stats():
    """ Test loading a corrupted stats file created by outputting data in the wrong format. """

    stats_manager = StatsManager()

    with open(TEST_STATS_FILES[0], 'wt') as stats_file:
        stats_writer = get_csv_writer(stats_file)

        some_metric_key = 'some_metric'
        some_metric_value = str(1.2)
        some_frame_key = 100
        base_timecode = FrameTimecode(0, 29.97)
        some_frame_timecode = base_timecode + some_frame_key

        # Write out some invalid files.

        # File #0: Wrong Header Names [StatsFileCorrupt]
        # Swapped timecode & frame number.
        stats_writer.writerow(
            [COLUMN_NAME_TIMECODE, COLUMN_NAME_FRAME_NUMBER, some_metric_key])
        stats_writer.writerow([
            some_frame_key,
            some_frame_timecode.get_timecode(), some_metric_value
        ])

        stats_file.close()

        with pytest.raises(StatsFileCorrupt):
            stats_manager.load_from_csv(TEST_STATS_FILES[0])
Beispiel #4
0
def write_scene_list(output_csv_file, scene_list, cut_list=None):
    """ Writes the given list of scenes to an output file handle in CSV format.

    Arguments:
        output_csv_file: Handle to open file in write mode.
        scene_list: List of pairs of FrameTimecodes denoting each scene's start/end FrameTimecode.
        cut_list: Optional list of FrameTimecode objects denoting the cut list (i.e. the frames
            in the video that need to be split to generate individual scenes). If not passed,
            the start times of each scene (besides the 0th scene) is used instead.
    """
    # type: (File, List[Tuple[FrameTimecode, FrameTimecode]], Optional[List[FrameTimecode]]) -> None
    csv_writer = get_csv_writer(output_csv_file)
    # Output Timecode List
    csv_writer.writerow(["Timecode List:"] + cut_list if cut_list else
                        [start.get_timecode() for start, _ in scene_list[1:]])
    csv_writer.writerow([
        "Scene Number", "Start Frame", "Start Timecode",
        "Start Time (seconds)", "End Frame", "End Timecode",
        "End Time (seconds)", "Length (frames)", "Length (timecode)",
        "Length (seconds)"
    ])
    for i, (start, end) in enumerate(scene_list):
        duration = end - start
        csv_writer.writerow([
            '%d' % (i + 1),
            '%d' % start.get_frames(),
            start.get_timecode(),
            '%.3f' % start.get_seconds(),
            '%d' % end.get_frames(),
            end.get_timecode(),
            '%.3f' % end.get_seconds(),
            '%d' % duration.get_frames(),
            duration.get_timecode(),
            '%.3f' % duration.get_seconds()
        ])
Beispiel #5
0
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)
Beispiel #6
0
 def save_to_csv(self, csv_file, base_timecode, force_save=True):
     # type: (File [w], FrameTimecode, bool) -> None
     csv_writer = get_csv_writer(csv_file)
     # Ensure we need to write to the file, and that we have data to do so with.
     if ((self.is_save_required() or force_save)
             and self._registered_metrics and self._frame_metrics):
         # Header rows.
         metric_keys = sorted(
             list(self._registered_metrics.union(self._loaded_metrics)))
         csv_writer.writerow(
             [COLUMN_NAME_FPS,
              '%.10f' % base_timecode.get_framerate()])
         csv_writer.writerow(
             [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE] + metric_keys)
         frame_keys = sorted(self._frame_metrics.keys())
         print("Writing %d frames to CSV..." % len(frame_keys))
         for frame_key in frame_keys:
             frame_timecode = base_timecode + frame_key
             csv_writer.writerow([
                 frame_timecode.get_frames(),
                 frame_timecode.get_timecode()
             ] + [
                 str(metric)
                 for metric in self.get_metrics(frame_key, metric_keys)
             ])
     else:
         if not self._registered_metrics:
             raise NoMetricsRegistered()
         if not self._frame_metrics:
             raise NoMetricsSet()
Beispiel #7
0
    def save_to_csv(self, csv_file, base_timecode, force_save=True):
        # type: (File [w], FrameTimecode, bool) -> None
        """ Save To CSV: Saves all frame metrics stored in the StatsManager to a CSV file.

        Arguments:
            csv_file: A file handle opened in write mode (e.g. open('...', 'w')).
            base_timecode: The base_timecode obtained from the frame source VideoManager.
                If using an OpenCV VideoCapture, create one using the video framerate by
                setting base_timecode=FrameTimecode(0, fps=video_framerate).
            force_save: If True, forcably writes metrics out even if there are no
                registered metrics or frame statistics. If False, a NoMetricsRegistered
                will be thrown if there are no registered metrics, and a NoMetricsSet
                exception will be thrown if is_save_required() returns False.

        Raises:
            NoMetricsRegistered: No frame metrics have been registered to save,
                nor is there any frame data to save.
            NoMetricsSet: No frame metrics have been entered/updated, thus there
                is no frame data to save.
        """
        csv_writer = get_csv_writer(csv_file)
        # Ensure we need to write to the file, and that we have data to do so with.
        if ((self.is_save_required() or force_save)
                and self._registered_metrics and self._frame_metrics):
            # Header rows.
            metric_keys = sorted(
                list(self._registered_metrics.union(self._loaded_metrics)))
            csv_writer.writerow(
                [COLUMN_NAME_FPS,
                 '%.10f' % base_timecode.get_framerate()])
            csv_writer.writerow(
                [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE] + metric_keys)
            frame_keys = sorted(self._frame_metrics.keys())
            print("Writing %d frames to CSV..." % len(frame_keys))
            for frame_key in frame_keys:
                frame_timecode = base_timecode + frame_key
                csv_writer.writerow([
                    frame_timecode.get_frames(),
                    frame_timecode.get_timecode()
                ] + [
                    str(metric)
                    for metric in self.get_metrics(frame_key, metric_keys)
                ])
        else:
            if not self._registered_metrics:
                raise NoMetricsRegistered()
            if not self._frame_metrics:
                raise NoMetricsSet()
    def save_to_csv(self, csv_file, base_timecode, force_save=True):
        # type: (File [w], FrameTimecode, bool) -> None
        """ Save To CSV: Saves all frame metrics stored in the StatsManager to a CSV file.

        Arguments:
            csv_file: A file handle opened in write mode (e.g. open('...', 'w')).
            base_timecode: The base_timecode obtained from the frame source VideoManager.
                If using an OpenCV VideoCapture, create one using the video framerate by
                setting base_timecode=FrameTimecode(0, fps=video_framerate).
            force_save: If True, forcably writes metrics out even if there are no
                registered metrics or frame statistics. If False, a NoMetricsRegistered
                will be thrown if there are no registered metrics, and a NoMetricsSet
                exception will be thrown if is_save_required() returns False.

        Raises:
            NoMetricsRegistered: No frame metrics have been registered to save,
                nor is there any frame data to save.
            NoMetricsSet: No frame metrics have been entered/updated, thus there
                is no frame data to save.
        """
        csv_writer = get_csv_writer(csv_file)
        # Ensure we need to write to the file, and that we have data to do so with.
        if ((self.is_save_required() or force_save) and
                self._registered_metrics and self._frame_metrics):
            # Header rows.
            metric_keys = sorted(list(self._registered_metrics.union(self._loaded_metrics)))
            csv_writer.writerow([COLUMN_NAME_FPS, '%.10f' % base_timecode.get_framerate()])
            csv_writer.writerow(
                [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE] + metric_keys)
            frame_keys = sorted(self._frame_metrics.keys())
            print("Writing %d frames to CSV..." % len(frame_keys))
            for frame_key in frame_keys:
                frame_timecode = base_timecode + frame_key
                csv_writer.writerow(
                    [frame_timecode.get_frames(), frame_timecode.get_timecode()] +
                    [str(metric) for metric in self.get_metrics(frame_key, metric_keys)])
        else:
            if not self._registered_metrics:
                raise NoMetricsRegistered()
            if not self._frame_metrics:
                raise NoMetricsSet()
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])
Beispiel #10
0
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 test_load_corrupt_stats(test_video_file):
    """ Test loading a corrupted stats file created by outputting data in the wrong format. """
    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_files = [open(stats_file, 'wt') for stats_file in TEST_STATS_FILES]
    try:

        stats_writers = [get_csv_writer(stats_file) for stats_file in stats_files]

        some_metric_key = 'some_metric'
        some_metric_value = str(1.2)
        some_frame_key = 100
        base_timecode = FrameTimecode(0, 29.97)
        some_frame_timecode = base_timecode + some_frame_key

        # Write out some invalid files.
        # File 0: Blank FPS [StatsFileCorrupt]
        stats_writers[0].writerow([COLUMN_NAME_FPS])
        stats_writers[0].writerow(
            [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key])
        stats_writers[0].writerow(
            [some_frame_key, some_frame_timecode.get_timecode(), some_metric_value])

        # File 1: Invalid FPS [StatsFileCorrupt]
        stats_writers[1].writerow([COLUMN_NAME_FPS, '%0.10f' % 0.0000001])
        stats_writers[1].writerow(
            [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key])
        stats_writers[1].writerow(
            [some_frame_key, some_frame_timecode.get_timecode(), some_metric_value])

        # File 2: Wrong FPS [StatsFileFramerateMismatch]
        stats_writers[2].writerow(
            [COLUMN_NAME_FPS, '%.10f' % (base_timecode.get_framerate() / 2.0)])
        stats_writers[2].writerow(
            [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key])
        stats_writers[2].writerow(
            [some_frame_key, some_frame_timecode.get_timecode(), some_metric_value])

        # File 3: Wrong Header Names [StatsFileCorrupt]
        stats_writers[3].writerow([COLUMN_NAME_FPS, '%.10f' % base_timecode.get_framerate()])
        stats_writers[3].writerow(
            [COLUMN_NAME_TIMECODE, COLUMN_NAME_FRAME_NUMBER, some_metric_key])
        stats_writers[3].writerow(
            [some_frame_key, some_frame_timecode.get_timecode(), some_metric_value])

        for stats_file in stats_files: stats_file.close()

        stats_files = [open(stats_file, 'rt') for stats_file in TEST_STATS_FILES]

        with pytest.raises(StatsFileCorrupt):
            stats_manager.load_from_csv(stats_files[0], base_timecode)
        with pytest.raises(StatsFileCorrupt):
            stats_manager.load_from_csv(stats_files[1], base_timecode)
        with pytest.raises(StatsFileFramerateMismatch):
            stats_manager.load_from_csv(stats_files[2], base_timecode)
        with pytest.raises(StatsFileCorrupt):
            stats_manager.load_from_csv(stats_files[3], base_timecode)

    finally:
        for stats_file in stats_files: stats_file.close()
        for stats_file in TEST_STATS_FILES: os.remove(stats_file)
def test_load_corrupt_stats(test_video_file):
    """ Test loading a corrupted stats file created by outputting data in the wrong format. """
    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_files = [open(stats_file, 'wt') for stats_file in TEST_STATS_FILES]
    try:

        stats_writers = [get_csv_writer(stats_file) for stats_file in stats_files]

        some_metric_key = 'some_metric'
        some_metric_value = str(1.2)
        some_frame_key = 100
        base_timecode = FrameTimecode(0, 29.97)
        some_frame_timecode = base_timecode + some_frame_key

        # Write out some invalid files.
        # File 0: Blank FPS [StatsFileCorrupt]
        stats_writers[0].writerow([COLUMN_NAME_FPS])
        stats_writers[0].writerow(
            [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key])
        stats_writers[0].writerow(
            [some_frame_key, some_frame_timecode.get_timecode(), some_metric_value])

        # File 1: Invalid FPS [StatsFileCorrupt]
        stats_writers[1].writerow([COLUMN_NAME_FPS, '%0.10f' % 0.0000001])
        stats_writers[1].writerow(
            [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key])
        stats_writers[1].writerow(
            [some_frame_key, some_frame_timecode.get_timecode(), some_metric_value])

        # File 2: Wrong FPS [StatsFileFramerateMismatch]
        stats_writers[2].writerow(
            [COLUMN_NAME_FPS, '%.10f' % (base_timecode.get_framerate() / 2.0)])
        stats_writers[2].writerow(
            [COLUMN_NAME_FRAME_NUMBER, COLUMN_NAME_TIMECODE, some_metric_key])
        stats_writers[2].writerow(
            [some_frame_key, some_frame_timecode.get_timecode(), some_metric_value])

        # File 3: Wrong Header Names [StatsFileCorrupt]
        stats_writers[3].writerow([COLUMN_NAME_FPS, '%.10f' % base_timecode.get_framerate()])
        stats_writers[3].writerow(
            [COLUMN_NAME_TIMECODE, COLUMN_NAME_FRAME_NUMBER, some_metric_key])
        stats_writers[3].writerow(
            [some_frame_key, some_frame_timecode.get_timecode(), some_metric_value])

        for stats_file in stats_files: stats_file.close()

        stats_files = [open(stats_file, 'rt') for stats_file in TEST_STATS_FILES]

        with pytest.raises(StatsFileCorrupt):
            stats_manager.load_from_csv(stats_files[0], base_timecode)
        with pytest.raises(StatsFileCorrupt):
            stats_manager.load_from_csv(stats_files[1], base_timecode)
        with pytest.raises(StatsFileFramerateMismatch):
            stats_manager.load_from_csv(stats_files[2], base_timecode)
        with pytest.raises(StatsFileCorrupt):
            stats_manager.load_from_csv(stats_files[3], base_timecode)

    finally:
        for stats_file in stats_files: stats_file.close()
        for stats_file in TEST_STATS_FILES: os.remove(stats_file)