ffmpeg使用filter_complex displace滤镜出现视频鬼影问题
FFmpeg displace滤镜输出鬼影问题排查与解决
问题复现
使用如下脚本可稳定复现问题:
# 生成蓝色背景空视频 ffmpeg -y -t 2 -f lavfi -i color=c=blue:s=160x120 -c:v libx264 -tune stillimage -pix_fmt rgb24 00_empty.mp4 # 叠加从右向左滚动的白色文字 ffmpeg -y -i 00_empty.mp4 -vf "drawtext=text=string1:y=h/2:x=w-t*w/2:fontcolor=white:fontsize=60" 01_text.mp4 # 生成纯灰色占位视频 ffmpeg -y -t 2 -f lavfi -i color=c=gray:s=160x120 -c:v libx264 -tune stillimage -pix_fmt rgb24 02_gray.mp4 # 调用displace滤镜做位移映射 ffmpeg -y -i 01_text.mp4 -i 02_gray.mp4 -i 02_gray.mp4 -filter_complex "[0][1][2]displace=edge=mirror" 03_displaced_text.mp4
现象说明
- 预期表现:100%纯中性灰的位移参考图对应位移量为0,不会改变原画面内容,最多出现固定值整体偏移
- 实际表现:输出视频存在明显阴影鬼影,滚动文字边缘出现重影
动态高斯噪声位移映射鬼影效果参考
纯灰参考图位移输出鬼影效果参考
已尝试排查方向:
- 切换yuv420p、yuv444p、rgb24三种像素格式,问题未解决
- 校验色度平面与亮度平面位移一致性,问题未解决
测试环境:FFmpeg 5.0.1 full_build版本
问题根因
核心问题是位移参考视频经过了libx264有损编码,像素值存在压缩误差:
- libx264本身不支持RGB像素格式编码,即便指定
-pix_fmt rgb24,FFmpeg也会自动做隐式格式转换,将画面转为YUV格式后再编码,无法保留精确的原始像素值 - 即便开启
tune stillimage、调低CRF,libx264的有损压缩特性依然会让本该逐像素为128灰度值的参考画面出现大量±1~3的像素值波动 - displace滤镜是逐像素读取参考图的像素值计算位移量,1个灰度值的偏差就会对应约0.5像素的位移偏移,编码带来的随机像素偏差直接导致画面局部出现不规则位移,最终形成鬼影。
解决方案
- 优先方案:位移参考素材直接在filter_complex链路内通过lavfi源实时生成,完全跳过中间文件编码环节,从根源避免像素值损失,单条命令即可实现正确效果:
ffmpeg -y -t 2 -f lavfi -i color=c=blue:s=160x120 \ -vf "drawtext=text=string1:y=h/2:x=w-t*w/2:fontcolor=white:fontsize=60" \ -filter_complex "[0]split=2[main][ref_x];color=c=gray:s=160x120:d=2[ref_y];[main][ref_x][ref_y]displace=edge=mirror" \ -c:v libx264 -pix_fmt yuv444p 03_displaced_text_fixed.mp4
- 若必须预先生成位移参考视频,禁止使用libx264等有损编码存储,改用FFV1、RawVideo等无损编码格式,保证参考图像素值100%精确,纯灰参考视频生成示例:
ffmpeg -y -t 2 -f lavfi -i color=c=gray:s=160x120 -c:v ffv1 -pix_fmt gbrp 02_gray_lossless.mkv
- 额外注意事项:
- 使用displace滤镜时,保证主输入、X方向参考输入、Y方向参考输入三者像素格式完全一致,避免隐式格式转换带来的像素值偏移
- 制作动态高斯噪声位移效果时,噪声源同样尽量在滤镜链路内直接生成,不要提前编码为有损视频,否则噪声值偏差会直接导致位移错乱、鬼影加重
内容的提问来源于stack exchange,提问作者raul.vila
相关产品推荐
相关产品推荐

