ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenReel Video 滤镜配方流水线:从 YAML Recipe 到 3D LUT 的完整生成与发布方案

OpenReel Video 滤镜配方流水线:从 YAML Recipe 到 3D LUT 的完整生成与发布方案 OpenReel Video 滤镜配方流水线从 YAML Recipe 到 3D LUT 的完整生成与发布方案【免费下载链接】openreel-videoOpenReel Video - Professional browser-based video editor. Open source CapCut alternative. 100% browser-based, no installation, no cloud uploads, no watermarks.项目地址: https://gitcode.com/GitHub_Trending/op/openreel-videoOpenReel Video开源浏览器端视频编辑器通过scripts/filters/目录实现了一套滤镜配方filter recipes→ LUT 生成器的构建工具链开发者在 YAML 文件中用声明式步骤描述一款滤镜如 Teal Orange一条命令即可批量生成标准.cube3D LUT 文件与带校验的manifest.json清单再通过 Cloudflare R2 发布供前端 filter-presets 子系统按需拉取。读完本文你将掌握该子系统的完整工作流环境搭建、recipe 语法与全部可用的变换步骤、生成管线的底层原理、清单结构、测试与部署方法并能够自行新增一款滤镜配方。一、子系统定位为 filter-presets 提供 LUT 资产在 OpenReel Video 的滤镜体系中预设滤镜filter presets最终以 3D LUT 的形式应用到画面。scripts/filters/README.md开宗明义地定义了本目录的职责Build LUTs from YAML recipes for the filter-presets subsystem——即把人类可读、易于维护的 YAML 配方编译成 GPU/渲染器可直接使用的.cubeLUT 文件。整个目录是一个独立的 Python 工程核心文件包括generate.py批量生成入口遍历 recipes 目录产出.cube与manifest.jsonrecipe.pyrecipe 的加载与步骤 → 变换函数解析STEP_REGISTRYtransforms.py13 个底层像素变换算子色温、对比度、分离色调等lut.pyLUT 的生成与.cube文件写出manifest.py 与 manifest_schema.json清单构建与 JSON Schema 校验recipes/配方目录当前包含 cinematic/teal_orange.yaml 示例tests/覆盖加载、变换、LUT 与清单生成的测试套件deploy.sh经 wrangler 将产物上传至 R2。README 中引用的设计文档docs/superpowers/specs/2026-05-22-filter-presets-design.md在本文写作时的仓库快照中尚未包含该文件读者可在后续版本中关注其补充。二、环境搭建最小的 Python 依赖README 提供了标准的虚拟环境初始化方式python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt依赖清单见 requirements.txt全部为纯 Python 数值/校验类库无系统级编译依赖包版本用途numpy1.26.4LUT 网格与逐像素变换的向量化计算pyyaml6.0.2解析 YAML recipe 文件jsonschema4.23.0校验生成的 manifest.jsonPillow10.4.0图像相关辅助测试/工具链pytest8.3.3测试运行器从 lut.py 可知 LUT 采用 33³ 的三维网格LUT_SIZE 33生成时对每个网格点执行变换因此 numpy 的向量化是性能关键identity_lut()用np.meshgrid构建 R/G/B 三个轴在[0,1]上的 33 等分点展开后共 35937 个采样点。三、Recipe 语法用 YAML 声明一款滤镜3.1 顶层字段recipe.py 定义了Recipe数据类load_recipe()从 YAML 读取以下字段字段类型说明idstring唯一标识同时作为.cube文件名如cinematic.teal_orangenamestring人类可读的滤镜名写入.cube的TITLE与 manifestcategorystring分类 id需与 generate 内置的分类集合对齐accentstring主题色#RRGGBB供前端 UI 展示sortint排序权重缺省为 0stepslist有序的变换步骤列表是滤镜效果的核心3.2 完整示例Teal Orange仓库自带的唯一配方 recipes/cinematic/teal_orange.yaml 完整展示了语法id: cinematic.teal_orange name: Teal Orange category: cinematic accent: #38BDF8 sort: 10 steps: - temperature: -8 - tint: 3 - contrast: curve: s_curve amount: 1.15 - split_tone: shadows: #1E3A5F highlights: #FFA94D balance: 0.0 - saturation: 1.10 - hue_shift: reds: -5它演示了两种步骤形态标量形式temperature: -8与映射形式contrast: {curve, amount}。步骤按数组顺序依次作用于像素顺序即效果叠加顺序因此调整步骤次序会直接改变最终观感。3.3 可用步骤全集STEP_REGISTRYrecipe.py 中的STEP_REGISTRY是 recipe 语法与变换函数之间的桥梁每个步骤名对应transforms模块中的一个apply_*函数以及一个参数映射器。完整清单如下步骤名变换函数参数与默认值temperatureapply_temperatureamount: floattintapply_tintamount: floatexposureapply_exposurestops: floatcontrastapply_contrastcurve: linear\|gamma\|s_curveamount: floatsaturationapply_saturationamount: floatvibranceapply_vibranceamount: floathue_shiftapply_hue_shiftreds/greens/blues/global: float均可选默认 0split_toneapply_split_toneshadows、highlights#RRGGBB或[r,g,b]balance默认 0.0lift_gamma_gainapply_lift_gamma_gainlift默认 0.0gamma默认 1.0gain默认 1.0channel_mixerapply_channel_mixermatrix: 3×3数值数组tone_curveapply_tone_curvepoints: [[x,y], ...]控制点列表clipapply_clip_levelsblack默认 0.0white默认 1.0monochromeapply_monochromeweights默认(0.2126, 0.7152, 0.0722)Rec.709 亮度权重颜色值_parse_color()同时接受#RRGGBB十六进制字符串与[r, g, b]浮点列表两种写法。recipe_to_transform_steps()对每个步骤要求严格必须是单键字典键必须存在于注册表否则抛出ValueError未知步骤或形状错误该行为由测试test_load_recipe_rejects_unknown_step覆盖。四、变换引擎源码解析13 个像素算子的实现原理transforms.py 是滤镜效果的数值核心。所有函数输入输出均为(N, 1, 3)的 float32 数组generate 阶段输入是展开的 LUT 网格最终统一经_clip01裁剪到[0,1]防止越界。关键算子实现色温apply_temperatureamount/100 × [1, 0.1, -1] × 0.5的 RGB 偏移——正值使 R 升、B 降画面偏暖橙负值偏冷蓝。测试验证了 10 使中灰变暖、-10 变冷。色调apply_tintamount/100 × [-0.25, 0.5, -0.25]正值推绿、负值推品红。曝光apply_exposure× 2^stops的幂乘——1 档恰好使亮度翻倍测试用stops1.0断言结果接近 1.0。对比度apply_contrast三种曲线分支——linear围绕 0.5 线性拉伸gamma用image^(1/amount)做幂次曲线s_curve用双曲正切构建 S 曲线k (amount-1)×31控制斜率亮部更亮、暗部更暗。饱和度apply_saturation基于 Rec.709 亮度[0.2126, 0.7152, 0.0722]做luma (image - luma) × amount的线性插值amount0时输出纯灰有测试断言。自然饱和度apply_vibrance用max-min作为饱和度估计weight 1 - saturation让低饱和区域获得更大增益实现保护高饱和色的效果。色相偏移apply_hue_shift逐像素转到 HSV 空间按色相区段红 345°~15°、绿 90°~150°、蓝 210°~270°分别叠加reds/greens/blues偏移另有global全盘偏移。测试验证红色在reds-15下向橙色方向G 通道增大移动。分离色调apply_split_tone以pivot 0.5 balance×0.5为分界阴影权重随亮度线性递减、高光权重递增各自向目标色偏移 0.4 强度。测试用 0.2 亮度的暗部验证 B 通道被推向阴影色。黑电平/伽马/增益apply_lift_gamma_gainlift按x lift×(1-x)抬升暗部gamma做指数gain整体乘系数。通道混合器apply_channel_mixer3×3 矩阵左乘 RGB 向量恒等矩阵不变换测试验证np.eye(3)输出与输入一致。色调曲线apply_tone_curve控制点按 x 排序后np.interp逐通道插值[(0,0),(1,1)]恒等曲线保持像素不变。黑白色阶apply_clip_levels(x - black)/(white - black)的线性重映射把[black, white]拉伸到[0,1]。单色apply_monochrome权重归一化后做加权亮度输出三通道相同的灰度。这些算子的单元测试集中在 tests/test_transforms.py每个函数都有对应的行为断言是理解各参数语义的最佳参照。五、生成管线一条命令产出全部资产5.1 命令与输出python generate.py按 generate.py 的执行流程递归发现recipes/下所有*.yaml→ 逐个加载并转步骤 → 在恒等 LUT 上依次施加变换 → 写出.cube并构建 manifest 条目 → 汇总写入out/manifest.json。最终产物out/ ├── cube/*.cube # 每个 recipe 一个 33³ 3D LUT └── manifest.json # 滤镜清单 分类信息5.2 CLI 参数generate.py使用argparse提供四个可选参数参数默认值说明--recipesscripts/filters/recipes配方目录支持自定义 YAML 目录--outscripts/filters/out输出目录cube 子目录与 manifest 写入处--base-urlhttps://filters.openreel.videoCDN 基础地址传了非默认值时重写每个条目的cubeUrl--versionUTC 时间戳%Y-%m-%dT%H%M%Smanifest 版本号便于前端缓存失效分类体系由CATEGORY_ORDER [cinematic, portrait, vlog, retro, mood, bw]定义CATEGORY_NAMES提供展示名manifest 中的categories数组按此顺序生成并带sort权重。5.3.cube文件格式lut.py 的write_cube()输出标准 Adobe.cube3D LUT 文本格式每个文件约 3.6 万行数据TITLE Teal Orange DOMAIN_MIN 0.0 0.0 0.0 DOMAIN_MAX 1.0 1.0 1.0 LUT_3D_SIZE 33 r g b # 共 33³ 行B 最外层、R 最内层循环值保留 6 位小数TITLE直接取自 recipe 的name说明 LUT 文件的元数据与配方一一对应。若 LUT 形状不是(33,33,33,3)会直接抛错保证产物规格严格一致。六、清单与校验manifest.json 的双重保障6.1 条目字段与哈希manifest.py 的build_manifest_entry()为每个滤镜生成字段说明id/name/category/accent/sort从 recipe 透传cubeUrl{base_url}/cube/{id}.cube的 CDN 地址sha256.cube文件内容的 SHA-256 十六进制摘要bytes.cube文件字节数sha256与bytes的意义在于完整性校验前端下载 LUT 后可验证文件未被篡改或截断测试test_build_manifest_entry_includes_sha_and_bytes专门断言了这两个字段。6.2 JSON Schema 校验write_manifest()在写盘前用 manifest_schema.json 做jsonschema.validate校验即先验证、后落盘。Schema 关键约束顶层必填version、filters、categories可选minClientVersion客户端最低版本门控每个 filter 必填 8 个字段accent需匹配^#[0-9A-Fa-f]{6}$cubeUrl必须是http(s)URIsha256匹配 64 位十六进制bytes≥ 1另有可选oldIds数组用于滤镜 id 迁移兼容每个 category 必填id、name、sort。输出时json.dumps(indent2, sort_keysTrue)保证清单可读且键序稳定便于 diff 与缓存。七、测试四组用例覆盖全链路README 中的测试命令为pytest tests/ -v测试套件按职责拆分四个文件含 fixtures 中的sample.cube与sample.yaml样例test_recipe_loader.py验证 recipe 加载字段映射、步骤到变换函数的解析、对未知步骤的拒绝、manifest 条目哈希与 Schema 校验行为test_transforms.py逐算子验证数值行为如色温方向、曝光翻倍、S 曲线两端外推、分离色调对暗部染色、恒等通道矩阵等test_lut.py与test_generate.py分别覆盖 LUT 网格/写出与整体生成流程。整条链路的可验证性很强recipe 解析有严格报错LUT 形状有强校验manifest 有 Schema 约束变换有数值断言——任何一环出错都会在 CI 或本地测试中暴露。八、部署经 wrangler 上传至 Cloudflare R28.1 命令与环境变量./deploy.sh # uploads out/ to R2 via wranglerdeploy.sh 的可配置项环境变量默认值说明OPENREEL_FILTERS_BUCKETopenreel-filtersR2 存储桶名OUT_DIRout上传产物目录脚本首先检查out/manifest.json是否存在不存在则提示先运行generate.py。8.2 上传与缓存策略LUT 文件逐个wrangler r2 object put到cube/{name}.cubecontent-type为text/plaincache-control: public, max-age31536000, immutable——LUT 内容由版本号与 sha256 管理一旦生成便不可变因此一年期强缓存manifest.json上传到桶根content-type: application/jsoncache-control: public, max-age300, s-maxage3600——清单经常随新增滤镜更新浏览器缓存 5 分钟、CDN 缓存 1 小时保证前端能较快获取新滤镜而不至于频繁回源。部署完成后前端通过https://filters.openreel.video/manifest.json拉取清单再按cubeUrl下载对应的 33³ LUT 应用到画面。九、端到端工作流如何新增一款滤镜综合以上各节在 OpenReel Video 中新增一款滤镜的完整流程是编写配方在 recipes/ 下新建 YAML建议按分类建子目录定义id/name/category/accent/sort/steps步骤组合参考 teal_orange.yaml本地生成python generate.py确认out/cube/{id}.cube与out/manifest.json正常产出且通过 Schema 校验验证效果运行pytest tests/ -v回归必要时为新增变换补充 test_transforms.py 风格的数值断言发布上线./deploy.sh可覆盖OPENREEL_FILTERS_BUCKET/OUT_DIRR2 中的.cube走不可变强缓存、manifest.json走短缓存前端在缓存过期后即可发现新滤镜。整个子系统体现了声明式配方 确定性编译 可校验产物的设计思路滤镜创作者只需关心 YAML 步骤与参数无需接触 LUT 二进制格式或 CDN 上传细节而渲染侧则获得规格统一、带哈希校验、可离线缓存的标准 3D LUT 资产。【免费下载链接】openreel-videoOpenReel Video - Professional browser-based video editor. Open source CapCut alternative. 100% browser-based, no installation, no cloud uploads, no watermarks.项目地址: https://gitcode.com/GitHub_Trending/op/openreel-video创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表