示例成品 看全文 ↓

Matte边缘有没有漏光

静帧边缘正常,也可能在运动中出现一闪而过的漏光或破洞。

免费看示例成品:表格 · 报告 · 代码写代码做网站 ›

有人这样说「这组镜头动起来边缘总闪一下,静帧看不出来,得赶紧查。」

能替你选的都选好了。不想动,直接点下面「交给 AI 办」,点一下就开始做;想改,就点一下要的那个。

已替你选好想改就点一下

只有你知道的不填就先空着,成品里留【待填】

还想怎么改可以不选

开工前请确认

高级选项一般不用动 · 这件事通常 1–3 分钟做好

示例成品全文按上面这组示例选项真跑出来的

先说清楚:当前对话里我没有实际收到可解码的 EXR/MOV 附件,没法给你编一份“真实逐帧图文报告”。下面给你一套直接能跑的检测方案 + 报告模板,按你的要求:连续3镜头、v02、逐5帧、重点查边缘闪变/破洞/亮边、平衡灵敏度。跑完把输出图和表贴回来就是成稿。


1. 先查什么

这种“静帧看不出来、动起来闪一下”基本优先查三类:

  1. 边缘闪变:相邻帧 matte alpha 在边缘带内变化大。
  2. 破洞:前景 alpha 内部小空洞忽有忽无。
  3. 亮边:合成后边缘亮度明显高于背景边缘,常见于 premultiply 错误、去黑边不好、边缘溢色。

2. 检测脚本(Python,平衡灵敏度)

你先装依赖:

pip install OpenEXR opencv-python numpy

下面脚本默认按你的文件命名规则抓序列:
matte_v02_comp_01234.*.exr / fg_01234.mov / bg_01234.*.exr

如果实际命名不一样,只改 MATTE_GLOB、BG_GLOB、FG_VIDEO 三行。

import glob, os
import numpy as np
import cv2
import OpenEXR, Imath

FLOAT = Imath.PixelType.FLOAT
SHOTS = [1234, 1235, 1236]      # 连续3个镜头
SEG = 5                         # 逐5帧
OUT = "reports/v02"
os.makedirs(OUT, exist_ok=True)

# 按实际命名改这里
MATTE_GLOB = "matte_v02_comp_{shot:05d}.*.exr"
BG_GLOB = "bg_{shot:05d}.*.exr"
FG_VIDEO = "fg_{shot:05d}.mov"

def save_map(path, arr):
    arr01 = np.clip(arr, 0, 1)
    cv2.imwrite(path, (arr01 * 255).astype(np.uint8))

def read_exr_alpha(path):
    f = OpenEXR.InputFile(path)
    h = f.header()
    dw = h['dataWindow']
    w = dw.max.x - dw.min.x + 1
    hh = dw.max.y - dw.min.y + 1
    ch = {c.lower(): c for c in h['channels'].keys()}

    if 'a' in ch:
        arr = np.frombuffer(f.channel(ch['a'], FLOAT), dtype=np.float32).reshape(hh, w)
    else:
        arrs = []
        for cc in ['r', 'g', 'b']:
            arr = np.frombuffer(f.channel(ch[cc], FLOAT), dtype=np.float32).reshape(hh, w)
            arrs.append(arr)
        arr = 0.2126 * arrs[0] + 0.7152 * arrs[1] + 0.0722 * arrs[2]
    return np.clip(arr, 0, 1)

def read_exr_rgb(path):
    f = OpenEXR.InputFile(path)
    h = f.header()
    dw = h['dataWindow']
    w = dw.max.x - dw.min.x + 1
    hh = dw.max.y - dw.min.y + 1
    ch = {c.lower(): c for c in h['channels'].keys()}

    rgb = []
    for cc in ['r', 'g', 'b']:
        arr = np.frombuffer(f.channel(ch[cc], FLOAT), dtype=np.float32).reshape(hh, w)
        rgb.append(arr)
    return np.stack(rgb, axis=2)

def read_video_rgb(path, frame_idx):
    cap = cv2.VideoCapture(path)
    if not cap.isOpened():
        raise IOError(f"can't open video: {path}")
    cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
    ok, frame = cap.read()
    cap.release()
    if not ok:
        raise IOError(f"can't read video {path} frame {frame_idx}")
    return cv2.cvtColor(frame, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0

def edge_band(a):
    gx = cv2.Sobel(a, cv2.CV_32F, 1, 0, ksize=3)
    gy = cv2.Sobel(a, cv2.CV_32F, 0, 1, ksize=3)
    g = np.hypot(gx, gy)
    return (g > 0.02) & (a > 0.01) & (a < 0.99)

def edge_flicker(a0, a1):
    m = edge_band(a0) | edge_band(a1)
    if not m.any():
        return 0.0, np.zeros_like(a0)
    diff = np.abs(a1 - a0)
    score = float(np.mean(diff[m]))
    return score, diff

def hole_score(a):
    b = (a > 0.5).astype(np.uint8)
    contours, hierarchy = cv2.findContours(b, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
    if hierarchy is None:
        return 0.0, np.zeros_like(a, dtype=np.uint8)

    fg_area = max(int(np.count_nonzero(b)), 1)
    hmap = np.zeros_like(a, dtype=np.uint8)
    total = 0.0
    h = hierarchy[0]

    for i, cnt in enumerate(contours):
        parent = h[i][3]
        if parent != -1:
            area = float(cv2.contourArea(cnt))
            if 4 <= area <= 0.02 * fg_area:
                total += area
                cv2.drawContours(hmap, [cnt], -1, 1, -1)

    return total / fg_area, hmap

def bright_

别人还这样问

同类还能办

全部 ›
把提示词失败日志转成归因表格免费看示例 ›死循环卡死怎么排查免费看示例 ›屎山代码怎么安全重构免费看示例 ›把报错日志转成排查步骤免费看示例 ›怎么给老代码补单元测试免费看示例 ›核对时钟配置是不是一致免费看示例 ›

同样出写代码做网站的

首页