3. 图像处理基础:像素操作、图像滤波与形态学操作

各位同学,欢迎来到第三章。说实话,这一章是整个光效提取流程的「地基」。你后面做的所有炫酷效果——光晕分离、高光保留、边缘羽化——底层都离不开今天讲的这几个操作。

我刚开始做图像处理那会儿,总觉得滤波不就是「模糊一下」嘛,形态学不就是「膨胀腐蚀」嘛,有啥好学的?直到有一次做工业检测项目,光源不均匀导致光效提取总是带噪点,折腾了两天才发现是滤波参数没调对。嗯,从那以后我再也不敢小看这些基础操作了。

3.1 像素操作:你看到的图,其实是个数字矩阵

先问个问题:一张图片在计算机眼里是什么?

说白了,就是一个多维数组。灰度图是二维矩阵,每个元素值 0-255 代表亮度。彩色图是三维矩阵,多了一个通道维度(RGB)。

我习惯把像素操作分成三类:

  • 点运算:每个像素独立处理,比如亮度调整、对比度拉伸
  • 邻域运算:像素值由周围像素决定,比如滤波、边缘检测
  • 几何变换:像素位置改变,比如旋转、缩放

光效提取中最常用的是点运算中的阈值分割和通道分离。举个例子,你要提取一个发光物体的高光区域,通常会在某个颜色通道上做阈值处理:

# 伪代码示例:基于亮度阈值提取高光区域
import numpy as np

def extract_highlight(image, threshold=200):
    # 转为灰度
    gray = np.mean(image, axis=2)
    # 生成二值掩码
    mask = (gray > threshold).astype(np.uint8) * 255
    return mask
我的习惯:做光效提取前,先看一眼三个通道的直方图。很多时候高光信息集中在某个通道,直接操作那个通道比处理全彩图高效得多。

3.2 图像滤波:去噪与保留的博弈

滤波的本质是什么?用一个「窗口」扫过整张图,每个像素的新值由窗口内的邻居决定。你想想看,这其实就是一种「信息交换」。

3.2.1 高斯滤波:平滑但不生硬

高斯滤波用的是加权平均——离中心越近的像素权重越大,权重分布服从高斯函数。我做过对比测试:同样半径下,高斯滤波比均值滤波保留的边缘细节多 30% 左右。

参数 作用 典型值
核大小 (ksize) 窗口尺寸,越大越模糊 3, 5, 7
标准差 (sigma) 控制权重衰减速度 0.5 ~ 2.0
# OpenCV 实现高斯滤波
import cv2

img = cv2.imread('light_effect.jpg')
blurred = cv2.GaussianBlur(img, (5, 5), 1.0)
避坑:我曾经在提取细小光效时用了太大的核(9x9),结果光晕边缘全糊了。记住:核大小必须是奇数,而且核越大,计算量呈平方增长。对于光效提取,3x3 或 5x5 通常就够了。

3.2.2 中值滤波:对付椒盐噪声的利器

中值滤波不取平均,取窗口内所有像素的中位数。这招对付椒盐噪声特别管用——因为噪声点的值要么极大要么极小,取中位数直接把它「踢出局」。

我有个实际案例:某次拍摄的光效图里有零星的高光噪点(类似盐粒噪声),用高斯滤波怎么调都去不干净,换成中值滤波,核大小设 3,一遍就干净了。

# 中值滤波
denoised = cv2.medianBlur(img, 3)  # 核大小 3

核心区别:

  • 高斯滤波:适合去除高斯噪声,保留边缘能力中等
  • 中值滤波:适合去除椒盐噪声,保留边缘能力强
  • 光效提取场景:先中值去噪,再高斯平滑,效果最好

3.3 形态学操作:让光效形状更「干净」

形态学操作处理的是二值图像(黑白图)。它的核心思想是用一个「结构元素」去探测图像中的形状。我常用它来修正光效提取后的掩码——去掉孤立噪点、填补空洞、平滑边缘。

3.3.1 膨胀与腐蚀:最基础的两个操作

膨胀:让白色区域「变胖」。结构元素扫过图像,只要窗口内有一个白点,中心就变白。
腐蚀:让白色区域「变瘦」。只有窗口内全是白点,中心才保留白色。

操作 效果 光效提取中的应用
膨胀 扩大高光区域,连接断裂部分 修复光效掩码中的细小断裂
腐蚀 缩小高光区域,去除孤立噪点 去掉误检的零星光点
# OpenCV 形态学操作
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

dilated = cv2.dilate(mask, kernel, iterations=1)
eroded = cv2.erode(mask, kernel, iterations=1)

3.3.2 开运算与闭运算:组合拳更实用

实际项目中我很少单独用膨胀或腐蚀,而是用它们的组合:

  • 开运算:先腐蚀后膨胀 → 去除小白点噪点,保持主体大小不变
  • 闭运算:先膨胀后腐蚀 → 填补小空洞,连接邻近区域

我记得有一次做舞台灯光提取,光效掩码里全是细小的断裂(因为灯光闪烁导致亮度不均)。闭运算跑一遍,iterations=2,断裂全接上了,效果立竿见影。

# 开运算 & 闭运算
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
参数调优建议:结构元素大小一般从 3x3 开始试。iterations 不要超过 3,否则形状会严重变形。我通常先闭运算修复断裂,再开运算去噪,顺序别搞反。

3.4 本章知识体系总览

下面这张图把本章的核心逻辑串起来了。你可以把它当作一个「操作决策树」:拿到一张光效图,先做什么后做什么,一目了然。

图像处理基础 · 知识体系 输入图像 像素操作 点运算 · 邻域运算 · 几何变换 图像滤波 高斯滤波 · 中值滤波 形态学操作 膨胀 · 腐蚀 · 开闭运算 预处理后的图像 光效提取典型流程 输入 → 中值滤波去噪 → 通道分离 → 阈值分割 → 闭运算修复断裂 → 开运算去噪 → 输出干净光效掩码

3.5 实战建议:先搭框架,再调参数

学完这一章,你可能会觉得「操作好多,记不住」。我的建议是:别死记参数,先记住每种操作能解决什么问题。

  • 图像有噪点 → 滤波
  • 光效区域有断裂 → 闭运算
  • 光效区域有杂点 → 开运算
  • 需要调整亮度范围 → 像素点运算