【ffmpeg】overlay带有透明通道的视频

直接用下面overlay带有透明通道的视频时会出现,浮层视频边缘锐化,或者亮度变暗等等问题

ffmpeg -i in.mp4 -i x.mov  -filter_complex "[0][1]overlay"  -y output.mp4

改进方式:
添加参数alpha=1

ffmpeg -i in.mp4 -i x.mov  -filter_complex "[0][1]overlay=alpha=1"  -y output.mp4

https://ffmpeg.org/ffmpeg-filters.html#overlay-1
解释:
alpha : Set format of alpha of the overlaid video, it can be straight or premultiplied. Default is straight.

  • straight
  • premultiplied

参考https://segmentfault.com/a/1190000002990030 解释了为什么要用premultiplied;

Alpha Blending

要搞清楚这个问题,先得理解Alpha通道的工作原理,如果你已经了解可以直接跳过。

最常见的像素表示格式是RGBA8888即 ( r , g , b , a ) (r, g, b, a) (r,g,b,a),每个通道8位,0-255。例如红色60%透明度就是 ( 255 , 0 , 0 , 153 ) (255, 0, 0, 153) (255,0,0,153),为了表示方便alpha通道一般记成正规化后的0-1的浮点数,也就是 ( 255 , 0 , 0 , 0.6 ) (255, 0, 0, 0.6) (255,0,0,0.6)。而 Premultiplied Alpha 则是把RGB通道乘以透明度也就是 (r a, g a, b * a, a),50%透明红色就变成了 ( 153 , 0 , 0 , 0.6 ) (153, 0, 0, 0.6) (153,0,0,0.6)

透明通道在渲染的时候通过 Alpha Blending 产生作用,如果一个透明度为 α s \alpha_s αs 的颜色 C s C_s Cs 渲染到颜色 C d C_d Cd上,混合后的颜色通过以下公式计算,
C o = α s ∗ C s + ( 1 − α s ) ∗ C d C_o = \alpha_s * C_s + (1- \alpha_s)* C_d Co=αsCs+1αsCd
以60% 透明的红色渲染到白色背景为例:
C o = ( 255 , 0 , 0 ) ⋅ 0.6 + ( 255 , 255 , 255 ) ⋅ ( 1 − 0.6 ) = ( 255 , 102 , 102 ) C_o =(255,0,0)⋅0.6+(255,255,255)⋅(1−0.6)=(255,102,102) Co=(255,0,0)0.6+(255,255,255)(10.6)=(255,102,102)
也就是说,从视觉上, ( 255 , 0 , 0 , 0.6 ) (255, 0, 0, 0.6) (255,0,0,0.6)渲染到白色背景上 和 ( 255 , 102 , 102 ) (255, 102, 102) (255,102,102) 是同一个颜色。如果颜色以 Premultiplied Alpha 形式存储,也就是 C s C_s Cs 已经乘以透明度了,所以混合公式变成了:

为什么要 Premultiplied Alpha 呢?

Premultiplied Alpha 后的像素格式变得不直观,因为在画图的时候都是先从调色板中选出一个RGB颜色,再单独设置透明度,如果RGB乘以透明度就搞不清楚原色是什么了。从前面的 Alpha Blending 公式可以看出,Premultiplied Alpha 之后,混合的时候可以少一次乘法,这可以提高一些效率,但这并不是最主要的原因。最主要的原因是:

没有 Premultiplied Alpha 的纹理无法进行 Texture Filtering(除非使用最近邻插值)。

以最常见的 filtering 方式线性插值为例,一个宽2px高1px的图片,左边的像素是红色,右边是绿色10%透明度,如果把这个图片缩放到1x1的大小,那么缩放后1像素的颜色就是左右两个像素线性插值的结果,也就是把两个像素各个通道加起来除以2。如果使用没有 Premultiplied Alpha 的颜色进行插值,那么结果就是:
( ( 255 , 0 , 0 , 1 ) + ( 0 , 255 , 0 , 0.1 ) ) ⋅ 0.5 = ( 127 , 127 , 0 , 0.55 ) ((255,0,0,1)+(0,255,0,0.1))⋅0.5=(127,127,0,0.55) ((255,0,0,1)+(0,255,0,0.1))0.5=(127,127,0,0.55)
如果绿色 Premultiplied Alpha,也就是 (0, 255 * 0.1, 0, 0.1),和红色混合后:

( ( 255 , 0 , 0 , 1 ) + ( 0 , 25 , 0 , 0.1 ) ) ⋅ 0.5 = ( 127 , 25 , 0 , 0.55 ) ((255,0,0,1)+(0,25,0,0.1))⋅0.5=(127,25,0,0.55) ((255,0,0,1)+(0,25,0,0.1))0.5=(127,25,0,0.55)
在这里插入图片描述
从上面的图里第三个颜色是没有 Premultiplied Alpha 的混合结果,对比第四个 Premultiplied Alpha 后颜色的结果,显然第四个颜色更符合直觉,第三个颜色太绿了,因为绿色通道没有乘以透明度,所以在线性插值的时候占了过大的权重。

所以 Premultiplied Alpha 最重要的意义是使得带透明度图片纹理可以正常的进行线性插值。这样旋转、缩放或者非整数的纹理坐标才能正常显示,否则就会像上面的例子一样,在透明像素边缘附近产生奇怪的颜色。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值