YOLOv9 实战指南:打造个性化视觉识别利器,从零开始训练你的专属测试集

论文地址:YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information

GitHub:WongKinYiu/yolov9: Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information (github.com)


一、摘要

今天的深度学习方法侧重于如何设计最合适的目标函数,从而使模型的预测结果能够最接近真实标签。同时,设计一个合适的体系结构,可以获取足够的信息进行预测。现有的方法忽略了输入数据在进行分层特征提取和空间转换时,会丢失大量信息。

本文研究数据通过深度网络传输时数据丢失的重要问题,即信息瓶颈和可逆函数。并且提出了可编程梯度信息(PGI)的概念,以应对深度网络实现多个目标所需的各种变化。PGI可以为目标任务提供完整的输入信息来计算目标函数,从而获得可靠的梯度信息来更新网络权值。

此外,还设计了一种基于梯度路径规划的新型轻量级网络体系结构——广义高效层聚合网络(GELAN)。GELAN的架构证实了PGI在轻量级模型上获得了更好的结果。并且基于MS COCO数据集的目标检测上验证了所提出的GELAN和PGI。结果表明,GELAN只使用传统的卷积算子来比基于深度卷积的先进方法获得更好的参数利用。

PGI可用于从轻量级到大型的各种模型。可以用来获得完整的信息,因此,从头开始训练的模型可以比使用大数据集预先训练的最先进的模型获得更好的结果。

在MS COCO数据集中,基于GELAN和PGI的目标检测方法在目标检测性能方面超过了以往所有的从头训练方法,在精度方面,新方法优于大数据集预训练的RT DETR,在参数利用方面也优于基于深度卷积的设计YOLO MS。

二、配置YOLOv9

2.1、下载yolov9

git clone https://github.com/WongKinYiu/yolov9.git

2.2、创建conda环境

conda create -n yolov9 python==3.8

然后切换到yolov9目录下,找到requirements.txt文件(yolov9需要的库)

# 1、激活yolov9
conda activate yolov9

# 2、切换地址
cd yolov9

# 3、安装相关库
pip install -r requirements.txt

注意:本文忽略了anaconda的安装和cuda、cudnn的安装过程

三、数据划分

环境都配置完成之后,开始对测试集进行划分,本文选择了一个insect测试集(包含7个类别['Leconte','Boerner','linnaeus','armandi','coleoptera','acuminatus','Linnaeus'])如下图所示

images:训练集和验证集

labels:训练集和验证集的标签

train.txt和val.txt:需要生成的列表(对于每个图片的地址)

test:测试集

train.cache和val.cache:训练过程中生成的

3.1、数据可视化

看下标签

<annotation>
	<folder>xxx</folder>
	<filename>1.jpeg</filename>
	<path>/home/fion/桌面/xxx/1.jpeg</path>
	<source>
		<database>Unknown</database>
	</source>
	<size>
		<width>1344</width>
		<height>1344</height>
		<depth>3</depth>
	</size>
	<segmented>0</segmented>
	<object>
		<name>Leconte</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>473</xmin>
			<ymin>578</ymin>
			<xmax>612</xmax>
			<ymax>727</ymax>
		</bndbox>
	</object>
	<object>
		<name>Boerner</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>822</xmin>
			<ymin>505</ymin>
			<xmax>948</xmax>
			<ymax>639</ymax>
		</bndbox>
	</object>
	<object>
		<name>linnaeus</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>607</xmin>
			<ymin>781</ymin>
			<xmax>690</xmax>
			<ymax>842</ymax>
		</bndbox>
	</object>
	<object>
		<name>armandi</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>756</xmin>
			<ymin>786</ymin>
			<xmax>841</xmax>
			<ymax>856</ymax>
		</bndbox>
	</object>
	<object>
		<name>coleoptera</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>624</xmin>
			<ymin>488</ymin>
			<xmax>711</xmax>
			<ymax>554</ymax>
		</bndbox>
	</object>
</annotation>

xml文件解析:

xml.etree.ElementTree库在Python中提供了多种处理XML数据的方法。以下是一些常见的用法:

1. 解析XML字符串:
   使用ET.fromstring(xml_string)可以从一个XML格式的字符串创建一个元素对象,并作为树的根节点。

2. 解析XML文件:
   使用ET.parse(file_path)可以加载并解析一个XML文件,返回一个树的根节点。

3. 获取元素标签和属性:
   使用element.tag获取元素的标签名称;使用`element.attrib`获取元素的属性字典。

4. 查找子元素:
   使用element.find(tag)查找第一个匹配的子元素;使用`element.findall(tag)`查找所有匹配的子元素。

5. 遍历元素:
   使用`element.iter()`或`element.iter(tag)`可以迭代遍历元素的所有后代元素。

等等......

这些是`xml.etree.ElementTree`库的一些基本用法,涵盖了解析、查询、修改和创建XML数据的常见操作。

import numpy as np
import os,cv2,sys

try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET

def plot_image():
    # 数据的类别
    INSECT_NAMES = ['Leconte','Boerner','linnaeus','armandi','coleoptera','acuminatus','Linnaeus']
    # 不同类别给不同颜色
    COLOR_NAMES = {'Leconte':(255,0,0),'Boerner':(0,255,0),'linnaeus':(0,0,255),'armandi':(0,0,0),
                   'coleoptera':(255,255,0),'acuminatus':(148,0,211),'Linnaeus':(255,255,255)}
    img_dir = r"E:\YOLO_insects\insects\train\images"
    xml_dir = r"E:\YOLO_insects\insects\train\annotations\xmls"
    save_dir = r"E:\YOLO_insects\insects\imshow"
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)

    for i in os.listdir(img_dir):
        img_path = os.path.join(img_dir, i)
        xml_path = os.path.join(xml_dir, i.split(".")[0]+".xml")
        img = cv2.imread(img_path)
        root = ET.parse(xml_path).getroot()
        for obj in root.findall('object'):
            difficult = obj.find('difficult').text
            cls = obj.find('name').text
            size = root.find('size')
            w = int(size.find('width').text)
            h = int(size.find('height').text)
            if cls not in INSECT_NAMES or int(difficult) == 1:
                continue
            cls_id = INSECT_NAMES.index(cls)
            xml_box = obj.find('bndbox')
            b = (float(xml_box.find('xmin').text), float(xml_box.find('xmax').text),
                 float(xml_box.find('ymin').text), float(xml_box.find('ymax').text))
            print(f"{cls}")
            cv2.rectangle(img, (int(b[0]),int(b[2])),(int(b[1]),int(b[3])), COLOR_NAMES[str(cls)],3)
            cv2.putText(img, cls,(int(b[0]),int(b[2])-5),cv2.FONT_HERSHEY_SIMPLEX,0.5,COLOR_NAMES[str(cls)],2,cv2.LINE_AA)
        cv2.imwrite(os.path.join(save_dir,i), img)

3.2、测试集标签转换

因为本文测试集已划分好了train、val和test,因此下面跳过了数据集划分部分,下面看下如何生成yolo所需的标签格式

代码部分:

import numpy as np
import os,cv2,sys

try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET


