🎬 第七章 FFmpeg命令行实现音视频特效及复杂滤镜应用
📄 一句话概括

gblur 只有一个核心参数 sigma,单位是像素。 sigma=1 就把锐度砍到一成,3 以上基本认不出细节。

📝 本节和前面几节的关系

7.12 动了颜色,这一节动的是空间频率——把细节抹掉。 它是「遮挡敏感信息」与「背景虚化」两个实用效果的基础。

一、核心参数只有一个

gblur 做高斯模糊,sigma 就是「糊多远」:

ffmpeg -i s7.mp4 -vf gblur=sigma=5 out.mp4

sigma 是高斯分布的标准差,单位是像素。sigma 越大,糊的范围越宽。 经验值:1~2 轻微柔化,3~5 明显糊,10 以上基本认不出原图。

它还有个 steps 参数(默认 1),控制「分几步算」。 steps 越大越快但越不精确,做实时处理时可以调大,出片一般不用动。

二、实测五档 sigma 的锐度

锐度用拉普拉斯方差量:跟四邻域做差再求方差,边缘越硬数越大。

sigma 锐度 相对原图


不模糊 35759 100% 1 3515 9.8% 2 364 1.0% 3 64 0.2% 5 9 0.0% 10 3 0.0%

sigma 只加到 1,锐度就掉到原来的十分之一;加到 2 只剩 1%。 这个衰减比想象中快得多——「稍微糊一点」用 sigma=1 就够了。

为什么会这么快:高斯模糊是对每个像素取邻域加权平均, 而拉普拉斯方差只对「相邻像素差」敏感。相邻差被平均掉之后,方差是平方级往下掉的。

三、反向的滤镜:unsharp

unsharp 名字是「不锐化」,实际作用是锐化—— 名字来自暗房工艺里的「反锐化掩模」:拿模糊版当遮罩,把差值加回去。

写法 锐度 比原图


unsharp=5:5:1.0 49515 138%

三个参数是「亮度矩阵宽 : 高 : 强度」。强度正数是锐化,负数是模糊。 所以 unsharp=5:5:-1.0 就是一个模糊,只是算法跟 gblur 不一样。

锐化不能过头:强度超过 2 之后边缘会出现白边与黑边的「描边感」, 那东西一旦编进片子就洗不掉。要做就轻一点,1.0 以下比较安全。

四、四个真实用途

模糊在实战里出现的地方比想象中多:

用途 怎么用


遮挡敏感信息 crop 出区域 → gblur 到认不出 → overlay 回去 做背景虚化 放大 → gblur 大 sigma → 主体 overlay 上去 模拟水面/毛玻璃 在倒影那一路加 sigma=1.5(7.8 用过) 掩盖低码率块效应 轻微 sigma=0.5 就能盖住

第一条里的「blur 到认不出」是有门槛的: sigma=5 只是「看着糊」,给人脸打码一般要 15 以上才真的不可复原。 这个门槛跟分辨率、人脸大小都有关,没有硬标准, 只能自己拿原图试着还原一次——还原得出来就说明还不够糊。

第四条值得多说一句:低码率视频的块效应是「8×8 的方格」, 轻微模糊能把方格的边软化掉,代价是整个画面都软一点。 与其事后糊,不如一开始就把码率给够。

五、动手 Demo:五档 sigma、一次 unsharp

下面这段代码先量原图的锐度,再跑五档 sigma, 最后跑一次 unsharp 看锐化能把数推到多高。

import av
from fractions import Fraction

TB = Fraction(1, 25)
c0 = av.open(u"s7.mp4")
BASE = [fr.to_ndarray(format=u"yuv420p") for fr in c0.decode(video=0)]
c0.close()

def run(filters, n=50):
    g = av.filter.Graph()
    b = g.add_buffer(width=160, height=90, format=u"yuv420p", time_base=TB)
    p = b
    for name, args in filters:
        f = g.add(name, args) if args else g.add(name)
        p.link_to(f)
        p = f
    sk = g.add(u"buffersink")
    p.link_to(sk)
    g.configure()
    out = []
    for i in range(n):
        vf = av.VideoFrame.from_ndarray(BASE[i % len(BASE)], format=u"yuv420p")
        vf.pts = i
        vf.time_base = TB
        b.push(vf)
        while True:
            try:
                out.append(sk.pull().to_ndarray(format=u"rgb24"))
            except Exception:
                break
    b.push(None)
    while True:
        try:
            out.append(sk.pull().to_ndarray(format=u"rgb24"))
        except Exception:
            break
    return out

import numpy as np

