Qt+OpenCV图像视觉框架全套源码上位机 基于 Qt5.12.12 + VS2019 + OpenCV 开发实现,支持多相机多线程,每个工具都是单独的 DLL,主程序通过公用的接口访问以及加载各个工具

Qt+OpenCV图像视觉框架全套源码上位机
工具可扩展。
除了opencv和相机sdk的dll,其它所有算法均无封装,可以根据自己需要补充自己的工具。
基于 Qt5.12.12 + VS2019 + OpenCV 开发实现,支持多相机多线程,每个工具都是单独的 DLL,主程序通过公用的接口访问以及加载各个工具。
包含涉及图像算法的工具、 逻辑工具、通讯工具和系统工具等工具。

 

QMacVisual

视觉使用说明书

attention-98513_640.png

使用前请务必仔细阅读本手册.

错误操作可能造成人身伤害及设备损坏.

操作人员必须熟知并遵守安全规则.

windeployqt *.exe

目录

1.软件架构 4

2.图像处理 8

2.1 获取图像 8

2.2 创建ROI 9

2.3 裁切图像 10

2.4 图像翻转 10

2.5 预处理 11

2.6 图像修复 13

2.7 图像旋转 14

2.8 图像拼接 14

2.9 图像显示 15

2.10 透视变换 16

2.11 图像细化 17

2.12 导出图像 18

3.检测识别 19

3.1 条形码识别 19

3.2 斑点分析 19

3.3 亮度检测 21

3.4 颜色识别 21

3.5 图像清晰度 22

3.6 二维码识别 23

3.7 轮廓特征选择 23

3.8 分类器 25

4.标定工具 26

4.1 畸变标定 26

4.2 N点标定 27

4.3 测量标定 29

5.对位工具 31

5.1 目标跟踪 31

5.2 线性计算 31

5.3 灰度匹配 32

5.4 形状匹配 33

6.几何工具 35

6.1 寻找圆 35

6.2 寻找直线 37

6.3 拟合圆 38

6.4 拟合椭圆 38

6.5 拟合直线 39

6.6 获取边界点 40

7.几何测量 41

7.1 线圆交点 41

7.2 线线交点 41

7.3 点+线 42

7.4 点+点 43

7.5 查找圆缺角 44

7.6 边缘宽度测量 45

8.三维检测 46

8.1 拟合平面 46

9.逻辑工具 47

9.1 扩展库 47

9.2 跳转语句 48

9.3 判断语句 48

9.4 结束语句 49

9.5 脚本编辑 49

10.通讯工具 52

10.1 通用I/O 52

10.2 PLC通信 53

10.3 串口通信 56

10.4 TCP/IP通信 57

11.系统工具 57

11.1 延时 57

11.2 导出CSV 58

1.软件架构

基于Qt5.12.12+OpenCV4.6.0的通用化视觉软件,支持多相机多线程,每个工具都是单独的DLL,主程序通过公用的接口访问以及加载各个工具。算法工具包含图像处理、检测识别、标定工具、对位工具、几何工具、几何测量、三维检测、逻辑工具、通讯工具和系统工具。

❧ 主画面

主画面包含标题栏、工具栏、状态栏、工具箱、流程图、显示窗体和运行日志。

❧ 用户登录与权限管理

①用户登录:该画面用于解锁权限后,对主画面相关按钮进行操作;

②权限管理:该画面用于用户名称和用户密码的查询、用户添加或删除。

❧ 设置

☛ 相机设置

先搜索相机后,再添加选择的相机。

☛ 仪器通讯

(1)通用IO

(2)PLC通信

(3)串口通信

说明:串口通信列表数量或连接状态改变后,需要更新流程的串口通信设置。

(4)TCP/IP通信

说明:①服务器连接后,需要在流程新建TCP/IP通信工具后,客户端才能连接;②TCP/IP通信列表数量或连接状态改变后,需要更新流程的TCP/IP通信设置。

☛ 全局变量

