halcon 条形码、二维码识别、opencv识别

news2025/2/21 21:36:39

一、条形码

函数介绍

create_bar_code_model

* 1.创建条码读取器的模板
* 参数一:通用参数的名称,针对条形码模型进行调整。默认值为空
* 参数二:针对条形码模型进行调整
* 参数三:条形码模型的句柄。
create_bar_code_model ([], [], BarCodeHandle)

 set_bar_code_param

* 参数一:条形码模型的句柄。
* 参数二:通用参数的名称,针对查找和解码条形码进行了调整
* 参数三:通用参数的值
set_bar_code_param (BarCodeHandle, 'stop_after_result_num', 1)

find_bar_code

* 3.在图像中读取条码数据和数据区域
* 参数一:要查找的图片
* 参数二:条码数据区域
* 参数三:条码模板句柄
* 参数四:条码类型
* 参数五:读取结果
find_bar_code (ImageReduced2, SymbolRegions, BarCodeHandle, 'auto', DecodedDataStrings)

效果 

 代码

* 1.创建条码读取器的模板
* 参数一:通用参数的名称,针对条形码模型进行调整。默认值为空
* 参数二:针对条形码模型进行调整
* 参数三:条形码模型的句柄。
create_bar_code_model ([], [], BarCodeHandle)

dev_set_color ('green')
dev_set_draw ('margin')

* 2.配置解码方式
* 参数一:条形码模型的句柄。
* 参数二:通用参数的名称,针对查找和解码条形码进行了调整
* 参数三:通用参数的值
set_bar_code_param (BarCodeHandle, 'stop_after_result_num', 1)
read_image (Image, 'D:/workplace/字符识别/Image_20250114144355733.bmp')
gen_rectangle2 (ROI_0, 2704.8, 2530.15, rad(0.89529), 882.925, 59.4154)
reduce_domain (Image, ROI_0, ImageReduced2)

* 用于将显示窗口的大小调整到适合图像大小的尺寸。
dev_resize_window_fit_image (ImageReduced2, 0, 0, -1, -1)

* 3.在图像中读取条码数据和数据区域
* 参数一:要查找的图片
* 参数二:条码数据区域
* 参数三:条码模板句柄
* 参数四:条码类型
* 参数五:读取结果
find_bar_code (ImageReduced2, SymbolRegions, BarCodeHandle, 'auto', DecodedDataStrings)
area_center (SymbolRegions, Area, Row, Column)

dev_close_window ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image)
dev_display (SymbolRegions)
disp_message (WindowHandle, DecodedDataStrings, 'image', Row+200, Column-500, 'black', 'true')

二、二维码

函数介绍:

create_data_code_2d_model

 *创建二维码模型
    * 创建二维码模型
    * 参数一:二维码类型
    * 参数二:通用参数的名称 针对二维数据代码模型进行了调整。
    * 参数三:针对二维数据代码模型进行了调整。
    * 参数四:数据代码模型的句柄。
    create_data_code_2d_model (_codeMode[Index1], 'default_parameters', 'maximum_recognition', DataCodeHandle)

 find_data_code_2d

    *检测二维码,最多可以检测到10个
    * 查找图形中二维码,并获取信息
    * 参数一:图片
    * 参数二:围绕成功解码数据的 XLD 轮廓 代码符号。
    * 参数三:二维码模型的句柄。
    * 参数四:参数的名称 控制操作员的行为。
    * 参数五:可选泛型参数的值。
    * 参数六:所有成功解码的二维数据代码的句柄 符号。
    * 参数七:所有检测到的二维数据代码的解码数据字符串 图像中的符号。
    find_data_code_2d (ImageEmphasize, SymbolXLDs, DataCodeHandle, 'stop_after_result_num', 10, ResultHandles, \
                       DecodedDataStrings)
    

效果1: 

效果2

代码


* 二维码读取
read_image (Image, 'C:/Users/Albert/Desktop/qr/2.bmp')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
*创建二维码类型列表
_codeMode:=['Aztec Code', 'Data Matrix ECC 200', 'GS1 Aztec Code', 'GS1 DataMatrix', \
            'GS1 QR Code', 'Micro QR Code', 'PDF417', 'QR Code']
