0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

VPLC系列机器视觉运动控制一体机快速入门(十)

正运动技术 2021-11-08 17:09 次阅读

此前,我们依次讲解了软硬件介绍及计数实例、相机的基本使用、基于形状匹配的视觉定位、BLOB有无检测、测量尺寸、机器视觉方案中使用到的标定功能、ZDevelop软件实现识别条形码和二维码,测量点/直线/圆以及划痕检测功能。

本期课程我们和大家一起使用ZDevelop软件实现机器视觉中使用到的OCR功能。

一、 OCR 检测原理

什么是OCR?

OCR全称是Optical Character Recognition,即光学字符识别。在机器视觉中OCR是指使用图像处理方法将获取到的图像上的黑白字符进行分割训练后,识别并输出对应的字符。

2.png

OCR的检测原理?

在机器视觉中进行OCR检测时,首先根据字符(前景)和背景的对比度以及字符的宽度和高度等参数将字符进行分割后提取字符图像,然后对提取的字符逐一进行训练学习,将所有可能出现的字符进行训练学习后存储到训练库中,在执行识别检测时,将当前提取到的字符和训练库中的字符进行对比,输出相似度满足条件的字符结果。

3.png

二 、OCR 应用场景

1.验证字符准确性

可以验证待测产品上印刷字符的准确性。

2.获取产品字符信息

可以获取待测产品上的字符信息上传数据库或录入系统。

3.信息对比

可以将待测产品识别出的字符和条码输出的信息进行对比,判断字符印刷和条码信息是否一致。

三、 软件实现

(一)流程图

4.png

(二)实例演示

1.打开ZDevelop软件:新建项目→新建HMI文件→新建main.bas文件,用于编写界面响应函数→新建global_variable.bas文件用于存放全局变量并开启HMI自动运行任务→新建InitParam.bas文件用于初始化测量参数→新建camera.bas文件用于实现相机采集功能→新建draw.bas文件用于更新绘制图形刷新界面→文件添加到项目。

5.png

2.设计HMI界面。

6.png

3.在global_variable.bas文件中定义全局变量,定义完成后运行Hmi.hmi文件。

'''''全局变量大部分使用数组结构'''''

''注:basic编程中很多函数会以TABLE(系统的数据结构)做为参数

''在这里table均是做为中间变量

''table 21-22,鼠标按键,控件坐标系

''table 31-35,旋转矩ROI参数,cx、cy、width、height、angle,控件坐标系

''table 41-45,旋转矩形控件坐标转换后对应的图像坐标,图像坐标系

'主任务状态

'0 - 未初始化

'1 - 停止

'2 - 运行中

'3 - 正在停止

GLOBAL DIM main_task_state

main_task_state = 1

'采集开关

'0 - 停止采集

'1 - 请求采集

GLOBAL DIM grab_switch

grab_switch = 0

'相机个数

GLOBAL cam_num

cam_num = 0

'相机种类,"zmotion;mvision;basler;mindvision;huaray"

GLOBAL DIM CAMERA_TYPE(16)

CAMERA_TYPE = "mvision"

' 定义主任务id - 10

GLOBAL DIM main_task_id

main_task_id = 10

'定义连续采集任务id - 9

GLOBAL DIM grab_task_id

grab_task_id = 9

'定义全局图像变量

GLOBAL ZVOBJECT grabImg '采集图像

'定义常用颜色变量

GLOBAL C_RED, C_GREEN, C_BLUE, C_YELLOW

C_RED = RGB(255, 0, 0)

C_GREEN = RGB( 0,255, 0)

C_BLUE = RGB( 0, 0,255)

C_YELLOW= RGB(255,255, 0)

'训练的字符库、输出的字符结果

GLOBAL DIM nameSample(32),result(32)

'旋转矩形ROI参数:cx、cy、width、height、angle

GLOBAL DIM d_roi_rect2(5)

'检测参数:阈值模式、阈值参数、最小字符面积、最大字符面积、最小字符宽度、最大字符宽度、最小字符高度、最大字符高度、字符极性、形态学类型、结构元宽、结构元高、字符最小间距

GLOBAL DIM d_detect_param(13)

'***********定义读取本地文件功能相关变量**************

''注意,该功能只在使用仿真器时有效

