这一篇在干嘛?
二维信号处理实战:图像格式与基本操作、HDL 边缘检测、中值滤波、VGA 系统、视频运动检测协处理器。 原书代码为 VHDL,本篇所有代码已改写为 Verilog。
- 图像和视频处理
- 10.1 图像和视频处理概述
- 10.2 案例研究 1: HDL 中的边缘检测
- 10.3 案例研究 2: 使用图像处理库进行中值滤波
- 10.4 案例研究 3: 视频处理中的运动检测由自定义协处理器改进
- 练习
自测一下
RGB 与 YUV 各是什么?为什么要转 YUV?
RGB 是三原色分量;YUV 是亮度+色度。人眼对亮度敏感、色度不敏感,转 YUV 后可对色度降采样省带宽,压缩/传输标准都基于 YUV。
3×3 中值滤波为什么比均值滤波好?
中值滤波取中间值,能完全去除椒盐噪声而保住边缘;均值滤波会把噪声扩散成模糊斑。中值排序网络的实现用比较器树,FPGA 友好。
Sobel 边缘检测的原理?
用水平/垂直两个 3×3 差分核分别卷积,得到梯度分量 Gx/Gy,幅值超过阈值即判定边缘。二维卷积用行缓存+乘加阵列实现。
运动检测的基本思路?
相邻帧做差分(或背景建模),变化超过阈值判为运动区域。视频流处理需要帧缓存与流水线设计,常用协处理器+软核分工:硬件做像素级运算,软核做决策。
图像和视频处理
如果说一维 DSP 处理的是随时间变化的波形,那么图像处理就是把信号”升了一个维度”——多出一个空间坐标 ;视频处理则再升一维,加入时间。好消息是,前面学过的滤波、FFT 等算法大部分都能直接推广到二维、三维;但也有一些内容是纯一维世界里完全不出现的:
- 去除脉冲噪声的非线性滤波器(中值、最大/最小滤波等);
- 用于发现视觉不连续点的边缘检测,目的是压缩输入特征、保留最有用的信息;
- 视频中的运动向量,用来描述一个数据块如何从上一帧移动到下一帧,是视频压缩的核心工具;
- 形态学图像处理,这类操作在一维 DSP 中根本没有对应物。
为什么这本书要专门用 FPGA 讲图像处理?关键在硬件条件的变化:现代 FPGA 配备了大容量片内存储块(例如 Stratix II 有 512 Mbit 的片上存储),图像处理算法中大量的行缓存、帧缓存可以直接放在片内,实现效率大幅提升。放在过去没有快速片上存储的年代,工程师必须花费大量开发时间去搭建与外部存储芯片(DDRAM、QDR、RLDRAM、SDRAM 等)的接口,门槛高得多。
实现图像处理算法有几种典型路线:1) 直接用 HDL 设计;2) 使用 IP 库;3) 嵌入式微处理器加定制协处理器(μP)。本章的案例研究会覆盖这些方法。初学者建议先在 MATLAB 的图像处理和计算机视觉工具箱中练习,UNIX 系统上还有集成了许多算法的图形程序 XV 可以参考。
在进入二维、三维细节之前,先弄清楚一维处理、图像和视频在格式与基本处理上的差异。
10.1 图像和视频处理概述
一维处理与图像处理有一个根本性的态度差别:一维滤波强调因果性——输出只能依赖过去时刻的输入,否则硬件不可实现;而图像处理面对的是一整幅已经存好的数据,我们并不希望每次滤波都把图像”翻转”一遍。于是图像处理中的惯例是:
- 使用”类因果”滤波:用滤波器输出替换中心像素;
- 只用 、 方向都为奇数长度的滤波器,如 、、,这样才存在真正的”中心像素”;
- 滤波器用**核(掩模)**定义而不是卷积运算。对尺寸 的核,输出为
注意这里没有做卷积要求的翻转——如果真按卷积定义来,矩阵运算前信号要先翻转 180°,图像处理中通常省略这一步。
边界效应
二维中比一维更突出的另一个问题是边界效应:一个 的掩模在 的图像上滑动时,掩模一旦出界就无法完整计算,损失的像素数为
计算示例:拉普拉斯-高斯(LoG)滤波器取 时核尺寸 ,作用在 的图像上,丢失像素数为 ,占整幅图的 ——将近四分之一的边界面积没了!这个损失相当可观。
就保持边界而言,IIR 滤波器理论上表现更好(不需要掩模完整覆盖),但由于非线性相位和稳定性问题,图像处理中很少使用。更常见的做法是把图像向外扩展半个核宽,扩展方式有四种:
- 常数值填充,通常取 ;
- 对称扩展:…3,2,1 | 1,2,3,…(镜像);
- 复制边界值:…1,1,1 | 1,2,3,…;
- 圆形(环绕)扩展:…,8,9,10 | 1,2,3…,8,9,10 |。
行方向和列方向都要做同样的扩展。
硬件中的折中:一行偏移
真正做硬件时,图像数据通常以一维流的方式进出,我们常采用类似”圆形扩展、只偏移一行”的近似:
| … 1 2 | 3 4 5 | 10 11 12 … |
|---|---|---|
| 3 4 5 | 10 11 12 | 13 14 … |
也就是第一行的末尾值(3、4、5)直接接到第二行的开头参与计算,第二行的开头值(10、11、12)与第一行的末尾一并处理。这种”跨行借用”只有在假设图像边界是背景、且整幅图背景相似时才合理——大多数自然图像满足这一点,所以工程上很实用。
10.1.1 图像格式
数字图像中最基本的单元叫像素,常用 8 位表示(医学成像可达 12 位)。编码约定是:0 代表黑,最大值(8 位格式即 255)代表白。
彩色怎么来?全彩色谱只用三种基色——红、绿、蓝(RGB)就能合成;从灰度图转 RGB 时三个通道赋相同的灰度值即可。但人眼有个特点:对亮度变化比对颜色变化敏感得多,所以实用的编码方案把灰度(亮度 Y)和差分色度分开传输——亮度用更高的精度/分辨率,色度可以适当压缩,图像质量几乎不降。RGB 中三通道位数相同,没有利用这一特性,于是在电视、JPEG、MPEG 中流行两种分离方案:YIQ 和 YUV(也叫 YCrCb)。
NTSC 电视系统采用的 YIQ 编码变换为:
ITU BT.601-5 建议的 YCrCb 方案则是:
考虑到 8 位量化下亮度范围限定在 16~220(留工作余量)、色度零电平在 128,ITU 给出整数化映射:
Altera 视频处理工具箱采用略有修改的近似(亮度范围 16 至 ,色度最大 ):
分辨率与显示顺序
传统图像显示在阴极射线管(CRT)显示器上:像素从左上角开始,从左到右扫完一行,再回到左边开始下一行。分辨率用”先水平 后垂直 “的像素数表示,常见有 、、、。坐标排列如下:
| (0,0) | (0,1) | … | (0,C-1) |
|---|---|---|---|
| (1,0) | (1,1) | … | (1,C-1) |
| ⋮ | ⋮ | ||
| (R-1,0) | (R-1,1) | … | (R-1,C-1) |
视频处理中,典型图像大小是 宏块的倍数,最流行的是 的通用中间格式(CIF)和 的四分之一 CIF(QCIF)。
彩色图像的每个像素由 R、G、B 三个子像素组成,但并非所有格式都按这个顺序存储——例如流行的原始 BMP 格式从左下角开始,到右上角结束。大多数格式对灰度数据用 8 位、每个 RGB 分量也用 8 位;典型的图像文件以包含行列数、颜色表、压缩方案等信息的文件头开始,随后才是图像数据。有些格式支持无损或有损压缩(如 GIF、JPEG)。只有少数静止图像格式(JPEG、JPEG-2000)由 ISO/IEC/ITU 等国际委员会定义,其余很多由公司定义,知识产权未必完全清晰。MATLAB 的 imread() 函数支持下述所有格式。
BMP:不压缩的原始图像格式,使用 RGB 颜色表、每分量 8 位,也允许用少于 24 位编码(例如只存常用颜色的 8 位颜色表放进文件头;8 位灰度则不需要颜色表)。DE2 演示工程(DE2_Default)用的就是它,在嵌入式 μP 设计中也很流行;DE2 板附带的 BMP2MIF 转换器教程见逻辑教材附录 F。
GIF:包含无损图像压缩,做 PPT 幻灯片是好选择,也常被用来做小动画(GIF 动画)。
PNG:另一种无损压缩方案,常用于网页。PNG 采用差分编码,但不使用 GIF 的 Lempel-Ziv-Welch(LZW)压缩算法,因此不需要 LZW 的许可证费用。
| 格式 | Int.STD | 无损压缩 | 有损压缩 | MATLAB |
|---|---|---|---|---|
| BMP | - | - | - | √ |
| GIF | - | √ | LZW | √ |
| PNG | - | √ | DPCM | √ |
| JPEG | √ | √ | DCT | √ |
| JPEG-2K | √ | √ | DWT | √ |
JPEG:唯一官方静止图像标准之一
JPEG 标准(即 ITU-T 建议 T.81)可在 CCITT 网页免费下载。注意一个细节:标准只规定了解码器,没有限制编码器,给实现改进留了空间。图 10-1 是基本 DCT 有损压缩的主要编码与解码步骤。