☛ 图像布局

☛ 系统参数

2.图像处理

2.1 获取图像

☛ 基本设置

①本地图像:用于读取本地的单个图像;

②文件夹:用于读取本地文件夹里的所有图像;

③相机:用于相机实时取像。

☛ 标定设置

①链接参数方式:用于畸变标定时校正图像采用的方式;

②读取标定文件方式:用于畸变标定时校正图像采用的方式。

2.2 创建ROI

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②输入轮廓:创建ROI所用到的轮廓,轮廓为vector<vector<cv::Point>>数据类型;

③创建的ROI类型:输出的ROI类型包括矩形和旋转矩形。

2.3 裁切图像

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②ROI对象:ROI类型包括矩形、旋转矩形、圆形和多边形。

2.4 图像翻转

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②翻转类型:类型包括不翻转、上下翻转、左右翻转和上下左右同时翻转。

2.5 预处理

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②预处理类型:类型包括图像操作、阈值处理、图像滤波、形态运算和图像增强。

➷图像操作

➷阈值处理

➷图像滤波

➷形态运算

➷图像增强

☛ ROI设置

①ROI对象:ROI类型包括矩形、旋转矩形、圆形和多边形。

2.6 图像修复

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②最小阈值:修复图像部分的灰度最小阈值;

③最大阈值:修复图像部分的灰度最大阈值;

④半径:修复图像部分的邻域半径。

输入合适的阈值和半径,修复后的图像如下所示:

2.7 图像旋转

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②旋转角度:图像旋转的角度。

2.8 图像拼接

☛ 基本设置

①图像对象:输入拼接所需要的图像;

②配置分辨率:该值越小拼接速度越快,但匹配点变少。

2.9 图像显示

☛ 图像设置

①输入图像:工具算法处理所用到的图像;

②窗体编号:显示图像的窗体号;

③轮廓对象:轮廓特征选择工具生成的轮廓。

☛ 文本设置

①显示位置:全局变量的QPoint数据类型;

②状态链接:选择链接的状态,作为结果判断为OK或NG;

③显示内容:输出文本的内容。

2.10 透视变换

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②输入点:图像区域透视变换前的4个点,全局变量cv::Point2f数据类型;

③输出点:图像区域透视变换后的4个点,全局变量cv::Point2f数据类型。

2.11 图像细化

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②迭代次数:图像细化的次数。

☛ ROI设置

①ROI对象:ROI类型包括矩形、旋转矩形、圆形和多边形。

2.12 导出图像

☛ 设置

①输入图像:工具算法处理所用到的图像;

②存储路径:保存图像的文件夹;

③文件名称:全局变量QString类型。

 

3.检测识别

3.1 条形码识别

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②支持的条形码类型:类型包括EAN8、EAN13、UPC-A;

③相乘系数:图像相乘时的系数,用于提高识别率。

3.2 斑点分析

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②面积:Blob特征检测器根据面积进行筛选;

③灰度值:Blob特征检测器根据阈值和黑白颜色进行筛选;

④圆度:Blob特征检测器根据圆度进行筛选;

⑤凸度:Blob特征检测器根据凸度进行筛选;

⑥惯性:Blob特征检测器根据惯性率进行筛选,圆形的偏心率等于0, 椭圆的偏心率介于0和1之间,直线的偏心率接近于0。惯性率与偏心率的关系如下:

E*E + I*I = 1 其中,E表示偏心率,I表示惯性率

☛ ROI设置

①使用ROI:ROI类型包括矩形、旋转矩形、圆形和多边形;

②显示ROI:在图像显示工具显示该ROI。

3.3 亮度检测

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②最小/最大亮度:小于最小亮度/大于最大亮度时,输出状态为False。

3.4 颜色识别

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②H通道颜色最大值:HSV颜色空间的H通道颜色最大值;

③S通道颜色最大值:HSV颜色空间的S通道颜色最大值;

④最小颜色相似度:相似度若小于该值,输出状态为False。