def convert(size, box):
    dw = 1. / (size[0])
    dh = 1. / (size[1])
    x = (box[0] + box[1]) / 2.0 - 1
    y = (box[2] + box[3]) / 2.0 - 1
    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 generate_labels():
    train_dir = r'E:\YOLO_insects\insects\val\annotations\xmls'
    train_xml = './insects/labels/val'
    if not os.path.exists(train_xml):
        os.makedirs(train_xml,exist_ok=True)

    num = 0
    classes = ['Leconte','Boerner','linnaeus','armandi','coleoptera','acuminatus','Linnaeus']
    for file in os.listdir(train_dir):
        xml_path = os.path.join(train_dir,file)
        outfile = open(os.path.join(train_xml,file.split(".xml")[0]+".txt"),'w',encoding="utf8")
        num +=1
        print(xml_path)
        content = ET.parse(xml_path)
        root = content.getroot()
        size = root.find('size')
        w = int(size.find('width').text)
        h = int(size.find('height').text)
        channel = int(size.find('depth').text)
        print(f"size: {w}x{h}, channel: {channel}")
        for obj in root.iter('object'):
            difficult = obj.find('difficult').text
            cls = obj.find('name').text
            # classes.append(cls) # 可以查看有哪些类
            if cls not in classes or int(difficult) == 1:
                continue
            cls_id = classes.index(cls)
            xml_box = obj.find('bndbox')
            b = (float(xml_box.find('xmin').text), float(xml_box.find('xmax').text),
                 float(xml_box.find('ymin').text),float(xml_box.find('ymax').text))
            b1, b2, b3, b4 = b
            # 标注越界修正
            if b2 > w:
                b2 = w
            if b4 > h:
                b4 = h
            b = (b1, b2, b3, b4)
            bbox = convert((w,h),b)
            print(bbox)
            outfile.write(str(cls_id) + " " + " ".join([str(i) for i in bbox]) + "\n")

    print(f"total_num:{num}")

标签生成之后,生成测试列表

def produce_txt(input_dir=r'E:\yolov9\data\insects\images\val', output_file=r"E:\yolov9\data\insects\val.txt"):
    with open(output_file, 'w') as f:
        for root, dirs, files in os.walk(input_dir):
            for file in files:
                file_path = os.path.join(root, file)
                f.write(file_path + '\n')

四、开始训练

4.1、在github里下载yolov9-c.pt文件

存放位置随意

4.2、创建对应的yaml配置文件

yolov9/data/insect.yaml
path: E:\yolov9\data\insects  # dataset root dir
train: train.txt  # train images (relative to 'path')
val: val.txt  # val images (relative to 'path')

# Classes
names: ['Leconte','Boerner','linnaeus','armandi','coleoptera','acuminatus','Linnaeus']

4.3、修改yolov9-c.yaml文件中的类别数目

# YOLOv9

# parameters
nc: 7  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
#activation: nn.LeakyReLU(0.1)
#activation: nn.ReLU()

# anchors
anchors: 3

4.4、配置train_dual.py参数

--weights:设置下载好的yolov9-c.pt文件地址
--cfg:选择yolov9-c.yaml
--data:自己创建的配置文件
--imgsz:图像的尺寸:我这里图设置320,也可以设置640
--batch-size:批次大小,太大可能跑不了
--epoch:训练epoch次数
其他参数都是选择默认值
def parse_opt(known=False):
    parser = argparse.ArgumentParser()
    # parser.add_argument('--weights', type=str, default=ROOT / 'yolo.pt', help='initial weights path')
    # parser.add_argument('--cfg', type=str, default='', help='model.yaml path')
    parser.add_argument('--weights', type=str, default='weights/yolov9-c.pt', help='initial weights path')
    parser.add_argument('--cfg', type=str, default='models/detect/yolov9-c.yaml', help='model.yaml path')
    parser.add_argument('--data', type=str, default='data/insect.yaml', help='dataset.yaml path')
    parser.add_argument('--hyp', type=str, default='data/hyps/hyp.scratch-high.yaml', help='hyperparameters path')
    parser.add_argument('--epochs', type=int, default=20, help='total training epochs')
    parser.add_argument('--batch-size', type=int, default=8, help='total batch size for all GPUs, -1 for autobatch')
    parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=320, help='train, val image size (pixels)')
    parser.add_argument('--rect', action='store_true', help='rectangular training')
    parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training')
    parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
    parser.add_argument('--noval', action='store_true', help='only validate final epoch')
    parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor')
    parser.add_argument('--noplots', action='store_true', help='save no plot files')
    parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations')
    parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
    parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk')
    parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
    parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%')
    parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class')
    parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW', 'LION'], default='SGD', help='optimizer')
    parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
    parser.add_argument('--workers', type=int, default=0, help='max dataloader workers (per RANK in DDP mode)')
    parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name')
    parser.add_argument('--name', default='exp', help='save to project/name')
    parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
    parser.add_argument('--quad', action='store_true', help='quad dataloader')
    parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler')
    parser.add_argument('--flat-cos-lr', action='store_true', help='flat cosine LR scheduler')
    parser.add_argument('--fixed-lr', action='store_true', help='fixed LR scheduler')
    parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon')
    parser.add_argument('--patience', type=int, default=10, help='EarlyStopping patience (epochs without improvement)')
    parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2')
    parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)')
    parser.add_argument('--seed', type=int, default=0, help='Global training seed')
    parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify')
    parser.add_argument('--min-items', type=int, default=0, help='Experimental')
    parser.add_argument('--close-mosaic', type=int, default=0, help='Experimental')

    # Logger arguments
    parser.add_argument('--entity', default=None, help='Entity')
    parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='Upload data, "val" option')
    parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval')
    parser.add_argument('--artifact_alias', type=str, default='latest', help='Version of dataset artifact to use')

    return parser.parse_known_args()[0] if known else parser.parse_args()

