yolov8-制作数据集,数据集格式转换(yolo格式-voc格式)附完整代码

yolo训练时可使用的数据集格式为yolo格式以及voc格式, voc格式的数据集在训练时需要先转换为yolo格式,然后根据自己的数据集的位置更改yaml配置文件的文件路径即可。基于目前对Yolo系列训练模型的讲解已经很全面,所以本文主要讲解yolo数据集与voc数据集之间的转换。

两种数据集形式的最大区别就是yolo是直接采用txt文件保存模型的labels标签,如下图,每一行都代表着该图像中的一个标签GT。

而voc格式的标签是保存在Annotations目录下的xml文件当中,除此之外无差别。

目前大部分数据集的保存都是以voc格式, 在我们训练yolo时需要将voc转换成yolo,说白了就是将基于xml的标签转换为txt保存的标签。

为了深刻理解数据转换的步骤,接下来以coco数据集(yolo格式)为例,实现yolo格式->voc格式->yolo格式的转换。

yolo格式->voc格式

coco数据集:

我们创建一个voc格式的文件目录:

Annotations:存放标签的xml文件

images: 数据集图片.jpg

imageSets: 存放分好的数据集: 训练集,验证集,测试集。

labels: 给yolo模型训练的标签(txt格式)

设置好文件路径:

        # coco数据集路径pre_pic = "../coco128/images/train2017/"txtPath = "../coco128/labels/train2017/"# 新voc数据集保存路径xmlPath = "../my_datasets/Annotations/"  # xml标签after_pic = "../my_datasets/images/"  # 训练集图片

 实现yolo->voc的转换:

        # 将标签转换为xml格式makexml(pre_pic, txtPath, xmlPath)
def makexml(picPath, txtPath, xmlPath):"""此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件Args:picPath:   图片所在路径txtPath:   txt格式labels标签xmlPath:   xml文件保存路径Returns:"""dic = config["names"]  # 数据集类别字典files = os.listdir(txtPath)for i, name in enumerate(files):xmlBuilder = Document()annotation = xmlBuilder.createElement("annotation")  # 创建annotation标签xmlBuilder.appendChild(annotation)txtFile = open(txtPath + name)txtList = txtFile.readlines()img = cv2.imread(picPath + name[0:-4] + ".jpg")Pheight, Pwidth, Pdepth = img.shapefolder = xmlBuilder.createElement("folder")  # folder标签foldercontent = xmlBuilder.createTextNode("driving_annotation_dataset")folder.appendChild(foldercontent)annotation.appendChild(folder)  # folder标签结束filename = xmlBuilder.createElement("filename")  # filename标签filenamecontent = xmlBuilder.createTextNode(name[0:-4] + ".jpg")filename.appendChild(filenamecontent)annotation.appendChild(filename)  # filename标签结束size = xmlBuilder.createElement("size")  # size标签width = xmlBuilder.createElement("width")  # size子标签widthwidthcontent = xmlBuilder.createTextNode(str(Pwidth))width.appendChild(widthcontent)size.appendChild(width)  # size子标签width结束height = xmlBuilder.createElement("height")  # size子标签heightheightcontent = xmlBuilder.createTextNode(str(Pheight))height.appendChild(heightcontent)size.appendChild(height)  # size子标签height结束depth = xmlBuilder.createElement("depth")  # size子标签depthdepthcontent = xmlBuilder.createTextNode(str(Pdepth))depth.appendChild(depthcontent)size.appendChild(depth)  # size子标签depth结束annotation.appendChild(size)  # size标签结束for j in txtList:oneline = j.strip().split(" ")object = xmlBuilder.createElement("object")  # object 标签picname = xmlBuilder.createElement("name")  # name标签namecontent = xmlBuilder.createTextNode(dic[oneline[0] if type(oneline[0]) == int else int(oneline[0])])picname.appendChild(namecontent)object.appendChild(picname)  # name标签结束pose = xmlBuilder.createElement("pose")  # pose标签posecontent = xmlBuilder.createTextNode("Unspecified")pose.appendChild(posecontent)object.appendChild(pose)  # pose标签结束truncated = xmlBuilder.createElement("truncated")  # truncated标签truncatedContent = xmlBuilder.createTextNode("0")truncated.appendChild(truncatedContent)object.appendChild(truncated)  # truncated标签结束difficult = xmlBuilder.createElement("difficult")  # difficult标签difficultcontent = xmlBuilder.createTextNode("0")difficult.appendChild(difficultcontent)object.appendChild(difficult)  # difficult标签结束bndbox = xmlBuilder.createElement("bndbox")  # bndbox标签xmin = xmlBuilder.createElement("xmin")  # xmin标签mathData = int(((float(oneline[1])) * Pwidth + 1) - (float(oneline[3])) * 0.5 * Pwidth)xminContent = xmlBuilder.createTextNode(str(mathData))xmin.appendChild(xminContent)bndbox.appendChild(xmin)  # xmin标签结束ymin = xmlBuilder.createElement("ymin")  # ymin标签mathData = int(((float(oneline[2])) * Pheight + 1) - (float(oneline[4])) * 0.5 * Pheight)yminContent = xmlBuilder.createTextNode(str(mathData))ymin.appendChild(yminContent)bndbox.appendChild(ymin)  # ymin标签结束xmax = xmlBuilder.createElement("xmax")  # xmax标签mathData = int(((float(oneline[1])) * Pwidth + 1) + (float(oneline[3])) * 0.5 * Pwidth)xmaxContent = xmlBuilder.createTextNode(str(mathData))xmax.appendChild(xmaxContent)bndbox.appendChild(xmax)  # xmax标签结束ymax = xmlBuilder.createElement("ymax")  # ymax标签mathData = int(((float(oneline[2])) * Pheight + 1) + (float(oneline[4])) * 0.5 * Pheight)ymaxContent = xmlBuilder.createTextNode(str(mathData))ymax.appendChild(ymaxContent)bndbox.appendChild(ymax)  # ymax标签结束object.appendChild(bndbox)  # bndbox标签结束annotation.appendChild(object)  # object标签结束f = open(xmlPath + name[0:-4] + ".xml", 'w')xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')f.close()print("txt2xml ok!")