☛ ROI设置

①使用ROI:ROI类型为矩形;

②位置跟随:链接匹配基准中心,用于位置跟随;

③显示ROI:在图像显示工具显示该ROI。

3.5 图像清晰度

☛ 基本设置

①文件夹路径:工具算法处理所用到的图像所在文件夹路径;

②清晰度算法:算法包括Tenengrad梯度算法、Laplacian梯度算法和SMD灰度差分绝对值之和算法。

3.6 二维码识别

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②支持的二维码类型:类型为QRCode;

③相乘系数:图像相乘时的系数,用于提高识别率。

3.7 轮廓特征选择

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②轮廓的检索模式:检索模式包括RETR_EXTERNAL、RETR_LIST、RETR_CCOMP和RETR_TREE;

③轮廓的近似方法:近似方法包括CHAIN_APPROX_TC89_KCOS、CHAIN_APPROX_TC89_L1、CHAIN_APPROX_NONE和CHAIN_APPROX_SIMPLE;

④轮廓的形状特征:形状特征包括area、max_area、contlength、vertices、circle_radius、rectangularity、inner_width、inner_height、row、column、rect2_len1、rect2_len2、rect2_phi、ellipse_lena、ellipse_lenb和ellipse_phi;

⑤轮廓特征的链接类型:链接类型有and和or。

☛ ROI设置

①使用ROI:ROI类型包括矩形、旋转矩形、圆形和多边形;

②显示ROI:在图像显示工具显示该ROI。

☛ 输出显示

3.8 分类器

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②图像标签文件:包含图像标签信息的.txt文件;

③图像列表文件:包含图像所在路径信息的.txt文件;

④模型文件:用于预测图像类别的.xml文件。

☛ 参数设置

①图像类别数量:需要分类的类别数;

②图像类别名称:需要写入图像类别的名称。

4.标定工具

4.1 畸变标定

☛ 基本设置

①文件夹路径:工具算法处理所用到的图像所在文件夹路径;

②畸变参数:找出标定板圆点所需要的Blob参数。

☛ 输出显示

4.2 N点标定

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②标定示意图:机器人按图示的轨迹运动。

☛ 找圆工具

①扫描方向:扫描方向有外到内和内到外;

②灰度方向:灰度方向有白到黑和黑到白;

③边缘强度:扫描点的阈值比较;

④分割数量:圆分割线的数量;

⑤剔除距离:大于剔除距离的点不参与拟合圆计算。

☛ 标定设置

①九点标定参数:输入获取得到的9个点的图像坐标和机械坐标。

①标定方式:标定方式有三点拟合圆标定和两点+角度标定;

②基准角度:标准Mark的基准角度。

☛ 输出显示

4.3 测量标定

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②标定模式:标定模式有比例模式和测量模式;

③灰度方向:灰度方向有白到黑和黑到白;

④边缘强度:扫描点的阈值比较;

⑤分割数量:卡尺分割线的数量;

⑥剔除距离:大于剔除距离的点不参与拟合计算;

⑦实际尺寸:图像测量区域所对应的实际尺寸;

⑧测量方向:测量方向有X方向像素和Y方向像素。

☛ ROI设置

①使用ROI:ROI类型为卡尺;

②显示ROI:在图像显示工具显示该ROI;

③ROI宽度:在图像显示工具显示ROI时的线条宽度;

④交叉线长度:标记寻找到的边界点交叉线的长度。

5.对位工具

5.1 目标跟踪

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②使用ROI:ROI类型为矩形;

③S通道颜色最小值:HSV颜色空间的S通道颜色最小值;

④显示线宽:显示目标跟踪的线宽;

⑤中值滤波核大小:用于平滑图像时的滤波核大小。

5.2 线性计算

线性计算用于计算Robot移动量(使用旋转中心)、计算Robot移动量(不使用旋转中心)和图像坐标系统→世界坐标系统。