4.5、开始训练

直接运行:train_dual.py

16 epochs completed in 6.767 hours.
Optimizer stripped from runs\train\exp3\weights\last.pt, 102.8MB
Optimizer stripped from runs\train\exp3\weights\best.pt, 102.8MB

Validating runs\train\exp3\weights\best.pt...
Fusing layers...
yolov9-c summary: 604 layers, 50712138 parameters, 0 gradients, 236.7 GFLOPs
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 01:11
                   all        245       1856      0.743      0.782      0.836      0.588
               Leconte        245        594       0.92      0.871      0.964      0.714
               Boerner        245        318       0.85      0.893      0.928      0.722
               armandi        245        231      0.611      0.754      0.712      0.497
            coleoptera        245        186      0.437      0.909      0.757      0.456
            acuminatus        245        235      0.763        0.8       0.86      0.555
              Linnaeus        245        292      0.877      0.464      0.796      0.584

训练过程中在runs/train目录下生成中间文件,如下图

五、模型测试

5.1、修改detect_dual.py文件

--weights:训练好的模型,选择best.pt
--source:设置测试图片地址,或者采用电脑摄像头,设置为0时
--data:自己创建的insect.yaml配置文件
--imgsz:这里选择320,和训练时保持一致
其他参数选择默认配置
def parse_opt():
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'runs/train/exp3/weights/best.pt', help='model path or triton URL')
    # parser.add_argument('--source', type=str, default=ROOT / 'E:\yolov9\data\insects\\test', help='file/dir/URL/glob/screen/0(webcam)')
    parser.add_argument('--source', type=str, default=ROOT / 'E:\YOLO_insects\insects\\test\images',help='file/dir/URL/glob/screen/0(webcam)')
    parser.add_argument('--data', type=str, default=ROOT / 'data/insect.yaml', help='(optional) dataset.yaml path')
    parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[320], help='inference size h,w')
    parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold')
    parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold')
    parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image')
    parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--view-img', action='store_true', help='show results')
    parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
    parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
    parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes')
    parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
    parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3')
    parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
    parser.add_argument('--augment', action='store_true', help='augmented inference')
    parser.add_argument('--visualize', action='store_true', help='visualize features')
    parser.add_argument('--update', action='store_true', help='update all models')
    parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name')
    parser.add_argument('--name', default='exp', help='save results to project/name')
    parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
    parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)')
    parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels')
    parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences')
    parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
    parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference')
    parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride')
    opt = parser.parse_args()
    opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1  # expand
    print_args(vars(opt))
    return opt

在runs\detect\exp目录下生成对应的测试效果图

六、遇到的问题

AttributeError: 'FreeTypeFont' object has no attribute 'getsize'

这个问题 主要是:

'FreeTypeFont' object has no attribute 'getsize', is caused by a compatibility problem with the new version of Pillow.

# 1、查看pillow的版本
conda list

# 2、卸载高版本安装9.5版本
pip uninstall pillow

