예제 #1
0
    def pick_and_save(self,
                      range_list: typing.List[VideoCutRange],
                      frame_count: int,
                      to_dir: str = None,
                      compress_rate: float = None,
                      *args, **kwargs) -> str:
        stage_list = list()
        for index, each_range in enumerate(range_list):
            picked = each_range.pick(frame_count, *args, **kwargs)
            logger.info(f'pick {picked} in range {each_range}')
            stage_list.append((index, picked))

        # create parent dir
        if not to_dir:
            to_dir = toolbox.get_timestamp_str()
        os.makedirs(to_dir, exist_ok=True)

        for each_stage_id, each_frame_list in stage_list:
            # create sub dir
            each_stage_dir = os.path.join(to_dir, str(each_stage_id))
            os.makedirs(each_stage_dir, exist_ok=True)

            with toolbox.video_capture(self.video_path) as cap:
                for each_frame_id in each_frame_list:
                    each_frame_path = os.path.join(each_stage_dir, f'{uuid.uuid4()}.png')
                    each_frame = toolbox.get_frame(cap, each_frame_id - 1)
                    if compress_rate:
                        each_frame = toolbox.compress_frame(each_frame, compress_rate)
                    cv2.imwrite(each_frame_path, each_frame)
                    logger.debug(f'frame [{each_frame_id}] saved to {each_frame_path}')

        return to_dir
예제 #2
0
    def pick_and_save(
            self,
            range_list: typing.List[VideoCutRange],
            frame_count: int,
            to_dir: str = None,
            prune: float = None,

            # in kwargs
            # compress_rate: float = None,
            # target_size: typing.Tuple[int, int] = None,
            # to_grey: bool = None,
            *args,
            **kwargs) -> str:
        """
        pick some frames from range, and save them as files

        :param range_list: VideoCutRange list
        :param frame_count: default to 3, and finally you will get 3 frames for each range
        :param to_dir: will saved to this path
        :param prune: float, 0-1. if set it 0.9, some stages which are too similar (ssim > 0.9) will be removed
        :param args:
        :param kwargs:
        :return:
        """
        stage_list = list()
        # build tag and get frames
        for index, each_range in enumerate(range_list):
            picked = each_range.pick(frame_count, *args, **kwargs)
            picked_frames = each_range.get_frames(picked)
            logger.info(f'pick {picked} in range {each_range}')
            stage_list.append((str(index), picked_frames))

        # prune
        if prune:
            stage_list = self._prune(prune, stage_list)

        # create parent dir
        if not to_dir:
            to_dir = toolbox.get_timestamp_str()
        os.makedirs(to_dir, exist_ok=True)

        for each_stage_id, each_frame_list in stage_list:
            # create sub dir
            each_stage_dir = os.path.join(to_dir, str(each_stage_id))
            os.makedirs(each_stage_dir, exist_ok=True)

            for each_frame_object in each_frame_list:
                each_frame_path = os.path.join(each_stage_dir,
                                               f'{uuid.uuid4()}.png')
                compressed = toolbox.compress_frame(each_frame_object.frame,
                                                    **kwargs)
                cv2.imwrite(each_frame_path, compressed)
                logger.debug(
                    f'frame [{each_frame_object.frame_id}] saved to {each_frame_path}'
                )

        return to_dir
예제 #3
0
파일: base.py 프로젝트: ssfanli/sepmachine
    def __init__(
        self, preload: bool = None, frame_count: int = None, result_path: str = None
    ):
        # config here
        self.preload: bool = preload or True
        self.frame_count: int = frame_count or 5
        # result
        self.classifier_result: typing.Optional[ClassifierResult] = None
        self.result_path: str = result_path
        self.result_report_path: str = ""
        if not self.result_path:
            self.result_path = toolbox.get_timestamp_str()
        os.makedirs(self.result_path, exist_ok=True)

        logger.info(f"handler config: {self.__dict__}")