5.3 灰度匹配

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②模板区域:使用矩形选取模板所在的区域;

③模板匹配模式:匹配模式有TM_CCORR、TM_CCORR_NORMED和TM_CCOEFF_NORMED;

④图像金字塔层数:图像采样时用到的层数;

⑤匹配个数:匹配到的模板个数;

⑥搜索角度范围:搜索模板的角度范围;

⑦最低分数:搜索到模板的最低分值;

⑧重叠区域比例:;搜索到模板的重叠区域比例大小。

☛ ROI设置

①使用ROI:ROI类型为矩形;

②显示ROI:在图像显示工具显示该ROI。

☛ 输出显示

5.4 形状匹配

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②模板区域:使用矩形选取模板所在的区域;

③搜索角度范围:搜索模板的角度范围;

④特征点:特征点的数量;

⑤弱阈值:提取特征点的弱阈值;

⑥强阈值:提取特征点的强阈值;

⑦图像金字塔层数:图像采样时用到的层数,建立模板时设置;

⑧匹配个数:匹配到的模板个数(一个/多个);

⑨最低分数:搜索到模板的最低分值;

⑩重叠区域比例:;搜索到模板的重叠区域比例大小。

☛ ROI设置

①使用ROI:ROI类型为矩形;

②显示ROI:在图像显示工具显示该ROI。

☛ 输出显示

6.几何工具

6.1 寻找圆

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②扫描方向:扫描方向有外到内和内到外;

③灰度方向:灰度方向有白到黑和黑到白;

④边缘强度:扫描点的阈值比较;

⑤分割数量:圆分割线的数量;

⑥剔除距离:大于剔除距离的点不参与拟合圆计算。

☛ ROI设置

①使用ROI:ROI类型为圆环;

②位置跟随:链接匹配基准中心,用于位置跟随;

③显示ROI:在图像显示工具显示该ROI。

6.2 寻找直线

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②扫描方向:扫描方向有左到右、右到左、上到下和下到上;

③灰度方向:灰度方向有白到黑和黑到白;

④边缘强度:扫描点的阈值比较;

⑤分割数量:卡尺分割线的数量;

⑥剔除距离:大于剔除距离的点不参与拟合直线计算。

☛ ROI设置

①使用ROI:ROI类型为卡尺;

②位置跟随:链接匹配基准中心,用于位置跟随;

③显示ROI:在图像显示工具显示该ROI。

6.3 拟合圆

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②轮廓点集:用于拟合圆的轮廓点集,vector<cv::Point2f>数据类型。

6.4 拟合椭圆

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②轮廓点集:用于拟合椭圆的轮廓点集,vector<cv::Point2f>数据类型。

6.5 拟合直线

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②轮廓点集:用于拟合直线的轮廓点集,vector<cv::Point2f>数据类型。

6.6 获取边界点

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②最小阈值:边缘检测Canny算法的最小阈值;

③最大阈值:边缘检测Canny算法的最大阈值;

④Sigma值:高斯滤波的Sigma值;

⑤剔除比例:获取边界点的剔除比例。

☛ ROI设置

①使用ROI:ROI类型有矩形和圆形;

②显示ROI:在图像显示工具显示该ROI。

7.几何测量

7.1 线圆交点

☛ 全局变量设置

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②构建参数:构建参数有直线斜率/截距方式和直线两点方式。

7.2 线线交点

☛ 全局变量设置

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②构建参数:构建参数有直线斜率/截距方式和直线两点方式。

7.3 点+线

☛ 全局变量设置

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②构建参数:构建参数有直线斜率/截距方式和直线两点方式。

7.4 点+点

☛ 全局变量设置

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②构建参数:输入的两点坐标。

7.5 查找圆缺角

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②扫描方向:扫描方向有外到内和内到外;

③灰度方向:灰度方向有白到黑和黑到白;

④边缘强度:扫描点的阈值比较;

⑤分割数量:圆分割线的数量;

⑥缺口差值:大于该值的点为缺口位置的点。