图 10-1 JPEG 压缩方案
流程是这样的:8 位输入图像(假定灰度;彩色图像通常先用式 10.1 的 YIQ 或式 10.2 的 YCrCb 变换)被划分为互不重叠的 块,做二维 DCT。因为二维 DCT-II 在 、 方向可分离,实现时先对八行做一维变换,再对八列做变换。DC 分量(块内均值)位于 数据块左上角。之后用不同的表量化亮度和色度 DCT 系数——标准第 143 页建议的亮度量化表见图 10-2(a)。
| 16 | 11 | 10 | 16 | 24 | 40 | 51 | 61 |
|---|---|---|---|---|---|---|---|
| 12 | 12 | 14 | 19 | 26 | 58 | 60 | 55 |
| 14 | 13 | 16 | 24 | 40 | 57 | 69 | 56 |
| 14 | 17 | 22 | 29 | 51 | 87 | 80 | 62 |
| 18 | 22 | 37 | 56 | 68 | 109 | 103 | 77 |
| 24 | 35 | 55 | 64 | 81 | 104 | 113 | 92 |
| 49 | 64 | 78 | 87 | 103 | 121 | 120 | 101 |
| 72 | 92 | 95 | 98 | 112 | 100 | 103 | 199 |
(a) 量化表

(b) AC 系数的 Zig-zag 编码
图 10-2 JPEG 压缩方案细节
表中的值是解码端重构 DCT 值时要乘的系数;编码端则先除以这些值再四舍五入到整数——把昂贵的除法负担放在编码器一侧。从量化表可以看出:左上(低频)量化因子小,用更多比特表示;右下(高频)量化因子大,8 位输入的高频系数通常只剩 0 或 ±1。随后按”之字形”顺序排列系数,编码器对第一个非零系数对编码,用块结束(EOB)符号终止整个块,见图 10-2(b)。
由于相邻块的 DC 值(即 块内所有像素的平均值)通常相近,DC 先做差分编码(),再做霍夫曼编码:先用 4 位编码”大小”,再编码差值本身:
| 4位SSSS | DIFF 值 |
|---|---|
| 0 | 0 |
| 1 | -1, 1 |
| 2 | -3, -2, 2, 3 |
| 3 | -7,…,-4, 4,…,7 |
其余 63 个 AC 系数用可变游程长度编码(VLC),格式为(零游程长度,下一个值),各用 4 位;游程长于 15 时插入特殊符号 (15,0),EOB 用 (0,0) 编码。
计算示例:DCT 编码系数
先依据前一个块的 DC 值译出 DC,AC 系数则译码为:
其中 (0,3) 表示”零游程 0、数值 3”,(2,-1) 表示”跳过 2 个零后是 -1”,依次类推,(0,0) 即 EOB。DCT 值还可以再用霍夫曼编码进一步压缩;标准附录 K 给出了需写入 JPEG 文件头的 DC/AC 亮度和色度示例表。编码表通常是中等偏高压缩率的——这也是很多文件的实际压缩比不如预期的原因之一。
图 10-3 给出了几个 JPEG 编码结果:低压缩比时 JPEG 与 BMP 几乎看不出差别;高压缩时则能看到 DCT 分块带来的块效应。

