用 Matlab 做一套“水果识别系统”,是数字图像处理课程里出现频率很高的综合实践题目。很多同学能做到“灰度化 + 边缘检测 + 显示几张图”就停了,但一旦把目标改成“给一张含有苹果、香蕉、橘子的图片,让程序自动说出图中是什么水果”,就需要把图像预处理、图像分割、特征提取、模式识别这几个模块真正串起来。这次我们看的这套【源码32期】Matlab 水果识别系统,就是围绕这个完整流程做的数字图像处理项目。它适合做课程设计、毕业设计的前期验证,也适合刚学完图像处理基础、想用 Matlab 独立完成一个小系统的读者。
这套系统最值得关注的地方有三个:第一,它不是只做单一算法的演示,而是从图像读入到分类结果输出形成了一条完整的技术链路;第二,识别过程用到了颜色特征、形状特征等经典数字图像处理方法,原理在冈萨雷斯《数字图像处理》里都能找到对应章节,便于写报告;第三,系统提供 GUI 交互界面,操作过程直观,适合答辩演示。下面先给出核心能力速览,再逐步拆解源码结构、实现思路、运行方式和常见坑点。
1. Matlab 水果识别系统核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | Matlab 数字图像处理综合项目,图像分类识别系统 |
| 主要功能 | 水果图像预处理、图像分割、颜色/形状特征提取、分类识别、GUI 演示 |
| 运行环境 | Windows / macOS / Linux 上的 Matlab,推荐 R2018b 及以上版本 |
| 依赖工具箱 | Image Processing Toolbox,GUI 功能依赖 App Designer 或 GUIDE |
| 硬件门槛 | 普通办公电脑即可,不需要 GPU;处理速度取决于图片分辨率和算法复杂度 |
| 启动方式 | 在 Matlab 中打开主程序文件并运行,或通过编译后的独立应用运行 |
| 可扩展方向 | 增加训练样本、更换分类器、加入深度学习模型、做实时摄像头识别 |
| 适合场景 | 数字图像处理课程设计、Matlab 综合实验、图像分类入门研究、答辩演示 |
需要提前说明一点:本文不是某个固定版本的逐行代码解读。因为【源码32期】这类项目在流传过程中经常存在函数命名、目录结构、GUI 布局不一致的情况,更稳妥的做法是把“水果识别系统应该包含哪些模块、每个模块怎么实现、遇到问题怎么排查”讲清楚,再根据你自己拿到的源码目录对号入座。
2. 适用场景与使用边界
2.1 适合谁使用
如果你正在做数字图像处理课程设计,题目是“基于 Matlab 的水果识别系统”,这套源码的参考价值很明显。它覆盖了图像处理课程中最核心的几个环节:读图、灰度化、去噪、分割、特征提取、分类。每个环节都可以在报告里单独展开,工作量容易写清楚。
如果你是刚接触 Matlab 图像处理的学生,也可以通过这套系统理解“从图像到特征再到类别”的完整流程。只看教材里的函数说明,很难体会到为什么先要做分割、为什么特征要归一化。跑一遍真实系统,比单纯看语法更有效。
如果你是准备做毕业设计的前期验证,可以把这套系统当作一个基线版本。先用传统图像处理思路跑通水果识别,再慢慢把分类器换成 SVM 或者卷积神经网络,形成一个“传统方法 + 深度学习方法”的对比实验。
2.2 使用边界与合规提醒
这类源码主要用于教学和实验验证。使用时有几点要注意:
第一,数据集的版权。源码自带的样本图片来源不明时,只能用于本地学习和课程作业验证,不能随意打包传播,更不能直接用于商业演示。如果要做正式实验,建议自己用手机拍摄水果照片,按类别整理成数据集。
第二,课题要求的边界。如果学校要求独立完成,源码只能作为思路参考,不能直接原样提交。把别人源码改成加注释、换图片,仍然是抄袭风险。
第三,识别系统的局限性。传统图像处理方法对背景复杂度、光照变化非常敏感。拍一张白底苹果图能识别,换到自然场景果园里可能就不稳定。报告里要如实写系统的适用条件和误差来源,不要夸大精度。
第四,如果后续扩展为真实应用场景,比如果园产量统计、农产品分拣,需要遵守相关数据采集和设备使用规范。涉及他人果园、他人肖像的场景,必须取得授权。
3. Matlab 水果识别系统环境准备与前置条件
3.1 安装 Matlab 与工具箱
运行该系统前,先确认本机 Matlab 版本。传统数字图像处理代码兼容性较好,R2018b、R2020a、R2022b、R2023a 都能跑,并不一定需要最新版本。但要注意两点:
第一,必须安装 Image Processing Toolbox。没有这个工具箱,rgb2gray、imread、imshow、bwlabel等核心函数会直接报错。
第二,如果源码包含 .mlapp 文件,需要 App Designer 支持;如果包含 .fig 文件,可能是 GUIDE 创建,R2016a 之后 GUIDE 虽然在更新列表里逐步弱化,但已经生成的 .fig 文件大多仍能在新版 Matlab 中打开。
检查工具箱是否安装完整,可以在 Matlab 命令行执行:
ver输出列表里应能看到 Image Processing Toolbox 对应版本。如果列表里没有,需要重新运行 Matlab 安装程序,勾选所需工具箱。
3.2 工作目录与路径设置
拿到源码包后,先解压到不含中文路径的目录。这是 Matlab 新手最容易忽略的问题。很多老代码内部使用相对路径读图片,如果整个工程放在C:\Users\张三\桌面\水果识别系统,运行时可能出现找不到文件或编码异常。
建议按下面结构整理工程目录:
FruitRecognition/ ├── main.m % 主程序入口 ├── data/ % 样本图片 │ ├── apple/ │ ├── banana/ │ └── orange/ ├── src/ % 核心算法函数 │ ├── preprocess.m │ ├── segment.m │ ├── extractFeatures.m │ └── classifyFruit.m ├── gui/ % GUI 相关文件 │ ├── fruit_gui.mlapp │ └── fruit_gui.fig └── results/ % 输出结果目录然后在 Matlab 中把当前文件夹切换到工程根目录,或者右键文件夹选择“添加到路径”。如果遇到Undefined function错误,第一步先检查被调用的函数文件是否在当前工作目录或搜索路径中。
3.3 硬件需求
Matlab 水果识别系统的计算量远低于深度学习模型,普通办公电脑和轻薄本都能运行。图像预处理和特征提取是 CPU 计算,不会调用 GPU。如果处理 4K 超清图片速度较慢,先用imresize把图像缩小到合适尺寸即可。不需要单独准备显卡配置。
4. 源码工程结构与功能模块划分
一套标准的水果识别系统源码,通常不会只有一个文件,而是按模块拆分成多个函数。拿到源码后建议先浏览目录结构,找到下面几类文件。
| 文件类型 | 常见文件名 | 作用 |
|---|---|---|
| 主脚本 | main.m、FruitRecognition.m | 程序入口,串联整个识别流程 |
| GUI 入口 | .mlapp、.fig、*.m | 可视化交互界面 |
| 图像预处理函数 | preprocess.m、myFilter.m | 灰度化、滤波去噪、增强 |
| 图像分割函数 | segment.m、segByColor.m | 分割出水果目标区域 |
| 特征提取函数 | extractFeatures.m、getColorFeat.m | 提取颜色、形状等特征 |
| 分类函数 | classifyFruit.m、knnClassifier.m | 完成水果种类判别 |
| 辅助工具 | showResult.m、plotFigures.m | 显示中间过程和结果 |
在 Matlab 编辑器中打开主文件,使用Depends On功能可以快速查看整个工程调用了哪些自定义函数和工具箱函数,这是理解源码结构最高效的方式。也可以选中函数名后按Ctrl + D直接跳转到函数定义位置。
5. 水果图像预处理与图像分割实现
5.1 图像读取与灰度化
系统第一步是把彩色图像读入工作区。传统水果识别通常先转灰度图,降低后续计算量。代码框架大致如下:
% 读取图像 img = imread('data/apple/apple_01.jpg'); figure; imshow(img); title('原始水果图像');如果是背景复杂或者光照不均匀的图片,直接使用原始图像做分割效果不稳定。此时把 RGB 转为灰度图,再用直方图均衡化增强前景与背景的对比度:
% RGB 转灰度 grayImg = rgb2gray(img); % 直方图均衡化,增强对比度 enhancedImg = histeq(grayImg); figure; imshow(enhancedImg); title('增强后灰度图像');注意:部分水果的颜色差异在灰度图上不明显。比如红苹果和青苹果在灰度上可能接近,但属于不同类别,这时候灰度图只适合做目标区域的粗提取,真正分类时仍然需要回到彩色空间提取颜色特征。
5.2 滤波去噪
拍摄图像或读取过程中会引入噪声。教材里最常用的是中值滤波和高斯滤波。中值滤波对椒盐噪声抑制效果突出,高斯滤波对高斯噪声更有效。水果识别系统里,使用中值滤波可以同时保留边缘信息,避免水果轮廓被过度平滑:
% 3x3 中值滤波去噪 filteredImg = medfilt2(enhancedImg, [3 3]);如果运行到medfilt2报错,说明当前输入不是二维灰度图像。确保前面已经执行过rgb2gray。
5.3 图像分割:从背景中分离水果目标
图像分割是水果识别系统的关键环节。分割质量直接影响后续特征提取和分类精度。最常用的方法是基于阈值分割。假设背景是浅色或均匀色,水果与背景有明显灰度差异:
% 自动计算阈值 level = graythresh(filteredImg); bw = imbinarize(filteredImg, level); % 形态学操作去除小噪声、填充孔洞 bw = imopen(bw, strel('disk', 3)); bw = imfill(bw, 'holes'); figure; imshow(bw); title('分割后的二值图像');基于灰度阈值分割实现简单,但彩色背景下容易误分割。彩色水果识别系统往往不直接在灰度图上分,而是转换到 HSV 颜色空间,通过 H 分量范围提取特定颜色区域。
% 转换为 HSV 色彩空间 hsvImg = rgb2hsv(img); H = hsvImg(:, :, 1); S = hsvImg(:, :, 2); V = hsvImg(:, :, 3); % 以红色水果为例,提取红色区域 redMask = (H >= 0.9 | H <= 0.05) & (S > 0.3) & (V > 0.2);HSV 颜色空间对光照变化更鲁棒,是水果识别系统里非常常见的处理方法。如果你的源码里包含类似rgb2hsv的调用,那说明它在颜色分割上做了专门优化,而不是简单灰度阈值。
分割完成后,通过bwlabel标记连通区域,找出面积最大的区域作为水果目标:
labeled = bwlabel(bw); stats = regionprops(labeled, 'Area', 'BoundingBox', 'Centroid'); % 找出面积最大的连通区域 [~, idx] = max([stats.Area]); % 裁剪出水果区域,返回给后续特征提取 bbox = stats(idx).BoundingBox; fruitRegion = imcrop(img, bbox);这段代码也是报告里强调“基于区域的分割方法”时常用的核心操作。
6. 水果颜色特征与形状特征提取
6.1 为什么不直接用像素值分类
图像分割完成后,每个水果区域仍然包含大量像素,直接把这些像素作为分类器输入会产生维度灾难。水果识别系统需要把图像区域压缩成一组数值特征。以苹果、香蕉、橙子三类为例,理想特征应该满足:同一水果不同照片的特征尽量接近,不同水果的特征差异尽量明显。
6.2 颜色特征提取
颜色特征是水果识别最直接的特征。Matlab 中常用的颜色特征包括 RGB 各通道均值、HSV 各分量均值与方差。一般统计分割后水果区域的像素:
function feat = extractColorFeatures(rgbRegion) % 分离 RGB 通道,只统计水果区域像素 R = rgbRegion(:, :, 1); G = rgbRegion(:, :, 2); B = rgbRegion(:, :, 3); % 计算各通道均值 meanR = mean(R(:)); meanG = mean(G(:)); meanB = mean(B(:)); % 转换 HSV 提取色调信息 hsvRegion = rgb2hsv(rgbRegion); H = hsvRegion(:, :, 1); S = hsvRegion(:, :, 2); V = hsvRegion(:, :, 3); meanH = mean(H(:)); meanS = mean(S(:)); meanV = mean(V(:)); feat = [meanR, meanG, meanB, meanH, meanS, meanV]; end除了均值,颜色矩也是数字图像处理中提取颜色特征的基础方法。颜色矩利用一阶矩均值、二阶矩方差、三阶矩偏度描述颜色分布,不需要把颜色空间量化,特征维度低,适合小样本分类。
6.3 形状特征提取
形状特征可以区分颜色接近但外形不同的水果。例如青苹果和青枣颜色可能相近,但圆形度、面积、周长差异明显。常见形状特征包括:
| 形状特征 | 计算公式 | 说明 |
|---|---|---|
| 面积 | 区域内像素总数 | 图像大小不同时需归一化 |
| 周长 | 区域边界长度 | 用regionprops的Perimeter获取 |
| 圆形度 | 4pi面积 / 周长^2 | 越接近 1 越圆 |
| 离心率 | 区域拟合椭圆参数 | 香蕉较长,离心率通常高于苹果 |
| 矩形度 | 面积 / 最小外接矩形面积 | 反映物体规则程度 |
Matlab 中可以直接通过regionprops获取这些参数:
props = regionprops(bw, 'Area', 'Perimeter', 'Eccentricity', 'Extent', 'MajorAxisLength', 'MinorAxisLength'); area = props.Area; perimeter = props.Perimeter; circularity = 4 * pi * area / (perimeter ^ 2); eccentricity = props.Eccentricity; extent = props.Extent;形状特征与颜色特征拼接后,一行一个样本,构成最终特征向量。特征向量的维度不需要太多,6 个颜色特征加上 4 到 5 个形状特征,已经足够支撑课程设计级别的分类任务。
6.4 特征归一化
不同特征的量纲差异很大。面积可能达到数千,颜色均值在 0 到 255 之间,圆形度在 0 到 1 之间。如果直接把原始特征送入分类器,面积会主导距离计算。正确的做法是先对特征做归一化或标准化:
% 假设 features 是 N x M 的特征矩阵,每行是一个样本 mu = mean(features); sigma = std(features); featuresNorm = (features - mu) ./ sigma;源码里如果没有归一化步骤,分类准确率会明显下降。你可以自己补上这一步,并在报告中作为“实验改进”部分写出前后性能对比。
7. 水果分类识别算法与实验评价
7.1 分类流程
在特征提取完成后,水果识别就变成了标准的分类问题。一个典型的流程是:对训练集中的每张图片提取特征,组成训练矩阵;为新输入的测试图片提取特征,计算其与训练样本之间的距离或通过分类器决策,输出水果类别。
作为演示系统,源码里最常见的分类器是 KNN(K 近邻)和朴素贝叶斯,因为它们不需要训练耗时过程,代码量少,易于在小样本上解释。
如果源码里没有现成分类器,用 Matlab 自带的fitcknn可以快速构建一个 KNN 分类模型:
% 假设 trainFeatures 是已归一化的训练特征 % trainLabels 是类别标签,如 {'apple';'apple';'banana';...} % 训练 KNN 分类器 mdl = fitcknn(trainFeaturesNorm, trainLabels, 'NumNeighbors', 3); % 预测测试样本 predictLabel = predict(mdl, testFeatureNorm); disp(['识别结果:', char(predictLabel)]);如果训练样本数量较多,也可以使用fitcecoc实现多分类 SVM。这里不展开复杂调参,课程设计级别通常用默认参数就能得到不错效果。
7.2 分类精度评价
写报告时不能只给一张识别成功截图,应该统计准确率并给出混淆矩阵。把数据集分成训练集和测试集,测试集比例通常取 10% 到 30%。
% 使用交叉验证评价分类器性能 cvmdl = crossval(mdl, 'KFold', 5); classLoss = kfoldLoss(cvmdl); accuracy = 1 - classLoss; fprintf('交叉验证准确率:%.2f%%\n', accuracy * 100);如果多类测试结果不均衡,比如橘子总是被识别成橙子,需要回到特征提取部分检查颜色特征是否有效区分了这两种类别。也可以通过confusionchart可视化混淆矩阵,在答辩时展示更具说服力。
7.3 常见改进方向
源码集里提供的是基线版本。算法层面可以做的改进很多:
第一,分割算法从固定阈值替换为自适应阈值或 K-means 聚类分割。K-means 分割在彩色图像中效果更精细,适合背景复杂的水果图像。
第二,分类器从 KNN 升级为 SVM 或随机森林。不同分类器在同特征集上的表现可以做对比实验。
第三,增加纹理特征。利用灰度共生矩阵(GLCM)提取能量、对比度、相关性等纹理参数,可以提升对果皮纹理差异的判别力。
第四,用深度学习模型替代传统特征提取。直接用预训练模型如 ResNet 提取图像特征,在小数据集上做迁移学习。不过这就脱离了“数字图像处理课程设计”的范畴,更适合毕业设计阶段的扩展。
8. GUI 交互界面设计与运行操作
8.1 界面整体功能
源码中的 GUI 通常包含以下几个区域:
| 界面区域 | 功能 |
|---|---|
| 图像显示区 | 显示原始图像和识别结果 |
| 功能按钮 | 打开图片、开始识别、清空结果 |
| 参数设置区 | 选择分割阈值、分类方法 |
| 结果文本区 | 显示识别出的水果名称和置信度 |
运行 GUI 主文件后,点击按钮即可完成交互式操作,这也是答辩中最容易讲解的部分。
8.2 在 Matlab 中运行 GUI
如果主文件是.mlapp:
% 在命令行输入文件名运行 fruit_gui如果主文件是.m脚本:
fruit_recognition如果主文件是.fig:
% 先加载 fig,再通过 handle 调用回调函数 guide; open('fruit_gui.fig');运行时如果报错说找不到按钮回调函数,检查.fig文件与回调函数是否在同一个文件夹。常见错误是把.fig复制到新文件夹,但回调函数的.m文件没有一并复制。
8.3 GUI 界面调用的核心流程
GUI 和命令行版本的区别只在外层交互。点击“识别”按钮后,在按钮回调函数内部执行的核心算法与本文第 5 到 7 节描述完全一致。排查 GUI 问题时也要回到算法函数去验证,不要只盯着按钮事件。
9. Matlab 水果识别系统批量测试与结果分析
9.1 为什么要做批量测试
单张图片识别成功不能证明系统有效。准备测试集时,应该包含每个水果类别多张不同背景、不同光照、不同角度的照片。如果用同一张图片既训练又测试,会得到虚高的准确率,答辩时很容易被老师戳穿。
9.2 批量测试脚本示例
写一个循环脚本,遍历测试目录内所有图片并输出识别结果:
clc; close all; clear; % 指向测试图片目录 testDir = 'data/test'; categories = {'apple', 'banana', 'orange'}; % 记录统计 total = 0; correct = 0; for ci = 1:length(categories) categoryPath = fullfile(testDir, categories{ci}); imageFiles = dir(fullfile(categoryPath, '*.jpg')); for fi = 1:length(imageFiles) imgPath = fullfile(categoryPath, imageFiles(fi).name); img = imread(imgPath); predictLabel = recognizeFruit(img); % 调用识别函数 actualLabel = categories{ci}; total = total + 1; if strcmp(predictLabel, actualLabel) correct = correct + 1; disp(['正确:', imgPath, ' -> ', predictLabel]); else disp(['错误:', imgPath, ' -> ', predictLabel, ',真实标签:', actualLabel]); end end end fprintf('测试样本总数:%d\n', total); fprintf('识别正确数:%d\n', correct); fprintf('准确率:%.2f%%\n', correct / total * 100);这里的recognizeFruit函数需要你在源码提供的单张识别流程上自行封装,把读图、预处理、分割、特征提取、分类识别串起来。如果源码已经提供这类识别函数,直接调用即可。
9.3 典型结果分析与报告写作
批量测试后,你至少应该得到三组数据:总体准确率、每个类别的准确率、识别错误的图片清单。报告里不要只说“该系统能识别苹果香蕉橙子”,要具体到“在 90 张测试图片上总体准确率为 93.3%,其中苹果识别率为 96.7%,香蕉为 90%”。错误图片通常集中在背景复杂、遮挡、颜色相近等场景,分析这些失败案例反而能体现你对图像处理原理的理解深度。
10. Matlab 常见安装与运行问题排查
10.1 常见问题表格
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 启动 Matlab 后找不到 m 文件 | 工作目录未切换 | 检查当前文件夹路径 | cd切换到源码目录 |
报错Undefined function 'imread' | 缺少图像处理工具箱 | 执行ver查看工具箱 | 重新安装 Image Processing Toolbox |
报错Undefined function 'rgb2gray' | 输入不是彩色图像或工具箱缺失 | 检查图片通道数 | 用size(img,3)确认通道数 |
| 打开 fig 文件空白 | GUIDE 组件缺失或回调函数丢失 | 检查同目录.m文件 | 补充对应回调文件 |
| GUI 点击按钮无反应 | 回调函数路径错误 | 打开 .m 查看按钮回调名 | 将回调文件加入搜索路径 |
| 中文乱码 | 文件编码不兼容 | 查看源码注释乱码位置 | 改用英文路径与英文文件名 |
| 分割结果包含大面积背景 | 阈值选取不合适 | 显示中间二值图 | 调整阈值或改用颜色空间分割 |
| 识别结果总偏向某一类 | 各类训练样本数不均衡 | 查看样本分布 | 增加少数类训练样本 |
| 处理速度很慢 | 图片分辨率过高或代码循环较多 | 查看是否用循环逐像素处理 | 使用向量化运算或imresize压缩图片 |
提示License checkout failed | Matlab 许可证问题 | 查看许可证状态 | 检查授权文件或重新激活 |
10.2 排查问题的通用逻辑
在 Matlab 中运行源码时遇到报错,不要急着问别人。先在命令行执行dbstop if error,再运行主程序,报错后 Matlab 会自动停在出错行,使用dbstack查看调用栈,就知道错误来自哪个函数、哪一行。
如果错误出在你没看过的工具箱函数里,优先怀疑前面的输入数据格式不对。例如函数要求输入 double 类型,你传入的是 uint8 类型;函数要求输入灰度图像,你传入彩色图像。
11. 最佳实践与使用建议
11.1 先跑通灰度版本,再优化彩色版本
第一次运行源码时,不要追求完美的分割效果。先用一张白底、光照均匀的图片,把整个预处理到分类识别的流程跑通,确认主函数没有报错。流程通了,再换成不同背景和光照的图片观察效果差异。
11.2 建立自己的数据集
只靠源码自带图片做实验,很难体现自己的工作。建议用手机拍摄 5 类水果、每类 30 张以上,统一缩放到合理分辨率,按类别放在不同文件夹,并分成训练集和测试集。自己做数据集的过程中,会自然地遇到光照不均、阴影、反光等问题,这些问题就是报告中的“难点与改进”。
11.3 保留中间过程图像
数字图像处理报告非常看重过程展示。在预处理、分割、特征提取每个环节后都使用figure; imshow(...)或imwrite保存结果。报告中放一张包含原始图、灰度图、二值图、分割结果、识别标记的对比图,能显著提升工作量表现。
11.4 检查图像尺寸与类型
使用whos命令查看变量类型。很多图像处理函数要求特定数据范围,例如 double 类型时像素值范围为 0 到 1,uint8 类型时范围为 0 到 255。混用时先做类型转换:
imgDouble = im2double(img);11.5 合理使用搜索资源
Matlab 官方文档中的图像处理函数说明、冈萨雷斯《数字图像处理》教材、以及各高校数字图像处理课程实验资料,都可以作为源码理解与报告撰写的辅助。搜索“Matlab水果识别系统”相关博客时,重点看实现思路和常见错误,不要直接整段复制,实验代码和报告文字都建议用自己的语言重写。
12. 总结与后续扩展方向
Matlab 水果识别系统最值得尝试的点,是它把数字图像处理课程里零散的知识点组合成了一个完整可演示的项目。从读入一张图片开始,完成灰度化、去噪、分割、特征提取、分类识别,每一步都有可视化输出,非常适合用来检验自己对图像处理基础知识的掌握程度。
拿到这套源码后,最先应该做的是准备几张不同背景的水果测试图,跑通main函数或 GUI 入口,记录每张图的识别结果。最容易踩的坑有两个:一是工作目录或路径设置不对导致找不到函数或图片,二是分割环节没有根据水果颜色特性选择合适的特征空间,导致背景和水果混在一起。
后续可以扩展的方向也比较明确:把固定阈值分割替换成 K-means 彩色分割,增加 GLCM 纹理特征,把 KNN 分类器换成 SVM 并做交叉验证,甚至通过摄像头实时采集图像做动态识别。对想深入数字图像处理的同学来说,这套系统算得上一个实用的起点。建议收藏备用,做课程设计或实验报告时可以直接对照参考。