4.3 图像处理与ndimage


文档摘要

4.3 图像处理与ndimage 本节摘要:scipy.ndimage 把图像当作 N 维数组,提供滤波、形态学、连通域标记与几何变换等基础操作。高斯滤波擅长对付高斯噪声,中值滤波擅长对付椒盐噪声;形态学四件套在二值图上工作;label 与 findobjects 完成连通域计数与对象定位。本节用一张合成图跑通全流程,并划清 scipy.ndimage 与 skimage 的分工边界。 4.3 图像处理与ndimage 核心问题 阅读完本节,你应当能够: 用 gaussianfilter 与 medianfilter 去噪,并按噪声类型选择方法; 解释形态学膨胀、腐蚀、开运算、闭运算的效果,并能组合出目标操作; 用 label 与 findobjects 完成连通域计数与对象切片定位;

4.3 图像处理与ndimage

本节摘要:scipy.ndimage 把图像当作 N 维数组,提供滤波、形态学、连通域标记与几何变换等基础操作。高斯滤波擅长对付高斯噪声,中值滤波擅长对付椒盐噪声;形态学四件套在二值图上工作;label 与 find_objects 完成连通域计数与对象定位。本节用一张合成图跑通全流程,并划清 scipy.ndimage 与 skimage 的分工边界。

4.3 图像处理与ndimage

核心问题

阅读完本节,你应当能够:

  1. 用 gaussian_filter 与 median_filter 去噪,并按噪声类型选择方法;
  2. 解释形态学膨胀、腐蚀、开运算、闭运算的效果,并能组合出目标操作;
  3. 用 label 与 find_objects 完成连通域计数与对象切片定位;
  4. 用 rotate、zoom 做几何变换,并说清插值阶数的取舍;
  5. 说清 scipy.ndimage 与 skimage 的边界,遇到图像问题知道去哪里找工具。

一、问题与直觉

图像在 SciPy 眼里就是二维数组:灰度图的每个像素是一个数字,整张图就是一个矩阵;彩色图则是三个通道叠起来的三维数组。有了这个视角,上一节的一维滤波经验可以平移过来,而且几乎不用改思维。

场景是显微镜照片。成像过程混入了随机坏点,有的像素突然变白、有的突然变黑,这就是椒盐噪声。我们想在不破坏真实结构的前提下把坏点抹掉。先上最小代码:

import numpy as np from scipy import ndimage rng = np.random.default_rng(0) img = np.zeros((128, 128)) img[30:90, 40:100] = 1 # 白色矩形作为目标 salt = rng.random(img.shape) < 0.05 # 撒 5% 的椒盐噪声 img[salt] = 1 - img[salt] clean = ndimage.median_filter(img, size=3)

median_filter 把每个像素替换成周围 3 乘 3 邻域的中位数。孤立坏点不可能成为邻域的中位数,所以会被直接清除;而矩形边缘两侧的像素差异大,取中位数依然能保住边界。这一段代码就是本节的最小入口——和上一节的 lfilter 一样,三行跑通,再谈原理。

同样是这张图,如果目标是工业质检——数一数传送带上有几个零件、每个零件多大——光去噪还不够,还需要把连成片的白色区域逐个分开计数,这就是后面连通域标记要解决的问题。先记住这个场景,它决定了我们为什么要学 label。

二、核心原理

2.1 高斯滤波与中值滤波的分工

gaussian_filter 是加权平均:以像素为中心,按高斯权重把邻域值混合,sigma 控制权重的扩散范围。它对高斯噪声(每个像素叠加一个随机扰动,整张图灰蒙蒙)效果好,代价是边缘被模糊。median_filter 是排序操作:取邻域的中位数,对椒盐噪声有天然免疫力,而且几乎不伤边缘——中位数不依赖极端值,坏点再黑再白也影响不了它。

选择依据是噪声类型,不是个人喜好。传感器暗电流造成的噪声更像高斯噪声,用高斯滤波;传输丢包、扫描脏点造成的黑白坏点,用中值滤波。怎么判断?看一眼图像:噪声是"满屏灰蒙蒙"还是"零星黑白点",答案就出来了。