☛ ROI设置

①使用ROI:ROI类型为圆环;

②位置跟随:链接匹配基准中心,用于位置跟随;

③显示ROI:在图像显示工具显示该ROI。

7.6 边缘宽度测量

☛ 基本设置

①输入图像:工具算法处理所用到的图像;

②灰度方向:灰度方向有白到黑和黑到白;

③边缘强度:扫描点的阈值比较;

④分割数量:卡尺分割线的数量;

⑤剔除距离:大于剔除距离的点不参与宽度计算。

☛ ROI设置

①使用ROI:ROI类型为卡尺;

②位置跟随:链接匹配基准中心,用于位置跟随;

③显示ROI:在图像显示工具显示该ROI。

8.三维检测

8.1 拟合平面

☛ 全局变量设置

☛ 基本设置

①输入点集X:double类型的数组;

②输入点集Y:double类型的数组;

③输入点集Z:double类型的数组;

④三维输入点:cv::Point3d类型的输入点。

9.逻辑工具

9.1 扩展库

☛ 扩展库参数

①输入图像:工具算法处理所用到的图像;

②动态库文件路径:.dll所在的文件路径。

☛ 扩展库示例

9.2 跳转语句

☛ 基本设置

①判断方式:方式有Bool链接和计算表达式;

②Bool数据链接:当链接的状态为true时发生跳转;

③表达式链接:当链接的表达式条件满足时发生跳转;

④跳转到工具:发生跳转时,选择跳到的工具名称。

9.3 判断语句

☛ 基本设置

①判断方式:方式有Bool链接和计算表达式;

②Bool数据链接:当链接的状态为true时进行下一步流程;

③表达式链接:当链接的表达式条件满足时进行下一步流程。

9.4 结束语句

☛ 基本设置

①判断方式:方式有Bool链接和计算表达式;

②Bool数据链接:当链接的状态为true时停止下一步流程;

③表达式链接:当链接的表达式条件满足时停止下一步流程。

9.5 脚本编辑

☛ 基本设置

(1)Vision方法

①设置全局变量值(ProjectSetGlobalValue):用于设置全局的变量值;

②获取当前时间(GetCurrentTime):用于获取当前的时间;

③ProjectGetGlobalValue:用于获取全局的变量值;

④GetFlowToolValue:用于获取流程工具的变量值;

⑤GetArraySize:用于获取数组的大小;

⑥ConvertToPoint:用于获取QPoint或cv::Point数据里的x和y值;

⑦ConvertToPoint2f:用于获取QPointF或cv::Point2f数据里的x和y值;

⑧ConvertToPoint3f:用于获取cv::Point3f数据里的x、y和z值;

⑨ConvertToPoint3d:用于获取cv::Point3d数据里的x、y和z值;

⑩ConvertToArrayInt:用于获取Int数组里的某个值;

⑪ConvertToArrayBool:用于获取Bool数组里的某个值;

⑫ConvertToArrayFloat:用于获取Float数组里的某个值;

⑬ConvertToArrayDouble用于获取Double数组里的某个值;

⑭ConvertToArrayQString用于获取QString数组里的某个值;

⑮ConvertToArrayCvPoint2f用于获取cv::Point2f数组里的某个值。

(2)Log方法

①LogInfo:用于输出Info类型的Log信息;

②LogWarn:用于输出Warn类型的Log信息;

③LogError:用于输出Error类型的Log信息。

(3)脚本示例

//示例1

var state = true;

if (state == true)

{

ProjectSetGlobalValue(“变量名”, “值”);

}

//示例2

for (var i=0;i<3;i++)

{

LogInfo(GetCurrentTime());

}

//示例3(数组类型)

var array= ProjectGetGlobalValue(“变量名”);

var count = GetArraySize(array);

for (var i=0;i<count;i++)

{

LogInfo(ConvertToArrayFloat(array, i));

}

//示例4(QPoint或cv::Point类型)

