目标检测:数据集划分 XML数据集转YOLO标签

news2024/11/24 12:35:06

文章目录

  • 1、前言:
  • 2、生成对应的类名
  • 3、xml转为yolo的label形式
  • 4、优化代码
  • 5、划分数据集
  • 6、画目录树
  • 7、目标检测系列文章

1、前言:

本文演示如何划分数据集,以及将VOC标注的xml数据转为YOLO标注的txt格式,且生成classes的txt文件。

# 本文演示的项目目录
E:
└──dataset
        ├── images_package  # 存放图片文件夹
        │    ├── 000002.jpg
        │    ├── 000003.jpg
        │    ├── 000004.jpg
        │    ├── 000005.jpg
        │    ├── 000006.jpg
        │    ├── zebra_crossing_20180129-000545_362.jpg
        │    ├── zebra_crossing_20180129-000545_364.jpg
        │    ├── zebra_crossing_20180129-000545_366.jpg
        │    └── zebra_crossing_20180129-000645_368.jpg
        └── xml_outputs  # 存放图片对应的XML
            ├── 000002.xml
            ├── 000003.xml
            ├── 000004.xml
            ├── 000005.xml
            ├── 000006.xml
            ├── zebra_crossing_20180129-000545_362.xml
            ├── zebra_crossing_20180129-000545_364.xml
            ├── zebra_crossing_20180129-000545_366.xml
            └── zebra_crossing_20180129-000645_368.xml

2、生成对应的类名

创建create_classes_json.py自动生成对应的类名json文件,以及在控制台输出对应的类名集。

from doctest import REPORTING_FLAGS
from lib2to3.pgen2.token import RPAR
import os
from tqdm import tqdm
from lxml import etree
import json
 
 
# 读取 xml 文件信息,并返回字典形式
def parse_xml_to_dict(xml):
    if len(xml) == 0:  # 遍历到底层,直接返回 tag对应的信息
        return {xml.tag: xml.text}
 
    result = {}
    for child in xml:
        child_result = parse_xml_to_dict(child)  # 递归遍历标签信息
        if child.tag != 'object':
            result[child.tag] = child_result[child.tag]
        else:
            if child.tag not in result:  # 因为object可能有多个,所以需要放入列表里
                result[child.tag] = []
            result[child.tag].append(child_result[child.tag])
    return {xml.tag: result}
 
 
# 提取xml中name保留为json文件
def xml2json(data,json_path):
    xml_path = [os.path.join(data, i) for i in os.listdir(data)]
    classes = []      # 目标类别
    num_object = 0
    for xml_file in tqdm(xml_path, desc="loading..."):
        with open(xml_file,encoding='gb18030',errors='ignore') as fid:      # 防止出现非法字符报错
            xml_str = fid.read()
        xml = etree.fromstring(xml_str)
        data = parse_xml_to_dict(xml)["annotation"]  # 读取xml文件信息
        for j in data['object']:        # 获取单个xml文件的目标信息
            ob = j['name']
            num_object +=1
            if ob not in classes:
                classes.append(ob)
    print(num_object)
    # 生成json文件
    labels = {}
    for index,object in enumerate(classes):
        labels[index] = object

    # 打印类名
    classes_name=[labels[key] for key in labels]
    print(f'类名:{classes_name}')
    # 打印类型字典
    print(f'字典形式:{labels}')

    # json.dumps将python对象转为json对象(将dict转化成str)。 json.loads将json字符串解码成python对象(将str转化成dict)
    labels = json.dumps(labels,indent=4)
    json_path=os.path.join(json_path,'classes_indices.json')
    with open(json_path,'w') as f:
        f.write(labels)
 
 
if __name__ == "__main__":
    # 数据集的 xml 目录
    xml_path = 'E:\\dataset\\xml_outputs' 
    # 存放类名json路径
    json_path='E:\\dataset'        
    xml2json(xml_path,json_path)

    pass


'''
输出效果如下:
loading...: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 9/9 [00:00<00:00, 143.24it/s]        
9
类名:['red', 'crosswalk']
字典形式:{0: 'red', 1: 'crosswalk'}
'''

classes_indices.json文件如下

在这里插入图片描述

3、xml转为yolo的label形式

