FFmpeg:如何使用自定义透明度将PNG图像叠加到视频上?

17

假设我有一个视频 foo.mkv 和一张图片 bar.png(其中包含 alpha 通道),我可以像这样将这张图片与视频混合:

ffmpeg 
 -i foo.mkv 
 -i bar.png 
 -filter_complex "[0:v][1:v]overlay" 
 -vcodec libx264 
 myresult.mkv

(这里为了易读性使用多行,通常这是一条命令行。)。

除了png图像本身具有alpha通道外,当混合此图像到视频中时,我还会应用自定义的 整体透明度

在上面的例子中,图像将以100%的可见度出现在视频上方——或者至少是其alpha通道完全不透明的部分。

是否有一种方法可以添加自定义的整体不透明度或透明度混合因子,比如 opacity=0.5 或其他值,这将使图像只有50%可见?

3个回答

20

我想我明白了:

ffmpeg 
 -i foo.mkv 
 -i bar.png 
 -filter_complex "[1:v]format=argb,geq=r='r(X,Y)':a='0.5*alpha(X,Y)'[zork]; 
   [0:v][zork]overlay" 
 -vcodec libx264 
 myresult.mkv

其中0.5是不透明度因子。我包含format=argb, 以便它也可用于叠加图像本身没有α通道的情况。


更完整的演示性答案 - dvdhns

11

除了geq之外,另一种选择是colorchannelmixer

[1:v]format=argb,colorchannelmixer=aa=0.5[zork]

谢谢!我喜欢的是它不强制我显式地设置一个颜色通道(就像geq一样,因此我的虚拟变量r='r(X,Y)')。你知道有什么方法可以强制格式包含alpha,而不需要显式地强制颜色模型吗?(就像我用format=argb一样)也就是说,有没有类似于format=a<currentcolormodel>这样的东西? - RocketNuts
不要以一种方式覆盖掉 alpha 通道,如果它存在的话。 - Gyan
出于好奇,有什么方法可以覆盖现有的 alpha 通道? - RocketNuts
1
颜色=灰色,格式=灰色[c];[c][0]scale2ref[a][v];[v][a]alphamerge[ovrly]。颜色灰色最终会导致50%的alpha通道。虽然更繁琐,但避免了知道源格式的问题。 - Gyan
另一种获得结果的方法是使用混合滤镜,在覆盖模式下应用透明度为0.5的顶层。 - Gyan
显示剩余2条评论

-1

在FFmpeg Android中使用此函数来叠加带透明度的图像到视频中

fun addimagemerge(inputVideo: String, imageInput: String, output: String): Array<String> {
    val inputs: ArrayList<String> = ArrayList()
    inputs.apply {
        add("-i")
        add(inputVideo)
        add("-i")
        add(imageInput)
        add("-filter_complex")
        add("[1:v]format=argb,geq=r='r(X,Y)':a='0.5*alpha(X,Y)'[zork]; [0:v][zork]overlay")
        add("-preset")
        add("ultrafast")
        add(output)
    }
    return inputs.toArray(arrayOfNulls<String>(inputs.size))
}

使用此功能来调用转换按钮上的函数

val outputPath = getFilePath(this, VIDEO)
  
    val query = ffmpegQueryExtension.addimagemerge(
        selectedVideoPath!!,
        selectedImagePath!!,
        outputPath
    )

    CallBackOfQuery().callQuery(this, query, object : FFmpegCallBack {
        override fun process(logMessage: LogMessage) {

            runOnUiThread {
                tvOutputPath.text = logMessage.text
            }
        }

        override fun success() {
            tvOutputPath.text = String.format(getString(R.string.output_path), outputPath)
            processStop()
            runOnUiThread {
                videoPlayclass.stopVideoPlay(bottmLay, videoPlayAct)
                videoPlayclass.videoPlayStart(
                    this@MergeImageVideoActivity,
                    bottmLay,
                    videoPlayAct,
                    outputPath
                )
            }
        }

        override fun cancel() {
            processStop()
        }

        override fun failed() {
            processStop()
        }
    })

你为什么更喜欢这个答案,而不是明显更简单的得票最高的答案?这种方法提供的功能是否比使用命令行选项更加丰富? - Jeremy Caney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接