示例#1
0
from stagesepx.cutter import VideoCutter
from stagesepx.classifier import SVMClassifier
from stagesepx.reporter import Reporter
from stagesepx.video import VideoObject


video_path = "../videos/long.mp4"
video = VideoObject(video_path)
video.load_frames()

# --- cutter ---
cutter = VideoCutter()
res = cutter.cut(video)
stable, unstable = res.get_range()
data_home = res.pick_and_save(stable, 5)

# --- classify ---
cl = SVMClassifier(compress_rate=0.4)
cl.load(data_home)
cl.train()
classify_result = cl.classify(video, stable, keep_data=True)
result_dict = classify_result.to_dict()

# --- draw ---
r = Reporter()
r.draw(classify_result)
示例#2
0
from stagesepx.classifier import SVMClassifier
from stagesepx.reporter import Reporter

# 默认情况下使用 HoG 进行特征提取
# 你可以将其关闭从而直接对原始图片进行训练与测试:feature_type='raw'
cl = SVMClassifier(feature_type='hog')

# 基本与SSIM分类器的流程一致
# 但它对数据的要求可能有所差别,具体参见 cut.py 中的描述
data_home = './cut_result'
cl.load(data_home)

# 在加载数据完成之后需要先训练
cl.train()

# # 在训练后你可以把模型保存起来
# cl.save_model('model.pkl')
# # 或者直接读取已经训练好的模型
# cl.load_model('model.pkl')

# 开始分类
res = cl.classify(
    '../test.mp4',
    # 步长,可以自行设置用于平衡效率与颗粒度
    # 默认为1,即每帧都检测
    step=1,
)

# 为了更方便的可读性,stagesepx已经内置了图表绘制功能
# 你可以直接把分析结果绘制成图表
report = Reporter()
示例#3
0
from stagesepx.reporter import Reporter

video_list = [
    '../test.mp4',
    # 把别的视频也配置在这里即可
]

for each_video_path in video_list:
    cutter = VideoCutter()
    res = cutter.cut(each_video_path)
    stable = res.get_stable_range()
    data_home = res.pick_and_save(stable, 3)
    print(stable)

    # classify
    cl = SVMClassifier()
    cl.load(data_home)
    cl.train()

    # 注意,如果在classify方法指定了范围
    # 那么分析时只会分析处于范围内的帧!
    # 例如,这里只传入了stable的范围,那么非stable范围内的帧都会被忽略掉,标记为 -1
    res = cl.classify(
        each_video_path,
        stable,
        # 步长,可以自行设置用于平衡效率与颗粒度
        # 默认为1,即每帧都检测
        step=1)

    # draw
    Reporter.draw(
示例#4
0
    # 采样结果保存的位置
    # 不指定的话则会在当前位置生成文件夹并返回它的路径
    # './cut_result',

    # prune被用于去除重复阶段(>=0.4.4)
    # float(0-1.0),设置为0.9时,如果两个stage相似度超过0.9,他们会合并成一个类别
    prune=None,
)

# --- classify ---

cl = SVMClassifier(
    # 默认情况下使用 HoG 进行特征提取
    # 你可以将其关闭从而直接对原始图片进行训练与测试:feature_type='raw'
    feature_type='hog',
    # 默认为0.2,即将图片缩放为0.2倍
    # 主要为了提高计算效率
    # 如果你担心影响分析效果,可以将其提高
    compress_rate=0.2,
)

# 加载数据
cl.load(data_home)
# 在加载数据完成之后需要先训练
cl.train()
# 在训练后你可以把模型保存起来
# cl.save_model('model.pkl')
# 或者直接读取已经训练好的模型
# cl.load_model('model.pkl')

# 注意,如果在classify方法指定了范围
示例#5
0
文件: mini.py 项目: zsg555/stagesepx
"""
这是一个最小化的 stagesepx 使用例子
每一行的注释均可以在 cut_and_classify.py 中找到
"""
from stagesepx.cutter import VideoCutter
from stagesepx.classifier import SVMClassifier
from stagesepx.reporter import Reporter
from stagesepx.video import VideoObject

video_path = "../demo.mp4"
video = VideoObject(video_path)
video.load_frames()

# --- cutter ---
cutter = VideoCutter()
res = cutter.cut(video)
stable, unstable = res.get_range()
data_home = res.pick_and_save(stable, 5)

# --- classify ---
cl = SVMClassifier()
cl.load(data_home)
cl.train()
classify_result = cl.classify(video, stable)

# --- draw ---
r = Reporter()
r.draw(classify_result)
示例#6
0
文件: train.py 项目: zsg555/stagesepx
"""
这个例子描述了如何训练一个后续可用的模型

在 cut 流程之后,你应该能得到一个已经分拣好的训练集文件夹
我们将基于此文件夹进行模型的训练
"""
from stagesepx.classifier import SVMClassifier

