def _draw_line(result: ClassifierResult) -> Line: # draw line chart x_axis = [str(i) for i in result.get_timestamp_list()] y_axis = result.get_stage_list() line = Line(init_opts=opts.InitOpts( bg_color=constants.BACKGROUND_COLOR)) line.add_xaxis(x_axis) line.add_yaxis("stage", y_axis, is_step=False, is_symbol_show=True) line.set_global_opts( title_opts=opts.TitleOpts( title="Trend", subtitle="describe how these stages switching"), toolbox_opts=opts.ToolboxOpts(is_show=True), tooltip_opts=opts.TooltipOpts(is_show=True, trigger="axis", axis_pointer_type="cross"), brush_opts=opts.BrushOpts(x_axis_index="all", tool_box=["lineX"]), ) return line
def _draw_bar(result: ClassifierResult) -> Bar: # draw bar chart bar = Bar(init_opts=opts.InitOpts(bg_color=constants.BACKGROUND_COLOR)) x_axis = sorted(list(result.get_stage_set())) y_axis = list() offset = result.get_offset() for each_stage_name in x_axis: each_stage = result.get_specific_stage(each_stage_name) # last frame - first frame time_cost = each_stage[-1].timestamp - each_stage[ 0].timestamp + offset y_axis.append(time_cost) bar.add_xaxis(x_axis) bar.add_yaxis("time cost", y_axis) bar.set_global_opts( title_opts=opts.TitleOpts(title="Time Cost", subtitle="... of each stages"), toolbox_opts=opts.ToolboxOpts(is_show=True), ) logger.debug(f"time cost: {dict(zip(x_axis, y_axis))}") return bar
def load(cls, from_file: str) -> typing.List[ClassifierResult]: assert os.path.isfile(from_file), f"file {from_file} not existed" with open(from_file, encoding=constants.CHARSET) as f: content = json.load(f) return [ClassifierResult(**each) for each in content]
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}")
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}")
def draw( self, classifier_result: ClassifierResult, report_path: str = None, cut_result: VideoCutResult = None, language: str = None, *args, **kwargs, ): """ draw report file :param classifier_result: classifierResult, 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(classifier_result) bar = self._draw_bar(classifier_result) # merge charts page = Page() page.add(line) page.add(bar) # calc time cost cost_dict = classifier_result.calc_changing_cost() # 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(classifier_result, 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=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}")