注意:xml文件中保存的是标签框的左上角点和右下角点的坐标。

数据集划分

为了让Yolo模型能读取到标签数据,我们需要将voc格式的xml标签转换为txt标签,并且需要对数据集进行划分:

def splitxml(trainval_percent, train_percent):"""将数据集分为train,val,test, 并存放在'../my_datasets/ImageSets'这个路径当中Args:trainval_percent:  训练集和验证集的比例train_percent:  训练集比例Returns:"""xmlfilepath = '../my_datasets/Annotations/'txtsavepath = '../my_datasets/ImageSets'total_xml = os.listdir(xmlfilepath)num = len(total_xml)list = range(num)tv = int(num * trainval_percent)tr = int(tv * train_percent)trainval = random.sample(list, tv)train = random.sample(trainval, tr)ftrainval = open(txtsavepath + '/trainval.txt', 'w')ftest = open(txtsavepath + '/test.txt', 'w')ftrain = open(txtsavepath + '/train.txt', 'w')fval = open(txtsavepath + '/val.txt', 'w')for i in list:name = total_xml[i][:-4] + '\n'if i in trainval:ftrainval.write(name)if i in train:ftrain.write(name)else:fval.write(name)else:ftest.write(name)ftrainval.close()ftrain.close()fval.close()ftest.close()print("split dataset_xml ok!")

这一步会在ImageSets目录下生成:

这几个文件,文件里存放划分后数据集的文件名

voc格式 -> yolo格式

这里有个要注意的地方就是,xml文件里真实框的表示形式是对角点的坐标, Yolo格式标签的预测框表示形式为xywh(中心点坐标和预测框的长宽)并且需要做归一化。

    # 将xml格式数据转换为txtxml2yolo()