*图像放大1.5倍
zoom_image_factor (Image, ImageZoomed, 1.5, 1.5, 'constant')
*图像锐化
emphasize (ImageZoomed, ImageEmphasize, 20, 20, 1)
*遍历二维码类型列表
for Index1 := 0 to |_codeMode| by 1
    *创建二维码模型
    * 创建二维码模型
    * 参数一:二维码类型
    * 参数二:通用参数的名称 针对二维数据代码模型进行了调整。
    * 参数三:针对二维数据代码模型进行了调整。
    * 参数四:数据代码模型的句柄。
    create_data_code_2d_model (_codeMode[Index1], 'default_parameters', 'maximum_recognition', DataCodeHandle)
    *设置超时500ms
    set_data_code_2d_param (DataCodeHandle, 'timeout', 500)
    *检测二维码,最多可以检测到10个
    * 查找图形中二维码,并获取信息
    * 参数一:图片
    * 参数二:围绕成功解码数据的 XLD 轮廓 代码符号。
    * 参数三:二维码模型的句柄。
    * 参数四:参数的名称 控制操作员的行为。
    * 参数五:可选泛型参数的值。
    * 参数六:所有成功解码的二维数据代码的句柄 符号。
    * 参数七:所有检测到的二维数据代码的解码数据字符串 图像中的符号。
    find_data_code_2d (ImageEmphasize, SymbolXLDs, DataCodeHandle, 'stop_after_result_num', 10, ResultHandles, \
                       DecodedDataStrings)
    
    *获取当前图像的二维码类型
    code_type := _codeMode[Index1]
    *如果检测到图像有二维码,就显示在窗体上
    if (|DecodedDataStrings| > 0)
        disp_message (WindowHandle, code_type+':'+DecodedDataStrings, 'window', 12, 12, 'black', 'true')
    endif
endfor

dev_clear_window ()

三、csharpopencv 识别二维码

 

C#中生成二维码(QR码)与读取二维码内容_c#将字符串生成二维码图片-CSDN博客

实用主义,完全是按照上面这位老哥抄的

 

gitee如下: 

OCRQR: 有百度的飞浆 C# opencv、以及其他开源软件的集合

四、全部代码

* 1.创建条码读取器的模板
* 参数一:通用参数的名称,针对条形码模型进行调整。默认值为空
* 参数二:针对条形码模型进行调整
* 参数三:条形码模型的句柄。
create_bar_code_model ([], [], BarCodeHandle)

dev_set_color ('green')
dev_set_draw ('margin')

* 2.配置解码方式
* 参数一:条形码模型的句柄。
* 参数二:通用参数的名称,针对查找和解码条形码进行了调整
* 参数三:通用参数的值
set_bar_code_param (BarCodeHandle, 'stop_after_result_num', 1)
read_image (Image, 'D:/workplace/字符识别/Image_20250114144355733.bmp')
gen_rectangle2 (ROI_0, 2704.8, 2530.15, rad(0.89529), 882.925, 59.4154)
reduce_domain (Image, ROI_0, ImageReduced2)

* 用于将显示窗口的大小调整到适合图像大小的尺寸。
dev_resize_window_fit_image (ImageReduced2, 0, 0, -1, -1)

* 3.在图像中读取条码数据和数据区域
* 参数一:要查找的图片
* 参数二:条码数据区域
* 参数三:条码模板句柄
* 参数四:条码类型
* 参数五:读取结果
find_bar_code (ImageReduced2, SymbolRegions, BarCodeHandle, 'auto', DecodedDataStrings)
area_center (SymbolRegions, Area, Row, Column)

dev_close_window ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image)
dev_display (SymbolRegions)
disp_message (WindowHandle, DecodedDataStrings, 'image', Row+200, Column-500, 'black', 'true')

* 4.使用完毕,删除条码匹配模板