'定义是否使用本地图片标志

GLOBAL DIM d_use_imgfile

d_use_imgfile=1

'定义本地图片索引

GLOBAL DIM d_index

d_index=0

'定义读取图片的路径

GLOBAL DIM File_Name(100)

'***********结束定义读取本地文件功能相关变量**********

'运行HMI文件

RUN "Hmi1.hmi",1

4.在InitParam.bas文件中初始化测量参数。

end

GLOBAL SUB init_detect_param()'初始化测量参数

'初始化roi参数

d_roi_rect2(0) = 160.0 'roi中心x

d_roi_rect2(1) = 120.0 'roi中心y

d_roi_rect2(2) = 80.0 'roi宽

d_roi_rect2(3) = 60.0 'roi高

d_roi_rect2(4) = 0.0 'roi角度

TABLE(31) = d_roi_rect2(0) '将roi变量赋值给起始地址为31的table数组

TABLE(32) = d_roi_rect2(1)

TABLE(33) = d_roi_rect2(2)

TABLE(34) = d_roi_rect2(3)

TABLE(35) = d_roi_rect2(4)

'初始化检测参数:阈值模式、阈值参数、最小字符面积、最大字符面积、最小字符宽度、最大字符宽度、最小字符高度、最大字符高度、字符极性、形态学类型、结构元宽、结构元高、字符最小间距

d_detect_param(0) = 0 '手动阈值

d_detect_param(1) = 187 '低阈值

d_detect_param(2) = 500 '最小字符面积

d_detect_param(3) = 80000 '最大字符面积

d_detect_param(4) = 10 '最小字符宽度

d_detect_param(5) = 500 '最大字符宽度

d_detect_param(6) = 10 '最小字符高度

d_detect_param(7) = 500 '最大字符高度

d_detect_param(8) = 1 '白底黑字

d_detect_param(9) = 1 '开运算

d_detect_param(10) = 1 '结构元宽,正奇数

d_detect_param(11) = 10 '结构元高,正奇数

d_detect_param(12) = 1 '字符最小间距

nameSample="" '初始化训练字符样本为空字符串

result=" " '初始化字符结果变量为空字符串

END SUB

5.关联HMI界面值显示控件变量。

7.png

具体变量关联操作可参考视频中相关内容或获取程序代码进行参考。

6.在main.bas文件中添加HMI界面初始化函数并在Hmi系统设置中关联初始化函数。

'HMI界面初始化函数

GLOBAL SUB hmi_init()

grab_switch = 0 '初始化采集开关为停止采集

main_task_state = 1 '初始化主任务状态为停止状态

'初始化时依据图像分辨率设置区域的裁剪尺寸,此处图像分辨率为1280x960

ZV_RESETCLIPSIZE(1280, 960)

'设置锁存通道0的大小,以适应图片元件控件大小

ZV_LATCHSETSIZE(0, HMI_CONTROLSIZEX(10, 1), HMI_CONTROLSIZEY(10, 1))

ZV_SETSYSINT("LineWidth",5) '设置绘制画笔宽度为5个像素

init_detect_param() '初始化测量参数

ZV_LATCHCLEAR(0) '清空锁存通道0

END SUB

8.png

7.在camera.bas文件中添加HMI界面中采集相关按钮响应的函数并关联动作函数。

9.png

end


'主界面按下扫描相机按钮时响应的函数

GLOBAL SUB cam_scan_all()

if(d_use_imgfile=1)then

?"请先按下使用本地图片按钮关闭该功能"

return

endif

ZV_SETSYSINT("LogLevel", 7) '设置控制器信息

ZV_SETSYSSTR("DataDir","")

CAM_SCAN(CAMERA_TYPE) '扫描相机,CAMERA_TYPE="mvision"

cam_num = CAM_COUNT() '获取扫描到的相机数量

if (0 = cam_num) then '如果相机数量=0,打印提示信息

? "未找到相机"

return '退出子函数,不往下执行

endif

?"cam_num = " cam_num '如果扫描到相机,打印相机数量

CAM_SEL(0) '选择扫描到的第一个相机进行操作

CAM_SETEXPOSURE(5000) '设置相机曝光时间为5000us

CAM_SETMODE(0) '设置软件触发模式