def xml2yolo():sets = ['train', 'test', 'val']classes = list(dic.values())for image_set in sets:# 先找labels文件夹如果不存在则创建if not os.path.exists('../my_datasets/labels/'):os.makedirs('../my_datasets/labels/')image_ids = open('../my_datasets/ImageSets/%s.txt' % (image_set)).read().strip().split()list_file = open('../my_datasets/%s.txt' % (image_set), 'w')# 将对应的文件_id以及全路径写进去并换行for image_id in image_ids:list_file.write('my_datasets/images/%s.jpg\n' % (image_id))convert_annotation(image_id, classes)# 关闭文件list_file.close()print("xml2txt ok!")def convert_annotation(image_id, classes):# 对应的通过year 找到相应的文件夹,并且打开相应image_id的xml文件,其对应bund文件# print('my_datasets/Annotations/%s.xml' % (image_id))in_file = open('../my_datasets/Annotations/%s.xml' % (image_id), encoding='utf-8')# 准备在对应的image_id 中写入对应的label,分别为# <object-class> <x> <y> <width> <height>out_file = open('../my_datasets/labels/%s.txt' % (image_id), 'w', encoding='utf-8')# 解析xml文件tree = ET.parse(in_file)# 获得对应的键值对root = tree.getroot()# 获得图片的尺寸大小size = root.find('size')# 如果xml内的标记为空,增加判断条件if size != None:# 获得宽w = int(size.find('width').text)# 获得高h = int(size.find('height').text)# 遍历目标objfor obj in root.iter('object'):# 获得difficult ??difficult = obj.find('difficult').text# 获得类别 =string 类型cls = obj.find('name').text# 如果类别不是对应在我们预定好的class文件中,或difficult==1则跳过# if cls not in classes or int(difficult) == 1:#     continue# 通过类别名称找到idcls_id = classes.index(cls)# 找到bndbox 对象xmlbox = obj.find('bndbox')# 获取对应的bndbox的数组 = ['xmin','xmax','ymin','ymax']b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))# print(image_id, cls, b)# 带入进行归一化操作# w = 宽, h = 高, b= bndbox的数组 = ['xmin','xmax','ymin','ymax']bb = convert((w, h), b)# bb 对应的是归一化后的(x,y,w,h)# 生成 calss x y w h 在label文件中out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')# 进行归一化操作
def convert(size, box):  # size:(原图w,原图h) , box:(xmin,xmax,ymin,ymax)dw = 1. / size[0]  # 1/wdh = 1. / size[1]  # 1/hx = (box[0] + box[1]) / 2.0  # 物体在图中的中心点x坐标y = (box[2] + box[3]) / 2.0  # 物体在图中的中心点y坐标w = box[1] - box[0]  # 物体实际像素宽度h = box[3] - box[2]  # 物体实际像素高度x = x * dw  # 物体中心点x的坐标比(相当于 x/原图w)w = w * dw  # 物体宽度的宽度比(相当于 w/原图w)y = y * dh  # 物体中心点y的坐标比(相当于 y/原图h)h = h * dh  # 物体宽度的宽度比(相当于 h/原图h)return (x, y, w, h)  # 返回 相对于原图的物体中心点的x坐标比,y坐标比,宽度比,高度比,取值范围[0-1]

执行完代码后会在数据集目录下生成

 test,train,val三个txt文件,里面存放着各数据集的路径, 训练模型时只需要将这三个txt文件的路径写入my_datasets.yaml里,然后让Yolo模型读取这个yaml文件即可。

完整代码:

# -*- coding: utf-8 -*-
# xml解析包
from xml.dom.minidom import Document
import os
import cv2
import random
import xml.etree.ElementTree as ET
import yaml
import shutil# 将数据转换为xml格式
def makexml(picPath, txtPath, xmlPath):"""此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件Args:picPath:   图片所在路径txtPath:   txt格式labels标签xmlPath:   xml文件保存路径Returns:"""dic = config["names"]  # 数据集类别字典files = os.listdir(txtPath)for i, name in enumerate(files):xmlBuilder = Document()annotation = xmlBuilder.createElement("annotation")  # 创建annotation标签xmlBuilder.appendChild(annotation)txtFile = open(txtPath + name)txtList = txtFile.readlines()img = cv2.imread(picPath + name[0:-4] + ".jpg")Pheight, Pwidth, Pdepth = img.shapefolder = xmlBuilder.createElement("folder")  # folder标签foldercontent = xmlBuilder.createTextNode("driving_annotation_dataset")folder.appendChild(foldercontent)annotation.appendChild(folder)  # folder标签结束filename = xmlBuilder.createElement("filename")  # filename标签filenamecontent = xmlBuilder.createTextNode(name[0:-4] + ".jpg")filename.appendChild(filenamecontent)annotation.appendChild(filename)  # filename标签结束size = xmlBuilder.createElement("size")  # size标签width = xmlBuilder.createElement("width")  # size子标签widthwidthcontent = xmlBuilder.createTextNode(str(Pwidth))width.appendChild(widthcontent)size.appendChild(width)  # size子标签width结束height = xmlBuilder.createElement("height")  # size子标签heightheightcontent = xmlBuilder.createTextNode(str(Pheight))height.appendChild(heightcontent)size.appendChild(height)  # size子标签height结束depth = xmlBuilder.createElement("depth")  # size子标签depthdepthcontent = xmlBuilder.createTextNode(str(Pdepth))depth.appendChild(depthcontent)size.appendChild(depth)  # size子标签depth结束annotation.appendChild(size)  # size标签结束for j in txtList:oneline = j.strip().split(" ")object = xmlBuilder.createElement("object")  # object 标签picname = xmlBuilder.createElement("name")  # name标签namecontent = xmlBuilder.createTextNode(dic[oneline[0] if type(oneline[0]) == int else int(oneline[0])])picname.appendChild(namecontent)object.appendChild(picname)  # name标签结束pose = xmlBuilder.createElement("pose")  # pose标签posecontent = xmlBuilder.createTextNode("Unspecified")pose.appendChild(posecontent)object.appendChild(pose)  # pose标签结束truncated = xmlBuilder.createElement("truncated")  # truncated标签truncatedContent = xmlBuilder.createTextNode("0")truncated.appendChild(truncatedContent)object.appendChild(truncated)  # truncated标签结束difficult = xmlBuilder.createElement("difficult")  # difficult标签difficultcontent = xmlBuilder.createTextNode("0")difficult.appendChild(difficultcontent)object.appendChild(difficult)  # difficult标签结束bndbox = xmlBuilder.createElement("bndbox")  # bndbox标签xmin = xmlBuilder.createElement("xmin")  # xmin标签mathData = int(((float(oneline[1])) * Pwidth + 1) - (float(oneline[3])) * 0.5 * Pwidth)xminContent = xmlBuilder.createTextNode(str(mathData))xmin.appendChild(xminContent)bndbox.appendChild(xmin)  # xmin标签结束ymin = xmlBuilder.createElement("ymin")  # ymin标签mathData = int(((float(oneline[2])) * Pheight + 1) - (float(oneline[4])) * 0.5 * Pheight)yminContent = xmlBuilder.createTextNode(str(mathData))ymin.appendChild(yminContent)bndbox.appendChild(ymin)  # ymin标签结束xmax = xmlBuilder.createElement("xmax")  # xmax标签mathData = int(((float(oneline[1])) * Pwidth + 1) + (float(oneline[3])) * 0.5 * Pwidth)xmaxContent = xmlBuilder.createTextNode(str(mathData))xmax.appendChild(xmaxContent)bndbox.appendChild(xmax)  # xmax标签结束ymax = xmlBuilder.createElement("ymax")  # ymax标签mathData = int(((float(oneline[2])) * Pheight + 1) + (float(oneline[4])) * 0.5 * Pheight)ymaxContent = xmlBuilder.createTextNode(str(mathData))ymax.appendChild(ymaxContent)bndbox.appendChild(ymax)  # ymax标签结束object.appendChild(bndbox)  # bndbox标签结束annotation.appendChild(object)  # object标签结束f = open(xmlPath + name[0:-4] + ".xml", 'w')xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')f.close()print("txt2xml ok!")def moveimage(pre_path, after_path):path_dir = os.listdir(pre_path)for file in path_dir:shutil.copy(pre_path + file, after_path)# 将数据集分为train,val,test
def splitxml(trainval_percent, train_percent):"""将数据集分为train,val,test, 并存放在'../my_datasets/ImageSets'这个路径当中Args:trainval_percent:  训练集和验证集的比例train_percent:  训练集比例Returns:"""xmlfilepath = '../my_datasets/Annotations/'txtsavepath = '../my_datasets/ImageSets'total_xml = os.listdir(xmlfilepath)num = len(total_xml)list = range(num)tv = int(num * trainval_percent)tr = int(tv * train_percent)trainval = random.sample(list, tv)train = random.sample(trainval, tr)ftrainval = open(txtsavepath + '/trainval.txt', 'w')ftest = open(txtsavepath + '/test.txt', 'w')ftrain = open(txtsavepath + '/train.txt', 'w')fval = open(txtsavepath + '/val.txt', 'w')for i in list:name = total_xml[i][:-4] + '\n'if i in trainval:ftrainval.write(name)if i in train:ftrain.write(name)else:fval.write(name)else:ftest.write(name)ftrainval.close()ftrain.close()fval.close()ftest.close()print("split dataset_xml ok!")def xml2yolo():sets = ['train', 'test', 'val']classes = list(dic.values())for image_set in sets:# 先找labels文件夹如果不存在则创建if not os.path.exists('../my_datasets/labels/'):os.makedirs('../my_datasets/labels/')image_ids = open('../my_datasets/ImageSets/%s.txt' % (image_set)).read().strip().split()list_file = open('../my_datasets/%s.txt' % (image_set), 'w')# 将对应的文件_id以及全路径写进去并换行for image_id in image_ids:list_file.write('my_datasets/images/%s.jpg\n' % (image_id))convert_annotation(image_id, classes)# 关闭文件list_file.close()print("xml2txt ok!")def convert_annotation(image_id, classes):# 找到相应的文件夹,并且打开相应image_id的xml文件# print('my_datasets/Annotations/%s.xml' % (image_id))in_file = open('../my_datasets/Annotations/%s.xml' % (image_id), encoding='utf-8')# 准备在对应的image_id 中写入对应的label,分别为# <object-class> <x> <y> <width> <height>out_file = open('../my_datasets/labels/%s.txt' % (image_id), 'w', encoding='utf-8')# 解析xml文件tree = ET.parse(in_file)# 获得对应的键值对root = tree.getroot()# 获得图片的尺寸大小size = root.find('size')# 如果xml内的标记为空,增加判断条件if size != None:# 获得宽w = int(size.find('width').text)# 获得高h = int(size.find('height').text)# 遍历目标objfor obj in root.iter('object'):# 获得difficult ??difficult = obj.find('difficult').text# 获得类别 =string 类型cls = obj.find('name').text# 如果类别不是对应在我们预定好的class文件中,或difficult==1则跳过(一般用不到)# if cls not in classes or int(difficult) == 1:#     continue# 通过类别名称找到idcls_id = classes.index(cls)# 找到bndbox 对象xmlbox = obj.find('bndbox')# 获取对应的bndbox的数组 = ['xmin','xmax','ymin','ymax']b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))# print(image_id, cls, b)# 带入进行归一化操作# w = 宽, h = 高, b= bndbox的数组 = ['xmin','xmax','ymin','ymax']bb = convert((w, h), b)# bb 对应的是归一化后的(x,y,w,h)# 生成 calss x y w h 在label文件中out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')# 进行归一化操作
def convert(size, box):  # size:(原图w,原图h) , box:(xmin,xmax,ymin,ymax)dw = 1. / size[0]  # 1/wdh = 1. / size[1]  # 1/hx = (box[0] + box[1]) / 2.0  # 物体在图中的中心点x坐标y = (box[2] + box[3]) / 2.0  # 物体在图中的中心点y坐标w = box[1] - box[0]  # 物体实际像素宽度h = box[3] - box[2]  # 物体实际像素高度x = x * dw  # 物体中心点x的坐标比(相当于 x/原图w)w = w * dw  # 物体宽度的宽度比(相当于 w/原图w)y = y * dh  # 物体中心点y的坐标比(相当于 y/原图h)h = h * dh  # 物体宽度的宽度比(相当于 h/原图h)return (x, y, w, h)  # 返回 相对于原图的物体中心点的x坐标比,y坐标比,宽度比,高度比,取值范围[0-1]config_file = "../my_datasets/my_datasets.yaml"
with open(config_file, "r") as file:config = yaml.safe_load(file)
dic = config["names"]  # 类别字典
if __name__ == "__main__":isyolo = Trueif isyolo:# Yolo格式数据路径# coco数据集路径pre_pic = "../coco128/images/train2017/"txtPath = "../coco128/labels/train2017/"# 新voc数据集保存路径xmlPath = "../my_datasets/Annotations/"  # xml标签after_pic = "../my_datasets/images/"  # 训练集图片# 将标签转换为xml格式makexml(pre_pic, txtPath, xmlPath)# 将图像移动到images中moveimage(pre_pic, after_pic)# 将数据集分为train,val,testsplitxml(0.9, 0.9)# 将xml格式数据转换为txtxml2yolo()

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

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