创建xml_to_yolo_label_txt.py,在转换之前,我们需要获取数据集目标类别的列表,即运行上方create_classes_json.py,得到类名集,再替换CLASSES值。程序运行完后自动生成Annotations文件夹,里面就是yolo的label形式txt文件了。

import xml.etree.ElementTree as ET
import os


def convert(size,box):
    # 将bbox的左上角点,右下角点坐标的格式,转换为bbox中心点+bbox的W,H的格式,并进行归一化
    dw=1./size[0]
    dh=1./size[1]
    x=(box[0]+box[1])/2.0
    y=(box[2]+box[3])/2.0
    w=box[1]-box[0]
    h=box[3]-box[2]
    x=x*dw
    w=w*dw
    y=y*dh
    h=h*dh
    return (x,y,w,h)

def convert_annotation(xml_path,labels_path,CLASSES,image_id):
    # 把图像image_id的xml文件转换为目标检测的label文件(txt)
    # 其中包含物体的类别cls,bbox的中心点坐标,以及bbox的W,H
    # 并将四个物理量归一化
    in_file=open(xml_path+image_id)
    stats = os.stat(in_file.name)
    if stats.st_size!=0:
        image_id=image_id.split(".")[0]
        out_file=open(labels_path+"%s.txt"%(image_id),"w")
        tree=ET.parse(in_file)
        root=tree.getroot()
        size=root.find("size")
        w=int(size.find("width").text)
        h=int(size.find("height").text)
        for obj in root.iter("object"):
            #  difficult 代表是否难以识别,0表示易识别,1表示难识别。
            difficult=obj.find("difficult").text
            obj_cls=obj.find("name").text
            
            if obj_cls not in CLASSES:
                continue
            cls_id=CLASSES.index(obj_cls)
            xmlbox=obj.find("bndbox")
            points=(float(xmlbox.find("xmin").text),
                    float(xmlbox.find("xmax").text),
                    float(xmlbox.find("ymin").text),
                    float(xmlbox.find("ymax").text))
            bb=convert((w,h),points)
            out_file.write(str(cls_id)+" "+" ".join([str(a) for a in bb])+"\n")

def make_label_txt(xml_path,labels_path,CLASSES):
    # labels文件夹下创建image_id.txt
    # 对应每个image_id.xml提取出的bbox信息
    image_ids=os.listdir(xml_path)
    for file in image_ids:
        convert_annotation(xml_path,labels_path,CLASSES,file)

if __name__=="__main__":
    # 类别,运行create_classes_json.py,得到类名集
    CLASSES=['red', 'crosswalk']
    # 数据整体文件路径
    common_path='E:\\dataset'
    # xml文件路径
    xml_path=os.path.join(common_path,'xml_outputs\\')
    # Annotations路径,即存放xml转为全部lables的路径
    labels_path=os.path.join(common_path,'Annotations\\')
    if not os.path.exists(labels_path):
        os.mkdir(labels_path)

    # 开始提取和转换
    make_label_txt(xml_path,labels_path,CLASSES)

4、优化代码

有人问,上方两个代码,需要运行两次,能否直接一次性运行就完呢?

答案:是可以的,上方代码关键就在获取类名集,于是将两者合并,创建final_xml2yolo.py代码

from doctest import REPORTING_FLAGS
from lib2to3.pgen2.token import RPAR
import os
from tqdm import tqdm
from lxml import etree
import json
import xml.etree.ElementTree as ET
import os
 
# 读取 xml 文件信息,并返回字典形式
def parse_xml_to_dict(xml):
    if len(xml) == 0:  # 遍历到底层,直接返回 tag对应的信息
        return {xml.tag: xml.text}
 
    result = {}
    for child in xml:
        child_result = parse_xml_to_dict(child)  # 递归遍历标签信息
        if child.tag != 'object':
            result[child.tag] = child_result[child.tag]
        else:
            if child.tag not in result:  # 因为object可能有多个,所以需要放入列表里
                result[child.tag] = []
            result[child.tag].append(child_result[child.tag])
    return {xml.tag: result}
 
 