CAM_START(0) '开启相机

END SUB

'主界面按下单次采集按钮执行的函数

GLOBAL SUB btn_grab()

'如果d_use_imgfile=1时使用读取本地图片功能,使用控制器时请将此部分代码注释掉

if (d_use_imgfile=1) then

if(d_index=3) then

d_index=0

endif

File_Name="\10"+TOSTR(d_index,1,0)+".bmp" '.../flash/10/目录下的图片所在的路径名称

ZV_IMGREAD(grabImg,File_Name,1)

ZV_LATCH(grabImg, 0)

d_index=d_index+1

return

endif

''读取本地图片功能结束

'如果相机数量为0,提示先扫描相机,并退出子函数不往下执行

if cam_num = 0 then

?"请先扫描相机!"

return

endif

CAM_SETPARAM("TriggerSoftware", 0) '发送触发指令

CAM_GET(grabImg, 0) '获取一帧图像存放到grabImg变量中

ZV_LATCH(grabImg, 0) '将图像显示到锁存通道0中

END SUB

'主界面按下连续采集按钮响应的函数

GLOBAL SUB btn_cgrab()

if grab_switch =1 then '如果已经处于连续执行状态,打印提示信息并退出函数

?"正在连续运行中,请勿重复操作!"

return

endif

if( d_use_imgfile =0) then '如果使用相机采集功能

if cam_num = 0 then '判断如果相机数量=0,打印提示信息并退出函数

?"请先扫描相机!"

return

endif

endif

grab_switch = 1 '采集任务开关置1

if (1 = grab_switch) then

if (0 = PROC_STATUS(grab_task_id)) then

RUNTASK grab_task_id, grab_task '开启连续采集任务

endif

endif

END SUB

'采集任务实现函数

grab_task:

while(1)

if (0 = grab_switch) then '如果采集任务开关=0即停止采集按钮按下时

exit while '退出循环

endif

'grab_switch=1时重复执行以下操作

btn_grab()'单次采集按钮响应的函数

wend

END

'主界面按下停止采集按钮响应的函数

GLOBAL SUB btn_stopCgrab()

if grab_switch =0 then '如果已经处于停止采集状态,打印提示信息并退出函数

?"未开启连续采集!"

return

endif

grab_switch = 0 '将采集任务开关置0

END SUB

8.在draw.bas文件中添加检测ROI更新绘制函数,并在自定义元件属性窗口中关联刷新函数和绘制函数。

end

'和绘制(即选择ROI)有关的界面的刷新绘制函数放在这个bas文件里

DIM is_redraw '绘图标志,0表示未进行绘制,1表示正在进行绘制

is_redraw = 0

DIM hit_pos '定义调整操作标志

'根据鼠标操作更新ROI位置区域函数

GLOBAL SUB update_roi()

if mouse_scan(21) = 1 then '扫描鼠标按下操作

'只有按下时可以改变击中位置,获取鼠标点击位置对应的击中区域编号

hit_pos = ZV_HMIADJRECT2(table(21), table(22), 31, -1)

is_redraw = 1 '绘图标志置1

endif

if mouse_scan(21) = -1 then '扫描鼠标松开操作

'根据区域编号调整roi区域位置

ZV_HMIADJRECT2(table(21), table(22), 31, hit_pos)

is_redraw = 1 '绘图标志置1

endif

if (MOUSE_state(21)) then '鼠标按下时

'根据区域编号调整roi区域位置

ZV_HMIADJRECT2(table(21), table(22), 31, hit_pos)

is_redraw = 1 '绘图标志置1

endif

if (1 = is_redraw) then '如果绘制标志=1

is_redraw = 0 '绘图标志置0

'控件roi坐标转图像roi坐标,控件坐标存放在起始地址为111的数组,图像坐标存放在起始地址为50的数组

ZV_POSTOIMG(0, 1, 31, 41)

d_roi_rect2(0) = TABLE(41)'将图像坐标的数据赋值给ROI变量

d_roi_rect2(1) = TABLE(42)

d_roi_rect2(2) = ZV_LENTOIMG(0, TABLE(33))

d_roi_rect2(3) = ZV_LENTOIMG(0, TABLE(34))

d_roi_rect2(4) = TABLE(35)