相关文章

C#中 使用yield return 优化大数组或集合的访问

概要 我们在开发过程中&#xff0c;经常需要在一个很大的数组或集合中搜索元素&#xff0c;以满足业务需求。 本文主要介绍通过使用yield return的方式&#xff0c;避免将大量数据全部加载进入内存&#xff0c;再进行处理。从而提高程序的性能。 设计和实现 基本业务场景&a…

docker安装nginx并配置SSL

1、拉取镜像 docker pull nginx2、启动nginx容器&#xff0c;复制一份默认配置文件出来 // 以nginx镜像为基础镜像创建一个名为nginx01的容器 docker run -d -p 80:80 --name nginx01 nginx创建成功后会看到nginx的欢迎页面 3、挂载nginx目录 拷贝nginx的配置信息到主机目录…

【图论】强连通分量

一.定义 强连通分量&#xff08;Strongly Connected Components&#xff0c;简称SCC&#xff09;是图论中的一个概念&#xff0c;用于描述有向图中的一组顶点&#xff0c;其中任意两个顶点之间都存在一条有向路径。换句话说&#xff0c;对于图中的任意两个顶点u和v&#xff0c;…

Python爬虫—破解JS加密的Cookie

前言 在进行网站数据爬取时&#xff0c;很多网站会使用JS加密来保护Cookie的安全性&#xff0c;而为了防止被网站反爬虫机制识别出来&#xff0c;我们通常需要使用代理IP来隐藏我们的真实IP地址。 本篇文章将介绍如何结合代理IP破解JS加密的Cookie&#xff0c;主要包括以下几个…

