CV毕业宝典[02_目标检测概述]

目标检测概述

1.什么是目标检测任务?

在这里插入图片描述

目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标,并确定它们的类别和位置

目标检测任务的要素

  • (检测)关注到特定的物体目标
    • 要关注什么东西具体取决于当前任务(数据集)需要检测什么物体,如:人脸 ,汽车
    • 图像分类更关注整体,是对整张图片的内容描述
  • 获取该物体目标的类别(Classification)和位置(Localization)信息

举个例子:假设我们的目标检测模型任务是检测交通工具(汽车,摩托,直升机…),那么模型对任何一张图片的输出就只有上述交通工具中的一种,而不会输出驾驶员,道路,植被等其他无关的结果

2.目标位置信息的表示法

  1. 矩形边界框表示(Bounding Box)

主流数据集的位置信息表示方法(以图片左上角为原点O):

在这里插入图片描述

  • 两点表示法

    • 格式:(x_min, y_min, x_max, y_max)
    • 优点:直观,易于计算交并比IoU
    • 应用场景:PASCAL VOC数据集
  • 中心点 +宽高表示法

    • 格式:(x_center, y_center, width, height)
    • 优点:便于归一化处理(数值范围通常为 [0,1],相对于图像尺寸)。
    • 应用场景:YOLO 系列算法
  • 左上角+宽高表示法

    • 格式:(x_min, y_min, width, height)
    • 优点:直观,符合计算机图形学的矩形绘制方式
    • 应用场景:MS COCO 数据集

2.旋转边界框(Rotated Bounding Box)

  • 格式:(x_center, y_center, width, height, angle)[在矩形框基础上增加旋转角度].

  • 优点:可检测带有方向的物体(如车辆、飞机)。

  • 应用场景:遥感图像(DOTA数据集)、文本检测(ICDAR)。


3.关键点(Keypoints)

  • 通过一组关键点坐标描述物体轮廓或结构,例如:
    • 人体姿态估计中的关节坐标。
    • 车辆检测中的角点(如 (x1, y1), (x2, y2), ..., (xn, yn))。
  • 优点:提供更精细的物体形状信息。
  • 应用场景:人脸特征点检测、复杂形状物体定位。

  1. 多边形/轮廓(Polygon/Contour)
  • 用多个顶点坐标组成的多边形表示物体轮廓,例如:
    [(x1, y1), (x2, y2), ..., (xn, yn)]
  • 优点:适用于不规则形状物体(如医学图像中的器官)。
  • 应用场景:实例分割(COCO数据集部分标注)、地图标注。

  1. 掩码(Mask)
  • 通过像素级二值掩码(0/1)标记物体位置,格式为与图像同尺寸的矩阵。
  • 优点:提供像素级精度,适合复杂形状。
  • 应用场景:实例分割(如Mask R-CNN)。

  1. 归一化与相对坐标
  • 归一化坐标:将绝对坐标转换为相对于图像宽高的比例值([0,1]),例如:
    • YOLO格式:(x_center/width, y_center/height, width/image_width, height/image_height)
  • 锚框偏移量:在基于锚框(Anchor)的算法中,位置信息表示为偏移量:
    • 如Faster R-CNN预测 (Δx, Δy, Δw, Δh),表示相对于锚框的调整。

3.两种主流数据集介绍

1.PASCAL VOC

PASCAL VOC是目标检测领域的经典数据集。PASCAL VOC包含约10,000张带有边界框的图片用于训练和验证。PASCAL VOC数据集是目标检测问题的一个基准数据集,很多模型都是在此数据集上得到的,常用的是VOC2007VOC2012两个版本数据,共20个类别。

  • 两个版本的数据集介绍:

    • VOC2007:训练集(2501张)+ 验证集(2510张)+ 测试集(4952张)。
    • VOC2012:训练集(5717张)+ 验证集(5823张)。
  • 物体类别介绍

类别名称标签
动物鸟,猫,牛,狗,马,羊
交通工具飞机,自行车,船,公共汽车,汽车,摩托车,火车
室内瓶子,椅子,餐桌,盆栽,沙发,电视/显示器