예제 #4
0
    def pick_and_save(self,
                      range_list: typing.List[VideoCutRange],
                      frame_count: int,
                      to_dir: str = None,

                      # in kwargs
                      # compress_rate: float = None,
                      # target_size: typing.Tuple[int, int] = None,
                      # to_grey: bool = None,

                      *args, **kwargs) -> str:
        """
        pick some frames from range, and save them as files

        :param range_list: VideoCutRange list
        :param frame_count: default to 3, and finally you will get 3 frames for each range
        :param to_dir: will saved to this path
        :param args:
        :param kwargs:
        :return:
        """
        stage_list = list()
        for index, each_range in enumerate(range_list):
            picked = each_range.pick(frame_count, *args, **kwargs)
            logger.info(f'pick {picked} in range {each_range}')
            stage_list.append((index, picked))

        # create parent dir
        if not to_dir:
            to_dir = toolbox.get_timestamp_str()
        os.makedirs(to_dir, exist_ok=True)

        for each_stage_id, each_frame_list in stage_list:
            # create sub dir
            each_stage_dir = os.path.join(to_dir, str(each_stage_id))
            os.makedirs(each_stage_dir, exist_ok=True)

            with toolbox.video_capture(self.video_path) as cap:
                for each_frame_id in each_frame_list:
                    each_frame_path = os.path.join(each_stage_dir, f'{uuid.uuid4()}.png')
                    each_frame = toolbox.get_frame(cap, each_frame_id - 1)
                    each_frame = toolbox.compress_frame(each_frame, **kwargs)
                    cv2.imwrite(each_frame_path, each_frame)
                    logger.debug(f'frame [{each_frame_id}] saved to {each_frame_path}')

        return to_dir
예제 #5
0
    def pick_and_save(
        self,
        range_list: typing.List[VideoCutRange],
        frame_count: int,
        to_dir: str = None,
        prune: float = None,
        meaningful_name: bool = None,
        # in kwargs
        # compress_rate: float = None,
        # target_size: typing.Tuple[int, int] = None,
        # to_grey: bool = None,
        *args,
        **kwargs,
    ) -> str:
        """
        pick some frames from range, and save them as files

        :param range_list: VideoCutRange list
        :param frame_count: default to 3, and finally you will get 3 frames for each range
        :param to_dir: will saved to this path
        :param prune: float, 0-1. if set it 0.9, some stages which are too similar (ssim > 0.9) will be removed
        :param meaningful_name: bool, False by default. if true, image names will become meaningful (with timestamp/id or something else)
        :param args:
        :param kwargs:
        :return:
        """
        stage_list = list()
        # build tag and get frames
        for index, each_range in enumerate(range_list):
            picked = each_range.pick(frame_count, *args, **kwargs)
            picked_frames = each_range.get_frames(picked)
            logger.info(f"pick {picked} in range {each_range}")
            stage_list.append((str(index), picked_frames))

        # prune
        if prune:
            stage_list = self._prune(prune, stage_list)

        # create parent dir
        if not to_dir:
            to_dir = toolbox.get_timestamp_str()
        logger.debug(f"try to make dirs: {to_dir}")
        os.makedirs(to_dir, exist_ok=True)

        for each_stage_id, each_frame_list in stage_list:
            # create sub dir
            each_stage_dir = os.path.join(to_dir, str(each_stage_id))

            if os.path.isdir(each_stage_dir):
                logger.warning(f"sub dir [{each_stage_dir}] already existed")
                logger.warning(
                    "NOTICE: make sure your data will not be polluted by accident"
                )
            os.makedirs(each_stage_dir, exist_ok=True)

            # create image files
            for each_frame_object in each_frame_list:
                if meaningful_name:
                    # - video name
                    # - frame id
                    # - frame timestamp
                    image_name = (
                        f"{os.path.basename(os.path.splitext(self.video.path)[0])}"
                        f"_"
                        f"{each_frame_object.frame_id}"
                        f"_"
                        f"{each_frame_object.timestamp}"
                        f".png"
                    )
                else:
                    image_name = f"{uuid.uuid4()}.png"

                each_frame_path = os.path.join(each_stage_dir, image_name)
                compressed = toolbox.compress_frame(each_frame_object.data, **kwargs)
                cv2.imwrite(each_frame_path, compressed)
                logger.debug(
                    f"frame [{each_frame_object.frame_id}] saved to {each_frame_path}"
                )

        return to_dir