银河麒麟V10 QtCreator安装配置说明(断网离线)

文章目录 1.安装要求:2.安装Qt1.安装要求: 拥有Qt软件安装包qt5.12-arm链接:https://pan.baidu.com/s/1FJerT6SckfjABxAn60rsrA?pwd=mfi6 提取码:mfi6 2.安装Qt 1)拷贝Qt软件包qt5.12-arm至系统/home/kylin/桌面 2)安装Qt软件包 cd /home/kylin/qt5.12-arm/桌面 su…

Flutter:gsy_flutter_demo项目学习——布局切换动画、列表滑动监听、列表滑动到指定位置、高斯模糊

前言 gsy_flutter_demo是一个关于各种小案例和小问题的方案解决。项目是由flutter大佬恋猫de小郭维护的 项目地址&#xff1a;https://github.com/CarGuo/gsy_flutter_demo 感兴趣的可以看一下大佬的文章&#xff1a;Flutter完整开发实战详解系列&#xff0c;GSY Flutter 系…

非凸科技受邀参加中科大线上量化分享

7月30日&#xff0c;非凸科技受邀参加由中国科学技术大学管理学院学生会、超级量化共同组织的“打开量化私募的黑箱”线上活动&#xff0c;分享量化前沿以及求职经验&#xff0c;助力同学们拿到心仪的offer。 活动上&#xff0c;非凸科技量化策略负责人陆一洲从多个角度分享了如…

485modbus转profinet网关连三菱变频器modbus通讯触摸屏监控

本案例介绍了如何通过485modbus转profinet网关连接威纶通与三菱变频器进行modbus通讯。485modbus转profinet网关提供了可靠的连接方式&#xff0c;使用户能够轻松地将不同类型的设备连接到同一网络中。通过使用这种网关&#xff0c;用户可以有效地管理和监控设备&#xff0c;从…

【华秋干货铺】PCB布线技巧升级:高速信号篇

如下表所示&#xff0c;接口信号能工作在8Gbps及以上速率&#xff0c;由于速率很高&#xff0c;PCB布线设计要求会更严格&#xff0c;在前几篇关于PCB布线内容的基础上&#xff0c;还需要根据本篇内容的要求来进行PCB布线设计。 高速信号布线时尽量少打孔换层&#xff0c;换层优…

