手把手 Golang 实现静态图像与视频流人脸识别

news2024/11/23 21:13:52

说起人脸识别,大家首先想到的实现方式应该是 Python 去做相关的处理,因为相关的机器学习框架,库都已经封装得比较好了。但是我们今天讨论的实现方式换成 Golang,利用 Golang 去做静态图像和视频流人脸识别的相应处理。


静态图像人脸识别

首先我们来进行静态的人脸识别,Golang 这边相较于 Python 社区来说相对少一些,不过依然有一些优秀的库可以供我们使用。今天我们用到的就是 go-face 这个库。该库利用 dlib 去实现人脸识别,一个很受欢迎的机器学习工具集,它可以说是人脸识别中使用最多的软件包之一。在产学界有广泛应用,涵盖了机器人学,嵌入式设备,移动设备等等。在它官网的文档中提到在 Wild 基准测试中识别标记面部的准确度达到惊人的 99.4%,这也说明为什么它能得到广泛的应用。


在我们开始码代码之前,首先需要安装 dlib。Windows 平台相对麻烦一些,具体在官网有安装方案,这里我介绍两个平台。

Ubuntu 18.10+, Debian sid

最新版本的 Ubuntu 和 Debian 都提供合适的 dlib 包,所以只需要运行。

# Ubuntusudo apt-get install libdlib-dev libblas-dev liblapack-dev libjpeg-turbo8-dev# Debiansudo apt-get install libdlib-dev libblas-dev liblapack-dev libjpeg62-turbo-dev
复制代码

macOS

确保安装了 Homebrew。

brew install dlib
复制代码


创建项目及准备工作

在 GOPATH 的 src 目录下,创建项目文件,命令如下。

sudo makedir go-face-test# 创建 main.gosudo touch main.go
复制代码

然后进入该目录下,生成 mod 文件。

sudo go mod init
复制代码

调用该命令后,在 go-face-test 目录下应该已经生成了 go.mod 文件。


该库需要三个模型 shape_predictor_5_face_landmarks.datmmod_human_face_detector.dat 和 dlib_face_recognition_resnet_model_v1.dat,在 go-face-test 目录下下载相应的测试数据。

git clone https://github.com/Kagami/go-face-testdata testdata
复制代码


最终的项目结构应该如图。


代码实现

首先,我们利用代码检查环境是否正常。初始化识别器,释放资源。

package main
import ( “fmt”
“github.com/Kagami/go-face”)
const dataDir = “testdata”
// testdata 目录下两个对应的文件夹目录const ( modelDir = dataDir + “/models” imagesDir = dataDir + “/images”)
func main() { fmt.Println(“Face Recognition…”)
// 初始化识别器 rec, err := face.NewRecognizer(modelDir) if err != nil { fmt.Println(“Cannot INItialize recognizer”) } defer rec.Close()
fmt.Println(“Recognizer Initialized”)}
复制代码


编译然后运行代码。

sudo go run main.go
复制代码

应该得到下面输出。

Face Recognition…Recognizer Initialized
复制代码


到这一步,我们已经成功的设置好了需要的一切。


检测图片中人脸数量

首先准备一张林俊杰的照片,放到任意目录下,为了演示方便,我放在了 main.go 同级目录下。


如你所见,现在什么都没有,只有一张图片,接下来我们要让计算机计算图片中的人脸数量。