SET_REDRAW '重新绘制全部区域

endif

END SUB

'ROI区域更新后实时绘制ROI区域

GLOBAL SUB draw_roi()

SET_COLOR(C_BLUE) '设置画笔颜色为蓝色

ZV_HMIRECT2(31, 300) '将旋转矩形roi分解为HMI支持的绘图图元并添加控制参数,便于HMI绘图显示

DRAWLINE(TABLE(300), TABLE(301), TABLE(302), TABLE(303)) '绘制外矩形

DRAWLINE(TABLE(302), TABLE(303), TABLE(304), TABLE(305))

DRAWLINE(TABLE(304), TABLE(305), TABLE(306), TABLE(307))

DRAWLINE(TABLE(306), TABLE(307), TABLE(300), TABLE(301))

DRAWLINE(TABLE(308), TABLE(309), TABLE(310), TABLE(311)) '绘制方向箭头

DRAWLINE(TABLE(312), TABLE(313), TABLE(310), TABLE(311))

DRAWLINE(TABLE(314), TABLE(315), TABLE(310), TABLE(311))

END SUB

10.png

9.在main.bas文件中添加HMI界面按下【提取训练】按钮时响应的函数并关联动作函数名。

'HMI界面按下提取字符按钮时响应的函数

GLOBAL SUB btn_segment()

'定义检测需要用到的变量:分割参数、样本图片库、训练样本库、OCR分类器、结果图片

GLOBAL ZVOBJECT param,sample,trainSample,ocr,colorImg

'根据界面输入参数生成分割参数

ZV_OCRSEGSETPARAM_(param,d_detect_param(0),d_detect_param(1),d_detect_param(2),d_detect_param(3),d_detect_param(4),d_detect_param(5),d_detect_param(6),d_detect_param(7),d_detect_param(8),d_detect_param(9),d_detect_param(10),d_detect_param(11),d_detect_param(12))

'根据分割参数和检测区域进行字符分割,分割的字符样本图片存放到sample变量中

ZV_OCRSEGCHAR_(grabImg,param,sample,d_roi_rect2(0),d_roi_rect2(1),d_roi_rect2(2),d_roi_rect2(3),d_roi_rect2(4))

'获取样本数量,存放到table(100)中

ZV_OCRSAMPLECNT_(sample,100)

'灰度图转换到RGB图,作为结果图像

ZV_GRAYTORGB(grabImg, colorImg)

if(TABLE(100)>0) then '如果识别到的字符数量大于0

for i=0 to TABLE(100)-1'根据识别到的字符次数进行循环

ZV_OCRSAMPLERECT2_(sample,i,150)'获取每个样本字符的最小外接矩阵,用于显示分割结果

'将样本的最小外接矩阵绘制到界面中

ZV_RECT2(colorImg,table(150),table(151),table(152),table(153),table(154),C_GREEN)

next

elseif (TABLE(100)=0) then '如果未分割提取到字符

?"未成功分割提取出字符!" '打印提示并退出执行

return

endif

ZV_LATCH(colorImg,0)'在锁存通道0中显示结果图像

if (STRCOMP(nameSample, "")=0)then '如果输入的训练字符样本是空的

?"请先输入训练字符样本再重新分割训练!" '打印提示

return '返回子函数,不往下执行

endif

'清空OCR分类器

ZV_CLEAR(ocr)

if(ZV_ISEMPTY(trainSample)=0) then '如果训练样本库不为空

ZV_OCRSAMPLECLR_(trainSample)'在训练字符之前先清空样本库

endif

'根据输入的训练库字符生成训练样本库

ZV_OCRSAMPLEAPP_(sample,trainSample,nameSample)

'使用训练样本库训练分类器,0.8为优化参数(惩罚系数),表示分类器的预测能力, 越小预测能力越强但越容易出错,范围[0,1],建议 0.8;

'0.15为径向基核参数,表示非线性映射能力,值越大非线 性映射能力就越强,范围[0,1],建议 0.15

ZV_OCRTRAINSVM_(trainSample,ocr,0.8,0.15)

if(ZV_ISEMPTY(ocr)=0) then '如果分类器训练成功

?"字符分割训练已完成!" '打印成功提示

else

?"训练字符和分割提取的字符不匹配!"