read_image (Image1111, 'D:/workplace/字符识别/1111.jpg')
rgb1_to_gray (Image1111, GrayImage)
gen_rectangle1 (ROI_0, 76.0361, 119.731, 257.755, 779.377)
reduce_domain (GrayImage, ROI_0, ImageReduced)
threshold (ImageReduced, Region, 0, 155)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','contlength'], 'and', [490.84,114.53], [50000,2051.7])
sort_region (SelectedRegions, SortedRegions, 'first_point', 'true', 'row')
read_ocr_class_mlp ('Document_0-9A-Z_NoRej.omc', OCRHandle)
do_ocr_multi_class_mlp (SortedRegions, ImageReduced, OCRHandle, Class, Confidence)



*汉字识别
read_image (Image22, 'D:/workplace/字符识别/22.png')
rgb1_to_gray (Image22, GrayImage1)
gen_rectangle1 (ROI_0, 21.3781, 182.366, 148.383, 1159.65)
reduce_domain (GrayImage1, ROI_0, ImageReduced1)
threshold (ImageReduced1, Region1, 128, 255)
closing_circle (Region1, RegionClosing, 3.5)
connection (RegionClosing, ConnectedRegions1)
select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 150, 99999)
sort_region (SelectedRegions1, SortedRegions1, 'first_point', 'true', 'column')
dev_display (ImageReduced1)
words:=['国','外','电','子','与','通','信','教','材','系','列']
for Index := 1 to |words| by 1
    * 按顺序拿到单个字符
    select_obj (SortedRegions1, obj, Index)
    append_ocr_trainf (obj, ImageReduced1, words[Index-1], 'D:/workplace/字符识别/trainChinese.trf')
endfor


*读取训练文件
read_ocr_trainf_names ('D:/workplace/字符识别/trainChinese.trf', CharacterNames, CharacterCount)
*创建模型
create_ocr_class_mlp (8, 10, 'constant', 'default', CharacterNames, 80, 'none', 10, 42, OCRHandle1)

* 训练模型
trainf_ocr_class_mlp (OCRHandle1, 'D:/workplace/字符识别/trainChinese.trf', 200, 1, 0.01, Error, ErrorLog)

*识别:
do_ocr_multi_class_mlp (SortedRegions1, ImageReduced1, OCRHandle1, Class1, Confidence1)







* 二维码读取
read_image (Image, 'C:/Users/Albert/Desktop/qr/1.jpg')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
*创建二维码类型列表
_codeMode:=['Aztec Code', 'Data Matrix ECC 200', 'GS1 Aztec Code', 'GS1 DataMatrix', \
            'GS1 QR Code', 'Micro QR Code', 'PDF417', 'QR Code']
*图像放大1.5倍
zoom_image_factor (Image, ImageZoomed, 1.5, 1.5, 'constant')
*图像锐化
emphasize (ImageZoomed, ImageEmphasize, 20, 20, 1)
*遍历二维码类型列表
for Index1 := 0 to |_codeMode| by 1
    *创建二维码模型
    * 创建二维码模型
    * 参数一:二维码类型
    * 参数二:通用参数的名称 针对二维数据代码模型进行了调整。
    * 参数三:针对二维数据代码模型进行了调整。
    * 参数四:数据代码模型的句柄。
    create_data_code_2d_model (_codeMode[Index1], 'default_parameters', 'maximum_recognition', DataCodeHandle)
    *设置超时500ms
    set_data_code_2d_param (DataCodeHandle, 'timeout', 500)
    *检测二维码,最多可以检测到10个
    * 查找图形中二维码,并获取信息
    * 参数一:图片
    * 参数二:围绕成功解码数据的 XLD 轮廓 代码符号。
    * 参数三:二维码模型的句柄。
    * 参数四:参数的名称 控制操作员的行为。
    * 参数五:可选泛型参数的值。
    * 参数六:所有成功解码的二维数据代码的句柄 符号。
    * 参数七:所有检测到的二维数据代码的解码数据字符串 图像中的符号。
    find_data_code_2d (ImageEmphasize, SymbolXLDs, DataCodeHandle, 'stop_after_result_num', 10, ResultHandles, \
                       DecodedDataStrings)
    
    *获取当前图像的二维码类型
    code_type := _codeMode[Index1]
    *如果检测到图像有二维码,就显示在窗体上
    if (|DecodedDataStrings| > 0)
        disp_message (WindowHandle, code_type+':'+DecodedDataStrings, 'window', 12, 12, 'black', 'true')
    endif