核心信息

  • 时间跨度:2005–2012年(经典版本为VOC2007VOC2012)。
  • 任务类型:目标检测、图像分类、语义分割、动作识别等。
  • 数据规模
    • VOC2007:9,963张图像,24,640个标注对象。
    • VOC2012:11,530张图像,27,450个标注对象。
  • 类别数量:20个常见物体类别(如人、车、动物、家具等)。
PASCAL VOC数据集结构
VOC2007/
├── Annotations/          # 目标检测标注文件(XML格式)
├── ImageSets/            # 数据集划分文件(txt文本格式)
│   ├── Layout/           # 人体布局任务划分(train/val等)
│   ├── Main/             # 分类/检测任务划分(按类别列出正负样本)
│   └── Segmentation/     # 分割任务划分(train/val等)
├── JPEGImages/           # 原始图像文件(JPEG格式)
├── SegmentationClass/    # 语义分割标注(PNG掩码,按类别区分)
└── SegmentationObject/   # 实例分割标注(PNG掩码,按对象区分)
  • Annotations/目录

  • 作用:存储目标检测任务的标注信息。

  • 文件格式:每个图像对应一个XML文件(如000001.xml)。

在这里插入图片描述

  • ImageSets/ 目录

    (1) Main/ 子目录

    • 作用:定义分类/检测任务的数据集划分(训练集、验证集、测试集)。

    • 文件格式:文本文件(如train.txtval.txttest.txt),每行包含图像ID和类别标记。

    • 示例文件

      • aeroplane_train.txt:飞机类别的训练样本列表。

        复制

        000001 -1        # -1表示负样本(图像中无飞机)
        000002 1         # 1表示正样本(图像中有飞机)
        
      • train.txt:所有训练集图像ID(如000001000002)。

    (2) Layout/Segmentation/ 子目录

    • Layout/:人体布局任务(标注人体部位关键点)的数据划分。
    • Segmentation/:语义分割任务的数据划分(如train.txt列出分割训练集图像ID)。
  • SegmentationClass/SegmentationObject/ 目录

    • SegmentationClass/
      • 作用:语义分割标注,每个像素标记类别(如“人”、“车”)。
      • 文件格式:PNG图像,像素值对应类别ID(如0=背景,15=人)。
    • SegmentationObject/
      • 作用:实例分割标注,每个对象实例独立标记。
      • 文件格式:PNG图像,同一类别的不同实例用不同像素值区分。

2.COCO数据集

MS COCO的全称是Microsoft Common Objects in Context,微软于2014年出资标注的Microsoft COCO数据集,与ImageNet竞赛一样,被视为是计算机视觉领域最受关注和最权威的比赛之一。

COCO数据集是一个大型的、丰富的物体检测,分割和字幕数据集。这个数据集以场景理解为目标,主要从复杂的日常场景中截取,图像中的目标通过精确的分割进行位置的标定。图像包括91类目标,328,000影像和2,500,000个label。目前为止目标检测的最大数据集,提供的类别有80 类,有超过33 万张图片,其中20 万张有标注,整个数据集中个体的数目超过150 万个。

核心信息

属性描述
数据规模- 训练集:118,287张图像 - 验证集:5,000张图像 - 测试集:41,000张图像(无公开标注)
标注对象数量总计约 1.5 million 个实例(平均每图约12个对象)
类别数量80个类别,涵盖常见物体(如人、车、动物、日用品等)
标注类型目标检测、实例分割、关键点检测(人体姿态)、图像描述(Caption)
图像分辨率多数为中等分辨率(640×480至1280×720)
COCO数据集目录结构
coco/
├── annotations/          # 所有标注文件(JSON格式)
│   ├── instances_train2017.json  # 目标检测/实例分割训练标注
│   ├── instances_val2017.json
│   ├── person_keypoints_train2017.json  # 关键点检测标注
│   ├── captions_train2017.json   # 图像描述标注
│   └── ...
├── train2017/            # 训练集图像
├── val2017/              # 验证集图像
├── test2017/             # 测试集图像(无标注)
└── ...                   # 其他辅助文件(如可视化工具)
  • Annotations/目录

    COCO的标注以 JSON文件 组织,包含以下核心字段:

    1. 全局结构
    {
      "info": {...},       // 数据集元信息(版本、描述等)
      "licenses": [...],   // 图像版权信息
      "images": [...],     // 图像列表(ID、文件名、尺寸等)
      "annotations": [...],// 所有实例的标注信息
      "categories": [...]  // 类别定义(ID、名称、关键点定义等)
    }
    
    1. 关键字段说明

      (1) images 字段

    {
      "id": 1,                   // 图像唯一ID
      "file_name": "000001.jpg",  // 图像文件名
      "width": 640,              // 图像宽度
      "height": 480              // 图像高度
    }
    
      (2) **`annotations` 字段**(目标检测/实例分割)	
    
    {
      "id": 1,                   // 标注唯一ID(整数)
      "image_id": 1,             // 对应的图像ID(整数)
      "category_id": 18,         // 类别ID(对应categories中的ID)
      "bbox": [x, y, w, h],      // 边界框:[左上角x, 左上角y, 宽度, 高度]
      "area": 903.5,             // 区域面积(单位:像素²)
      "segmentation": [          // 实例分割坐标(多边形或RLE编码)
        [x1, y1, x2, y2, ..., xn, yn]  // 单个多边形坐标(浮点数列表)
      ],
      "iscrowd": 0               // 0=单个对象,1=密集群体(如人群)
    }
    