# 提取xml中name保留为json文件
def xml2json(data,json_path):
    xml_path = [os.path.join(data, i) for i in os.listdir(data)]
    classes = []      # 目标类别
    num_object = 0
    for xml_file in tqdm(xml_path, desc="loading..."):
        with open(xml_file,encoding='gb18030',errors='ignore') as fid:      # 防止出现非法字符报错
            xml_str = fid.read()
        xml = etree.fromstring(xml_str)
        data = parse_xml_to_dict(xml)["annotation"]  # 读取xml文件信息
        for j in data['object']:        # 获取单个xml文件的目标信息
            ob = j['name']
            num_object +=1
            if ob not in classes:
                classes.append(ob)
    print(num_object)
    # 生成json文件
    labels = {}
    for index,object in enumerate(classes):
        labels[index] = object

    # 打印类名
    classes_name=[labels[key] for key in labels]
    print(f'类名:{classes_name}')
    # 打印类型字典
    print(f'字典形式:{labels}')

    # json.dumps将python对象转为json对象(将dict转化成str)。 json.loads将json字符串解码成python对象(将str转化成dict)
    labels = json.dumps(labels,indent=4)
    json_path=os.path.join(json_path,'classes_indices.json')
    with open(json_path,'w') as f:
        f.write(labels)

    # 返回类名 
    return classes_name


def convert(size,box):
    # 将bbox的左上角点,右下角点坐标的格式,转换为bbox中心点+bbox的W,H的格式,并进行归一化
    dw=1./size[0]
    dh=1./size[1]
    x=(box[0]+box[1])/2.0
    y=(box[2]+box[3])/2.0
    w=box[1]-box[0]
    h=box[3]-box[2]
    x=x*dw
    w=w*dw
    y=y*dh
    h=h*dh
    return (x,y,w,h)

def convert_annotation(xml_path,labels_path,CLASSES,image_id):
    # 把图像image_id的xml文件转换为目标检测的label文件(txt)
    # 其中包含物体的类别cls,bbox的中心点坐标,以及bbox的W,H
    # 并将四个物理量归一化
    in_file=open(xml_path+image_id)
    stats = os.stat(in_file.name)
    if stats.st_size!=0:
        image_id=image_id.split(".")[0]
        out_file=open(labels_path+"%s.txt"%(image_id),"w")
        tree=ET.parse(in_file)
        root=tree.getroot()
        size=root.find("size")
        w=int(size.find("width").text)
        h=int(size.find("height").text)
        for obj in root.iter("object"):
            #  difficult 代表是否难以识别,0表示易识别,1表示难识别。
            difficult=obj.find("difficult").text
            obj_cls=obj.find("name").text
            
            if obj_cls not in CLASSES:
                continue
            cls_id=CLASSES.index(obj_cls)
            xmlbox=obj.find("bndbox")
            points=(float(xmlbox.find("xmin").text),
                    float(xmlbox.find("xmax").text),
                    float(xmlbox.find("ymin").text),
                    float(xmlbox.find("ymax").text))
            bb=convert((w,h),points)
            out_file.write(str(cls_id)+" "+" ".join([str(a) for a in bb])+"\n")

def make_label_txt(xml_path,labels_path,CLASSES):
    # labels文件夹下创建image_id.txt
    # 对应每个image_id.xml提取出的bbox信息
    image_ids=os.listdir(xml_path)
    for file in image_ids:
        convert_annotation(xml_path,labels_path,CLASSES,file)

 
if __name__ == "__main__":
    # 数据整体文件路径,同时也是存放类名json路径
    common_path=json_path='E:\\dataset'
    # xml文件路径
    xml_path=os.path.join(common_path,'xml_outputs\\')
    # 获取类别     
    CLASSES=xml2json(xml_path,json_path)
   
    # Annotations路径,即存放xml转为全部lables的路径
    labels_path=os.path.join(common_path,'Annotations\\')
    if not os.path.exists(labels_path):
        os.mkdir(labels_path)

    # 开始提取和转换
    make_label_txt(xml_path,labels_path,CLASSES)

    pass

5、划分数据集

创建split_train_val.py,根据具体情况分别修改cur_path,image_original_path,label_original_path 值,程序运行完后,分别生成images,labes和data_txt文件夹。

# 将图片和标注数据按比例切分为 训练集和测试集
import shutil
import random
import os

# 原始路径
# 数据整体文件路径(注意这里需要修改)
cur_path='E:\\dataset'
# 图像文件夹路径,注意一定要有\\,(注意这里需要修改)
image_original_path = os.path.join(cur_path,"images_package\\")

# 标注结果的路径即labels路径,该路径下不要有classes.txt,注意一定要有\\,(注意这里需要修改)
label_original_path = os.path.join(cur_path,"Annotations\\")		