endfor

dev_clear_window ()
stop ()













* 1 读取条形码

* 创建一个条形码处理模型,这里使用默认参数。
create_bar_code_model([], [], BarCodeHandle)
* 设置参数,使得在找到第一个条形码后停止搜索,因为我们期望每张图像中只有一个条形码。
set_bar_code_param(BarCodeHandle, 'stop_after_result_num', 1)
* 减少最小代码长度到1个字符,因为有些2/5工业条形码可能只有一个数字。
* 注意:在实际应用中不推荐这样做,因为它可能会导致更多的误读。
set_bar_code_param_specific(BarCodeHandle, '2/5 Industrial', 'min_code_length', 1)
* 关闭任何已打开的窗口,以确保新窗口可以被正确创建。
dev_close_window()
* 打开一个新的图形窗口,用于显示处理结果。
* 参数分别是:窗口的左上角坐标 (0, 0),宽度 (120),高度 (300),背景颜色 ('black'),以及返回的窗口句柄 (WindowHandle)。
dev_open_window(0, 0, 120, 300, 'black', WindowHandle)
* 设置显示字体大小为14,字体类型为等宽字体 ('mono'),加粗 ('true'),斜体 ('false')。
set_display_font(WindowHandle, 14, 'mono', 'true', 'false')
* 设置绘图模式为边距 ('margin'),这意味着绘制的元素将与窗口边缘保持一定的距离。
dev_set_draw('margin')
* 设置线条宽度为3,这将影响绘制的线条或形状的粗细。
dev_set_line_width(3)
* 开始循环,迭代4次,每次处理一张不同的条形码图像。
for I := 1 to 4 by 1
    * 构造图像文件路径并读取图像,这里的I是一个变量,代表当前迭代的次数。
    * 文件名格式为'barcode/25industrial/25industrial0' + I,例如,第一次迭代时会读取'25industrial01'。
    read_image(Image, 'barcode/25industrial/25industrial0' + I)
    * 获取图像的尺寸,以便正确设置显示窗口的范围。
    get_image_size(Image, Width, Height)
    * 设置窗口的显示区域,使图像完整地填充窗口。
    dev_set_window_extents(0, 0, Width - 1, Height - 1)
    * 在窗口中显示图像。
    dev_display(Image)
    * 设置绘制颜色为绿色。
    dev_set_color('green')
    * 配置为不考虑校验字符进行条形码读取。
    set_bar_code_param(BarCodeHandle, 'check_char', 'absent')
    * 尝试找到并解码条形码,返回解码后的字符串。
    find_bar_code(Image, SymbolRegions, BarCodeHandle, '2/5 Industrial', DecodedDataStrings)
    * 显示解码后的字符串。
    disp_message(WindowHandle, DecodedDataStrings, 'window', 12, 12, 'black', 'false')
    * 计算解码字符串的最后一个字符的位置。
    LastChar := strlen(DecodedDataStrings) - 1
    * 显示最后一个字符,假设这是校验字符,并用森林绿颜色标记。
    disp_message(WindowHandle, sum(gen_tuple_const(LastChar,' ')) + DecodedDataStrings{LastChar}, 'window', 12, 12, 'forest green', 'false')
    * 暂停程序执行,让用户有时间查看结果。
    stop()
    * 现在配置为使用校验字符验证结果。
    set_bar_code_param(BarCodeHandle, 'check_char', 'present')
    * 再次尝试找到并解码条形码,这次包括校验字符的验证。
    * 如果校验字符不正确,条形码读取将会失败。
    find_bar_code(Image, SymbolRegions, BarCodeHandle, '2/5 Industrial', DecodedDataStrings)
    * 显示解码后的字符串(不包括校验字符)。
    disp_message(WindowHandle, DecodedDataStrings, 'window', 36, 12, 'black', 'false')
    * 改变绘制颜色为洋红色。
    dev_set_color('magenta')
    * 如果不是最后一张图片,则暂停,等待用户继续。
    if (I < 4)
        stop()
    endif
