├── .gitignore ├── README.md ├── auto ├── README.md └── start_without_report.py ├── dynamic ├── README.md ├── classify_with_model.py ├── get_data.py └── train_model.py ├── manual ├── README.md ├── report.png └── start.py ├── run_with_config ├── README.md ├── classify_with_model.json ├── cut_only.json └── cut_only_and_save_trainset.json └── videos ├── douyin1.mp4 ├── douyin2.mp4 ├── douyin3.mp4 ├── douyin4.mp4 ├── douyin5.mp4 ├── douyin6.mp4 ├── long.mp4 └── short.mp4 /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # work_with_stagesepx 2 | 3 | about how to use stagesepx in production 4 | 5 | 该项目旨在介绍如何将 [stagesepx](https://github.com/williamfzc/stagesepx) 落地到生产项目中发挥作用。所有的例子均开箱即用,可以在应用中逐渐增进理解,避免止步在前期准备阶段。 6 | 7 | ## 目录 8 | 9 | ### all in one 10 | 11 | 感谢 wsc106 同学编写的 [超级详细的文档](https://blog.csdn.net/wsc106/article/details/107351675),看完基本可以解答大部分的问题,并对这个项目的运作方式有所理解。 12 | 13 | ### 基础 14 | 15 | - [手动测试APP启动速度](./manual) 16 | - [自动测试APP启动速度](./auto) 17 | - ... 18 | 19 | ### 进阶 20 | 21 | - [动态场景的判定与区分](./dynamic) 22 | - [无需代码的配置化运行(0.15.0)](./run_with_config) 23 | - [一个真实的落地例子与详细教程](https://github.com/150109514/stagesepx_with_keras) 24 | - ... 25 | 26 | ## Q&A 27 | 28 | - 遇到问题请优先看一下 [主仓库的 issue](https://github.com/williamfzc/stagesepx/issues) 有没有相关的解答; 29 | - 错误与建议请 issue 告知,欢迎 PR :) 30 | -------------------------------------------------------------------------------- /auto/README.md: -------------------------------------------------------------------------------- 1 | # 注意 2 | 3 | 这里的方法仅作为如何训练、应用模型的指引,你可以通过这篇文章知悉使用流程。 4 | 5 | 但在真正落地时请使用 [keras方案](https://github.com/williamfzc/work_with_stagesepx/tree/master/dynamic) 来替代。SVM在很多场景下(例如不同分辨率视频)是无法满足需求的。 6 | 7 | --- 8 | 9 | # 自动测试APP启动速度 10 | 11 | ## 目的 12 | 13 | 基于手动版本,介绍如何自动化地完成整个过程。 14 | 15 | > 既然想做全自动化,这里默认读者已经拥有基本的计算机基础。 16 | 17 | ## 视频 18 | 19 | 这里用的是 `videos` 目录下的 `long.mp4` 与 `short.mp4` 。 20 | 21 | ## 先跑个脚本 22 | 23 | 运行 `python start_without_report.py`,你会看到控制台最终打出了一个字典: 24 | 25 | > -3 指没有匹配上任何一个类别 26 | 27 | ```text 28 | OrderedDict([('-3', 29 | [, 30 | , 31 | ... 32 | ('0', 33 | [, 34 | ... 35 | ``` 36 | 37 | 从这个字典中我们可以知道,每一帧被分类到**哪一个类别**,对应的时间戳,与帧编号等等。那么理论上,我们可以由下一段脚本来处理这些结果,达到自动计算的目的。 38 | 39 | ## 比想象中复杂 40 | 41 | 看到这里可能会有人觉得,流程基本已经完成了,毕竟只要有了上面的字典,去做一些固定的时间戳计算就可以得到我想要的结果。 42 | 43 | 确实说得没错,如果对于一些ui与流程都比较固定的业务来说,你直接计算就可以了。 44 | 45 | 但实际情况是非常复杂的,以APP为例,很可能会存在偶现的弹框与通知等等一系列不可控的事件。而这些事件会导致最终分类的结果对不上(例如弹框意味着你的视频至少多了一个阶段,此时你的阶段号会改变),从而引起时间计算的偏差。 46 | 47 | 最关键的问题是,你需要让机器知道并判断哪一个阶段才是你真正需要的。 48 | 49 | ## 基本原理 50 | 51 | ![](https://github.com/williamfzc/stagesepx/raw/master/docs/pics/stagesepx.svg?sanitize=true) 52 | 53 | 这是 stagesepx 的架构图。可以看到,实际上结果的生成是由 classifier 借助 cutter 的结果完成的。 54 | 55 | 而我们刚才的结果里除了html文件,还有一个图片文件夹。这个文件夹对应的就是图中的 image directory。也就是说,classifier的训练与分类是完全基于这里面的数据的。 56 | 57 | 既然如此,如果我们修改这里的数据,classifier 的分类结果就会随之改变。 58 | 59 | ## 怎么改 60 | 61 | 回到那个图片文件夹。不出意外的话,它大概长这样: 62 | 63 | ```text 64 | - 202002021234561234 65 | - 0 66 | - abcdef.png 67 | - cdefgh.png 68 | - ... 69 | - 1 70 | - 2 71 | - ... 72 | ``` 73 | 74 | 我们希望每次跑的时候分析出来的阶段都按照这里的数据来。那么非常简单: 75 | 76 | ```python 77 | # --- classify --- 78 | cl = SVMClassifier() 79 | 80 | # 将这里的目录指向你希望的文件夹 81 | cl.load("202002021234561234") 82 | 83 | cl.train() 84 | classify_result = cl.classify(video, stable, keep_data=True) 85 | result_dict = classify_result.to_dict() 86 | ``` 87 | 88 | 此时,所有分出来的阶段就是按照你希望的样子来的了。 89 | 90 | ## 怎么验证 91 | 92 | 你可以将代码中的 `long.mp4` 改成 `short.mp4` 试一下。理论上,你看到的分类结果是 0 与 4。 93 | -------------------------------------------------------------------------------- /auto/start_without_report.py: -------------------------------------------------------------------------------- 1 | from stagesepx.cutter import VideoCutter 2 | from stagesepx.classifier import SVMClassifier 3 | from stagesepx.video import VideoObject 4 | 5 | video_path = "../videos/short.mp4" 6 | video = VideoObject(video_path) 7 | video.load_frames() 8 | 9 | # --- cutter --- 10 | cutter = VideoCutter() 11 | res = cutter.cut(video) 12 | stable, unstable = res.get_range() 13 | data_home = res.pick_and_save(stable, 5) 14 | 15 | # --- classify --- 16 | cl = SVMClassifier() 17 | cl.load("2020011600164596") 18 | cl.train() 19 | classify_result = cl.classify(video, stable, keep_data=True) 20 | result_dict = classify_result.to_dict() 21 | 22 | import pprint 23 | pprint.pprint(result_dict) 24 | -------------------------------------------------------------------------------- /dynamic/README.md: -------------------------------------------------------------------------------- 1 | # 针对复杂动态场景的自动判定 2 | 3 | > 目前许多超级app都会具备UI动态化的设计,以达到更高的灵活度。在 0.10.0 之后,stagesepx 借助了 keras 来处理该类型问题。 4 | 5 | ## 背景 6 | 7 | 这个例子主要针对一些动态生成的特殊场景,例如: 8 | 9 | - 内容型APP每次打开首页内容都不一致 10 | - 插屏广告播放的内容是随机的 11 | - 游戏某个阶段场景是动态的(有循环播放的动画等,很多游戏的初始界面都会有) 12 | 13 | 而单纯靠 SVM classifier 难以很好地处理上述情况(详见 [issue#89](https://github.com/williamfzc/stagesep/issues/89))。为此,我们引入了神经网络用于处理这些特殊情况。 14 | 15 | ## 原理 16 | 17 | > 假设读者已阅读 [自动测试APP启动速度](../auto) 部分。 18 | 19 | 利用 神经网络 进行图像分类已经是种非常成熟的技术(可以参考 [面向小数据集构建图像分类模型](https://keras-cn.readthedocs.io/en/latest/legacy/blog/image_classification_using_very_little_data/)),效果也很好。此处不再赘述。 20 | 21 | 为什么一开始 stagesepx 没有采用这种技术: 22 | 23 | - 一方面是神经网络要达到比较好的效果需要更高的成本(更长的时间与更大的训练集),而我们希望的是低依赖且方便快速,不需要过多前置准备; 24 | - 另一方面,就初期需求而言,SVM的表现已经足够好,完全能够胜任单视频情况下的分类工作; 25 | - 至于为什么现在需要神经网络,在背景中有提到; 26 | 27 | 虽然在构造与原理上 SVM 与神经网络差异很大,但我们在 API 层面上尽可能地保证了该类 classifier 的调用模式相似。 28 | 29 | 与所有 classifier 相同,它本身与 cutter 并不会有任何耦合,我们可以通过自定义训练集来干预分类的结果。 30 | 31 | 在调用层面上,流程是一样的: 32 | 33 | - 加载数据 34 | - 训练模型 35 | - 应用模型 36 | 37 | 值得注意的是,它与SVM的表现上有一些差异: 38 | 39 | - 默认情况下我们使用 SVM + HOG 的组合进行分类,它表现为(与算法、api的设计都有关)较高的训练效率与较低的预测效率; 40 | - 神经网络的表现是,训练效率较低(耗时更长,算力需求更高)但预测效率较高(模型训练完成后预测速度快); 41 | 42 | ## 使用 43 | 44 | 下面将以抖音的启动为例。 45 | 46 | ### 前置资源 47 | 48 | #### 安装 49 | 50 | 使用 KerasClassifier 需要 tensorflow 的支持。 51 | 52 | ```bash 53 | pip install tensorflow 54 | ``` 55 | 56 | 其他方式请自行官网查看。 57 | 58 | #### 脚本 59 | 60 | 可以看到当前目录下有三个脚本: 61 | 62 | - `get_data.py`:从视频中得到训练集 63 | - `train_model.py`:将训练集转变为模型 64 | - `classify_with_model.py`:用训练好的模型预测新视频 65 | 66 | #### 视频 67 | 68 | videos 目录下有 6 个视频,均以 douyin 开头。 69 | 70 | ### 分析 71 | 72 | 对于抖音来说,启动过程会分为5个阶段(可根据需要自行设计划分): 73 | 74 | - 初始阶段(app没打开) 75 | - 首屏(抖音字样) 76 | - 插屏广告(可能有) 77 | - 应用内首屏(视频未加载,但主体控件已加载完成) 78 | - 应用完成(视频与控件均以加载完成) 79 | 80 | 那么,我们将根据划分好的阶段对数据集进行处理,并利用处理后的数据集训练模型。 81 | 82 | ### 流程 83 | 84 | > 先确保阅读过 [自动测试APP启动速度](../auto) ,相同处不赘述。keras 训练过程相对较长,在保存形态与流程上会有些许的不同。 85 | 86 | 对于一个app来说我们需要录制一组视频作为训练集。仓库里有6个,下面将以前三个视频为例介绍。 87 | 88 | 这次我特意将整个过程拆分成三个脚本,对应了不同的过程,更方便阅读与使用。利用 `get_data.py` 脚本可以将视频处理成训练集,那么,三个视频将可以得到三个文件夹的数据集。**理论上,当数据集越多时,对于动态情况的抵御能力将更强。** 89 | 90 | 之后进行人工分拣,将训练集整合成一个文件夹。在确保每个阶段都符合你的预期之后,执行 `train_model.py` 将数据集训练为模型(权重)并保存。在训练完成后你将可以看到 `keras_model.h5` 文件,即为你的模型权重。 91 | 92 | 有了模型之后,你将可以利用 `classify_with_model.py` 对新视频进行分析,而新视频的分类将根据你希望的分类进行。 93 | 94 | > 1、2、3视频中无插屏广告,可用4、5、6代替。 95 | 96 | ### 一些注意的点 97 | 98 | 你可以发现,似乎整个流程跟以前的版本没有差别。实际上是的,两种 classifier 在 api 与表现上并不会有太大差别。 99 | 100 | 动态情景下最大的问题是,每个阶段的表现可能是不相同的。以插屏广告为例,每次打开时插屏广告都不一样,此时我们需要扩大训练集,尽量让模型找到广告之间的共性,能够正确地将他们划分到同一类别。 101 | 102 | ## 相关 103 | 104 | https://testerhome.com/topics/22215 105 | -------------------------------------------------------------------------------- /dynamic/classify_with_model.py: -------------------------------------------------------------------------------- 1 | from stagesepx.cutter import VideoCutter 2 | from stagesepx.classifier.keras import KerasClassifier 3 | from stagesepx.reporter import Reporter 4 | from stagesepx.video import VideoObject 5 | 6 | 7 | video_path = "../videos/douyin1.mp4" 8 | video = VideoObject(video_path) 9 | video.load_frames() 10 | 11 | # --- cutter --- 12 | cutter = VideoCutter() 13 | res = cutter.cut(video) 14 | stable, unstable = res.get_range() 15 | 16 | # --- classifier --- 17 | cl = KerasClassifier( 18 | # 在使用时需要保证数据集格式统一(与训练集) 19 | # 因为 train_model.py 用了 600x800,所以这里设定成一样的 20 | target_size=(600, 800), 21 | ) 22 | model_file = "./keras_model.h5" 23 | cl.load_model(model_file) 24 | 25 | classify_result = cl.classify(video, stable, keep_data=True) 26 | result_dict = classify_result.to_dict() 27 | 28 | # --- draw --- 29 | r = Reporter() 30 | r.draw(classify_result) 31 | -------------------------------------------------------------------------------- /dynamic/get_data.py: -------------------------------------------------------------------------------- 1 | from stagesepx.cutter import VideoCutter 2 | from stagesepx.video import VideoObject 3 | 4 | 5 | video_path = "../videos/douyin1.mp4" 6 | video = VideoObject(video_path) 7 | video.load_frames() 8 | 9 | cutter = VideoCutter() 10 | res = cutter.cut(video) 11 | stable, unstable = res.get_range(offset=3) 12 | 13 | # save dataset 14 | data_home = "./dataset" 15 | res.pick_and_save(stable, 10, to_dir=data_home, meaningful_name=True) 16 | print(f"data saved to {data_home}") 17 | -------------------------------------------------------------------------------- /dynamic/train_model.py: -------------------------------------------------------------------------------- 1 | from stagesepx.classifier.keras import KerasClassifier 2 | 3 | 4 | data_home = "./dataset" 5 | model_file = "./keras_model.h5" 6 | 7 | cl = KerasClassifier( 8 | # 轮数 9 | epochs=10, 10 | # 保证数据集的分辨率统一性 11 | target_size=(600, 800), 12 | ) 13 | cl.train(data_home) 14 | cl.save_model(model_file, overwrite=True) 15 | -------------------------------------------------------------------------------- /manual/README.md: -------------------------------------------------------------------------------- 1 | # 手动测试APP启动速度 2 | 3 | ## 目的 4 | 5 | 本章节将以一个app的启动过程为例,介绍如何直接计算出视频中每个阶段的耗时。 6 | 7 | ## 视频 8 | 9 | 这里用的是 `videos` 目录下的 `long.mp4` 。 10 | 11 | ## 运行 12 | 13 | 直接运行 `python start.py` 即可,路径都是配置好的。在运行之后你会看到日志不断刷过,当它运行完毕之后,你可以看到目录下出现了一些东西: 14 | 15 | - 图片文件夹 16 | - html报告 17 | 18 | 图片文件夹对应的是每个阶段的截图,在手动使用时对我们没什么用,可以先忽略。 19 | 20 | 主要是 html 报告的部分,不出意外的话长这样: 21 | 22 | ![](report.png) 23 | 24 | 报告太长了,挑其中一段出来描述一下是什么意思。假设我的需求是计算加载页(星巴克图标)持续的时间: 25 | 26 | - 第一行是应用被打开的过程,可以看到在 `1.467755s` 时变化结束了,进入到第二行的状态 27 | - 第二行对应的就是我们想要的部分,可以看到它在这个过程停留了 `2.42938s` 28 | - 第三行是已经是图标逐步消失的过程了 29 | 30 | 那么,如果你希望: 31 | 32 | - 计算图标稳定存在的时间,那么就是 `2.42938s` 33 | - 计算图标从出现到最终真正消失,那么就是 `4.11646 - 1.467755 = 2.648705s` 34 | 35 | 以此类推,你可以得到任意你希望得到的耗时。 36 | -------------------------------------------------------------------------------- /manual/report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/manual/report.png -------------------------------------------------------------------------------- /manual/start.py: -------------------------------------------------------------------------------- 1 | from stagesepx.cutter import VideoCutter 2 | from stagesepx.classifier import SVMClassifier 3 | from stagesepx.reporter import Reporter 4 | from stagesepx.video import VideoObject 5 | 6 | 7 | video_path = "../videos/long.mp4" 8 | video = VideoObject(video_path) 9 | video.load_frames() 10 | 11 | # --- cutter --- 12 | cutter = VideoCutter() 13 | res = cutter.cut(video) 14 | stable, unstable = res.get_range() 15 | data_home = res.pick_and_save(stable, 5) 16 | 17 | # --- classify --- 18 | cl = SVMClassifier(compress_rate=0.4) 19 | cl.load(data_home) 20 | cl.train() 21 | classify_result = cl.classify(video, stable, keep_data=True) 22 | result_dict = classify_result.to_dict() 23 | 24 | # --- draw --- 25 | r = Reporter() 26 | r.draw(classify_result) 27 | -------------------------------------------------------------------------------- /run_with_config/README.md: -------------------------------------------------------------------------------- 1 | # 配置化运行 2 | 3 | 在 0.15.0 之后,`配置化运行` 的加入使得开发者能够在无需编写脚本的情况下使用 stagesepx ,只需要填写简单的配置文件。 4 | 5 | ## 手动模式 6 | 7 | 以原来的手动模式为例,你只需要一个简单的 json 文件: 8 | 9 | ```json 10 | { 11 | "output": ".", 12 | "video": { 13 | "path": "../videos/short.mp4", 14 | "fps": 30 15 | } 16 | } 17 | ``` 18 | 19 | 之后执行: 20 | 21 | ```bash 22 | stagesepx run cut_only.json 23 | ``` 24 | 25 | 即可得到一样的效果。如果要保留图片文件夹,也只需要加入一行配置即可。具体参考 [cut_only_and_save_trainset.json](./cut_only_and_save_trainset.json) 。 26 | 27 | ## 自动模式 28 | 29 | 配置化模式将大部分参数都通过配置的形式暴露出来,同样的,自动化使用也是可行的。具体原理此处不展开,参见 [其他章节](../dynamic)。 30 | 31 | 首先先训练一个模型: 32 | 33 | ```bash 34 | stagesepx train trainset model.h5 35 | ``` 36 | 37 | 运行之后我们可以得到一个 `model.h5` 文件。我们可以利用该模型进行分类: 38 | 39 | ```bash 40 | stagesepx run classify_with_model.json 41 | ``` 42 | 43 | 除了报告之外,仅仅通过配置即可进行额外的计算: 44 | 45 | ```json 46 | [ 47 | { 48 | "name": "cost between 1 and 3", 49 | "type": "between", 50 | "result": { 51 | "from": 14, 52 | "to": 33, 53 | "cost": 0.6333333333333333 54 | } 55 | } 56 | ] 57 | ``` 58 | 59 | 我们在命令行里完成了整个流程,而你没有编写一行代码。当然还有更多配置供选择: 60 | 61 | ```json 62 | { 63 | "output": ".", 64 | "video": { 65 | "path": "demo.mp4", 66 | "pre_load": true, 67 | "fps": 30 68 | }, 69 | "cutter": { 70 | "threshold": 0.95, 71 | "frame_count": 3, 72 | "offset": 3, 73 | "limit": null, 74 | "block": 3, 75 | "compress_rate": 0.2, 76 | "target_size": [ 77 | 600, 78 | 800 79 | ] 80 | }, 81 | "classifier": { 82 | "classifier_type": "svm", 83 | "model": null, 84 | "boost_mode": true, 85 | "compress_rate": 0.2, 86 | "target_size": [ 87 | 600, 88 | 800 89 | ] 90 | }, 91 | "extras": { 92 | "save_train_set": "./trainset" 93 | } 94 | } 95 | ``` 96 | 97 | 对于最新的配置,请参见:[完整配置项](https://github.com/williamfzc/stagesepx/blob/master/test/run_config.json) 98 | -------------------------------------------------------------------------------- /run_with_config/classify_with_model.json: -------------------------------------------------------------------------------- 1 | { 2 | "output": ".", 3 | "video": { 4 | "path": "../videos/short.mp4", 5 | "fps": 30 6 | }, 7 | "classifier": { 8 | "classifier_type": "keras", 9 | "model": "./model.h5", 10 | "target_size": [ 11 | 600, 12 | 800 13 | ] 14 | }, 15 | "calc": { 16 | "output": "./output.json", 17 | "operators": [ 18 | { 19 | "name": "cost between 1 and 3", 20 | "calc_type": "between", 21 | "args": { 22 | "from_stage": "1", 23 | "to_stage": "3" 24 | } 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /run_with_config/cut_only.json: -------------------------------------------------------------------------------- 1 | { 2 | "output": ".", 3 | "video": { 4 | "path": "../videos/short.mp4", 5 | "fps": 30 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /run_with_config/cut_only_and_save_trainset.json: -------------------------------------------------------------------------------- 1 | { 2 | "output": ".", 3 | "video": { 4 | "path": "../videos/short.mp4", 5 | "fps": 30 6 | }, 7 | "extras": { 8 | "save_train_set": "./trainset" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /videos/douyin1.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/videos/douyin1.mp4 -------------------------------------------------------------------------------- /videos/douyin2.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/videos/douyin2.mp4 -------------------------------------------------------------------------------- /videos/douyin3.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/videos/douyin3.mp4 -------------------------------------------------------------------------------- /videos/douyin4.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/videos/douyin4.mp4 -------------------------------------------------------------------------------- /videos/douyin5.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/videos/douyin5.mp4 -------------------------------------------------------------------------------- /videos/douyin6.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/videos/douyin6.mp4 -------------------------------------------------------------------------------- /videos/long.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/videos/long.mp4 -------------------------------------------------------------------------------- /videos/short.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamfzc/work_with_stagesepx/8db17a8227c128e6d52664438639391397d8de8e/videos/short.mp4 --------------------------------------------------------------------------------