参数上有个容易忽视的点:高斯核的实际尺寸由 sigma 决定,ndimage 的 gaussian_filter 默认截断在 3 倍 sigma 处,sigma 取 3 时核要覆盖约 7 乘 7 的邻域才够。核太小等于没滤,核太大图像糊成一片。选 sigma 的实用办法:从 1 起步,每次加 0.5,直到噪声消失而边缘还在。

方法 原理 擅长 代价 对应噪声
gaussian_filter 加权平均 高斯噪声 模糊边缘 均匀叠加型
median_filter 邻域中位数 椒盐噪声 计算稍慢 孤立坏点型

2.2 形态学操作

形态学处理二值图,核心是结构元素——一个小模板,通常 3 乘 3 或 5 乘 5,可以是方形也可以是十字形。四种基本操作:

膨胀:模板覆盖范围内只要有 1,中心就变 1,白色区域向外扩张,效果是填补小孔、连接断开的线段。腐蚀:模板覆盖范围内必须全是 1,中心才保留,白色区域向内收缩,效果是去掉细小的突起和孤立噪点。开运算:先腐蚀后膨胀,去掉小突起而保持主体大小基本不变。闭运算:先膨胀后腐蚀,填补小孔而保持主体大小基本不变。

类比一下:膨胀像涨潮,潮水把沙滩上脚印的边缘抹圆;腐蚀像风化,把石头的棱角慢慢磨掉;开运算是"把小石子冲走,再把原来的石头放回原处";闭运算是"把坑填平,再恢复原样"。这四个操作组合起来,可以清理二值图里几乎所有类型的瑕疵。

结构元素的形状影响结果:方形模板各向同性,十字模板只沿四个方向传播,对角线方向的细线用十字模板会被切断。多数场景方形 3 乘 3 够用,方向性明显的结构(血管、道路)才需要专门设计模板。顺带一提,ndimage 的形态学函数也能处理灰度图——把灰度当作高度场做膨胀腐蚀,对应灰度形态学,但工程上更常见的用法还是二值图。

2.3 label 与 find_objects

label 把二值图里连通的 1 区域逐个编号,返回两个东西:标记数组和区域个数。连通的定义有两种:4 连通只看上下左右四个邻居,8 连通把对角也算上。对角相接的两个像素,在 4 连通下算两个对象,在 8 连通下算一个——选哪个要看你的物理问题:晶粒计数常用 8 连通,电路板走线分析常用 4 连通。数细胞、找缺陷、检测零件,都是这一个函数起家。find_objects 更进一步,返回每个区域的切片,可以直接用来裁剪对象、做后续的尺寸测量或特征统计。

一段完整的计数代码长这样:labeled, n = ndimage.label(img_bool),对象个数就是 n;每个对象的像素数用 np.bincount(labeled.ravel()) 统计;find_objects 返回的切片可以直接取出单个对象。整套操作加起来不到十行,却是显微计数、缺陷统计这类任务的标准起手式。

2.4 rotate 与 zoom 几何变换

rotate 旋转图像,zoom 缩放图像,shift 平移。它们都涉及插值:变换后的网格点不一定落在原像素上,需要从周围像素估算灰度。order 参数控制插值阶数:0 是最近邻,最快但锯齿明显;1 是双线性,质量与速度的折中;3 是三次样条,最平滑但最慢。几何变换还有个边界问题——图像边缘外的值怎么取,ndimage 提供了多种边界模式,默认补零,旋转 45 度时四角会出现黑边,需要时改用反射模式更自然。rotate 默认会扩大画布以容纳旋转后的内容,图像尺寸随之改变;如果你的后续分析要求尺寸不变,设 reshape=False,多余部分按边界模式填充。zoom 的 zoom 参数可以逐轴指定,非均匀缩放时注意各轴插值阶数一致,否则会出现奇怪的条带。

几何变换在配准任务里通常成套出现:先旋转校正角度,再缩放统一尺度,最后平移对齐。ndimage 的这三个函数组合起来就是一套手动配准管线;自动配准(按图像内容自行寻找变换参数)则属于更高层的库,比如 skimage 的配准模块——又是那条分工线:原语在 ndimage,成套算法去 skimage。

