深度学习——yolov5的txt和xml互转

在学习工作的过程中,有时会需要自己新建数据集,向训练数据中添加新的数据,存在已有模型对新数据进行检测,得到yolov5对应的txt文件,之后转成xml,使用标注工具对数据进行校正。后续将xml转成yolov5训练使用的txt格式。
以下是使用多进程和多线程两种方式实现的txt和xml互转的代码。

xml->txt

# -*- coding: UTF-8 -*-
"""
@Project :yolov5_relu_fire_smoke_v1.3 
@IDE     :PyCharm 
@Author  :mufeng
@Date    :2024/2/22 15:58将xml转为yolo训练使用的txt格式
xml保存时使用的是[x1,y1,x2,y2]坐标格式
yolo训练使用的是[xn,yn,wn,hn]坐标格式
data_root|----annotations|----images|----labels
"""
import os
import multiprocessing
from concurrent import futures
from typing import List, Tuple
from copy import deepcopyimport xml.etree.ElementTree as ET
import cv2
import numpy as npdef decodeVocAnnotation(voc_xml_path, class_index_dict):"""voc数据集格式的文件解析,将一个文件解析成一个list,使用空格间隔不同对象注意:返回的类别不是整型,而是字符串的类别名称注意判断返回值是否为 空,如果是空说明没有目标,是一张背景图:param voc_xml_path: xml路径:param class_index_dict: 类别字典:return:"""assert voc_xml_path.endswith(".xml"), "voc_xml_path must endswith .xml"xml_file = open(voc_xml_path, 'r', encoding='utf-8')# 打开xml文件,并返回根节点root = ET.ElementTree().parse(xml_file)# 定义一个列表,专门保存目标information = []# 查找root节点下所有目标信息for obj in root.iter('object'):# 目标的名称name = obj.find('name').text# 目标的bbox坐标,一般voc是保存的corner格式的bboxbox = obj.find('bndbox')xmin = box.find('xmin').textymin = box.find('ymin').textxmax = box.find('xmax').textymax = box.find('ymax').text# 添加一个目标的信息# NOTE:返回值的listinformation.append((class_index_dict[name], int(xmin), int(ymin), int(xmax), int(ymax)))xml_file.close()return informationdef xyxy2xywh(matrix):""":param matrix: np矩阵, x1, y1, x2, y2:return:"""# 确保输入矩阵的形状为 (n, 4),其中 n 是矩阵中矩形的数量if matrix.ndim < 2 or matrix.shape[1] != 4:raise ValueError("Input matrix must have shape (n, 4)")# 计算中心点坐标center_x = (matrix[:, 0] + matrix[:, 2]) / 2center_y = (matrix[:, 1] + matrix[:, 3]) / 2# 计算宽度和高度width = np.abs(matrix[:, 2] - matrix[:, 0])height = np.abs(matrix[:, 3] - matrix[:, 1])# 返回结果,组合为 (center_x, center_y, width, height) 形式return np.column_stack((center_x, center_y, width, height))def run_thread(root, file, class_index_dict):""":param root::param file: 图片路径:param class_index_dict::return:"""image_name, suffix = os.path.splitext(file)image_path = os.path.join(root, file)xml_path = image_path.replace("images", "annotations").replace(suffix, ".xml")txt_path = image_path.replace("images", "labels").replace(suffix, ".txt")if os.path.exists(xml_path):# cls_index, x1, y1, x2, y2bbox = decodeVocAnnotation(xml_path, class_index_dict)bbox = np.array(bbox, dtype=np.float32)else:bbox = np.zeros(shape=(0, 5), dtype=np.float32)returnif len(bbox) == 0:bbox = np.zeros(shape=(0, 5), dtype=np.float32)returnimage = cv2.imread(image_path)if image is None:print(f"\n\033[31m{image_path} is None\033[0m")returnelse:print(f"\r\033[32m{image_path}\033[0m", end='')imh, imw = image.shape[:2]# # 画框,视为了检查框是否正确# for cls_id, xmin, ymin, xmax, ymax in np.array(bbox.copy(), dtype=np.int32):#     cv2.putText(image, text=f"{cls_id}", org=(xmin, ymin),#                 fontScale=2, fontFace=1, color=(0, 255, 0), thickness=1)#     cv2.rectangle(image, pt1=(xmin, ymin), pt2=(xmax, ymax), color=(0, 255, 0), thickness=2)# cv2.imwrite(os.path.join(data_root, "temp", image_file), image)# 坐标转换 xyxy -> xywhbbox[:, 1:] = xyxy2xywh(bbox[:, 1:])# 归一化bbox[..., [1, 3]] /= imwbbox[..., [2, 4]] /= imhos.makedirs(os.path.dirname(txt_path), exist_ok=True)# 保存结果with open(txt_path, "w", encoding="utf-8") as wFile:for cls_id, x, y, w, h in bbox:wFile.write(f"{int(cls_id)} {x:.6f} {y:.6f} {w:.6f} {h:.6f}\n")def run_process(root_file, class_index_dict):""":param root_file: [(root, file), ...] 因为进程的创建花费时间长,所以一个进程处理多个图片:param class_index_dict::return:"""for root, file in root_file:image_name, suffix = os.path.splitext(file)image_path = os.path.join(root, file)xml_path = image_path.replace("images", "annotations").replace(suffix, ".xml")txt_path = image_path.replace("images", "labels").replace(suffix, ".txt")if os.path.exists(xml_path):# cls_index, x1, y1, x2, y2bbox = decodeVocAnnotation(xml_path, class_index_dict)bbox = np.array(bbox, dtype=np.float32)else:bbox = np.zeros(shape=(0, 5), dtype=np.float32)continueif len(bbox) == 0:bbox = np.zeros(shape=(0, 5), dtype=np.float32)continueimage = cv2.imread(image_path)if image is None:print(f"\n\033[31m{image_path} is None\033[0m")continueelse:print(f"\r\033[32m{image_path}\033[0m", end='')imh, imw = image.shape[:2]# # 画框,视为了检查框是否正确# for cls_id, xmin, ymin, xmax, ymax in np.array(bbox.copy(), dtype=np.int32):#     cv2.putText(image, text=f"{cls_id}", org=(xmin, ymin),#                 fontScale=2, fontFace=1, color=(0, 255, 0), thickness=1)#     cv2.rectangle(image, pt1=(xmin, ymin), pt2=(xmax, ymax), color=(0, 255, 0), thickness=2)# cv2.imwrite(os.path.join(data_root, "temp", image_file), image)# 坐标转换 xyxy -> xywhbbox[:, 1:] = xyxy2xywh(bbox[:, 1:])# 归一化bbox[..., [1, 3]] /= imwbbox[..., [2, 4]] /= imhos.makedirs(os.path.dirname(txt_path), exist_ok=True)# 保存结果with open(txt_path, "w", encoding="utf-8") as wFile:for cls_id, x, y, w, h in bbox:wFile.write(f"{int(cls_id)} {x:.6f} {y:.6f} {w:.6f} {h:.6f}\n")if __name__ == '__main__':# 需要已知目标的名称和类别索引class_index_dict = {"fire": 0,"smoke": 1,}# data_root = r"Z:\Datasets\Detection\FireSmoke\TSMFireSmoke"# data_root = r"Z:\Datasets\Detection\FireSmoke\TSMCandle"# data_root = r"Z:\Datasets\FireSmoke_v4"data_root = r"E:\CodeFiles\pycharm\YOLO\yolov5\my_test\data"# data_root = r"Z:\Datasets\Detection\FireSmoke\candle-test"data_root = os.path.abspath(data_root)# 需要跳过的目录exclude_dirs = [r"background",]# NOTE:多线程/多进程 程序不好调试,将线程池/进程池 中的数量改为1,可以调试程序max_workers = 6  # 线程/进程 数# 使用的类型# run_type = "thread"  # 多线程run_type = "process"  # 多进程print(f"running use run_type={run_type}, max_workers:{max_workers}")if run_type == "thread":# 使用线程池控制程序执行with futures.ThreadPoolExecutor(max_workers=max_workers) as executor:for root, _, files in os.walk(os.path.join(data_root, "images")):# 需要排除的目录if any(exclude_dir in root for exclude_dir in exclude_dirs):continuefor file in files:# 向线程池中提交任务,向线程池中提交任务的时候是一个一个提交的executor.submit(run_thread, *(root, file, class_index_dict))print("\nFinish ...")elif run_type == "process":# 一个进程处理多少图片max_file_num = 1000# 保存root和file的listroot_file_list: List[Tuple] = list()# 创建进程池,根据自己的设备自行调整,别太多,否则会变慢pool = multiprocessing.Pool(processes=max_workers)# for image_file in os.listdir(os.path.join(data_root, "images", sub_dir)):for root, _, files in os.walk(os.path.join(data_root, "images")):# 需要排除的目录if any(exclude_dir in root for exclude_dir in exclude_dirs):continuefor file in files:root_file_list.append((root, file))if len(root_file_list) > max_file_num:# 启动一个进程,开始处理当前list中的信息,使用deepcopy是为了防止下面清除list后导致进程崩溃pool.apply_async(run_process, (deepcopy(root_file_list), class_index_dict))# 清除列表中的存储root_file_list.clear()else:# for循环正常结束的话,如果剩下的文件数量不足max_file_num,上面不会启动新的进程,# 所以为了防止丢掉信息,在for循环正常结束之后,丢掉信息,就将root_file_list中的信息处理掉# 启动一个进程,开始处理当前list中的信息pool.apply_async(run_process, (deepcopy(root_file_list), class_index_dict))# 清除列表中的存储root_file_list.clear()# 关闭进程池pool.close()# 等待所有子进程执行结束pool.join()print("\nFinish ...")else:print("run_type should be thread or process.")