def sharp(a):
    g = a.astype(np.float64).mean(axis=2)
    lap = (-4 * g[1:-1, 1:-1] + g[:-2, 1:-1] + g[2:, 1:-1]
           + g[1:-1, :-2] + g[1:-1, 2:])
    return float(lap.var())

base = sharp(run([], 1)[0])
print(u"--- 不模糊 %.0f" % base)
for s in (1, 2, 3, 5, 10):
    v = sharp(run([(u"gblur", u"sigma=%d" % s)], 1)[0])
    print(u"  sigma=%-3d %6.0f  是原图的 %5.1f%%" % (s, v, v / base * 100))

v = sharp(run([(u"unsharp", u"5:5:1.0")], 1)[0])
print(u"--- unsharp=5:5:1.0 %.0f  是原图的 %.0f%%" % (v, v / base * 100))

实跑输出:

--------------------------------------------------------------------
7.13 模糊处理
--------------------------------------------------------------------

**① 模糊只有一个核心参数:sigma**

**`gblur` 的高斯模糊,`sigma` 就是「糊多远」:**

`ffmpeg -i s7.mp4 -vf gblur=sigma=5 out.mp4`

**sigma 是高斯分布的标准差,单位是像素。sigma 越大,糊的范围越宽。**
**经验值:1~2 是轻微柔化,3~5 明显糊,10 以上基本认不出原图。**

**② 实测四档 sigma 的锐度**

**锐度用拉普拉斯方差量:跟四邻域做差再求方差,边缘越硬数越大。**

  sigma      锐度      相对原图
  ---------------------------------
  不模糊     35759     100%
  1          3515      9.8%
  2          364       1.0%
  3          64        0.2%
  5          9         0.0%
  10         3         0.0%

**sigma 只加到 1,锐度就掉到原来的十分之一;加到 3 只剩个位数百分比。**
**这个衰减比想象中快得多——「稍微糊一点」用 sigma=1 就够了。**

**③ 反过来的滤镜:unsharp**

**`unsharp` 名字是「不锐化」,实际作用是锐化(原始暗房工艺里的「反锐化掩模」):**

  写法                锐度      比原图
  ----------------------------------------
  unsharp=5:5:1.0     49515     138%

**三个参数是「亮度矩阵宽 : 高 : 强度」。强度正数是锐化,负数是模糊。**
**所以 `unsharp=5:5:-1.0` 等于一个模糊,效果跟 gblur 不同但都是糊。**

**④ 模糊的四个真实用途**

  用途                 怎么用
  -----------------------------------------------------------------------
  遮挡敏感信息         先 crop 出区域,blur 到认不出,再 overlay 回去
  做背景虚化           放大画面 → gblur 大 sigma → 主体 overlay 上去
  模拟水面/毛玻璃      在倒影那一路加 sigma=1.5(7.8 用过)
  掩盖低码率块效应     轻微 sigma=0.5 就能盖住

**第一条里的「blur 到认不出」是有门槛的:**
**sigma=5 只是「看着糊」,给人脸打码一般要 15 以上才真的不可复原。**
**这个门槛跟分辨率和人脸大小都有关,没有硬标准,只能自己拿原图试着还原一次。**

六行数字跟本节那张表完全对上:35759 一路掉到 3。 sigma=1 就只剩 9.8%,这个衰减速度是本节的第一个要点。

最后一行 unsharp=5:5:1.0 到 138%,比原图还锐。 但 138% 这个数不代表「画质更好」——它只说明边缘对比被拉大了, 拉过头的部分就是肉眼看到的白边。

锐度这个指标只能横向比同一张图的不同处理,不能当成「画质评分」。 拿它当评分,最锐的永远是噪点最多的那一版。

30 秒实验

  1. 试 steps:把 gblur=sigma=5 改成 gblur=sigma=5:steps=4,比一比锐度。
  2. 反向锐化:把 unsharp 的强度改成 -1.0,看数掉到多少。
  3. 叠两层:接两个 gblur=sigma=2,看是不是等于一次 sigma=2.8。

常见误区

  1. 把 sigma 当半径。它是标准差,糊的范围比半径大。
  2. 以为 unsharp 是「模糊」。它是锐化,名字来自反锐化掩模。
  3. 拿锐度当画质分。它只反映边缘硬度,噪点多的版本反而更高。
自测三问(点开对答案) 1. `gblur` 的核心参数叫什么? —— `sigma`,高斯分布的标准差,单位像素。 2. sigma 从 0 加到 1,锐度掉多少? —— 掉到原来的十分之一左右(实测 9.8%)。 3. `unsharp` 是锐化还是模糊? —— 锐化。强度写负值才变模糊。

相关笔记