(a) 原始 BMP 图像(677KB)

(b) Q20 的 JPEG 低压缩图像(53KB)

(c) Q1 的 JPEG 高压缩图像(22KB)
图 10-3 JPEG 压缩结果
JPEG-2000:从小波出发的新工具箱
JPEG-2000 可以看作原始 JPEG 的更新版,但有几处实质性变化。最核心的是: DCT 块处理被 DWT(离散小波变换) 取代——有损压缩通常用浮点 Daubechies 9/7 小波滤波器,无损压缩用 5/3 整数滤波器。初始 DWT 之后进行量化与算术编码,见图 10-4。

图 10-4 JPEG-2000 压缩方案
JPEG-2000 是 ISO、IEC/ITU 多个小组的联合成果,遗憾的是标准规范文档并不免费(本书写作时售价 96 瑞士法郎),不过有许多出版物把基本思想讲得很清楚。新标准不是单一算法,而是一个”工具箱”,其中最有趣的特点有:
- 低比特率下性能卓越——DWT 天然避免了经典 JPEG 的块效应;
- 同时支持无损与有损压缩;
- 感兴趣区域(ROI)编码:允许对图像中特别重要的部分(例如说话者的面部相对背景)用更高质量编码;
- 通过同步标记、固定长度编码器和重复报头增强抗比特错误鲁棒性;
- 通过水印、标签、冲压和加密实现图像安全。
代价是复杂度更高。JPEG-2000 通常以比 JPEG 更高的计算复杂度换取更好的 PSNR、MSE 或 SSIM。如果应用需要高质量或低比特率,或需要安全性等特性,就选 JPEG-2000。
10.1.2 基本图像处理操作
图像/视频工具箱里最常用的基本操作包括:
- 改变图像尺寸,增减处理的像素数;
- 裁剪出感兴趣区域(ROI);
- 旋转图像;
- 对一幅或多幅图像做加、减、乘、除和平均;
- 彩色↔灰度转换;
- 以 BMP、GIF、JPEG 等格式读取和存储图像。
点操作
基于像素自身值进行变换的叫点操作。典型用途包括调整整体过亮/过暗的图像,或依据局部/全局像素统计(直方图)进行调整。CRT 显示器必备的点操作是 γ 校正,对 8 位数据:
时是指数型曲线,图像变暗; 时是对数型曲线,图像变亮。例如 的曲线在低输入区抬升缓慢、在高输入区快速上升,暗部被进一步压暗; 则相反,暗部被大幅提亮。NTSC 电视系统采用 。