endif

END SUB

11.png

10.在main.bas文件中添加HMI界面按下【识别】按钮时响应的函数并关联动作函数名。

'HMI界面按下识别按钮时响应的函数

GLOBAL SUB btn_test()

result=" " '清空字符结果变量

'根据界面输入参数生成分割参数

ZV_OCRSEGSETPARAM_(param,d_detect_param(0),d_detect_param(1),d_detect_param(2),d_detect_param(3),d_detect_param(4),d_detect_param(5),d_detect_param(6),d_detect_param(7),d_detect_param(8),d_detect_param(9),d_detect_param(10),d_detect_param(11),d_detect_param(12))

'根据分割参数和检测区域进行字符分割,分割的字符样本存放到sample变量中

ZV_OCRSEGCHAR_(grabImg,param,sample,d_roi_rect2(0),d_roi_rect2(1),d_roi_rect2(2),d_roi_rect2(3),d_roi_rect2(4))

'获取分割到的字符数量,存放到table(100)中

ZV_OCRSAMPLECNT_(sample,100)

if(TABLE(100)=0) then '如果未分割提取到字符

?"未成功分割提取出字符!" '打印提示并退出执行

return

endif

'使用训练样本和分类器识别字符并输出字符结果到起始地址为50的变量中

ZV_OCRCLASSIFYSVM_(ocr,sample,32,50)

'获取识别到的字符数量,存放到table(100)中

ZV_OCRSAMPLECNT_(sample,100)

'灰度图转换到RGB图,作为结果图像

ZV_GRAYTORGB(grabImg, colorImg)

if(TABLE(100)>0) then '如果识别到的字符数量大于0

for i=0 to TABLE(100)-1'将字符结果循环赋值给结果变量显示到界面中

result(i)=TABLE(50+i)

ZV_OCRSAMPLERECT2_(sample,i,150)'获取每个样本字符的最小外接矩阵,用于显示分割结果

'将样本的最小外接矩阵绘制到界面中

ZV_RECT2(colorImg,table(150),table(151),table(152),table(153),table(154),C_GREEN)

next

endif

ZV_LATCH(colorImg,0)'在锁存通道0中显示结果图像

END SUB

12.png

11.在main.bas文件中添加【运行】按钮响应的函数并关联动作函数。

'HMI界面按下运行按钮时响应的函数

GLOBAL SUB btn_run()

if(2 = main_task_state) then '如果主任务处于运行中状态

?"已经开启连续运行任务,请勿重复操作!" '打印提示

return

endif

if (1 = main_task_state) then '如果主任务处于停止状态

if (0 = PROC_STATUS(main_task_id)) then'如果程序中任务未开启

main_task_state = 2 '将主任务状态设置为运行中状态

RUNTASK main_task_id, main_task'开启主任务

endif

endif

END SUB

'主任务执行的函数

main_task:

while(1)

'如果主任务状态处于正在停止状态即停止按钮按下时

if (3 = main_task_state) then

main_task_state = 1'将主任务状态设置为停止状态

exit while '退出循环

endif

'否则循环执行采集和识别函数

btn_grab()

btn_test()

wend

END

13.png

12.在main.bas文件中添加【停止】按钮响应的函数并关联动作函数。

'HMI界面按下停止按钮时响应的函数

GLOBAL SUB btn_stop()

if (2 = main_task_state) then '如果主任务状态处于2即任务运行中时

main_task_state = 3 '将主任务状态置为3,退出循环

endif

END SUB

14.png

(三)仿真演示效果

15.png

16.png

17.png

本次,正运动技术VPLC系列机器视觉运动控制一体机快速入门(十)——OCR功能,就分享到这里。

更多精彩内容请关注“正运动小助手”公众号,需要相关开发环境与例程代码,请咨询正运动技术销售工程师:400-089-8936。

本文由正运动技术原创,欢迎大家转载,共同学习,一起提高中国智能制造水平。文章版权归正运动技术所有,如有转载请注明文章来源。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 机器视觉
    +关注

    关注

    161

    文章

    4334

    浏览量

    120031
  • 字符识别
    +关注

    关注

    0

    文章

    17

    浏览量

    8636
  • OCR
    OCR
    +关注

    关注

    0

    文章

    144

    浏览量

    16316
  • 正运动技术
    +关注

    关注

    0

    文章

    97

    浏览量

    303