package main
import ( “fmt” “log”
“github.com/Kagami/go-face”)
const dataDir = “testdata”
// testdata 目录下两个对应的文件夹目录const ( modelDir = dataDir + “/models” imagesDir = dataDir + “/images”)
func main() { fmt.Println(“Face Recognition…”)
// 初始化识别器 rec, err := face.NewRecognizer(modelDir) if err != nil { fmt.Println(“Cannot INItialize recognizer”) } defer rec.Close()
fmt.Println(“Recognizer Initialized”)
// 调用该方法,传入路径。返回面部数量和任何错误 faces, err := rec.RecognizeFile(“linjunjie.jpeg”) if err != nil { log.Fatalf(“无法识别: %v”, err) } // 打印人脸数量 fmt.Println(“图片人脸数量: “, len(faces))}
复制代码


核心代码其实就是一行,go-face 封装进行识别的方法,传入相应路径的图片文件,执行代码后结果如下。

Face Recognition…Recognizer Initialized图片人脸数量:  1
复制代码


现在笨笨的计算机已经会数人脸数量了。那…如果一张照片里面有多人准不准呢,我们试试看,准备一张多人合照图片。

heyin.jpeg


我们将第 31 行代码换成如下即可。

faces, err := rec.RecognizeFile(“heyin.jpeg”)
复制代码


运行后的结果应该打印 (图片人脸数量: 6),接下来正式看展我们的人脸识别。


人脸识别

首先我们准备一张合照,这里依然沿用上面的 heyin.jpeg


整个处理过程大致分为以下几步。

  1. 将合影中人物映射到唯一 ID, 然后将唯一 ID 和对应人物相关联。

var samples []face.Descriptor	var peoples []int32	for i, f := range faces {		samples = append(samples, f.Descriptor)		// 每张脸唯一 id		peoples = append(peoples, int32(i))	}
// Pass samples to the recognizer. rec.SetSamples(samples, peoples)
复制代码
  1. 接下来我们封装一个人脸识别的方法,传入识别器和照片路径,打印对应人物 ID,人物名字。

func RecognizePeople(rec *face.Recognizer, file string) {	people, err := rec.RecognizeSingleFile(file)	if err != nil {		log.Fatalf(“无法识别: %v”, err)	}	if people == nil {		log.Fatalf(“图片上不是一张脸”)	}	peopleID := rec.Classify(people.Descriptor)	if peopleID < 0 {		log.Fatalf(“无法区分”)	}	fmt.Println(peopleID)	fmt.Println(labels[peopleID])}
复制代码
  1. 最后我们传入想要识别的图片,目前传入了 3 张图片,感兴趣的小伙伴可以传入其他图片尝试。

jay.jpeg


linjunjie.jpeg


taozhe.jpeg
  1. 调用三次。

RecognizePeople(rec, “jay.jpeg”)	RecognizePeople(rec, “linjunjie.jpeg”)	RecognizePeople(rec, “taozhe.jpeg”)
复制代码


代码如下

package main
import ( “fmt” “log”
“github.com/Kagami/go-face”)
const dataDir = “testdata”
// testdata 目录下两个对应的文件夹目录const ( modelDir = dataDir + ”/models” imagesDir = dataDir + “/images”)
// 图片中的人名var labels = []string{ “萧敬腾”, “周杰伦”, “unknow”, “王力宏”, “陶喆”, “林俊杰”,}
func main() { fmt.Println(“Face Recognition…”)
// 初始化识别器 rec, err := face.NewRecognizer(modelDir) if err != nil { fmt.Println(“Cannot INItialize recognizer”) } defer rec.Close()
fmt.Println(“Recognizer Initialized”)
// 调用该方法,传入路径。返回面部数量和任何错误 faces, err := rec.RecognizeFile(“heyin.jpeg”) if err != nil { log.Fatalf(“无法识别: %v”, err) } // 打印人脸数量 fmt.Println(“图片人脸数量: “, len(faces))
var samples []face.Descriptor var peoples []int32 for i, f := range faces { samples = append(samples, f.Descriptor) // 每张脸唯一 id peoples = append(peoples, int32(i)) }
// 传入样例到识别器 rec.SetSamples(samples, peoples)
RecognizePeople(rec, “jay.jpeg”) RecognizePeople(rec, “linjunjie.jpeg”) RecognizePeople(rec, “taozhe.jpeg”)}
func RecognizePeople(rec *face.Recognizer, file string) { people, err := rec.RecognizeSingleFile(file) if err != nil { log.Fatalf(“无法识别: %v”, err) } if people == nil { log.Fatalf(“图片上不是一张脸”) } peopleID := rec.Classify(people.Descriptor) if peopleID < 0 { log.Fatalf(“无法区分”) } fmt.Println(peopleID) fmt.Println(labels[peopleID])}
复制代码

运行结果

最后我们运行代码。

go build main.go./main
复制代码

结果如下

图片人脸数量:  61周杰伦5林俊杰4陶喆
复制代码

恭喜你,你已经成功的识别出这三张图片是谁了,到这一步,静态的图像人脸识别已经完成了。


静态人脸识别总结

到这一步我们已经可以成功的利用 Go 实现了静态人脸识别。将其运用到项目中也不是不可,不过它有诸多局限,使用的场景较为单一,只能用在例如用户上传人脸身份识别,单一人脸识别等场景;图片格式较为单一,暂时不支持 PNG 格式等缺点。


视频流人脸识别

背景

静态的人脸识别应用场景较为局限,不能够放到比较重要的环境中,例如金融,保险,安防等领域,存在伪造等可能。而且单纯的静态人脸识别,意义不大。动态的视频流拥有更加广阔的应用空间,充分应用在智能安防,手势识别,美颜等领域。5G 时代,众多业务将围绕视频这一块展开,如何将视频业务与核心业务实现解耦,声网的 RTE 组件做得不错,作为 RTE-PaaS 的开创者,声网已经有较多的技术积累,通过 RTE 组件的形式有很多好处。


RTE 优点

  1. 应用无关性

可以在不同的项目间共享,实现复用,避免多次开发的重复性工作

  1. 平台无关性

广泛应用于操作系统,编程语言及各领域

  1. 丰富的三方模块

能够提供例如白板教学,视频美颜,鉴黄等众多模块供开发者使用


代码实现

这里我们来实现一下视频流的相关人脸识别,之前的静态识别就是为了动态视频流人脸识别做铺垫。我们来说一下视频流的人脸识别的实现思路,静态的图像人脸识别已经完成,而视频是多帧的连续,我们只需要抽取片段捕获关键帧,识别出人像,人后输出对应关联的人名。


准备工作

这里我们用到的是 gocv(底层使用 OpenCV),这里我们暂时略过具体的安装流程,按照官方文档安装即可。


  1. 设置视频捕捉的设备,一般来说默认 0

// set to use a video capture device 0    deviceID := 0
// open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Println(err) return } defer webcam.Close()
复制代码
  1. 打开展示窗口

// open display window	window := gocv.NewWindow(“Face Detect”)	defer window.Close()
复制代码
  1. 准备图像矩阵,检测到人脸时显示矩形框的配置

// prepare image matrix	img := gocv.NewMat()	defer img.Close()
// color for the rect when faces detected blue := color.RGBA{0, 0, 255, 0}
复制代码
  1. 加载人脸识别分类器,用一个死循环,里面加上我们的相关识别服务

for {		if ok := webcam.Read(&img); !ok {			fmt.Printf(“cannot read device %v\n”, deviceID)			return		}		if img.Empty() {			continue		}
// detect faces rects := classifier.DetectMultiScale(img) fmt.Printf(“found %d faces\n”, len(rects))
// draw a rectangle around each face on the original image for _, r := range rects { gocv.Rectangle(&img, r, blue, 3) imgFace := img.Region® buff, err:=gocv.IMEncode(”.jpg”,imgFace) if err != nil { fmt.Println(“encoding to jpg err:%v”, err) break }
RecognizePeopleFromMemory(rec, buff) }
// show the image in the window, and wait 1 millisecond window.IMShow(img) window.WaitKey(1) }
复制代码

其中有几个步骤需要将一下,目前来说 gocv.IMEncode 只支持将捕获到的图片转成 PNGJPGGIF 三种格式。转换后的字节流放在内存中,然后将字节流传入我们的人脸识别函数中即可。

// RecognizeSingle returns face if it’s the only face on the image or// nil otherwise. Only JPEG format is currently supported. Thread-safe.func (rec *Recognizer) RecognizeSingle(imgData []byte) (face *Face, err error) {	faces, err := rec.recognize(0, imgData, 1)	if err != nil || len(faces) != 1 {		return	}	face = &faces[0]	return}
复制代码


注意事项

由于 go-face 只支持 JPEG 的格式,所以我们捕捉的帧只能转换成 JPG 格式

然后简单的封装一个字符流的识别函数。这里需要说明一下,之所以将 log.Fatal 换成了 log.Println 的原因是在视频流级别的识别中可能会出现没有人脸的情况,这个时候程序应当是正常运行的,不能退出。

func RecognizePeopleFromMemory(rec *face.Recognizer, img []byte) {	people, err := rec.RecognizeSingle(img)	if err != nil {		log.Println(“无法识别: %v”, err)		return	}	if people == nil {		log.Println(“图片上不是一张脸”)		return	}	peopleID := rec.Classify(people.Descriptor)	if peopleID < 0 {		log.Println(“无法区分”)		return	}	fmt.Println(peopleID)	fmt.Println(labels[peopleID])}
复制代码

最后完整代码如下

package main
import ( “fmt” “image/color” “log”
“github.com/Kagami/go-face” “gocv.io/x/gocv”)
const dataDir = “testdata”
// testdata 目录下两个对应的文件夹目录const ( modelDir = dataDir + “/models” imagesDir = dataDir + “/images”)
// 图片中的人名var labels = []string{ “萧敬腾”, “周杰伦”, “unknow”, “王力宏”, “陶喆”, “林俊杰”,}
func main() { // 初始化识别器 rec, err := face.NewRecognizer(modelDir) if err != nil { fmt.Println(“Cannot INItialize recognizer”) } defer rec.Close()
fmt.Println(“Recognizer Initialized”)
// 调用该方法,传入路径。返回面部数量和任何错误 faces, err := rec.RecognizeFile(“heyin.jpeg”) if err != nil { log.Fatalf(“无法识别: %v”, err) } // 打印人脸数量 fmt.Println(“图片人脸数量: “, len(faces))
var samples []face.Descriptor var peoples []int32 for i, f := range faces { samples = append(samples, f.Descriptor) // 每张脸唯一 id peoples = append(peoples, int32(i)) }
// Pass samples to the recognizer. rec.SetSamples(samples, peoples)
RecognizePeople(rec, “jay.jpeg”) RecognizePeople(rec, “linjunjie.jpeg”) RecognizePeople(rec, “taozhe.jpeg”)
// set to use a video capture device 0 deviceID := 0
// open webcam webcam, err := gocv.OpenVideoCapture(deviceID) if err != nil { fmt.Println(err) return } defer webcam.Close()
// open display window window := gocv.NewWindow(“Face Detect”) defer window.Close()
// prepare image matrix img := gocv.NewMat() defer img.Close()
// color for the rect when faces detected blue := color.RGBA{0, 0, 255, 0}
// load classifier to recognize faces classifier := gocv.NewCascadeClassifier() defer classifier.Close()
if !classifier.Load(”./haarcascade_frontalface_default.xml”) { fmt.Println(“Error reading cascade file: data/haarcascade_frontalface_default.xml”) return }
fmt.Printf(“start reading camera device: %v\n”, deviceID) for { if ok := webcam.Read(&img); !ok { fmt.Printf(“cannot read device %v\n”, deviceID) return } if img.Empty() { continue }
// detect faces rects := classifier.DetectMultiScale(img) if len(rects) == 0 { continue }
fmt.Printf(“found %d faces\n”, len(rects))
// draw a rectangle around each face on the original image for _, r := range rects { gocv.Rectangle(&img, r, blue, 3)
imgFace := img.Region® buff, err:=gocv.IMEncode(“.jpg”,imgFace) if err != nil { fmt.Println(“encoding to jpg err:%v”, err) break }
RecognizePeopleFromMemory(rec, buff) }
// show the image in the window, and wait 1 millisecond window.IMShow(img) window.WaitKey(1) }}
func RecognizePeople(rec *face.Recognizer, file string) { people, err := rec.RecognizeSingleFile(file) if err != nil { log.Fatalf(“无法识别: %v”, err) } if people == nil { log.Fatalf(“图片上不是一张脸”) } peopleID := rec.Classify(people.Descriptor) if peopleID < 0 { log.Fatalf(“无法区分”) } fmt.Println(peopleID) fmt.Println(labels[peopleID])}
func RecognizePeopleFromMemory(rec *face.Recognizer, img []byte) { people, err := rec.RecognizeSingle(img) if err != nil { log.Println(“无法识别: %v”, err) return } if people == nil { log.Println(“图片上不是一张脸”) return } peopleID := rec.Classify(people.Descriptor) if peopleID < 0 { log.Println(“无法区分”) return } fmt.Println(peopleID) fmt.Println(labels[peopleID])}
复制代码


接下来我们运行代码,应该能够拉起摄像头,这个时候我手持林俊杰的照片进行识别,我们可以看到左下角已经输出对应的人名了。


视频流人脸识别总结

到这一步,恭喜你,你已经能够完成视频流人脸识别了。但是,这里要说明一下,为了快速的实现,我们的样本集是比较少的,识别成功率相对来说比较低。不过一个简单的动态人脸识别已经搭好了。

总结

虽然我们实现了动态的人脸识别,但是在更为复杂的应用场景下难以实现相应的需求,而且存在图片格式等限制,缺乏人脸处理的其他模块,美颜,鉴黄等功能。不过通过第三方的 SDK,例如声网等平台去实现对应的需求,园区的人脸识别,视频会议,云课堂等场景,能够实现快速搭建,能够几行代码就能够完成相应的接入,并围绕 RTE 等组件进行人脸识别的相关开发。为开发节约大量时间和成本,可以将开发重心转移到更加核心的业务。

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

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

相关文章

【leaflet】1. 初见

▒ 目录 ▒ &#x1f6eb; 导读需求开发环境 1️⃣ 概念概念解释特点 2️⃣ 学习路线图3️⃣ html示例&#x1f6ec; 文章小结&#x1f4d6; 参考资料 &#x1f6eb; 导读 需求 要做游戏地图了&#xff0c;看到大量产品都使用的leaflet&#xff0c;所以开始学习这个。 开发环境…

IP可视对讲实时录制系统

介绍 软件架构 技术支持 CallRecored介绍 IP可视对讲实时录制系统设计了数据库表&#xff0c;并完成了数据库建模&#xff0c;采用了视频编解码技术&#xff0c;高效网络传输&#xff0c;磁盘高效读写技术&#xff0c;以及提供开放接口。 系统客户端采用扁平化UI&#xff0c;…

说说对高阶组件的理解?应用场景?

一、是什么 高阶函数&#xff08;Higher-order function&#xff09;&#xff0c;至少满足下列一个条件的函数 接受一个或多个函数作为输入输出一个函数 在React中&#xff0c;高阶组件即接受一个或多个组件作为参数并且返回一个组件&#xff0c;本质也就是一个函数&#xf…

【c趣编程】输入一个整数,判断其有几位

目录 1题目要求&#xff1a; 2解题思路&#xff1a; 3代码如下所示&#xff1a; 4运行代码如下&#xff1a; 5总结&#xff1a; 1题目要求&#xff1a; 只用一个scanf输出一串数&#xff0c;不可以一个一个的输入并计数&#xff0c;那样太浪费时间了。 C语言是一门面向过…

RabbitMQ 系列教程

一、RabbitMQ 部署及配置详解(集群部署) 二、RabbitMQ 部署及配置详解 (单机) 三、RabbitMQ 详解及实例&#xff08;含错误信息处理&#xff09; 四、RabbitMq死信队列及其处理方案 五、RabbitMQ Java开发教程—官方原版 六、RabbitMQ Java开发教程&#xff08;二&#x…

2022年03月 Python(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 关于函数,以下选项中描述错误的是? A:函数能完成特定的功能,对函数的使用不需要了解函数内部实现原理,只要了解函数的输入输出方式即可。 B:使用函数的主要目的是减低编程难度和…

利用mybatis-plus的分页插件在xml文件中联表查询实现分页(MySQL数据库)

文章目录 准备工作Mybatis-Plus分页插件配置进行分页测试domain层Controller层Service层ServiceImplMapper层分页接口测试带其他条件的分页查询 自定义的 mapper#method&#xff08;xml文件中&#xff09; 使用分页domain层Controller层Service层ServiceImplMapper层UserMapper…

机器视觉目标检测 - opencv 深度学习 计算机竞赛

文章目录 0 前言2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 0 前言 &#x1f5…

【Python大数据笔记_day05_Hive基础操作】

一.SQL,Hive和MapReduce的关系 用户在hive上编写sql语句,hive把sql语句转化为MapReduce程序去执行 二.Hive架构映射流程 用户接口: 包括CLI、JDBC/ODBC、WebGUI&#xff0c;CLI(command line interface&#xff09;为shell命令行&#xff1b;Hive中的Thrift服务器允许外部客户端…

UPLOAD-LABS1

less1 (js验证) 我们上传PHP的发现不可以&#xff0c;只能是jpg&#xff0c;png&#xff0c;gif&#xff08;白名单限制了&#xff09; 我们可以直接去修改限制 在查看器中看到使用了onsubmit这个函数&#xff0c;触发了鼠标的单击事件&#xff0c;在表单提交后马上调用了re…

Ajax请求中的跨域问题及其解决方案

跨域问题 跨域是指从一个域名的网页去请求另一个域名的资源, 比如当前在百度页面(https://baidu.com)去请求京东服务器(https://www.jd.com)的资源 传统请求不会跨域 在a站点可以通过超链接或者form表单提交或者window.location.href的方式跨域访问b站点的资源(静态或者动态)…

35岁危机来临前,程序员如何未雨绸缪?

程序员逼近35岁”高龄“&#xff0c;救命。。。 &#xff08;目瞪口呆)什么&#xff1f; 程序员而立之年&#xff0c;为未来担忧&#xff1f;&#xff08;双手抱头不敢置信&#xff09; 不可能&#xff01;他们明明那么努力、那么辛苦了&#xff01;&#xff01;&#xff01;&a…

用趋动云GPU部署自己的Stable Diffusion

注&#xff1a;本文内容来自于对DataWhale的开源学习项目——免费GPU线上跑AI项目实践的学习&#xff0c;参见&#xff1a;Docs&#xff0c;引用了多处DataWhale给出的教程。 1.创建项目 1&#xff09;进入趋动云用户工作台&#xff0c;在当前空间处选择注册时系统自动生成的…

debian/ubuntu/windows配置wiregurad内网服务器(包含掉线自启动)

文章目录 前言一、服务器配置安装wireguard软件生成私钥公钥配置服务器参数配置服务器sysctl参数启动、停止服务端 二、用户端配置安装wireguard软件生成私钥公钥配置客户端参数启动、停止客户端配置服务开机启动 三、服务器添加、删除客户四、配置掉线自启动配置掉线自启动脚本…

基于轻量级卷积神经网络CNN开发构建打架斗殴识别分析系统

在很多公共场合中&#xff0c;因为一些不可控因素导致最终爆发打架斗殴或者大规则冲突事件的案例层出不穷&#xff0c;基于视频监控等技术手段智能自动化地识别出已有或者潜在的危险行为对于维护公共场合的安全稳定有着重要的意义。本文的核心目的就是想要基于CNN模型来尝试开发…

MySQL中的多列子查询

-- 多列子查询 -- 如何查询与WOARD 的部门和岗位完全相同的所有雇员(并且不含smith本人) -- (字段1&#xff0c;字段2...) (select 字段1&#xff0c;字段2 from ...) -- 分析&#xff1a; 1. 得到smith的部门和岗位 SELECT deptno,job FROM empWHERE ename WARD; -- 2.使…

字符编码转换时发生内存越界引发的摄像头切换失败问题的排查

目录 1、问题说明 2、初步分析 3、字符串字符编码说明 4、进一步分析 5、为啥在日常测试时没有遇到切换摄像头失败的问题呢&#xff1f; 6、华为MateBook笔记本使用高通的CPU 7、最后 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更…

电脑msvcp110.dll丢失怎么办,msvcp110.dll缺失的详细修复步骤

在现代科技发展的时代&#xff0c;电脑已经成为我们生活和工作中不可或缺的工具。然而&#xff0c;由于各种原因&#xff0c;电脑可能会出现一些问题&#xff0c;其中之一就是msvcp110.dll文件丢失。这个问题可能会导致一些应用程序无法正常运行&#xff0c;给我们的生活和工作…

[直播自学]-[汇川easy320]搞起来(3)看文档安装软件 查找设备

2023.11.09 20&#xff1a;04 按照文档 解压压缩包得到&#xff1a; 打开 里面有一条值得注意&#xff1a; 想把软件安装到C盘&#xff0c;但是C盘没什么空间了&#xff0c;把C盘清理清理。 20&#xff1a;35 安装很快完成&#xff0c;然后阅读 由于PLC是新的&#xff0c…