DATA_HOME = './cut_result'
cl = SVMClassifier()

# 加载数据
cl.load(DATA_HOME)
# 在加载数据完成之后需要先训练
cl.train()
# 在训练后你可以把模型保存起来
cl.save_model('model.pkl')
示例#7
0
    # 采样结果保存的位置
    # 不指定的话则会在当前位置生成文件夹并返回它的路径
    # './cut_result',
    # prune被用于去除重复阶段(>=0.4.4)
    # float(0-1.0),设置为0.9时,如果两个stage相似度超过0.9,他们会合并成一个类别
    prune=None,
)

# --- classify ---

cl = SVMClassifier(
    # 默认情况下使用 HoG 进行特征提取
    # 你可以将其关闭从而直接对原始图片进行训练与测试:feature_type='raw'
    feature_type="hog",
    # 默认为0.2,即将图片缩放为0.2倍
    # 主要为了提高计算效率
    # 如果你担心影响分析效果,可以将其提高
    compress_rate=0.2,
    # 或者直接指定尺寸
    # 当压缩率与指定尺寸同时传入时,优先以指定尺寸为准
    # target_size=(200, 400),
)

# 加载数据
cl.load(data_home)
# 在加载数据完成之后需要先训练
cl.train()
# 在训练后你可以把模型保存起来
# cl.save_model('model.pkl')
# 或者直接读取已经训练好的模型
# cl.load_model('model.pkl')
示例#8
0
def test_boost():
    cl = SVMClassifier()
    cl.load_model(MODEL_PATH)
    classify_result = cl.classify(VIDEO_PATH, boost_mode=True)
    assert classify_result
示例#9
0
from stagesepx.cutter import VideoCutter
from stagesepx.classifier import SVMClassifier
from stagesepx.video import VideoObject

video_path = "../videos/short.mp4"
video = VideoObject(video_path)
video.load_frames()

# --- cutter ---
cutter = VideoCutter()
res = cutter.cut(video)
stable, unstable = res.get_range()
data_home = res.pick_and_save(stable, 5)

# --- classify ---
cl = SVMClassifier()
cl.load("2020011600164596")
cl.train()
classify_result = cl.classify(video, stable, keep_data=True)
result_dict = classify_result.to_dict()

import pprint
pprint.pprint(result_dict)
示例#10
0
from stagesepx.classifier import SVMClassifier
from stagesepx.cutter import VideoCutter
from stagesepx.reporter import Reporter

TARGET_VIDEO = '../../demo.mp4'

# cut
# 这里依旧使用了 cut,主要目的还是为了可以比较好的处理变化中的过程
# 但这次我们不需要用到 pick_and_save,因为这次 classifier 不会使用 cutter 的数据
cutter = VideoCutter()
res = cutter.cut(TARGET_VIDEO)
stable, _ = res.get_range()

# classify
# 这里的参数需要保持与train.py一致,如果你有改动的话
cl = SVMClassifier()
cl.load_model('./model.pkl')

classify_result = cl.classify(
    TARGET_VIDEO,
    stable,
)