endfor








本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2300767.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

平板作为电脑拓展屏

有线串流&#xff08;速度更快&#xff09; spacedesk 打开usb对安卓的连接 用usb线直接连接电脑和平板 无线串流&#xff08;延迟高&#xff0c;不推荐&#xff09; todesk pc和手机端同时下载软件&#xff0c;连接后可以进行远程控制或扩展屏幕 spacedesk 连接到同一个…

【算法与数据结构】字典树(Trie)详解

目录 一&#xff0c;字典树的定义 二&#xff0c;字典树的代码实现 完整代码详细注释&#xff1a; 测试用例测试结果&#xff1a; 三&#xff0c;处理其他字符 四&#xff0c;内存优化与扩展 1. 内存优化 2. 扩展功能 五&#xff0c;扩展功能支持通配符匹配 六&…

【JavaEE进阶】MyBatis通过注解实现增删改查

目录 &#x1f343;前言 &#x1f340;打印日志 &#x1f334;传递参数 &#x1f38b;增(Insert) &#x1f6a9;返回主键 &#x1f384;删(Delete) &#x1f332;改(Update) &#x1f333;查(Select) &#x1f6a9;起别名 &#x1f6a9;结果映射 &#x1f6a9;开启驼…

Simulink Ststeflow教程 — 2 创建和编辑状态

目录 2.1 创建和编辑状态 2.1.1 状态的创建 2.1.2 创建连接节点 2.1.3 转移 2.1.5 默认转移 在Stateflow模型中&#xff0c;将包含有状态的Stateflow框图称状态图而将不包含任何状态的Stateflow框图称为流程图。其中&#xff0c;状态图是Stateflow最常用的一种形式&#x…

Fiddler笔记

文章目录 一、与F12对比二、核心作用三、原理四、配置1.Rules:2.配置证书抓取https包3.设置过滤器4、抓取App包 五、模拟弱网测试六、调试1.线上调试2.断点调试 七、理论1.四要素2.如何定位前后端bug 注 一、与F12对比 相同点&#xff1a; 都可以对http和https请求进行抓包分析…

线上就医全流程医药机构接入文档接口代码-医保就医接口php-demo版本

2025年2月18日11:28:03 国密算法开发库推荐 lpilp/guomi 我测试过php 7.2 - 8.0都可以兼容&#xff0c;如果有能力可以自己开发 目前已经开发了核心的接口的测试demo,并且封装了工具类直接写业务逻辑即可&#xff0c;并且已经有线上项目在使用&#xff0c;如果需要demo代码可…

智能选路+NAT实验 作业

拓扑图 配置ip 防火墙安全区域划分 用户配置 dns透明

LLM:RAG

原文链接&#xff1a;LLM&#xff1a;RAG 1、RAG 概览 RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09;是一种结合了信息检索&#xff08;IR&#xff09;和 LLM 的技术。它的核心思想是在 LLM 生成回答之前&#xff0c;通过检索相关文档…

基于Qt 和微信小程序的用户管理系统:WebSocket + SQLite 实现注册与登录

目录 一. 概要 二. 技术栈 三. 系统功能设计 3.1 功能模块 3.2 数据表设计 四. 具体实现 4.1 Qt 服务端 4.1.1 初始化 WebSocket 服务器 4.1.2 用户管理界面 4.2 微信小程序端 4.2.1 注册功能 4.2.2 登录功能 五. 运行效果 六. 源码下载 一. 概要 在物联网和智能设备…

策略+适配器模式详解

文章目录 1.策略模式1.目录结构2.Strategy.java 策略接口3.StrategyA.java 策略A4.StrategyB.java 策略B5.StrategyC.java 策略C6.Context.java 策略上下文7.Client.java 客户端8.小结 2.适配器模式1.目录结构2.CustomPaymentProcessor.java 自己的支付接口3.PayPalPaymentServ…

未来游戏:当人工智能重构虚拟世界的底层逻辑