var p = ProjectGetGlobalValue(“变量名”);

var p_x = ConvertToPoint(p, “x”);

var p_y = ConvertToPoint(p, “y”);

//示例5(QPointF或cv::Point2f类型)

var p2f = ProjectGetGlobalValue(“变量名”);

var p2f_x = ConvertToPoint2f(p2f, “x”);

var p2f_y = ConvertToPoint2f(p2f, “y”);

//示例6(cv::Point3f类型)

var p3f = ProjectGetGlobalValue(“变量名”);

var p3f_x = ConvertToPoint3f(p3f, “x”);

var p3f_y = ConvertToPoint3f(p3f, “y”);

var p3f_z = ConvertToPoint3f(p3f, “z”);

//示例7(cv::Point3d类型)

var p3d = ProjectGetGlobalValue(“变量名”);

var p3d_x = ConvertToPoint3d(p3d, “x”);

var p3d_y = ConvertToPoint3d(p3d, “y”);

var p3d_z = ConvertToPoint3d(p3d, “z”);

//示例8(Float[]类型)

var array_float = ProjectGetGlobalValue(“变量名”);

var f_element = ConvertToArrayFloat(array_float, 0); //0表示获取数组索引0位置的值

//示例9(Double[]或vector<Double>类型)

var array_double = ProjectGetGlobalValue(“变量名”);

var d_element = ConvertToArrayDouble(array_double, 0); //0表示获取数组索引0位置的值

//示例10(vector<QString>类型)

var code = GetFlowToolValue(“条形码识别.条形码”);

var str = ConvertToArrayQString(code, 0); //0表示获取数组索引0位置的值

//示例11(vector<cv::Point2f>类型)

var center_points = GetFlowToolValue(“轮廓特征选择.重心”);

var p1_x = ConvertToArrayCvPoint2f(center_points,0, “x”); //0表示获取数组索引0位置的值

var p1_y = ConvertToArrayCvPoint2f(center_points,0, “y”); //0表示获取数组索引0位置的值

//示例12(QVector<Bool>类型)

var input = GetFlowToolValue(“通用I/O.输入点”);

var state = ConvertToArrayBool(input, 0); //0表示获取数组索引0位置的值

//示例13(QVector<int>类型)

var plc = GetFlowToolValue(“PLC通信.寄存器读取数据”);

var data = ConvertToArrayInt(plc, 0); //0表示获取数组索引0位置的值

10.通讯工具

10.1 通用I/O

☛ 基本设置

①IO卡型号:连接的IO卡型号为DAM-E3021N;

②IO输入点:DAM-E3021N卡的输入点信号;

③IO输出点:DAM-E3021N卡的输出点信号。

10.2 PLC通信

☛ 基本设置

①通讯名称:按下“更新列表”按钮后,选择相应的通讯名称;

②链接对象:读取或写入的PLC寄存器链接地址。

①通信数据代码:包含ASCII码和二进制码;

②通信模式:包含读和写两种模式;

③通信访问方式:包含字和双字;

④寄存器地址:PLC的寄存器地址;

⑤寄存器写入值:写模式时,PLC的寄存器地址写入的数值。

10.3 串口通信

☛ 基本设置

①通讯名称:按下“更新列表”按钮后,选择相应的通讯名称;

②发送内容:发送内容为全局变量的QString类型;

③接收内容:接收内容为串口仪器发来的内容。

10.4 TCP/IP通信

☛ 基本设置

①通讯名称:按下“更新列表”按钮后,选择相应的通讯名称;

②发送内容:发送内容为全局变量的QString类型;

③接收内容:接收内容为服务器或客服端发来的内容。

11.系统工具

11.1 延时

11.2 导出CSV

☛ 基本设置

①文本标题列数量:标题的列数,第一列默认为时间;

②标题名称:用于输入各列的标题名称;

③存储路径:用于存储CSV文件的文件夹路径。

☛ 内容设置

①文本各列内容:链接各列的文本内容。