(a)

(b)

(c)
图 10-5 γ 校正示例
滤波操作
图像滤波可线性可非线性,作用对象不只是单个像素,还包括相邻像素,多数用于图像增强。大多数线性方法也可以在变换域(FFT、DCT)中求解。几个典型例子:
- 低通滤波器消除随机噪声;
- 差分滤波器检测边缘;
- 最大值滤波器去除胡椒噪声(因为黑色编码为 0,取邻域最大值就把黑点抹掉了);
- 最小值滤波器去除盐噪声(因为白色编码为 255,取最小值把白点抹掉);
- 中值滤波器同时抑制盐和胡椒噪声;
- 去抖滤波器,消除相机移动时反褶积滤波造成的模糊;
- 自适应维纳滤波器去噪。
图像压缩(静止图像与视频)是活跃的研究领域,许多方法利用了人眼的物理特性——对低频变化比对高频变化更敏感。这类变换编码通常再结合可变长度编码、霍夫曼编码或算术编码等(无损)熵编码。图像/视频处理中最流行的二维变换是 FFT、DCT 和 DWT,Haar 变换、Hartley 变换等二维形式也有使用。
形态学操作
形态操作用于增强信息或减小模式识别系统的输入空间,基本动作是”在邻域中添加像素”(增厚,即膨胀/dilation)和”删除邻域中的像素”(稀疏,即侵蚀/erosion)。膨胀产生更多像素,使线条变粗、填拢小孔;侵蚀使线条变细,并去掉”单个像素”这类小噪声区域。两者通常组合使用:先侵蚀后膨胀称为开运算(opening),先膨胀后侵蚀称为闭运算(closing)。开、闭都能平滑物体轮廓,闭运算还能填充小孔和间隙。
这些操作可定义在灰度图像和黑白(BW)图像上,BW 更常见。灰度图的形态操作通常就是邻域内的最大/最小操作;BW 图则定义邻域掩模以何种规则替换像素。
图 10-6 展示了用 MATLAB 函数 bwmorph 和 bwperim 的若干形态操作:开运算能去掉手写文本下的背景横线(图 10-6(b));骨架化是一系列侵蚀与开运算的组合,为每个对象生成中心线,让所有对象的结构像 X 光片里的骨骼一样显现(图 10-6(c));边界提取可以先对图像用掩模 M 侵蚀,再用图像减法计算 ,其中 表示侵蚀,结果得到边界/周边图(图 10-6(d))。此外,“多数黑色”操作在邻域中多数像素为黑时把当前像素置黑,作用类似膨胀,对边缘检测也有帮助。