# cur_path = os.getcwd()

# 训练集路径
train_image_path = os.path.join(cur_path, "images/train/")
train_label_path = os.path.join(cur_path, "labels/train/")

# 验证集路径
val_image_path = os.path.join(cur_path, "images/val/")
val_label_path = os.path.join(cur_path, "labels/val/")

# 测试集路径
test_image_path = os.path.join(cur_path, "images/test/")
test_label_path = os.path.join(cur_path, "labels/test/")

# 训练集目录
data_txt_path=os.path.join(cur_path,'data_txt')
if not os.path.exists(data_txt_path):
    os.mkdir(data_txt_path)
list_train = os.path.join(data_txt_path, "train.txt")
list_val = os.path.join(data_txt_path, "val.txt")
list_test = os.path.join(data_txt_path, "test.txt")

# 划分数据集比例
train_percent = 0.8
val_percent = 0.1
test_percent = 0.1
 

def del_file(path):
    for i in os.listdir(path):
        file_data = path + "\\" + i
        os.remove(file_data)
 
 
def mkdir():
    if not os.path.exists(train_image_path):
        os.makedirs(train_image_path)
    else:
        del_file(train_image_path)
    if not os.path.exists(train_label_path):
        os.makedirs(train_label_path)
    else:
        del_file(train_label_path)
 
    if not os.path.exists(val_image_path):
        os.makedirs(val_image_path)
    else:
        del_file(val_image_path)
    if not os.path.exists(val_label_path):
        os.makedirs(val_label_path)
    else:
        del_file(val_label_path)
 
    if not os.path.exists(test_image_path):
        os.makedirs(test_image_path)
    else:
        del_file(test_image_path)
    if not os.path.exists(test_label_path):
        os.makedirs(test_label_path)
    else:
        del_file(test_label_path)
 
 
def clearfile():
    if os.path.exists(list_train):
        os.remove(list_train)
    if os.path.exists(list_val):
        os.remove(list_val)
    if os.path.exists(list_test):
        os.remove(list_test)
 
 
def main():
    mkdir()
    clearfile()
 
    file_train = open(list_train, 'w')
    file_val = open(list_val, 'w')
    file_test = open(list_test, 'w')
 
    total_txt = os.listdir(label_original_path)
    num_txt = len(total_txt)
    list_all_txt = range(num_txt)
 
    num_train = int(num_txt * train_percent)
    num_val = int(num_txt * val_percent)
    num_test = num_txt - num_train - num_val
 
    train = random.sample(list_all_txt, num_train)
    # train从list_all_txt取出num_train个元素
    # 所以list_all_txt列表只剩下了这些元素
    val_test = [i for i in list_all_txt if not i in train]
    # 再从val_test取出num_val个元素,val_test剩下的元素就是test
    val = random.sample(val_test, num_val)
 
    print("训练集数目:{}, 验证集数目:{}, 测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))
    for i in list_all_txt:
        name = total_txt[i][:-4]
 
        srcImage = image_original_path + name + '.jpg'
        srcLabel = label_original_path + name + ".txt"
 
        if i in train:
            dst_train_Image = train_image_path + name + '.jpg'
            dst_train_Label = train_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_train_Image)
            shutil.copyfile(srcLabel, dst_train_Label)
            file_train.write(dst_train_Image + '\n')
        elif i in val:
            dst_val_Image = val_image_path + name + '.jpg'
            dst_val_Label = val_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_val_Image)
            shutil.copyfile(srcLabel, dst_val_Label)
            file_val.write(dst_val_Image + '\n')
        else:
            dst_test_Image = test_image_path + name + '.jpg'
            dst_test_Label = test_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_test_Image)
            shutil.copyfile(srcLabel, dst_test_Label)
            file_test.write(dst_test_Image + '\n')
 
    file_train.close()
    file_val.close()
    file_test.close()
 
if __name__ == "__main__":
    main()