4.目标检测任务的评估指标

4.1 IOU

在目标检测算法中,IoU(intersection over union,交并比)是目标检测算法中用来评价预测结果和真实结果之间相似度的指标
I o U = U n i o n I n t e r s e c t i o n = ∣ A ∪ B ∣ ∣ A ∩ B ∣ IoU=\frac{Union}{Intersection}=\frac{∣A∪B∣}{∣A∩B∣} IoU=IntersectionUnion=ABAB

  • A:表示预测框(Detection Result)
  • B:表示真实框(Ground Result)
  • |A ∩ B|:表示预测框和真实框的交集面积(重叠部分的面积)
  • |A ∪ B|:表示预测框和真实框的并集面积(总的覆盖面积)

如下图所示:

在这里插入图片描述
通过一个例子看下在目标检测中的应用:

在这里插入图片描述

其中上图蓝色框框为检测结果,红色框框为真实标注。

那我们就可以通过预测结果与真实结果之间的交并比来衡量两者之间的相似度。一般情况下对于检测框的判定都会存在一个阈值,也就是IoU的阈值,一般可以设置当IoU的值大于0.5的时候,则可认为检测到目标物体。


如何计算交集矩形的面积?

设矩形A由左上角点( A x 1 A_{x1} Ax1, A y 1 A_{y1} Ay1)和右下角点( A x 2 A_{x2} Ax2, A y 2 A_{y2} Ay2)表示,矩形B由( B x 1 B_{x1} Bx1, B y 1 B_{y1} By1)和( B x 2 B_{x2} Bx2, B y 2 B_{y2} By2)表示,其中满足 A x 1 A_{x1} Ax1< A x 2 A_{x2} Ax2 , A y 1 < A y 2 A_{y1}<A_{y2} Ay1<Ay2 ,B同理。

​ 则矩形A 和矩形B在 x轴上的投影区间分别为 I x A I_{x_A} IxA=( A x 1 A_{x1} Ax1, A x 2 A_{x2} Ax2) I x B I_{x_B} IxB=( B x 1 B_{x1} Bx1, B x 2 B_{x2} Bx2)

​ 同理得矩形A 和矩形B在 y轴上的投影区间 I y A I_{y_A} IyA=( A y 1 A_{y1} Ay1, A y 2 A_{y2} Ay2) I y B I_{y_B} IyB=( B y 1 B_{y1} By1, B y 2 B_{y2} By2)

若 ( I x A I_{x_A} IxA I x B I_{x_B} IxB ) × ( I y A I_{y_A} IyA I y B I_{y_B} IyB) ≠ ∅,则交集存在,其宽度和高度分别为

​ Width = min( A x 1 A_{x1} Ax1, B x 1 B_{x1} Bx1) - max( A x 2 A_{x2} Ax2, B x 2 B_{x2} Bx2)

​ height = min( A y 2 A_{y2} Ay2, B y 2 B_{y2} By2) - max( A y 1 A_{y1} Ay1, B y 1 B_{y1} By1)