txt->xml

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :TestCode 
@IDE     :PyCharm 
@Author  :mufeng
@Date    :2023/7/21 17:15yolov5检测出来的目标结果,转成xml
xml保存时使用的是[x1,y1,x2,y2]坐标格式
yolo检测结果保存使用的是[xn,yn,wn,hn]坐标格式
如果保存txt保存了置信度则txt每一行是:[class_index, xn, yn, wn, hn, conf]
使用线程池实现data_root|----annotations|----images|----labels
"""
import os
import multiprocessing
from concurrent import futures
from typing import List, Tuple
from copy import deepcopyimport cv2
import numpy as np
import xml.etree.ElementTree as ET
import xml.dom.minidom as minidomdef create_voc_xml(image_folder, image_filename, width: int, height: int, labels,save_path, class_name_dict, conf_thresh_dict=None):""":param image_folder: 图片的相对路径:param image_filename: 000001.jpg:param width: 图片宽:param height: 图片高:param labels: 目标框:[[class_index, xmin, ymin, xmax, ymax], ...]:param save_path: 保存xml的根目录:param class_name_dict: cls_index:cls_name,根据index获取正确的类别name:param conf_thresh_dict: cls_index:conf_thresh,根据不同类别设置的阈值获取对应的目标,如果设置为None,则表示保存的txt没有置信度:return:"""# 创建 XML 文件的根元素root = ET.Element("annotation")# 添加图片信息folder = ET.SubElement(root, "folder")folder.text = str(image_folder)# 图片名字filename = ET.SubElement(root, "filename")filename.text = os.path.join(image_filename)# 图片大小size = ET.SubElement(root, "size")width_element = ET.SubElement(size, "width")width_element.text = str(width)height_element = ET.SubElement(size, "height")height_element.text = str(height)depth = ET.SubElement(size, "depth")  # 通道数depth.text = "3"# 添加目标框信息for label in labels:# 如果该参数设置为None,表示保存的txt没有Noneif conf_thresh_dict is None:# 保证这几项是整数class_index, x1, y1, x2, y2 = label.astype(dtype=np.int32)else:class_index, x1, y1, x2, y2, conf = label# 保证这几项是整数class_index, x1, y1, x2, y2 = np.array([class_index, x1, y1, x2, y2], dtype=np.int32)# 根据置信度过滤是否保存项if conf < conf_thresh_dict[class_index]:continueobj = ET.SubElement(root, "object")name = ET.SubElement(obj, "name")name.text = class_name_dict[int(class_index)]pose = ET.SubElement(obj, "pose")pose.text = "Unspecified"truncated = ET.SubElement(obj, "truncated")truncated.text = "0"difficult = ET.SubElement(obj, "difficult")difficult.text = "0"bndbox = ET.SubElement(obj, "bndbox")xmin = ET.SubElement(bndbox, "xmin")xmin.text = str(x1)ymin = ET.SubElement(bndbox, "ymin")ymin.text = str(y1)xmax = ET.SubElement(bndbox, "xmax")xmax.text = str(x2)ymax = ET.SubElement(bndbox, "ymax")ymax.text = str(y2)# 创建 XML 文件并保存xml_str = ET.tostring(root, encoding="utf-8")xml_str = minidom.parseString(xml_str)# 设置缩进为4个空格,xml可读性提高pretty_xml = xml_str.toprettyxml(indent=" " * 4)save_path = os.path.join(save_path, f"{os.path.splitext(image_filename)[0]}.xml")os.makedirs((os.path.dirname(save_path)), exist_ok=True)with open(save_path, "w") as xmlFile:xmlFile.write(pretty_xml)def run_thread(root, image_file, save_root, image_root, txt_root, class_name_dict, conf_thresh_dict=None):"""@param root: ..\images\train@param image_file: 0000000.jpg@param save_root: ..\annotations\train@param image_root: ..\images\train@param txt_root: ...\txt\train@param class_name_dict:@param conf_thresh_dict: 使用yolov5模型跑detect.py没有保存置信度conf,该参数可以不输入@return:"""# 获取图片的名称和后缀image_name, suffix = os.path.splitext(image_file)# 图片路径image_path = os.path.join(root, image_file)# 设置捕捉异常,防止因为异常导致的代码停止运行try:# 读图image = cv2.imread(image_path)if image is None:print(f"\n\033[31mError {image_path}\033[0m")return# 图片的宽高imh, imw = image.shape[:2]# txt路径txt_file = image_path.replace(image_root, txt_root).replace(suffix, ".txt")if not os.path.exists(txt_file):return# class_index xn yn wn hn conflabels = np.loadtxt(txt_file, dtype=np.float32)# 空txt跳过if len(labels) == 0:return# 确包所有矩阵维度都是2维,方便后续处理if labels.ndim == 1:labels = np.array([labels])# xywhn -> xywhlabels[:, [1, 3]] = labels[:, [1, 3]] * imwlabels[:, [2, 4]] = labels[:, [2, 4]] * imhcenter = labels[:, 1:5].copy()# xywh - > xyxycorner = np.zeros_like(center)corner[:, 0] = center[:, 0] - center[:, 2] / 2  # xmin = x - w / 2corner[:, 1] = center[:, 1] - center[:, 3] / 2  # ymin = y - h / 2corner[:, 2] = center[:, 0] + center[:, 2] / 2  # xmax = x + w / 2corner[:, 3] = center[:, 1] + center[:, 3] / 2  # ymax = y + h / 2# np.float32labels[:, 1:5] = corner[:, :]# 创建xmlcreate_voc_xml(root.replace(image_root + os.sep, ""),  # Z:\FireData\images\train -> trainimage_filename=image_file,width=imw,height=imh,labels=labels,save_path=root.replace(image_root, save_root),class_name_dict=class_name_dict,conf_thresh_dict=conf_thresh_dict)# 处理完成后打印信息,要不不知道执行到哪里了print(f"\r{image_path}", end='')except Exception as e:print(f"{image_path} \n{e}\n\n")def run_process(root_file, save_root, image_root, txt_root, class_name_dict, conf_thresh_dict=None):"""@param root_file: [(..\images\train, 0000000.jpg), ...]@param image_file:@param save_root: ..\annotations\train@param image_root: ..\images\train@param txt_root: ...\txt\train@param class_name_dict:@param conf_thresh_dict: 使用yolov5模型跑detect.py没有保存置信度conf,该参数可以不输入@return:"""for root, image_file in root_file:# 获取图片的名称和后缀image_name, suffix = os.path.splitext(image_file)# 图片路径image_path = os.path.join(root, image_file)# 设置捕捉异常,防止因为异常导致的代码停止运行try:# 读图image = cv2.imread(image_path)if image is None:print(f"\n\033[31mError {image_path}\033[0m")continue# 图片的宽高imh, imw = image.shape[:2]# txt路径txt_file = image_path.replace(image_root, txt_root).replace(suffix, ".txt")if not os.path.exists(txt_file):continue# class_index xn yn wn hn conflabels = np.loadtxt(txt_file, dtype=np.float32)# 空txt跳过if len(labels) == 0:continue# 确包所有矩阵维度都是2维,方便后续处理if labels.ndim == 1:labels = np.array([labels])# xywhn -> xywhlabels[:, [1, 3]] = labels[:, [1, 3]] * imwlabels[:, [2, 4]] = labels[:, [2, 4]] * imhcenter = labels[:, 1:5].copy()# xywh - > xyxycorner = np.zeros_like(center)corner[:, 0] = center[:, 0] - center[:, 2] / 2  # xmin = x - w / 2corner[:, 1] = center[:, 1] - center[:, 3] / 2  # ymin = y - h / 2corner[:, 2] = center[:, 0] + center[:, 2] / 2  # xmax = x + w / 2corner[:, 3] = center[:, 1] + center[:, 3] / 2  # ymax = y + h / 2# np.float32labels[:, 1:5] = corner[:, :]# 创建xmlcreate_voc_xml(root.replace(image_root + os.sep, ""),  # Z:\FireData\images\train -> trainimage_filename=image_file,width=imw,height=imh,labels=labels,save_path=root.replace(image_root, save_root),class_name_dict=class_name_dict,conf_thresh_dict=conf_thresh_dict)# 处理完成后打印信息,要不不知道执行到哪里了print(f"\r{image_path}", end='')except Exception as e:print(f"{image_path} \n{e}\n\n")if __name__ == '__main__':# 类别字典class_name_dict = {0: "fire",1: "smoke"}# 置信度阈值,不同类别设置不同的阈值,CONF_THRESH_DICT = None  # 如果该参数设置为None表示txt没有保存conf这一项# CONF_THRESH_DICT = {#     0: 0.2,#     1: 0.2# }if CONF_THRESH_DICT != None:assert class_name_dict.keys() == CONF_THRESH_DICT.keys(), "class_name_dict.keys() != CONF_THRESH_DICT.keys()."# 数据集根目录data_root = r"E:\CodeFiles\pycharm\YOLO\yolov5\my_test\data"data_root = os.path.abspath(data_root)# 指定的子目录sub_dir = r""# sub_dir = r"\train\fire_smoke"# 要保证这三个的目录结构是一致的# 保存xml的根路径 save_root\annotations\...if sub_dir == '':save_root = os.path.join(data_root, "annotations")# txt路径txt_root = os.path.join(data_root, "labels")  # txt和images不在一个目录下,目录结构应该和images一样# 图片路径image_root = os.path.join(data_root, "images")else:save_root = os.path.join(data_root, "annotations", sub_dir)# txt路径txt_root = os.path.join(data_root, "labels", sub_dir)  # txt和images不在一个目录下,目录结构应该和images一样# 图片路径image_root = os.path.join(data_root, "images", sub_dir)# 需要跳过的目录exclude_dirs = [r"background",]# NOTE:多线程/多进程 程序不好调试,将线程池/进程池 中的数量改为1,可以调试程序max_workers = 6  # 线程/进程 数# 使用的类型run_type = "thread"  # 多线程# run_type = "process"  # 多进程print(f"running use run_type={run_type}, max_workers:{max_workers}")if run_type == "thread":# 使用线程池控制程序执行with futures.ThreadPoolExecutor(max_workers=max_workers) as executor:for root, _, files in os.walk(image_root):# 需要排除的目录if any(exclude_dir in root for exclude_dir in exclude_dirs):continuefor file in files:# 向线程池中提交任务,向线程池中提交任务的时候是一个一个提交的executor.submit(run_thread,*(root, file, save_root, image_root, txt_root, class_name_dict, CONF_THRESH_DICT))print("\nFinish ...")elif run_type == "process":# 一个进程处理多少图片max_file_num = 1000# 保存root和file的listroot_file_list: List[Tuple] = list()# 创建进程池,根据自己的设备自行调整,别太多,否则会变慢pool = multiprocessing.Pool(processes=max_workers)# for image_file in os.listdir(os.path.join(data_root, "images", sub_dir)):for root, _, files in os.walk(image_root):# 需要排除的目录if any(exclude_dir in root for exclude_dir in exclude_dirs):continuefor file in files:root_file_list.append((root, file))if len(root_file_list) > max_file_num:# 启动一个进程,开始处理当前list中的信息,使用deepcopy是为了防止下面清除list后导致进程崩溃pool.apply_async(run_process,(deepcopy(root_file_list), save_root, image_root, txt_root,class_name_dict, CONF_THRESH_DICT))# 清除列表中的存储root_file_list.clear()else:# for循环正常结束的话,如果剩下的文件数量不足max_file_num,上面不会启动新的进程,# 所以为了防止丢掉信息,在for循环正常结束之后,丢掉信息,就将root_file_list中的信息处理掉# 启动一个进程,开始处理当前list中的信息pool.apply_async(run_process, (deepcopy(root_file_list), save_root, image_root, txt_root,class_name_dict, CONF_THRESH_DICT))# 清除列表中的存储root_file_list.clear()# 关闭进程池pool.close()# 等待所有子进程执行结束pool.join()print("\nFinish ...")else:print("run_type should be thread or process.")

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

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

相关文章

误删电脑C盘要重装系统吗 误删电脑C盘文件怎么恢复 误删c盘系统文件怎么修复 不小心删除C盘的东西恢复

C盘通常是操作系统(如Windows)的默认安装目录。它包含了操作系统的核心文件、驱动程序及系统所需的各种支持文件。这些文件对于计算机的正常运行至关重要。如果我们不小心将C盘的重要文件删除&#xff0c;会导致应用无法打开。本篇文章&#xff0c;我们将学习误删电脑C盘要重装…

面试算法-39-删除链表的倒数第 N 个结点

题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 解 class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {L…

基于支持向量机SVM的沉降预测,SVM详细原理,Libsvm详解

目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 Libsvm工具箱详解 简介 参数说明 易错及常见问题 完整代码和数据下载链接:基于支持向量机SVM的沉降预测资源-CSDN文库 https://download.csdn.net/download/abc991835105/88947544 SVM应用实例,基于支持向量机SVM的沉降预测…

vim,gcc,gdb与Makefile的使用

一、Linux编辑器-vim使用 1.vim的基本概念 vim的三种模式(其实有好多模式&#xff0c;目前掌握这3种即可),分别是命令模式&#xff08;command mode&#xff09;、插入模式&#xff08;Insert mode&#xff09;和底行模式&#xff08;last line mode&#xff09;&#xff0c;…

指挥航空公司架次与延误率占比

打开前端Vue项目kongguan_web&#xff0c;创建前端 src/components/Delay.vue 页面&#xff0c;并添加柱状图与折线图叠加&#xff0c;设置双Y轴。 页面div设计&#xff0c;代码如下&#xff1a; <template><div><div class"home"><div id&qu…

AJAX-XMLHttpRequest

XMLHttpRequest 定义&#xff1a; XMLHttpRequest对象用于与服务器交互。通过XMLHttpRequest可以在不断刷新页面的情况下请求特定URL&#xff0c;获取数据。这允许网页在不影响用户操作的情况下&#xff0c;更新页面的局部内容。 关系&#xff1a; axios内部采用XMLHttpReques…

关于volatile与指令重排序的探讨

写在开头 在之前的学习我们了解到&#xff0c;为了充分利用缓存&#xff0c;提高程序的执行速度&#xff0c;编译器在底层执行的时候&#xff0c;会进行指令重排序的优化操作&#xff0c;但这种优化&#xff0c;在有些时候会带来 有序性 的问题。 那何为有序性呢&#xff1f;…

乘积尾零啊填空题)

乘积尾零 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 如下的 10 行数据&#xff0c;每行有 10 个整数&#xff0c;请你求出它们的乘积的末尾有多少个零? 的乘积的末尾有多少个零? 5650 4542 3554 473 946 4…

Halcon OCR文字识别

1、OCR文字识别 OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;工具对图像中的文字进行识别和分析。 FontFile : Universal_0-9_NoRej dev_update_window (off) read_image (bottle, bottle2) get_image_size (bottle, Width, Height) dev…

JavaScript 中实现请求并发控制

文章目录 浏览器并发请求限制数&#xff08;图&#xff09;实现代码三方插件 假设有 30 个待办任务要执行&#xff0c;而我们希望限制同时执行的任务个数&#xff0c;即最多只有 3 个任务能同时执行。当正在执行任务列表 中的任何 1 个任务完成后&#xff0c;程序会自动从 待办…

(赋值)运算符号重载

概念以及语法 运算符重载&#xff1a;operator 函数原型&#xff1a;返回值类型 operator 操作符&#xff08;参数列表&#xff09; //操作符有几个操作数就有几个参数 //操作符只包含C/C已经有的&#xff0c;就是说我们不能创建新的操作符&#xff0c;只能重载已有的运算符 …

VMware安装Ubuntu 18.04.2

下载Ubuntu映像 下载地址&#xff1a;http://old-releases.ubuntu.com/releases/18.04/ 下载名称&#xff1a; ubuntu-18.04.2-desktop-amd64.iso 清华镜像站&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/ 阿里云镜像站&#xff1a;https://mirrors.ali…

python 统计中国观鸟记录中心官网已观测的鸟类种类

python 统计中国观鸟记录中心官网已观测的鸟类种类 中国观鸟记录中心网站&#xff1a;https://www.birdreport.cn/ 先下载官网 Excel 文件 文件放置目录如下&#xff1a; home dataset xxx.xlsxxxx.xlsxxxx.xlsx Excelgrep.py &#xff08;进行文件内容提取的程序&#xff…

关于Ubuntu虚拟机突然上不了网的问题

今天刚重新把Ubuntu虚拟机下回来准备大干一场&#xff0c;结果去吃饭回来虚拟机就上不去网了&#xff0c;具体体现为右上角没有网络的图标&#xff0c;下图是有网络的情况&#xff0c;废话不多说&#xff0c;直接给出解决方案&#xff1a;博客在此 我就是运行了这三行代码就成功…

如何杀死服务器出现的僵尸进程

今天在服务器上进行深度学习训练的时候&#xff0c;发现已经结束程序代码&#xff0c;但是GPU还是显示显存在运行。 为了解决这些问题&#xff0c;网上查找了大量的资料&#xff0c;发现是因为僵尸进程的原因&#xff0c;因此记录相关的解决步骤&#xff0c;方便自己和大家。 …

Error: Unable to find git in your PATH. flutter dart

我的是重装git &#xff0c;参考 flutter Unable to find git in your PATH - ZJH_BLOGS - 博客园 (cnblogs.com)

一周速递|全球车联网产业动态(2024年3月17日)

政策法规 1、3月16日&#xff0c;在中国电动汽车百人会论坛&#xff08;2024&#xff09;国际论坛上&#xff0c;国家发改委、工信部、科技部、商务部、住建部等国家部委表示将采取更多务实举措&#xff0c;支持新能源汽车行业企业发展&#xff0c;加大对全固态电池、智能网联…

Elasticsearch(12) match_bool_prefix的使用

elasticsearch version&#xff1a; 7.10.1 match_bool_prefix 是 Elasticsearch 中用于执行布尔前缀查询的一种查询类型。这种查询类型特别适用于当你想要匹配一个字段的前缀&#xff0c;并且希望这个字段中的词语是按照一定顺序出现的场景。 match_bool_prefix 语法 { &q…

设计模式 — — 单例模式

一、是什么 单例模式只会在全局作用域下创建一次实例对象&#xff0c;让所有需要调用的地方都共享这一单例对象 二、实现 // 单例构造函数 function CreateSingleton (name) {this.name name;this.getName(); };// 获取实例的名字 CreateSingleton.prototype.getName func…

✅技术社区—跨域问题及解决方案

一、什么是跨域、为什么会跨域&#xff1f; 我们把问题分解 谁出现的跨域&#xff1f; 》 浏览器&#xff01; 为何出现&#xff1f; 》 同源策略 什么是同源策略&#xff1f; 根据百度百科 同源策略/SOP&#xff08;Same origin policy&#xff09;是一种约定&#xff0…