未来游戏&#xff1a;当人工智能重构虚拟世界的底层逻辑 在《赛博朋克2077》夜之城的霓虹灯下&#xff0c;玩家或许已经注意到酒吧里NPC开始出现微表情变化&#xff1b;在《艾尔登法环》的开放世界中&#xff0c;敌人的战术包抄逐渐显露出类人智慧。这些细节预示着游戏产业正站…

Zabbix——Rocky9安装zabbix相关步骤记录

安装Zabbix 安装MariaDB 这里用MariaDB演示 https://mariadb.org/download/?trepo-config&dRedHatEnterpriseLinux9&v10.11&r_mneusoft 通过这个网址获得连接 选择对应的repo 根据系统版本和要安装的版本选择对应的repo 安装 新建一个repo文件&#xff0c;例…

startai产品精修教程

1.把产品放置ps画布中 打开startai插件选择产品精修功能&#xff0c;选择金属材质即可哦 调节一下参数就可以啦&#xff0c;最终效果图 下载地址&#xff1a;StartAI画图软件官网_PS插件StartAI绘画软件生成器_Photoshop图像处理插件

【YOLOv8】

文章目录 1、yolov8 介绍2、创新点3、模型结构设计3.1、backbone3.2、head 4、正负样本匹配策略5、Loss6、Data Augmentation7、训练、推理8、分割 Demo附录——V1~V8附录——相关应用参考 1、yolov8 介绍 YOLOv8 是 ultralytics 公司在 2023 年 1 月 10 号开源的 YOLOv5 的下…

【保姆级教程】DeepSeek R1+RAG,基于开源三件套10分钟构建本地AI知识库

一、总体方案 目前在使用 DeepSeek 在线环境时&#xff0c;页面经常显示“服务器繁忙&#xff0c;请稍后再试”&#xff0c;以 DeepSeek R1 现在的火爆程度&#xff0c;这个状况可能还会持续一段时间&#xff0c;所以这里给大家提供了 DeepSeek R1 RAG 的本地部署方案。最后实现…

Oracle视图(基本使用)

视图 视图是通过定制的方式显示一个或者多个表的数据。 视图可以视为“虚拟表”或“存储的查询”。 视图的优点&#xff1a; 提供了另外一种级别的表安全性隐藏了数据的复杂性简化了用户的SQL命令隔离基表结构的改变通过重命名列&#xff0c;从另一个角度提供数据。 视图里…

梁文锋亲自挂名DeepSeek发布新论文

由 DeepSeek 联合创始人梁文锋亲自挂名的研究团队&#xff0c;在 arXiv 上发表了一篇题为“Native Sparse Attention: Hardware-Aligned and Natively Trainable Sparse Attention”的论文&#xff0c;提出了一种全新的注意力机制架构 NSA&#xff08;Native Sparse Attention&…

低代码(Low Code)全解析:从概念到应用,从选择到价值

​在数字化浪潮席卷全球的当下&#xff0c;企业对软件开发的效率与灵活性愈发重视&#xff0c;低代码平台应运而生并迅速掀起技术热潮。 本文基于笔者 6 年的低代码实践经验&#xff0c;深入剖析低代码的诸多方面&#xff0c;涵盖其定义、发展历程、国内平台对比、开发流程、与…

C++--STL库-List

目录 1.list 的基本使用 1.1 创建和初始化 1.2. 插入元素 1.3. 删除元素 1.4. 访问元素 1.5 遍历 1.6 总结 list是C标准库&#xff08;STL&#xff09;中的双向链表容器&#xff0c;属于<list>头文件。 它的特点是&#xff1a; 动态大小&#xff1a;可以随时插入…

尚硅谷 java 学习Day19 抽象类与抽象方法、接口、内部类

6-5 抽象类(abstract)与抽象方法&#xff08;important&#xff09; 一、什么叫抽象类&#xff1a; 有时候将一个父类设计的非常抽象&#xff0c;以至于它没有具体的实例&#xff0c;这样的类称为抽象类 abstract关键字的使用&#xff1a; ​ 1、abstract:抽象的 ​ 2、abs…