예제 #6
0
    def draw(
        self,
        data_list: typing.List[ClassifierResult],
        report_path: str = None,
        cut_result: VideoCutResult = None,
        language: str = None,
        *args,
        **kwargs,
    ):
        """
        draw report file

        :param data_list: classifierResult list, output of classifier
        :param report_path: your report will be there
        :param cut_result: more charts would be built
        :param language: 'en' or 'zh'
        :return:
        """

        # draw
        line = self._draw_line(data_list)
        bar = self._draw_bar(data_list)

        # merge charts
        page = Page()
        page.add(line)
        page.add(bar)

        # calc time cost
        cost_dict = DataUtils.calc_changing_cost(data_list)

        # insert pictures
        if cut_result:
            # sim chart
            sim_line = self._draw_sim(cut_result)
            page.add(sim_line)

            _, unstable = cut_result.get_range(*args, **kwargs)
            # insert thumbnail
            if not self.thumbnail_list:
                logger.debug("auto insert thumbnail ...")

                for each in unstable:
                    self.add_thumbnail(
                        f"{each.start}({each.start_time}) - {each.end}({each.end_time}), "
                        f"duration: {each.end_time - each.start_time}",
                        cut_result.thumbnail(each, *args, **kwargs),
                    )

        # insert stable frames
        stable_stage_sample = self.get_stable_stage_sample(data_list, compress_rate=0.2)
        stable_stage_sample = toolbox.np2b64str(stable_stage_sample)

        # time stamp
        timestamp = toolbox.get_timestamp_str()

        # insert extras
        # default: zh_cn report
        if not language:
            language = "zh"
        template = Template(get_template(language))
        template_content = template.render(
            chart=Markup(page.render_embed()),
            dir_link_list=self.dir_link_list,
            thumbnail_list=self.thumbnail_list,
            stable_sample=stable_stage_sample,
            extras=self.extra_dict,
            background_color=BACKGROUND_COLOR,
            cost_dict=cost_dict,
            timestamp=timestamp,
            version_code=__VERSION__,
        )

        # save to file
        if not report_path:
            report_path = f"{timestamp}.html"
        with open(report_path, "w", encoding=constants.CHARSET) as fh:
            fh.write(template_content)
        logger.info(f"save report to {report_path}")