r = Reporter()
r.draw(
    classify_result,
    report_path='report.html',
    cut_result=res,
)
示例#11
0
def run(config: typing.Union[dict, str]):
    """
    run with config

    :param config: config file path, or a preload dict
    :return:
    """
    class _VideoUserConfig(BaseModel):
        path: str
        pre_load: bool = True
        fps: int = None

    class _CutterUserConfig(BaseModel):
        threshold: float = None
        frame_count: int = None
        offset: int = None
        limit: int = None
        block: int = None

        # common
        compress_rate: float = None
        target_size: typing.Tuple[int, int] = None

    class _ClassifierType(Enum):
        SVM = "svm"
        KERAS = "keras"

    class _ClassifierUserConfig(BaseModel):
        boost_mode: bool = None
        classifier_type: _ClassifierType = _ClassifierType.SVM
        model: str = None

        # common
        compress_rate: float = None
        target_size: typing.Tuple[int, int] = None

    class _CalcOperatorType(Enum):
        BETWEEN = "between"
        DISPLAY = "display"

    class _CalcOperator(BaseModel):
        name: str
        calc_type: _CalcOperatorType
        args: dict = dict()

    class _CalcUserConfig(BaseModel):
        output: str = None
        ignore_error: bool = None
        operators: typing.List[_CalcOperator] = None

    class _ExtraUserConfig(BaseModel):
        save_train_set: str = None

    class UserConfig(BaseModel):
        output: str
        video: _VideoUserConfig
        cutter: _CutterUserConfig = _CutterUserConfig()
        classifier: _ClassifierUserConfig = _ClassifierUserConfig()
        calc: _CalcUserConfig = _CalcUserConfig()
        extras: _ExtraUserConfig = _ExtraUserConfig()

    if isinstance(config, str):
        # path
        config_path = pathlib.Path(config)
        assert config_path.is_file(), f"no config file found in {config_path}"

        # todo: support different types in the future
        assert config_path.as_posix().endswith(
            ".json"), "config file should be json format"
        with open(config_path, encoding=constants.CHARSET) as f:
            config = json.load(f)

    config = UserConfig(**config)
    logger.info(f"config: {config}")

    # main flow
    video = VideoObject(
        # fmt: off
        path=config.video.path,
        fps=config.video.fps,
    )
    if config.video.pre_load:
        video.load_frames()

    # cut
    cutter = VideoCutter(
        # fmt: off
        compress_rate=config.cutter.compress_rate,
        target_size=config.cutter.target_size,
    )
    res = cutter.cut(
        # fmt: off
        video=video,
        block=config.cutter.block,
    )
    stable, unstable = res.get_range(
        # fmt: off
        threshold=config.cutter.threshold,
        offset=config.cutter.offset,
    )

    with tempfile.TemporaryDirectory() as temp_dir:
        # classify
        if config.classifier.classifier_type is _ClassifierType.SVM:
            cl = SVMClassifier(
                # fmt: off
                compress_rate=config.classifier.compress_rate,
                target_size=config.classifier.target_size,
            )
        elif config.classifier.classifier_type is _ClassifierType.KERAS:
            from stagesepx.classifier.keras import KerasClassifier

            cl = KerasClassifier(
                # fmt: off
                compress_rate=config.classifier.compress_rate,
                target_size=config.classifier.target_size,
            )
        # validation has been applied by pydantic
        # so no `else`

        if config.classifier.model:
            # no need to retrain
            model_path = pathlib.Path(config.classifier.model)
            assert model_path.is_file(), f"file {model_path} not existed"
            cl.load_model(model_path)
        else:
            # train a new model
            train_set_dir = config.extras.save_train_set or temp_dir
            os.makedirs(train_set_dir, exist_ok=True)

            res.pick_and_save(
                # fmt: off
                stable,
                frame_count=config.cutter.frame_count,
                to_dir=train_set_dir,
            )
            cl.train(data_path=train_set_dir)

    # start classifying
    classify_result = cl.classify(
        # fmt: off
        video,
        stable,
        boost_mode=config.classifier.boost_mode,
    )

    # calc
    def _calc_display() -> dict:
        # jsonify
        return json.loads(classify_result.dumps())

    def _calc_between(*, from_stage: str = None, to_stage: str = None) -> dict:
        assert classify_result.contain(
            from_stage), f"no stage {from_stage} found in result"
        assert classify_result.contain(
            to_stage), f"no stage {to_stage} found in result"
        from_frame = classify_result.last(from_stage)
        to_frame = classify_result.first(to_stage)
        cost = to_frame.timestamp - from_frame.timestamp
        return {
            "from": from_frame.frame_id,
            "to": to_frame.frame_id,
            "cost": cost,
        }

    _calc_func_dict = {
        _CalcOperatorType.BETWEEN: _calc_between,
        _CalcOperatorType.DISPLAY: _calc_display,
    }
    calc_output = config.calc.output
    if calc_output:
        output_path = pathlib.Path(calc_output)
        assert not output_path.is_file(), f"file {output_path} already existed"
        result = []
        for each_calc in config.calc.operators:
            func = _calc_func_dict[each_calc.calc_type]
            try:
                func_ret = func(**each_calc.args)
            except Exception as e:
                if not config.calc.ignore_error:
                    raise
                logger.warning(e)
                func_ret = traceback.format_exc()
            calc_ret = {
                "name": each_calc.name,
                "type": each_calc.calc_type.value,
                "result": func_ret,
            }
            result.append(calc_ret)
        with open(output_path, "w", encoding=constants.CHARSET) as f:
            json.dump(result, f)

    # draw
    r = Reporter()
    r.draw(
        # fmt: off
        classify_result,
        report_path=config.output,
    )
示例#12
0
from stagesepx.cutter import VideoCutter
from stagesepx.classifier import SVMClassifier

import pprint

video_path = '../0866.mp4'
another_video_path = '../0867.mp4'

cutter = VideoCutter()
res = cutter.cut(video_path, compress_rate=0.1)
res1 = cutter.cut(another_video_path, compress_rate=0.1)

stable, _ = res.get_range(limit=3)
stable1, _ = res1.get_range(limit=3)

data_path = res.pick_and_save(stable, 3)
data_path1 = res1.pick_and_save(stable1, 3)

cl = SVMClassifier()
cl1 = SVMClassifier()
cl.load(data_path)
cl1.load(data_path1)

pprint.pprint(cl.diff(cl1))