pip install pillow==9.5

参考博客:

1、YOLOv9目标识别——详细记录训练环境配置与训练自己的数据集_yolov9训练自己的数据集-CSDN博客

2、YOLOv9如何训练自己的数据集(NEU-DET为案列)_yolov9训练自己的数据集-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis数据结构的基础插入操作

数据结构与内部编码 Redis常见的数据结构 数据结构和内部编码 数据结构的插入操作 在Redis中&#xff0c;数据结构的插入操作取决于你要插入的数据类型。以下是一些常见的数据结构和它们的插入操作&#xff1a; 字符串 (String)&#xff1a;使用 SET 命令来插入字符串。例…

MySQL 日志:undo log、redo log、binlog 有什么用?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 从这篇「执行一条 SQL 查询语句&#xff0c;期间发生了什么&#xff1f; (opens new window)」中&#xff0c;我们知道了一条查询语句经历的过程&#xff0c;这属于「读」一条记录的过程&#xff0c;如下…

Qt/QML编程之路:QPainter与OpenGL的共用(49)

在Qt编程中,有时会有这样一种场景:用OpenGL显示了一个3维立体图,但是想在右下角画一个2D的表格,里面写上几个字。那么这个时候就会出现QPainter与OpenGL共用或者说2D、3D共用。但是问题是调用了QPainter,drawline之后呢,OPenGL的状态被清空了丢失了,3D不显示了。 在Ope…

【概率论与数理统计】Chapter2 随机变量及其分布

随机变量与分布函数 随机变量 随机变量&#xff1a;一个随机变量是对随机现象可能的结果的一种数学抽象 分布函数 分布函数&#xff1a; X为随机变量&#xff0c; F ( x ) F(x) F(x)定义为&#xff1a; F ( x ) P ( X ≤ x ) F(x) P(X \leq x) F(x)P(X≤x) 定义域&#…

【智能算法改进】混沌映射策略--一网打尽

目录 1.引言2.混沌映射3.分布特征4.混沌映射函数调用5.改进智能算法 1.引言 基本种群初始化是在整个空间内随机分布&#xff0c;具有较高的随机性和分布不均匀性&#xff0c;会导致种群多样性缺乏&#xff0c;搜索效率低等问题。 许多学者利用混沌映射机制来增加种群的多样性&…

初识C++之命名空间(namespace)