​ 交集面积为
I n t e r s e c t i o n A r e a = m a x ( 0 , W i d t h ∗ h e i g h t ) Intersection Area = max(0,Width * height) IntersectionArea=max(0,Widthheight)
代码实现

import numpy as np
# 定义方法计算IOU
def Iou(box1, box2):
    # 使用极坐标形式表示:直接获取两个bbox的坐标
    # 获取两个框的左上角坐标和右下角坐标
    xmin1, ymin1, xmax1, ymax1 = box1
    xmin2, ymin2, xmax2, ymax2 = box2
    # 获取矩形框交集对应的左上角和右下角的坐标(intersection)
    xx1 = np.max([xmin1, xmin2])
    yy1 = np.max([ymin1, ymin2])
    xx2 = np.min([xmax1, xmax2])
    yy2 = np.min([ymax1, ymax2])
    # 计算两个矩形框面积
    area1 = (xmax1-xmin1) * (ymax1-ymin1) 
    area2 = (xmax2-xmin2) * (ymax2-ymin2)
    #计算交集面积
    inter_area = (np.max([0, xx2-xx1])) * (np.max([0, yy2-yy1]))
    #计算交并比
    iou = inter_area / (area1+area2-inter_area)
    return iou

4.2 mAP(Mean Average Precision

目标检测问题中的每个图片都可能包含一些不同类别的物体,需要评估模型的物体分类和定位性能。因此,用于图像分类问题的标准指标precision不能直接应用于此。 在目标检测中,mAP是主要的衡量指标。

mAP是多个分类任务的AP的平均值,而AP(average precision)是PR曲线下的面积,所以在介绍mAP之前我们要先得到PR曲线。

  • TP、FP、FN、TN
    • True Positive (TP): (IoU> I O U t h r e s h o l d IOU_{threshold} IOUthreshold)的检测框数量(同一 Ground Truth 只计算一次)
    • False Positive (FP): (IoU ≤ I O U t h r e s h o l d IOU_{threshold} IOUthreshold )的检测框数量,或者是检测到同一个 GT 的多余检测框的数量
    • False Negative (FN): 没有检测到的 GT 的数量
    • True Negative (TN): 在 mAP 评价指标中不会使用到

I O U t h r e s h o l d IOU_{threshold} IOUthreshold一般取0.5

  • 查准率、查全率
    • 查准率(Precision)
      P r e c i s i o n = T P T P + F P = T P A l l d e c t i o n s Precision = \frac{TP}{TP+FP}=\frac{TP}{All\quad dections} Precision=TP+FPTP=AlldectionsTP
      all detctions : 所有预测框的数量

    • 查全率(Recall): TP/(TP + FN)

R e c a l l = T P T P + F N = T P A l l g r o u n d t r u t h s Recall = \frac{TP}{TP+FN}=\frac{TP}{All\quad ground \quad truths} Recall=TP+FNTP=AllgroundtruthsTP

all ground truths :所有 GT 的数量。

  • P - R 曲线

    y = (Recall,Precision)

在这里插入图片描述

AP = P - R 曲线的面积

  • mAP

    定义:计算所有类别 P-R 曲线下面积的平均值

假设我们有 7 张图片(Image1-Image7),这些图片有 15 个目标(绿色的框,GT 的数量,上文提及的 all ground truths)以及 24 个预测边框(红色的框,A-Y 编号表示,并且有一个置信度值):

在这里插入图片描述

根据上图以及说明,我们可以列出以下表格,其中 Images 代表图片的编号,Detections 代表预测边框的编号,Confidences 代表预测边框的置信度,TP or FP 代表预测的边框是标记为 TP 还是 FP(认为预测边框与 GT 的 IOU 值大于等于 0.3 就标记为 TP;若一个 GT 有多个预测边框,则认为 IOU 最大且大于等于 0.3 的预测框标记为 TP,其他的标记为 FP,即一个 GT 只能有一个预测框标记为 TP),这里的 0.3 是随机取的一个值。

在这里插入图片描述

置信度的来源:(如YOLO):置信度通常为 物体存在的概率 × 类别概率

通过上表,我们可以绘制出 P-R 曲线(因为 AP 就是 P-R 曲线下面的面积),但是在此之前我们需要计算出 P-R 曲线上各个点的坐标,根据置信度从大到小排序所有的预测框,然后就可以计算 Precision 和 Recall 的值,见下表。(需要记住一个叫累加的概念,就是下图的 ACC TP 和 ACC FP)

在这里插入图片描述

  • 标号为 1 的 Precision 和 Recall 的计算方式:Precision=TP/(TP+FP)=1/(1+0)=1,Recall=TP/(TP+FN)=TP/(all ground truths)=1/15=0.0666 (all ground truths 上面有定义过了
  • 标号 2:Precision=TP/(TP+FP)=1/(1+1)=0.5,Recall=TP/(TP+FN)=TP/(all ground truths)=1/15=0.0666
  • 标号 3:Precision=TP/(TP+FP)=2/(2+1)=0.6666,Recall=TP/(TP+FN)=TP/(all ground truths)=2/15=0.1333
  • 其他的依次类推

然后就可以绘制出 P-R 曲线

在这里插入图片描述

得到 P-R 曲线就可以计算 AP(P-R 曲线下的面积),要计算 P-R 下方的面积,有两种方法:

  • VOC2010以前,只需要选取当Recall >= 0, 0.1, 0.2, …, 1共11个点时的Precision最大值,然后AP就是这11个Precision的平均值,取 11 个点 [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1] 的插值所得

在这里插入图片描述

得到一个类别的 AP 结果如下:

在这里插入图片描述

要计算 mAP,就把所有类别的 AP 计算出来,然后求取平均即可 。

  • VOC2010及以后,需要针对每一个不同的Recall值(包括0和1),选取其大于等于这些Recall值时的Precision最大值,如下图所示:

在这里插入图片描述

然后计算PR曲线下面积作为AP值:

在这里插入图片描述

计算方法如下所示:

在这里插入图片描述

4.3 NMS(非极大值抑制)

非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素。例如在行人检测中,滑动窗口经提取特征,经分类器分类识别后,每个窗口都会得到一个分数。但是滑动窗口会导致很多窗口与其他窗口存在包含或者大部分交叉的情况。这时就需要用到NMS来选取那些邻域里分数最高(是行人的概率最大),并且抑制那些分数低的窗口。 NMS在计算机视觉领域有着非常重要的应用,如视频目标跟踪、数据挖掘、3D重建、目标识别以及纹理分析等 。


NMS的原理

NMS的原理是对于预测框的列表B及其对应的置信度S,选择具有最大score的检测框M,将其从B集合中移除并加入到最终的检测结果D中.通常将B中剩余检测框中与M的IoU大于阈值Nt的框从B中移除.重复这个过程,直到B为空。

使用流程如下图所示:

  • 首先是检测出一系列的检测框
  • 将检测框按照类别进行分类
  • 对同一类别的检测框应用NMS获取最终的检测结果

在这里插入图片描述

算法步骤描述

假设现在检测窗口有:A、B、C、D、E 5个候选框,接下来进行迭代计算

在这里插入图片描述

​ 原检测框集合 U = {A,B,C,D,E} 最终保留集合 S = {}

第一轮:

  1. 取置信度最高的检测框 B, 将 B移出集合U 并 将B加入到 S中

    ​ 此时, S = {B,} U = {A,C,D,E}

  2. 得分最高的检测框 B 与集合 U中的所有检测框计算 IoU , 计算出D,E的结果>0.5,剔除DE

    ​ 此时, S = {B,} U = {A,C}

第二轮:

  1. 取置信度最高的检测框 A, 将A移出集合U 并 将A加入到 S中

    ​ 此时, S = {B,A} U = {C}

  2. 得分最高的检测框 A 与集合 U中的所有检测框计算 IoU , 计算出C的结果>0.5,剔除C

    ​ 此时, S = {B,A} U = {}

U为空集,算法结束


  • 代码流程
import numpy as np


def get_nms(bboxes, confidence_score, threshold):
    """
    non-Maximum Suppression算法过程
    :param bboxes: bounding boxes:所有检测框的左上和右下坐标 e.g. [A,B,C,D]=>[[x_min1,y_min1,x_max1,y_max1],[x_min2,y_min2,x_max2,y_max2]............]
    :param confidence_score: 每个候选框的置信度 e.g. [A,B,C,D]=> [90%,80%,99%,10%..]
    :param threshold: 置信度阈值
    :return:
    """
    # todo:1- 强转数组,并取出每个框左上角坐标和右下角坐标
    bboxes = np.array(bboxes)  # e.g. [A,B,C,D]=>[[x_min1,y_min1,x_max1,y_max1],...]
    score = np.array(confidence_score)  # e.g. [A,B,C,D]=> [90%,80%,99%,10%..]

    # todo:2- 取出n个点的极坐标(左上 + 右下)
    x1 = bboxes[:, 0]  # [x_min1,x_min2,x_min3....]
    y1 = bboxes[:, 1]  # [y_min1,y_min2,y_min3....]
    y2 = bboxes[:, 3]  # [x_max1,x_max2,x_max3....]
    x2 = bboxes[:, 2]  # [y_max1,y_max2,y_max3....]

    # todo:3- 计算每个检测框的面积
    areas = (x2 - x1) * (y2 - y1)  # 每个检测框的面积 [area_A,area_B,area_C....]

    # todo:4- 定义返回的框坐标和分数,
    picked_boxes, picked_score = list(), list()
    # todo:5- 对置信度进行排序,获取排序后的下标序号,`np.argsort`默认从小到大排序
    order = np.argsort(score)  # [A,B,C,D] => [0,3,2,1] 表示置信度从小到大 A -> D -> C -> B

    # todo:6- NMS算法过程
    while order.size > 0:
        # 取置信度最大的检测框的索引下标
        index = order[-1]
        # 保留剩余框中置信度最大的那一个
        picked_boxes.append(bboxes[index])  # e.g. picked_boxes:[(A的左上坐标,A的右下坐标)]
        picked_score.append(score[index])  # e.g. picked_boxes:[A的分值]

        # todo:6.3- 计算交集区域的左上和右下坐标
        """
        `np.maximum`
        如果有两个数组a和b,形状相同的话,
        np.maximum(a, b)会生成一个新的数组,每个元素都是a和b对应位置中较大的那个。
        """
        # e.g. np.maximum([x_min2],[x_min1,x_min3,x_min4..]) => [max(x_min1,x_min2),max(x_min2,x_min3)..]
        x11 = np.maximum(x1[index], x1[order[:-1]])
        y11 = np.maximum(y1[index], y1[order[:-1]])
        x22 = np.minimum(x2[index], x2[order[:-1]])
        y22 = np.minimum(y2[index], y2[order[:-1]])

        # todo:4.6- 计算交并比
        # 计算交集的面积,不重叠时面积为0
        w = np.maximum(0.0, x22 - x11)  # e.g. [w1,w2,w3..]
        h = np.maximum(0.0, y22 - y11)  # e.g. [h1,h2,h3..]
        intersection = w * h
        ratio = intersection / (areas[index] + areas[
            order[0:-1:1]] - intersection)  # e.g. 取了B => ratio:[Iou(A,B),Iou(C,B),Iou(D,B)]
        # print('ratio:', ratio)

        # 保留IoU小于阈值的box
        # 如果 np.where(condition, x=None, y=None) 没有传入 `x和y`就会返回满足条件的索引下标
        keep_boxes_indices = np.where(ratio < threshold)  # e.g. np.where([0.1,0.2,0.6] < 0.3) => [0,1] 返回x和y的索引值
        # print('keep_boxes_indices->', keep_boxes_indices)

        order = order[keep_boxes_indices]  # e.g. order:[1,2,3]  order = order[[0,1]] => order: [1,2]
        # print('order->', order)
        return picked_boxes, picked_score
  • 测试结果
# 测试数据
bounding = [(187, 82, 337, 317), (150, 67, 305, 282), (246, 121, 368, 304)]
confidence_score = [0.9, 0.65, 0.8]
threshold = 0.3
picked_boxes, picked_score = get_nms(bounding, confidence_score, threshold)
print('阈值threshold为:', threshold)
print('NMS后得到的bbox是:', picked_boxes)
print('NMS后得到的bbox的confidences是:', picked_score)
#########################################################
# 阈值threshold为: 0.3
# NMS后得到的bbox是: [array([187,  82, 337, 317])]
# NMS后得到的bbox的confidences是: [0.9]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值