本文最终形成的目录形式

    E:
    └──dataset
        ├── Annotations
        │    ├── 000002.txt
        │    ├── 000003.txt
        │    ├── 000004.txt
        │    ├── 000005.txt
        │    ├── 000006.txt
        │    ├── zebra_crossing_20180129-000545_362.txt
        │    ├── zebra_crossing_20180129-000545_364.txt
        │    ├── zebra_crossing_20180129-000545_366.txt
        │    └── zebra_crossing_20180129-000645_368.txt
        ├── classes_indices.json
        ├── data_txt
        │    ├── test.txt
        │    ├── train.txt
        │    └── val.txt
        ├── images
        │    ├── test
        │    │    ├── 000005.jpg
        │    │    └── zebra_crossing_20180129-000545_362.jpg
        │    ├── train
        │    │    ├── 000002.jpg
        │    │    ├── 000003.jpg
        │    │    ├── 000004.jpg
        │    │    ├── 000006.jpg
        │    │    ├── zebra_crossing_20180129-000545_364.jpg
        │    │    ├── zebra_crossing_20180129-000545_366.jpg
        │    │    └── zebra_crossing_20180129-000645_368.jpg
        │    └── val
        ├── images_package
        │    ├── 000002.jpg
        │    ├── 000003.jpg
        │    ├── 000004.jpg
        │    ├── 000005.jpg
        │    ├── 000006.jpg
        │    ├── zebra_crossing_20180129-000545_362.jpg
        │    ├── zebra_crossing_20180129-000545_364.jpg
        │    ├── zebra_crossing_20180129-000545_366.jpg
        │    └── zebra_crossing_20180129-000645_368.jpg
        ├── labels
        │    ├── test
        │    │    ├── 000005.txt
        │    │    └── zebra_crossing_20180129-000545_362.txt
        │    ├── train
        │    │    ├── 000002.txt
        │    │    ├── 000003.txt
        │    │    ├── 000004.txt
        │    │    ├── 000006.txt
        │    │    ├── zebra_crossing_20180129-000545_364.txt
        │    │    ├── zebra_crossing_20180129-000545_366.txt
        │    │    └── zebra_crossing_20180129-000645_368.txt
        │    └── val
        └── xml_outputs
            ├── 000002.xml
            ├── 000003.xml
            ├── 000004.xml
            ├── 000005.xml
            ├── 000006.xml
            ├── zebra_crossing_20180129-000545_362.xml
            ├── zebra_crossing_20180129-000545_364.xml
            ├── zebra_crossing_20180129-000545_366.xml
            └── zebra_crossing_20180129-000645_368.xml

6、画目录树

创建draw_tree.py,如本文输入

请输入文件夹路径(不含名称): E

请输入文件夹名称:dataset

自动生成 tree.txt

import os

def get_num(path):
    dirlist = os.listdir(path)
    j=0
    for i in dirlist:
        j+=1
    return j

def print_tree(path,last):
    num=get_num(path)
    if num!=0:
        dirlist = os.listdir(path)
        j=0
        for i in dirlist:
            for k in last:
                if k=='0':
                    print("  │",end=" ")
                else:
                    print("   ", end=" ")
            j+=1
            if j<num:
                print("  ├── ", end="")
                print(i)
                dir=path+"\\"+i
                if os.path.isdir(dir):
                    print_tree(dir,last+'0')
            else:
                print("  └── ", end="")
                print(i)
                dir = path + "\\" + i
                if os.path.isdir(dir):
                    print_tree(dir,last+'1')

def write_tree(path,last,f):
    num=get_num(path)
    if num!=0:
        dirlist = os.listdir(path)
        j=0
        for i in dirlist:
            for k in last:
                if k=='0':
                    f.write("    │")
                else:
                    f.write("    ")
            j+=1
            if j<num:
                f.write("    ├── ")
                f.write(i)
                f.write('\n')
                dir=path+"\\"+i
                if os.path.isdir(dir):
                    write_tree(dir,last+'0',f)
            else:
                f.write("    └── ")
                f.write(i)
                f.write('\n')
                dir = path + "\\" + i
                if os.path.isdir(dir):
                    write_tree(dir,last+'1',f)

if __name__=='__main__':
    path = input("请输入文件夹路径(不含名称):")
    root = input("请输入文件夹名称:")
    if len(path)==1:
        path+=':'
    #print("  └─root")
    #print_tree('D:\\root',"1")
    f = open("tree.txt", "w", encoding="utf-8")
    f.write("    └──"+root+"\n")
    write_tree(path+"\\"+root, "1",f)
    f.close()

