修补区域有没有重复纹理
大面积Clone看单帧自然,连续播放时会显出重复节奏。
有人这样说「这组镜头一放就露馅,克隆块在连贯动作里来回跳,得赶紧查。」
能替你选的都选好了。不想动,直接点下面「交给 AI 办」,点一下就开始做;想改,就点一下要的那个。
已替你选好想改就点一下
只有你知道的不填就先空着,成品里留【待填】
还想怎么改可以不选
开工前请确认
高级选项一般不用动 · 这件事通常 1–3 分钟做好
示例成品全文按上面这组示例选项真跑出来的
我这端没收到可打开的附件,只看到文件名,不能瞎报“第几帧有问题”。
你现在二选一:
- 重新上传
04_012_cleaned_v03.mov + 04_012_source_plate.exr,或给可读网盘链接; - 先按下面方法跑出逐帧标注,再把
mark_*.png + report.csv发我,我帮你人工复核。
1. 先把清理镜头转成逐帧图
ffmpeg -i 04_012_cleaned_v03.mov -start_number 1 frames/%05d.png源板如果是单张 EXR:
ffmpeg -i 04_012_source_plate.exr -vf format=rgb24 source_plate.png如果是 EXR 序列:
ffmpeg -i 04_012_source_plate_%04d.exr -start_number 1 source_%05d.png2. 自动查两件事
JUMP:时序抖动突变,即相邻帧局部运动方向/速度突然跳变。CLONE_REPEAT:可疑跳动区域周围还有高相似重复块,疑似克隆纹理。
脚本保存为 check_jump_clone.py:
import os, glob, csv
import cv2
import numpy as np
FRAME_DIR = "frames"
OUT_DIR = "marks"
os.makedirs(OUT_DIR, exist_ok=True)
files = sorted(glob.glob(os.path.join(FRAME_DIR, "*.png")))
if len(files) < 2:
raise SystemExit("没有帧,先跑 ffmpeg 转帧")
prev = cv2.imread(files[0])
prev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)
prev_flow = None
rows = []
for idx in range(1, len(files)):
cur = cv2.imread(files[idx])
if cur is None:
continue
gray = cv2.cvtColor(cur, cv2.COLOR_BGR2GRAY)
h, w = gray.shape
flow = cv2.calcOpticalFlowFarneback(
prev_gray, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0
)
if prev_flow is not None:
# 帧间运动变化量:jerk
jerk = np.linalg.norm(flow - prev_flow, axis=2)
jerk = cv2.GaussianBlur(jerk.astype(np.float32), (5, 5), 0)
med = float(np.median(jerk))
thr = max(1.0, med * 2.0) # 调小更敏感,调大更保守
_, mask = cv2.threshold(jerk, thr, 255, cv2.THRESH_BINARY)
mask = cv2.morphologyEx(
mask.astype(np.uint8), cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8)
)
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = cnts[0] if len(cnts) == 2 else cnts[1]
for c in contours:
x, y, bw, bh = cv2.boundingRect(c)
if bw * bh < 60 or bw < 5 or bh < 5:
continue
score = float(np.mean(jerk[y:y+bh, x:x+bw]))
rows.append([
idx, os.path.basename(files[idx]),
"JUMP", x, y, bw, bh, round(score, 2)
])
cv2.rectangle(cur, (x, y), (x+bw, y+bh), (0, 0, 255), 2)
cv2.putText(
cur, "JUMP", (x, y-5),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1
)
# 只在 JUMP 区域周边查重复纹理块
pad = 12
bx0, by0 = max(0, x-pad), max(0, y-pad)
bx1, by1 = min(w, x+bw+pad), min(h, y+bh+pad)
rw, rh = bx1-bx0, by1-by0
if rw < 16 or rh < 16:
continue
templ = gray[by0:by1, bx0:bx1]
res = cv2.matchTemplate(gray, templ, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(res)
cx, cy = max_loc
# 排除自己
if bx0 <= cx <= bx0 + rw and by0 <= cy <= by0 + rh:
continue
if max_val > 0.95: # 调高更严格,调低更敏感
rows.append([
idx, os.path.basename(files[idx]),
"CLONE_REPEAT", cx, cy, rw, rh, round(float(max_val), 3)
])
cv2.rectangle(cur, (cx, cy), (cx+rw, cy+rh), (0, 255, 255), 2)
cv2.putText(
cur, "CLONE", (cx, cy-5),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 1
)
cv2.imwrite(os.path.join(OUT_DIR, f"mark_{idx:05d}.png