去水印 / 去字幕
检测确认流程已实现。本文新增的保护区、精确写回和无转码空清单行为随协议 v2 部署生效;调用前以
GET /task/video_purify/capabilities返回的review_protocol: 2为准。未传phase的旧调用保持兼容。
检测文字候选,并通过文字框或手动区域处理水印、Logo、硬字幕等叠加元素,支持全屏净化、仅字幕区域净化、自定义区域净化、指定区域直接去除(可限定时间段),以及 ffmpeg / raft 两种去水印算法。
示例效果
subtitle 模式
处理前
处理后
full_screen 模式
处理前
处理后
两种使用方式
怎么选择
这个接口支持两种用法,请根据用户的实际需求选择:
客户端由调用方自行准备
本文所说的“客户端”不是同合云提供的现成界面,而是调用方自行准备、开发和维护的 GUI。它可以是 Web 端、桌面客户端或移动 App,具体形态由调用方决定。
调用方需要自行实现视频预览、检测结果展示、区域的新增/删除/修改、位置和大小调整、时间范围调整以及最终确认提交等可视化操作。同合云接口只负责返回检测结果和执行去水印,不负责提供这套用户界面。
方式一:一次性完成
如果用户已经知道要处理什么内容、处理哪一块区域,可以直接发起一次请求。接口按照 full_screen、subtitle、custom 或 region 的设置完成去水印任务并生成处理结果。这条路径不需要传 phase 这个参数,兼容原有调用方式。
方式二:先检测、再确认、再处理(检测确认模式)
如果用户想先看看系统找到了哪些水印,或者需要在检测结果上手动增删改查,就使用这条路径。它适合“系统负责找,用户负责决定”的场景。
第一步,调用方开发的客户端让系统扫描全屏、字幕区域,或者用户指定的一块区域。系统当前使用文字检测,返回候选文字位置;图形 Logo 和半透明图案需要调用方手动补框,不会生成处理后的视频。一个视频可能找到几千个候选区域,客户端需要拿到完整的检测结果。
第二步,客户端在 GUI 中让用户检查和编辑这些候选区域:
- 删除误检:从最终清单中移除候选;若它与其他保留框重叠,需添加保护框才能保证不被覆盖。
- 调整位置和大小:修改区域的坐标和宽高。
- 调整时间:修改这个区域需要处理的开始和结束时间。
- 新增处理区域:手动画一个区域,表示这个区域在指定时间内的全部内容都要去掉。
用户编辑完成后,客户端得到一份最终清单。用户不想处理的候选不放进清单,想处理的候选和新增区域都放进清单。
第三步,客户端把最终清单提交给同一个接口。服务端只处理清单里的区域,不会重新检测,也不会把用户删掉的区域自动加回来。实际处理范围为去除框的并集减去保护框的并集,保护框优先。
如果用户删除了全部候选,最终清单可以是空数组。协议 v2 会直接复制原文件,不转码、不启动修复引擎;HTTP 建单仍沿用既有计费。CLI 会本地直接返回源文件,不提交空处理任务。
下面的内容是给客户端和后端实现时查阅的字段约定。
接口字段和实现约定
- 使用 phase=detect 请求检测结果,只返回候选区域,不生成去水印视频。
- 客户端下载检测结果,在 GUI 中对候选区域进行增删改查。
- 使用 phase=purify 提交客户端最终保留的 regions,执行真实去水印。
处理请求中的 regions 是唯一权威集合:删除候选就是从数组中移除,修改候选就是修改对应字段,新增整块去水印区域就是追加一个 source=manual 的区域。服务端不会在处理请求中重新检测,也不会自动恢复被删除的候选。
检测结果可能达到数千个区域,完整检测结果通过 JSON 文件产物提供,执行请求支持提交大规模 regions;如果单个任务超过视频时长、分辨率或请求体等服务端资源限制,服务端会拒绝该任务。
检测请求和执行请求分别创建任务,分别按现有视频时长规则计费。调用方可以根据自己的产品流程决定是否先检测。
新增请求参数
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
phase | string | 使用检测确认模式时是 | — | detect:只检测;purify:按最终 regions 执行 |
detect_scope | string | phase=detect 时否 | full_screen | 检测范围:full_screen(全局)/ subtitle(字幕区域)/ custom(detect_roi 指定区域) |
detect_roi | object | detect_scope=custom 时是 | — | 检测区域,格式为 {x,y,w,h},坐标为 0-1 归一化画面比例 |
regions | array | phase=purify 时是 | — | 最终去除清单;每项须包含下文的区域对象全部字段,可为空数组 |
protect_regions | array | 否 | [] | phase=purify 的保护清单,结构与 regions 相同;与去除区域重叠时保护优先 |
source_file_id | string | 否 | — | phase=purify 的源文件绑定校验;提供时须与 file_id 一致 |
检测确认模式下,phase=purify 不使用 purify_scope;最终要处理的范围完全由 regions 决定。原有 purify_scope、roi 和 regions 参数继续保留给未传 phase 的一次性处理方式。
保护、精确范围与恢复
phase=purify 可传 protect_regions(默认空数组,结构与 regions 相同),保护范围在最终羽化之后扣除。source_file_id 可选;提供时必须与 file_id 相同,检测文件的 source.file_id 可用于绑定源素材。坐标相对旋转后显示画布,时间为秒,区间为 [start,end);video.fps_exact 保存有理帧率。区域边界写回限定在最终范围内,但有损成片编码仍可能改变邻近像素,不能承诺逐像素完全一致。VFR 源仍按现有 CFR 网格输出。
ffmpeg 是区域模糊,raft 是内容修复;修复不保证恢复遮挡前的真实画面。删除一个候选不会自动抵消其他重叠去除框。万级区域没有固定 16 框限制,但不承诺任意时长、分辨率或数量都能完成。
Agent 可以用 gtrk purify detect video.mp4 --json 获取完整区域文件与摘要;用 gtrk purify edit regions.json --delete-id det-000001 --out final.json 编辑,再 gtrk purify apply final.json --json 执行。目标范围已明确时使用 gtrk purify run video.mp4 --detect-scope subtitle --json。gtrk purify resume journal.json --json 复用已提交任务;提交响应丢失时停止并要求核对云端,不自动重发。CLI 在新的处理请求前检查协议 v2,旧服务不会静默丢弃保护框。
区域对象
检测确认模式的 regions 每项必须包含 id、source、x、y、w、h、start、end;最终提交时 end 也必须明确提供:
- id:稳定区域标识;检测结果由服务端生成,客户端新增区域时自行生成唯一 ID。
- source:detected(检测结果)或 manual(客户端新增)。
- x、y、w、h:0-1 归一化画面比例,区域不能越出画面。
- start、end:从视频开头计算的秒数,必须满足 start≥0 且 end>start。
同一份最终清单中的 id 必须唯一。区域可以重叠,服务端会在算法内部合并或复用重叠遮罩,但不会修改调用方提交的清单。
检测结果中的区域统一使用秒,不对外暴露算法内部的帧号。当前检测器不对外承诺稳定的识别文本或置信度字段。
检测结果文件
phase=detect 完成后,output_result 提供 JSON 文件 ID、下载路径和候选数量。完整 JSON 文件中的 regions 数组可以包含数千个候选区域,客户端编辑后将最终数组提交到 phase=purify。
JSON 文件结构固定为:
{
"version": 1,
"source": {"file_id": "537489015178246"},
"video": {
"width": 1920,
"height": 1080,
"duration": 120.0,
"fps": 30,
"fps_exact": "30/1"
},
"regions": []
}
查询协议能力
使用保护区与最终清单处理前,先查询服务能力。该查询需要鉴权,不创建任务、不计费;返回 data.review_protocol: 2 后再使用本文的 v2 行为。能力声明不能代替实际任务执行成功的验收。
curl https://api.ai-mcn.tv:10000/task/video_purify/capabilities \
-H "Authorization: YOUR_API_KEY"
{"code": 200, "data": {"review_protocol": 2}, "msg": "success"}
创建任务
基本信息
| 项目 | 值 |
|---|---|
| 请求方法 | POST |
| 请求路径 | /task/video_purify |
| Content-Type | application/json |
| 鉴权方式 | Authorization 请求头(直接传 API Key) |
请求参数(Body)
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
file_id | string | 是 | — | 已上传视频文件的 ID |
purify_scope | string | 否 | "full_screen" | 净化范围:full_screen(全屏检测去除所有水印)/ subtitle(仅净化字幕区域)/ custom(仅净化 roi 指定区域)/ region(按 regions 给出的框直接去除,可限定时间段) |
roi | object | custom 时必填 | — | 自定义净化区域,归一化坐标(0-1 画面比例):{"x","y","w","h"},需 w>0、h>0、x+w≤1、y+h≤1 |
regions | array | region 时必填 | — | 兼容模式下按给定区域直接去除;检测确认模式下由 phase=purify 提交最终区域集合,检测结果和执行请求都支持千级区域 |
purify_func_type | string | 否 | "ffmpeg" | ffmpeg(默认,区域模糊)/ raft(内容修复,仅支持 20 分钟以内视频);修复不保证还原被遮挡前的真实画面 |
请求示例
只处理已知角标,并保护与之重叠的画面文字:
此请求无需先检测。框内全部内容都会被处理,示例坐标须按实际视频调整;保护区可限定到更短的时间段。
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"source_file_id": "537489015178246",
"phase": "purify",
"purify_func_type": "ffmpeg",
"regions": [
{"id": "corner-1", "source": "manual", "x": 0.8, "y": 0.02, "w": 0.18, "h": 0.08, "start": 0, "end": 5}
],
"protect_regions": [
{"id": "keep-1", "source": "manual", "x": 0.8, "y": 0.08, "w": 0.08, "h": 0.02, "start": 2, "end": 5}
]
}'
检测确认模式:第一次请求(检测):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"phase": "detect",
"detect_scope": "full_screen"
}'
检测确认模式:第一次请求(只扫描指定区域):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"phase": "detect",
"detect_scope": "custom",
"detect_roi": {"x": 0.0, "y": 0.75, "w": 1.0, "h": 0.25}
}'
检测确认模式:第二次请求(确认后执行):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"phase": "purify",
"purify_func_type": "raft",
"regions": [
{
"id": "det-000001",
"source": "detected",
"x": 0.70,
"y": 0.04,
"w": 0.22,
"h": 0.09,
"start": 0.0,
"end": 5.2
},
{
"id": "manual-000001",
"source": "manual",
"x": 0.05,
"y": 0.05,
"w": 0.25,
"h": 0.20,
"start": 2.0,
"end": 8.0
}
]
}'
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"purify_scope": "subtitle",
"purify_func_type": "raft"
}'
custom 模式示例(仅净化底部 20% 区域):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"purify_scope": "custom",
"roi": {"x": 0.0, "y": 0.78, "w": 1.0, "h": 0.2}
}'
region 模式示例(去除右上角角标的前 5 秒,以及底部区域从第 120 秒到结尾):
curl -X POST https://api.ai-mcn.tv:10000/task/video_purify \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "537489015178246",
"purify_scope": "region",
"purify_func_type": "raft",
"regions": [
{"x": 0.8, "y": 0.02, "w": 0.18, "h": 0.08, "start": 0, "end": 5},
{"x": 0.3, "y": 0.85, "w": 0.4, "h": 0.1, "start": 120}
]
}'
custom与region怎么选
custom:在roi范围内识别文字,只去除识别到的文字,范围里的其它内容保持原样。region:不做识别,框内全部内容都会被处理(包括画面主体),适合图形台标、半透明图案、艺术字这类识别不到的元素,也适合只在某段时间出现的角标。ffmpeg方式在框内做模糊,raft方式做修复补全;框越小、越贴近要去除的元素,效果越好。框的边缘会有几个像素的柔和过渡。
成功响应示例
{
"code": 200,
"msg": "success",
"data": {
"task_id": "537489015178247",
"task_type": "video_purify",
"status": "queued"
}
}
查询任务结果
基本信息
| 项目 | 值 |
|---|---|
| 请求方法 | GET |
| 请求路径 | /task/video_purify/{task_id} |
| 鉴权方式 | Authorization 请求头(直接传 API Key) |
响应参数(output_result)
| 参数名 | 类型 | 说明 |
|---|---|---|
phase | string | 本次任务的阶段:detect / purify |
file_id | string | phase=purify 时返回,处理后的视频文件 ID |
download_url | string | phase=purify 时返回,处理后视频的下载路径 |
regions_file_id | string | phase=detect 时返回,检测结果 JSON 文件 ID |
regions_download_url | string | phase=detect 时返回,检测结果 JSON 文件下载路径 |
region_count | number | phase=detect 时返回,候选区域数量,可达到数千级 |
video | object | phase=detect 时返回的视频元数据:width、height、duration、fps |
检测请求完成时,output_result 不包含视频文件,而是包含检测结果 JSON 文件信息:
{
"phase": "detect",
"regions_file_id": "537489015178249",
"regions_download_url": "/download/a1/regions.json",
"region_count": 2387,
"video": {
"width": 1920,
"height": 1080,
"duration": 120.0,
"fps": 30
}
}
成功响应示例
{
"code": 200,
"msg": "success",
"data": {
"task_id": "537489015178247",
"status": "completed",
"progress": 100,
"output_result": {
"file_id": "537489015178248",
"download_url": "/download/a1/output.mp4"
},
"create_time": "2026-04-05T08:00:00Z",
"update_time": "2026-04-05T08:01:00Z"
}
}
错误码
| 错误码 | HTTP 状态码 | 说明 | 解决方案 |
|---|---|---|---|
6013 | 400 | file_id 缺失 | 传入 file_id 参数 |
6016 | 400 | 参数或区域非法,对应请求所需参数缺失,坐标越界,end 不大于 start,区域数量或请求体超过服务端资源限制,或 raft 模式视频时长超过 20 分钟 | 检查当前请求的参数和区域对象;若大规模任务仍超过服务端资源限制,请拆分任务或缩小视频范围,并确保 raft 模式视频不超过 20 分钟 |
6035 | 400 | 视频画面短边过小:raft 模式要求画面短边 ≥128 像素(报错信息会写明当前尺寸) | 改用 purify_func_type: ffmpeg,或提供画面更大的源片 |
6014 | 400 | 文件类型与接口不匹配 | 传入视频文件 |
6004 | 404 | 文件不存在 | 检查 file_id 是否正确 |
6502 | 401 | 鉴权失败 | 检查 Authorization 请求头 |
6202 | 402 | 余额不足 | 前往仪表盘充值 |