初识C之入门 命名空间(namespace) 文章目录 初识C之入门 命名空间(namespace)1.为什么要有命名空间2. 命名空间 namespace使用方法3. 作用域限定符(::&#xff09;和 命名空间(namespace)4. 命名空间的定义5. 命名空间的嵌套6. 命名空间的使用7. 总结 1.为什么要有命名空间 在C…

FLStudio多少钱FL Studio中文版软件序列号-激活码购买

fl studio是一款编曲软件&#xff0c;接触这款软件的大多都是做音乐的小伙伴吧&#xff0c;对于初学者想了解这款软件在意的应该就是它的价格。很多打算入手正版FL Studio的新手朋友都会纠结一个问题&#xff1a;哪个版本的FL Studio更适合我&#xff0c;到底应该入手哪一款FL …

HarmonyOS 应用开发之显式Want与隐式Want匹配规则

在启动目标应用组件时&#xff0c;会通过显式 Want 或者隐式 Want 进行目标应用组件的匹配&#xff0c;这里说的匹配规则就是调用方传入的 want 参数中设置的参数如何与目标应用组件声明的配置文件进行匹配。 显式Want匹配原理 显式 Want 匹配原理如下表所示。 名称类型匹配…

C++基础之虚函数(十七)

一.什么是多态 多态是在有继承关系的类中&#xff0c;调用同一个指令&#xff08;函数&#xff09;&#xff0c;不同对象会有不同行为。 二.什么是虚函数 概念&#xff1a;首先虚函数是存在于类的成员函数中&#xff0c;通过virtual关键字修饰的成员函数叫虚函数。 性质&am…

C++多重继承与虚继承

多重继承的原理 多重继承(multiple inheritance)是指从多个直接基类中产生派生类的能力。 多重继承的派生类继承了所有父类的属性。 在面向对象的编程中&#xff0c;多重继承意味着一个类可以从多个父类继承属性和方法。 就像你有一杯混合果汁&#xff0c;它是由多种水果榨取…

452. 用最少数量的箭引爆气球(力扣LeetCode)

文章目录 452. 用最少数量的箭引爆气球贪心算法代码 452. 用最少数量的箭引爆气球 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确…

花了100块大洋搞懂 ipv6的用户如何访问ipv4 服务器

大家好&#xff0c;今天蓝胖子花了100多块搞懂了 ipv6的用户如何访问ipv4 服务器&#xff0c;将收获与大家分享下。 ipv4和ipv6的协议栈不同&#xff0c;这意味着&#xff0c;其对应的ip包的封装和解析不同&#xff0c;那么只支持ipv4的机器就无法直接与ipv6的服务器进行通信。…

kubernetes K8s的监控系统Prometheus安装使用(一)

简单介绍 Prometheus 是一款基于时序数据库的开源监控告警系统&#xff0c;非常适合Kubernetes集群的监控。Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态&#xff0c;任意组件只要提供对应的HTTP接口就可以接入监控。不需要任何SDK或者其他的集成过程。这样做…

网络服务练习题

综合练习&#xff1a;请给 openlab 搭建 web 网站 网站需求&#xff1a; 1. 基于域名 www.openlab.com 可以访问网站内容为 welcome to openlab!!! 2. 给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料 和缴费网站&#xff0c;基于&#xff0c; www.openlab.c…

【Linux 驱动基础】Linux platform平台设备驱动

# 前置知识 总线驱动模型简介&#xff1a; 总线是处理器与一个或者多个设备之间的通道&#xff0c;在设备模型中&#xff0c;所有的设备都是通过总线相连&#xff0c;当然也包括虚拟的 platform 平台总线。 总线驱动模型中有三要素&#xff1a; 1. 总线 /*** struct bus_ty…

C语言书籍——B/陷阱之处(2)

文章参考于文献&#xff1a;《C陷阱与缺陷》[美]Andrew Koening &#x1f308;个人主页&#xff1a;慢了半拍 &#x1f525; 创作专栏&#xff1a;《史上最强算法分析》 | 《无味生》 |《史上最强C语言讲解》 | 《史上最强C练习解析》 &#x1f3c6;我的格言&#xff1a;一切只…

Obsidian插件-高亮块(Admonition)

在插件市场里面搜索Admonition并安装插件&#xff0c;就可以使用高亮块了。 添加高亮块 用法稍微有一些不同。按照下面的格式&#xff0c;输入Markdown就可以创建一个高亮块。 内容内容内容输入*ad-*会出现相应的类型可以选择

Dubbo管理控制台

1.将资料中的dubbo-admin-2.6.0.war文件复制到tomcat的webapps目录下 2.启动tomcat,修改WEB-INF下的dubbo.properties文件 #如果Zookeeper是安装在虚拟机上的那么注册中心的地址需要修改为虚拟机的ip地址 dubbo.registry.addresszookeeper://192.168.100.110:2181 dubbo.admin…

对象存储服务MinIO快速入门

对象存储服务MinIO快速入门 MinIO简介开箱使用快速入门封装MinIO为starter1 创建模块heima-file-starter2 配置类3 封装操作minIO类4 对外加入自动配置5 其他微服务使用 MinIO简介 官网文档 开箱使用 docker run -p 9000:9000 --name minio -d --restartalways -e "MINIO…

ocr之opencv配合paddleocr提高识别率

背景1&#xff1a;在这篇文章编写之前使用到的工具并不是opencv&#xff0c;而是java原有的工具BufferedImage。但因为在使用过程中会频繁切图&#xff0c;放大&#xff0c;模糊&#xff0c;所以导致的jvm内存使用量巨大&#xff0c;分秒中都在以百兆的速度累加内存空间。这种情…