7、目标检测系列文章

  1. YOLOv5s网络模型讲解(一看就会)

  2. 生活垃圾数据集(YOLO版)

  3. YOLOv5如何训练自己的数据集

  4. 双向控制舵机(树莓派版)

  5. 树莓派部署YOLOv5目标检测(详细篇)

  6. YOLO_Tracking 实践 (环境搭建 & 案例测试)

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

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

相关文章

AI绘图cuda与stable diffusion安装部署始末与避坑

stable diffusion的安装说起来很讽刺&#xff0c;最难的不是stable diffusion&#xff0c;而是下载安装cuda。下来我就来分享一下我的安装过程&#xff0c;失败了好几次&#xff0c;几近放弃。 一、安装cuda 我们都知道cuda是显卡CPU工作的驱动&#xff08;或者安装官网的解释…

vscode前后台分离Nodejs+vue校园影院售票系统_490gq

柚子校园影院在设计与实施时&#xff0c;采取了模块性的设计理念&#xff0c;把相似的系统的功能整合到一个模组中&#xff0c;以增强内部的功能&#xff0c;减少各组件之间的联系&#xff0c;从而达到减少相互影响的目的。 后台主要包括首页&#xff0c;个人中心&#xff0c;用…

【QT+QGIS跨平台编译】056:【pdal_arbiter+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal_arbiter介绍二、pdal下载三、文件分析四、pro文件五、编译实践一、pdal_arbiter介绍 pdal_arbiter是 PDAL 项目的一个库,用于帮助管理应用程序运行在 EC2 实例上的 AWS 凭证。 当应用程序需要调用 AWS API 时,它们必须使用 AWS 凭据对 AP…

Git、TortoiseGit、SVN、TortoiseSVN 的关系和区别

Git、TortoiseGit、SVN、TortoiseSVN 的关系和区别 &#xff08;二&#xff09;Git&#xff08;分布式版本控制系统&#xff09;:&#xff08;二&#xff09;SVN&#xff08;集中式版本控制系统&#xff09;&#xff08;三&#xff09;TortoiseGit一、下载安装 git二、安装过程…

HarmonyOS 应用开发之通过关系型数据库实现数据持久化

场景介绍 关系型数据库基于SQLite组件&#xff0c;适用于存储包含复杂关系数据的场景&#xff0c;比如一个班级的学生信息&#xff0c;需要包括姓名、学号、各科成绩等&#xff0c;又或者公司的雇员信息&#xff0c;需要包括姓名、工号、职位等&#xff0c;由于数据之间有较强…

docker容器之etcd

一、etcd介绍 1、etcd是什么 etcd是CoreOS团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。 2、etcd特点 简单的接口&#xff0c;通过标准的HTTP API进行调用&#xff0c;也可以使用官方提供的 etcdctl 操作存储的数据。…

HBuilder uniapp发行h5遇到报错:此应用 DCloud appid 为 __UNI__95950AD ,您不是这个应用的项目成员。

uniapp打包遇到不是项目成员问题&#xff0c;如下截图&#xff1a; 解决方法如下&#xff1a; 打开项目的mainfest.json文件&#xff0c;在AppID位置点击重新获取&#xff0c;获取后重新点发行打包即可 另遇到HBuilder账号认证问题&#xff0c;如公司wifi打不开认证地址&#…

深入理解 SQL 中的数据集合和数据关联

引言 在数据库管理系统中&#xff0c;数据集合和数据关联是 SQL 查询中常见的概念。它们是构建复杂查询和分析数据的基石。本文将深入探讨 SQL 中的数据集合和数据关联&#xff0c;包括它们的概念、常见用途以及实际示例。 首先引入一下数学中的集合 集合的基本概念&#x…

【MATLAB源码-第26期】基于matlab的FBMC/OQAM的误码率仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 FBMC&#xff08;Filter Bank Multicarrier&#xff09;是一种多载波调制技术&#xff0c;它采用滤波器组来处理频域内的子载波&#xff0c;以在有限带宽内实现高效的数据传输。OQAM&#xff08;Offset Quadrature Amplitude…

OpenHarmony分布式五子棋-使用Canvas组件 实现棋盘、棋子的绘制

介绍 五子棋是一款比较流行的棋类游戏&#xff0c;此游戏使用分布式数据管理功能开发完成的。 本示例使用Canvas组件 实现棋盘、棋子的绘制&#xff0c;使用分布式数据管理 实现两台设备间数据的同步。 本示例使用分布式设备管理能力接口ohos.distributedDeviceManager。 分…