예제 #7
0
    def draw(
        self,
        classifier_result: ClassifierResult,
        report_path: str = None,
        unstable_ranges: typing.List[VideoCutRange] = None,
        cut_result: VideoCutResult = None,
        compress_rate: float = None,
        *_,
        **__,
    ):
        """
        draw report file

        :param classifier_result: classifierResult, output of classifier
        :param report_path: your report will be there
        :param unstable_ranges: for marking unstable ranges
        :param cut_result: more charts would be built
        :param compress_rate:
        :return:
        """
        # default: compress_rate
        if not compress_rate:
            compress_rate = 0.2
        if not unstable_ranges:
            unstable_ranges = []

        # draw
        line = self._draw_line(classifier_result)
        bar = self._draw_bar(classifier_result)

        # merge charts
        page = Page()
        page.add(line)
        page.add(bar)

        # insert pictures
        if cut_result:
            # sim chart
            sim_line = self._draw_sim(cut_result)
            page.add(sim_line)

        # mark range
        for each in unstable_ranges:
            classifier_result.mark_range_unstable(each.start, each.end)

        offset = classifier_result.get_offset()
        stage_range = classifier_result.get_stage_range()
        for cur_index in range(len(stage_range)):
            each = stage_range[cur_index]
            middle = each[len(each) // 2]
            if middle.is_stable():
                label = self.LABEL_STABLE
                frame = toolbox.compress_frame(middle.get_data(),
                                               compress_rate=compress_rate)
            else:
                # todo: looks not good enough. `unspecific` looks a little weird but I have no idea now
                if middle.stage == constants.UNKNOWN_STAGE_FLAG:
                    label = self.LABEL_UNSPECIFIC
                else:
                    label = self.LABEL_UNSTABLE
                # add a frame
                if cur_index + 1 < len(stage_range):
                    new_each = [*each, stage_range[cur_index + 1][0]]
                else:
                    new_each = each
                frame = np.hstack([
                    toolbox.compress_frame(i.get_data(),
                                           compress_rate=compress_rate)
                    for i in new_each
                ])

            first, last = each[0], each[-1]
            self.add_thumbnail(
                f"{label} range {first.frame_id}({first.timestamp}) - {last.frame_id}({last.timestamp + offset}), "
                f"duration: {last.timestamp - first.timestamp + offset}",
                frame,
            )
        # calc time cost
        cost_dict = classifier_result.calc_changing_cost()

        # time stamp
        timestamp = toolbox.get_timestamp_str()

        # video
        self.add_extra("video path", classifier_result.video_path)
        self.add_extra("frame count", str(classifier_result.get_length()))
        self.add_extra("offset between frames",
                       str(classifier_result.get_offset()))

        # insert extras
        template = Template(get_template())
        template_content = template.render(
            chart=Markup(page.render_embed()),
            thumbnail_list=self.thumbnail_list,
            extras=self.extra_dict,
            background_color=constants.BACKGROUND_COLOR,
            cost_dict=cost_dict,
            timestamp=timestamp,
            version_code=__VERSION__,
        )

        # default: write to current dir
        default_name = f"{timestamp}.html"
        if not report_path:
            report_path = default_name
        # somewhere specific
        # existed dir?
        elif os.path.isdir(report_path):
            report_path = os.path.join(report_path, default_name)
        logger.debug(f"trying to save report to {report_path}")

        # write file
        with open(report_path, "w", encoding=constants.CHARSET) as fh:
            fh.write(template_content)
        logger.info(f"save report to {report_path}")
예제 #8
0
    def draw(
        self,
        classifier_result: ClassifierResult,
        report_path: str = None,
        unstable_ranges: typing.List[VideoCutRange] = None,
        cut_result: VideoCutResult = None,
        compress_rate: float = None,
        *_,
        **__,
    ):
        """
        draw report file

        :param classifier_result: classifierResult, output of classifier
        :param report_path: your report will be there
        :param unstable_ranges: for marking unstable ranges
        :param cut_result: more charts would be built
        :param compress_rate:
        :return:
        """
        # default: compress_rate
        if not compress_rate:
            compress_rate = 0.2
        if not unstable_ranges:
            unstable_ranges = []

        # draw
        line = self._draw_line(classifier_result)
        bar = self._draw_bar(classifier_result)

        # merge charts
        page = Page()
        page.add(line)
        page.add(bar)

        # insert pictures
        if cut_result:
            # sim chart
            sim_line = self._draw_sim(cut_result)
            page.add(sim_line)

        # mark range
        for each in unstable_ranges:
            classifier_result.mark_range_unstable(each.start, each.end)
        offset = classifier_result.get_offset()
        for each in classifier_result.get_stage_range():
            middle = each[len(each) // 2]
            if middle.is_stable():
                label = "stable"
                frame = toolbox.compress_frame(middle.get_data(),
                                               compress_rate=compress_rate)
            else:
                label = "unstable"
                frame = np.hstack([
                    toolbox.compress_frame(i.get_data(),
                                           compress_rate=compress_rate)
                    for i in each
                ])

            first, last = each[0], each[-1]
            self.add_thumbnail(
                f"{label} range {first.frame_id}({first.timestamp - offset}) - {last.frame_id}({last.timestamp}), "
                f"duration: {last.timestamp - first.timestamp + offset}",
                frame,
            )
        # calc time cost
        cost_dict = classifier_result.calc_changing_cost()

        # time stamp
        timestamp = toolbox.get_timestamp_str()

        # video
        self.add_extra("video path", classifier_result.video_path)
        self.add_extra("frame count", str(classifier_result.get_length()))
        self.add_extra("offset between frames",
                       str(classifier_result.get_offset()))

        # insert extras
        template = Template(get_template())
        template_content = template.render(
            chart=Markup(page.render_embed()),
            thumbnail_list=self.thumbnail_list,
            extras=self.extra_dict,
            background_color=constants.BACKGROUND_COLOR,
            cost_dict=cost_dict,
            timestamp=timestamp,
            version_code=__VERSION__,
        )

        # save to file
        if not report_path:
            report_path = f"{timestamp}.html"
        with open(report_path, "w", encoding=constants.CHARSET) as fh:
            fh.write(template_content)
        logger.info(f"save report to {report_path}")