收藏 人收藏

    评论

    相关推荐

    机器视觉运动控制一体机在DELTA并联机械手视觉上下料应用

    机器视觉运动控制一体机在DELTA并联机械手视觉上下料的应用
    的头像 发表于 10-24 09:02 226次阅读
    <b class='flag-5'>机器</b><b class='flag-5'>视觉</b><b class='flag-5'>运动</b><b class='flag-5'>控制</b><b class='flag-5'>一体机</b>在DELTA并联机械手<b class='flag-5'>视觉</b>上下料应用

    聚徽-工控一体机有什么创新

    工控一体机作为新代的工业控制设备,具有多项创新点,这些创新使得工控一体机能够更好地满足工业控制的需求,提高自动化生产的效率和质量。
    的头像 发表于 09-14 09:34 229次阅读

    蓝海华腾参股公司顶控科技发布运动控制一体机系列产品

    蓝海华腾参股公司深圳市顶控科技有限公司运动控制一体机系列产品上市!本次新品发布会发布三个系列产品,这三个
    的头像 发表于 09-03 09:28 436次阅读

    思道SEEKVIEU一体机电脑

    一体机
    jf_69621499
    发布于 :2024年09月03日 08:50:17

    机器视觉运动控制一体机VPLC532E在汽车胶带缠绕的开放式CNC应用

    机器视觉运动控制一体机VPLC532E在汽车胶带缠绕的开放式CNC应用
    的头像 发表于 08-19 10:03 285次阅读
    <b class='flag-5'>机器</b><b class='flag-5'>视觉</b><b class='flag-5'>运动</b><b class='flag-5'>控制</b><b class='flag-5'>一体机</b><b class='flag-5'>VPLC</b>532E在汽车胶带缠绕的开放式CNC应用

    VPLC系列机器视觉运动控制一体机在五轴联动点胶上的应用

    技术针对现有市场需求,开发了种基于VPLC系列机器视觉运动
    发表于 07-29 14:29

    聚徽触控-工控一体机和 PLC 一体机有什么不同

    在工业自动化领域,工控一体机和 PLC 一体机都扮演着重要角色。尽管它们在某种程度上有所重叠,但它们在功能、应用和设计结构等方面存在显著的不同。工控一体机和 PLC 一体机有什么不同,
    的头像 发表于 06-21 10:05 386次阅读

    聚徽触控-工控一体机如何运用在电力控制

    工业自动化已经成为了现代工业发展的重要趋势。在这进程中,工控一体机以其强大的功能和广泛的应用场景,成为了工业自动化控制领域的核心设备之。特别是在电力
    的头像 发表于 06-20 10:19 398次阅读

    集特一体机

    显卡一体机
    jf_67464575
    发布于 :2024年05月22日 09:05:55

    工业一体机在物联网领域的应用

    工业一体机在物联网领域的应用变得愈发重要,工业一体机作为种集计算、控制、通信于一体的设备,具备了在物联网环境下应用的独特特点.
    的头像 发表于 05-18 16:54 267次阅读

    基于VPLC711的曲面外观检测XYR运动控制解决方案

    中心线永远与产品表面垂直(曲面处相机中心线始终与切线方向垂直)。 (2)相机到被检测产品的距离保持致,任何位置L1=L2 VPLC711机器视觉
    发表于 04-16 17:58

    机器视觉运动控制一体机在喇叭跟随点胶上的应用

    等问题。 正运动技术视觉点胶整体解决方案: 在此背景下,正运动技术的视觉点胶整体解决方案脱颖而出,方案是基于VPLC
    发表于 04-16 17:37

    机器视觉运动控制一体机在光伏汇流焊机器人系统的解决方案

    一体机结合SCARA机械手+机器视觉的电池片汇流焊解决方案。可解决不同角度来料、规格等光伏太阳能电池板的串焊需求,实现生产效率和精度等大幅提升,同时将废品率降至仅12%,并显著加快数据处理速度,提高了
    发表于 02-28 15:01

    人脸考勤打卡一体机

    一体机
    jf_66410442
    发布于 :2024年01月09日 11:09:22