2.5 与 skimage 的边界

scipy.ndimage 提供的是 N 维数组原语:滤波、形态学、连通域、几何变换。它在任意维度上工作,不假设你处理的一定是"图像"——三维体数据、时间序列的二维切片,它照单全收。skimage 是高层图像算法库:颜色空间转换、图像分割、特征检测、直方图均衡,它知道什么是图像。分工建议很直接:基础操作找 ndimage,高级视觉任务找 skimage。两者不冲突,实际项目经常混用——ndimage 做形态学清理,skimage 做分割和特征提取。

选择边界还有一个实际判断:如果你的数据本身是多维的,比如三维体数据、多光谱图像,ndimage 几乎是唯一选择,因为它是按任意维度设计的;skimage 的很多函数固定假设二维图像。反过来,一旦任务里出现"分割、特征、颜色"这些词,就该去 skimage 翻一翻,它的分割算法族比 ndimage 完整得多。记住这条分工线,能省下大量在错误目录里翻文档的时间。

能力 scipy.ndimage skimage
通用 N 维滤波与形态学 核心主场 有但非重点
颜色空间与图像读写
分割与特征检测
几何变换 有,封装更友好
定位 底层原语 高层算法

三、工程实践要点

3.1 二值图操作的顺序

常见管线:去噪 → 二值化 → 形态学清理 → 连通域标记 → 测量。形态学放在二值化之后,因为它只对 0 和 1 有意义;如果输入还是灰度图,先确认它已经被阈值化。顺序反了,形态学操作会把灰度梯度当成结构,结果一团糟。

3.2 参数速查

中值滤波的 size 用奇数,3 或 5 足够,太大把细小结构都抹了;高斯滤波的 sigma 按噪声强度取 1 到 3,sigma 越大越糊;形态学结构元素用小尺寸,3 乘 3 起步,结构元素比对象还大时,一次开运算就能把对象整个吞掉。标定这类参数时,建议拿一小块真实图像反复试,比抽象调参快得多。

还有个常见疑问:ndimage 能不能直接读图片文件?不能——读图属于 IO 职责,scipy 早期版本有过 imread,后来移除了,现在统一由 skimage、imageio 这类库负责。另一个高频坑是数据类型:图像读进来常常是 uint8,范围 0 到 255,滤波结果是浮点数,直接当灰度显示会溢出或全黑,记得先归一化、显示前用 clip 把数值夹到合法范围。

⚠️ 常见坑:彩色图像是三通道数组,直接把 ndimage 的滤波函数套上去,会跨通道混合颜色,得到彩虹一样的花纹。处理彩色图要么逐通道操作,要么先转灰度。
💡 关键直觉:先看噪声长什么样再选滤波器。灰度蒙层用高斯,黑白坏点用中值,这个判断比调任何参数都重要。

3.3 一张图看懂形态学四件套

下面这张示意图展示了原始二值图与三种操作的差别:膨胀让白色区域扩张,腐蚀让白色区域收缩并把孤立噪点吃掉,开运算恢复主体大小、噪点消失。判断形态学效果时,就看"主体大小"和"瑕疵去向"这两个指标。

图 4-3 图像形态学操作示意

图 4-3 图像形态学操作示意

本章回顾

  • 要点一:高斯滤波对付高斯噪声,中值滤波对付椒盐噪声,选择依据是噪声类型。
  • 要点二:形态学操作对象是二值图,开运算去小突起,闭运算填小孔。
  • 要点三:膨胀扩张白色区域,腐蚀收缩白色区域,两者组合出开闭运算。
  • 要点四:label 完成连通域编号与计数,find_objects 给出每个对象的切片。
  • 要点五:rotate、zoom 的 order 参数控制插值质量与速度的取舍。
  • 要点六:彩色图不能直接整体滤波,需要逐通道处理或转灰度。
  • 要点七:scipy.ndimage 是 N 维原语,skimage 是高层图像算法库,按任务层级选择。

知识备齐了,下一节进入实战:一段含工频干扰的振动信号,从频谱分析到滤波器设计再到效果验证,最后再处理一张带噪图像,把本章的武器全部用一遍。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U