【stm32】USART编码部分--详细步骤

USART编码部分(文章最后附上源码) 如果看不懂步骤可以根据源码参考此篇文章就能轻而易举学会USART通信啦&#xff01; 编码步骤 第一步 开启时钟 把需要用到的USART和GPIO的时钟打开 第二部 GPIO初始化 把TX配置成复用输出&#xff0c;RX配置成输入(上拉输入、浮空输入)。…

VMware虚拟机添加磁盘

在VMware中添加磁盘 &#xff08;虚拟机关闭状态下执行&#xff09; 然后选择默认一步一步点下去&#xff0c;最后创建好新磁盘 开启虚拟机&#xff0c;挂载磁盘 通过命令 lsblk -f 查看未挂载的新磁盘 lsblk -f 通过fdisk命令进行磁盘分区 # 1. 给硬盘/dev/sdb进行分区&am…

2024年04月数据库流行度最新排名

点击查看最新数据库流行度最新排名&#xff08;每月更新&#xff09; 2024年04月数据库流行度最新排名 TOP DB顶级数据库索引是通过分析在谷歌上搜索数据库名称的频率来创建的 一个数据库被搜索的次数越多&#xff0c;这个数据库就被认为越受欢迎。这是一个领先指标。原始数…

Qt6.6添加多媒体模块Multimedia报错问题

问题 QT包含多媒体模块Multimedia时提示未知的模块&#xff1a; error: Project ERROR: Unknown module(s) in QT: multimedia 在帮助文档中只可以找到QMediaPlayer类&#xff0c;但是点进去是空的&#xff0c;这是因为没有安装多媒体模块及对应的帮助文档。 解决 使用在线…

RTOS中临界区嵌套保护的实现原理(基于RT-Thread)

0 前言 什么是临界区&#xff08;临界段&#xff09;&#xff1f; 裸机编程中由于不涉及线程和线程切换&#xff0c;因此没有临界区这一个概念。在RTOS中由于存在线程切换等场景&#xff0c;便有了临界区这个概念。简单来说&#xff0c;临界区就是不允许被中断的代码区域。什么…

【操作系统】FCFS、SJF、HRRN、RR、EDF、LLF调度算法及python实现代码

文章目录 一、先来先服务调度算法&#xff08;FCFS&#xff09; 二、短作业优先调度算法&#xff08;SJF&#xff09; 三、高响应比优先调度算法&#xff08;HRRN&#xff09; 四、轮转调度算法&#xff08;RR&#xff09; 五、最早截至时间优先算法&#xff08;EDF&#…

ES学习日记(七)-------Kibana安装和简易使用

前言 首先明确一点&#xff0c;Kibana是一个软件&#xff0c;不是插件。 Kibana 是一款开源的数据分析和可视化平台&#xff0c;它是 Elastic stack 成员之一&#xff0c;设计用于和Elasticsearch 协作。您可以使用 Kibana 对 Elasticsearch 索引中的数据进行搜索&#xff0c;…

机器学习——卷积的变种

机器学习——卷积的变种 卷积神经网络&#xff08;Convolutional Neural Networks, CNNs&#xff09;是深度学习领域中最重要的技术之一&#xff0c;它在图像处理、语音识别、自然语言处理等领域取得了巨大成功。在CNN中&#xff0c;卷积层是最核心的组成部分之一&#xff0c;…

Java与Go的并发世界:理解Work Sharing与Work Stealing

概述 最近在理解Golang中的Per P概念&#xff0c;于是我就去Go的源码中挖呀挖&#xff0c;结果挖到了Go的调度器设计。 Golang的调度器设计文档提到了Go中的P(OS线程)调度器使用的是work-stealing调度算法论文。 论文中提到了两个多线程调度算法&#xff1a;work sharing和wor…

ETL工具-nifi干货系列 第六讲 处理器JoltTransformJSON

1、处理器作用 使用Jolt转换JSON数据为其他结构的JSON,成功的路由到success,失败的failure。处理JSON的实用程序不是基于流的&#xff0c;因此大型JSON文档转换可能会消耗大量内存。 Jolt&#xff1a;JSON 到 JSON 转换库&#xff0c;用 Java 编写&#xff0c;其中转换的 &qu…