vue 3.0 + element-ui MessageBox弹出框的 让文本框显示文字 placeholder

inputPlaceholder:请填写理由, 方法实现如下: this.$prompt(, 是否确认&#xff1f;, { confirmButtonText: 确定, cancelButtonText: 取消, inputPlaceholder:请填写理由, }).then(({ value }) > { if(value null || value ""){ Message({message: 请填…

卷积神经网络【图解CNN】

文章目录 1.卷积运算2.池化3.全连接层 卷积神经网络可以看作一个函数或者黑箱&#xff0c;输入就是图片的像素阵列&#xff0c;输出就是这个图片是什么&#xff1f; 图片是X&#xff0c;那么就输出‘x’&#xff0c;图片是‘O’,那么就输出O&#xff1b; 在计算机眼中&#xff…

如何制作VR全景地图,VR全景地图可以用在哪些领域?

引言&#xff1a; 随着科技的迅速进步&#xff0c;虚拟现实&#xff08;VR&#xff09;技术正逐渐渗透到各个领域。VR全景地图作为其中的重要应用之一&#xff0c;为人们提供了身临其境的全新体验。 一.什么是VR全景地图&#xff1f; VR全景地图是一种利用虚拟现实技术&…

怎样做好字幕翻译服务?

我们知道&#xff0c;字幕泛指影视作品后期加工的文字&#xff0c;往往显示在电视、电影、舞台作品中。字幕翻译就是将外国影片配上本国字幕或者是将本国影片配上外国字幕。那么&#xff0c;字幕翻译的主要流程是什么&#xff0c;怎样做好字幕翻译服务&#xff1f; 据了解&…

企业既要用u盘又要防止u盘泄密怎么办?

企业在日常生产生活过程中&#xff0c;使用u盘交换数据是最企业最常用也是最便携的方式&#xff0c;但是在使用u盘的同时&#xff0c;也给企业的数据保密工作带来了很大的挑战&#xff0c;往往很多情况下企业的是通过u盘进行数据泄漏的。很多企业采用一刀切的方式&#xff0c;直…

【Kubernetes】

目录 一、Kubernetes 概述1、K8S 是什么&#xff1f;2、为什么要用 K8S?3、Kubernetes 集群架构与组件 二、核心组件1、Master 组件2、Node 组件3、K8S创建Pod的工作流程&#xff1f;&#xff08;重点&#xff09;4、K8S资源对象&#xff08;重点&#xff09;5、Kubernetes 核…

iOS数字转为图片

根据数字&#xff0c;转成对应的图片 - (void)viewDidLoad {[super viewDidLoad];[self testNum2String:10086]; }/// 根据数字&#xff0c;显示对应的图片 数字用特定的图片显示 - (void)testNum2String:(NSInteger)num {UIView *numContentView [[UIView alloc] initWithFr…

【外卖系统】套餐管理

新增套餐 需求分析 后台可以管理套餐信息&#xff0c;通过新增套餐功能来添加一个新的套餐&#xff0c;在添加套餐时需要选择当前套餐所属的套餐分类和包含的菜品&#xff0c;并需要上传套餐对应的图片。 页面发送ajax请求&#xff0c;请求服务端获取套餐分类数据并展示到下…

最细致讲解yolov8模型推理完整代码--(前处理,后处理)

研究yolov8时&#xff0c;一直苦寻不到Yolov8完整的模型推理代码演示&#xff0c;大部分人都是基于Yolo已经封装好的函数调用&#xff0c;这个网上教程很多&#xff0c;本文就不赘述这方面的内容了&#xff0c;接下来将细致全面的讲解yolov8模型推理代码&#xff0c;也就是yolo…

卡片的点击事件通过点击进行路由传参

下面是详情页 通过 接收 <template><div class"detail"><img :src"row.imgUrl"><van-icon name"arrow-left" click"back" /></div> </template><script> export default {created() {let …

LeetCode每日一题Day4——26. 删除有序数组中的重复项

✨博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;算法修炼之练气篇&#xff08;C\C版&#xff09; &#x1f353;专栏&#xff1a;算法修炼之筑基篇&#xff08;C\C版&#xff09; &#x1f433;专栏&#xff1a;算法修炼之练气篇&#xff08;Python版&#xff09; …