【目标检测】评价指标:mAP概念及其计算方法(yolo源码/pycocotools)

news2025/2/25 13:58:22

本篇文章首先介绍目标检测任务中的关键评价指标mAP的概念;然后介绍其在yolo源码pycocotools工具中的实现方法;最后比较两种mAP的计算方法的不同之处。

目标检测中的评价指标:

mAP概念及其计算方法(yolo源码/pycocotools)
混淆矩阵概念及其计算方法(yolo源码)

本文目录

  • 1 概念
  • 2 mAP计算(pycocotools)
    • 2.1 coco评价指标
    • 2.2 coco指标计算
      • 2.2.1 数据形式转换(yolo to coco)
      • 2.2.2 coco计算类
  • 3 mAP计算(yolo源码)
  • 4 计算方法对比(pycocotools和yolo源码)
    • 4.1 插值方法
    • 4.2 面积计算方法(mAP)

1 概念

  在分类任务中,多以精确率/查准率(Precision, P)召回率/查全率(Recall, R)作为类别预测的评价指标,其计算方法如下:
P = T P T P + F P P = {{TP} \over {TP + FP}} P=TP+FPTP
R = T P T P + F N R = {{TP} \over {TP + FN}} R=TP+FNTP
其中TP表示目标被预测为正样本且实际为正样本数量;FP表示预测为正样本但实际为负样本的数量;FN表示预测为负样本但实际为正样本数量,FN+TP为样本总数。
  在不同的置信度阈值下,模型对某一类别的预测有多组P和R,平均精度(Average Precison, AP)即P-R曲线所围面积,均值平均精度(mean Average Precison, mAP)为所有类别AP的均值。
  目标检测的任务为对目标进行分类定位,模型的预测结果p为(cls, conf, pos),其中cls为目标的类别,conf为目标属于该类别的置信度,pos为目标的预测边框。在预测结果评价中,使用pgt(真实结果)边框之间的交集和并集面积之比(Intersection over Union, IoU)衡量结果,其P和R的计算公式如下:
P = T P T P + F P = T P n u m p ( a l l ) P = {{TP} \over {TP + FP}} = {{TP} \over {nump(all)}} P=TP+FPTP=nump(all)TP
R = T P T P + F N = R n u m g t ( a l l ) R = {{TP} \over {TP + FN}} = {{R} \over {numgt(all)}} R=TP+FNTP=numgt(all)R

  • TP:pgt匹配的数量
    • IoU > IoU_thres且类别一致
    • 同一个gt至多匹配一个p(若一个gt匹配到多个p,则选择IoU最高的p作为匹配结果)
    • 同一个gt至多匹配一个p(若一个p匹配到多个gt,则选择IoU最高的gt作为匹配结果)
  • FP:p未能与gt匹配的数量
  • FN:gt未能与p匹配的数量
      假设某目标检测任务中具有两个类别,一共有八张检测图片,其检测结果如图1所示,其中数字表示类别置信度。
    在这里插入图片描述
图1 模型检测结果
  根据上图结果,设定IoU_thres为0.5,预测结果的TP和FP统计结果表1所示。
表1 预测结果TP/FP统计

在这里插入图片描述

  根据表1统计结果,计算表中底色为蓝色(class_1)的类别预测AP,根据置信度从大到小对其类别预测结果进行排序,并在不同的类别置信度下计算其P和R,得到的结果如表2所示。

表2 类别1在不同置信度阈值下的P和R

在这里插入图片描述
  根据表2统计结果,绘制类别1在不同置信度阈值下的P-R曲线,如图2所示,其中每个点最终P值为该点本身及右边点的最大值,计算P-R曲线面积即可得到最终mAP,关于面积在pycocotoolsyolo源码中的具体求法见下文。
在这里插入图片描述

图2 类别1在不同置信度下P-R曲线

2 mAP计算(pycocotools)

2.1 coco评价指标

coco的评价指标如图3所示,各个评价指标的意义如下:

  • Average Precision (AP):即mAP
  • Average Recall (AR):IoU阈值@0.5:0.95下的所有Recall(不常用)
  • IoU (@0.5,@0.75,@0.5:0.95):不同的IoU阈值下的结果
  • area:预测目标的面积大小
  • maxDets:每张图片中的最多预测目标数量

在这里插入图片描述

图3 coco评价指标

2.2 coco指标计算

pycocotools函数:

  • pycocotools.coco.COCO:COCO数据形式(gt)
  • pycocotools.coco.COCOeval:指标计算

coco数据形式(json)(cocoGT):

  • image
    • id(图片id)
    • height(图片高度)
    • width(图片宽度)
  • categories
    • id(类别1)
    • id(类别2)
  • annotations:
    • image_index(当前标签属于的图片id)
    • bbox(xmin,ymin,w,h 绝对坐标)
    • categoried_id(当前标签属于的类别id)
    • area(当前预测边框面积)
    • iscrowd(目标检测任务中设为0)

yolo数据数据(txt)(yoloGt):(class, x, y, w, h)

2.2.1 数据形式转换(yolo to coco)

def convert_to_coco_api(ds):
    '''
    实现yolo数据形式(txt)到coco数据形式(json)的转换
    :param ds: 数据类(yolo源码中形式)
    :return: coco数据类
    '''
    coco_ds = COCO()  # pycocotools.coco.COCO
    # labels IDs need to start at 1, not 0
    ann_id = 1
    # images: {'id'(图片id): , 'height':, 'width': }
    # categories: {'id'(类别id): , 'id': , ...}
    # annotations: {'image_id'(属于图片id): , 'bbox': (xmin, ymin, w, h)绝对坐标, 'categoried_id', 'area(面积)', 'iscrowd': , 'id': 标签id}
    dataset = {'images': [], 'categories': [], 'annotations': []}
    categories = set()
    # 遍历dataset中的每张图像
    for img_idx in tqdm(range(len(ds)), desc="loading eval info for coco tools."):
        # targets: [num_obj, 6] , 6 -> (img_index, obj_index, x, y, h, w)
        targets, shapes = ds.coco_index(img_idx)
        # 图像字典添加
        img_dict = {}
        img_dict['id'] = img_idx
        img_dict['height'] = shapes[0]
        img_dict['width'] = shapes[1]
        dataset['images'].append(img_dict)
        # 标签字典添加
        for obj in targets:
            ann = {}
            # 当前标签属于的图片id
            ann["image_id"] = img_idx
            # 将相对坐标转为绝对坐标 (x, y, w, h) -> (xmin, ymin, w, h)
            # 位置信息
            boxes = obj[1:]
            boxes[:2] -= 0.5*boxes[2:]
            boxes[[0, 2]] *= img_dict["width"]
            boxes[[1, 3]] *= img_dict["height"]
            boxes = boxes.tolist()
            ann["bbox"] = boxes  # 当前标签的边框信息(xmin,ymin,w,h)
            ann["category_id"] = int(obj[0])  # 当前标签属于的类别id
            categories.add(int(obj[0]))
            ann["area"] = boxes[2] * boxes[3]  # 当前标签边框面积
            ann["iscrowd"] = 0
            ann["id"] = ann_id  # 当前标签id
            dataset["annotations"].append(ann)
            ann_id += 1

    dataset['categories'] = [{'id': i} for i in sorted(categories)]
    # 构造coco数据形式
    coco_ds.dataset = dataset
    # ds.anns(标签id:标签信息)
    # ds.imgToAnns(图片id:标签信息(属于当前图片))
    # ds.catToImgs(类别id: 标签信息(属于当前类别))
    # ds.imgs(图片id:图片信息)
    # ds.cats(类别id:类别)
    coco_ds.createIndex()
    return coco_ds

2.2.2 coco计算类

调用pycocotools API实现coco指标计算类(CocoEvaluator)

  • 函数
    • update:在模型预测过程中添加模型的预测结果,并将其转换为coco数据形式
    • accumulate: 调用COCOeval.accumulate实现每一类别TP/FP计算
    • summarize: 调用COCOeval.summarize实现评价指标的计算
class CocoEvaluator(object):
    def __init__(self, coco_gt, iou_types):
        assert isinstance(iou_types, (list, tuple))
        coco_gt = copy.deepcopy(coco_gt)  # coco数据(gt)
        self.coco_gt = coco_gt

        self.iou_types = iou_types  # ['bbox']
        self.coco_eval = {}
        for iou_type in iou_types:
            self.coco_eval[iou_type] = COCOeval(coco_gt, iouType=iou_type)

        self.img_ids = []
        self.eval_imgs = {k: [] for k in iou_types}

    def update(self, predictions):
        img_ids = list(np.unique(list(predictions.keys())))
        self.img_ids.extend(img_ids)

        for iou_type in self.iou_types:
            results = self.prepare(predictions, iou_type)
            coco_dt = loadRes(self.coco_gt, results) if results else COCO()
            coco_eval = self.coco_eval[iou_type]

            coco_eval.cocoDt = coco_dt
            coco_eval.params.imgIds = list(img_ids)
            img_ids, eval_imgs = evaluate(coco_eval)

            self.eval_imgs[iou_type].append(eval_imgs)

    def synchronize_between_processes(self):
        for iou_type in self.iou_types:
            self.eval_imgs[iou_type] = np.concatenate(self.eval_imgs[iou_type], 2)
            create_common_coco_eval(self.coco_eval[iou_type], self.img_ids, self.eval_imgs[iou_type])

    def accumulate(self):
        for coco_eval in self.coco_eval.values():
            coco_eval.accumulate()

    def summarize(self):
        for iou_type, coco_eval in self.coco_eval.items():
            print("IoU metric: {}".format(iou_type))
            coco_eval.summarize()

    def prepare(self, predictions, iou_type):
        if iou_type == "bbox":
            return self.prepare_for_coco_detection(predictions)
        elif iou_type == "segm":
            return self.prepare_for_coco_segmentation(predictions)
        elif iou_type == "keypoints":
            return self.prepare_for_coco_keypoint(predictions)
        else:
            raise ValueError("Unknown iou type {}".format(iou_type))

    def prepare_for_coco_detection(self, predictions):
        coco_results = []
        for original_id, prediction in predictions.items():
            if len(prediction) == 0:
                continue

            boxes = prediction["boxes"]
            boxes = convert_to_xywh(boxes).tolist()
            scores = prediction["scores"].tolist()
            labels = prediction["labels"].tolist()

            coco_results.extend(
                [
                    {
                        "image_id": original_id,
                        "category_id": labels[k],
                        "bbox": box,
                        "score": scores[k],
                    }
                    for k, box in enumerate(boxes)
                ]
            )
        return coco_results

    def prepare_for_coco_segmentation(self, predictions):
        coco_results = []
        for original_id, prediction in predictions.items():
            if len(prediction) == 0:
                continue

            scores = prediction["scores"]
            labels = prediction["labels"]
            masks = prediction["masks"]

            masks = masks > 0.5

            scores = prediction["scores"].tolist()
            labels = prediction["labels"].tolist()

            rles = [
                mask_util.encode(np.array(mask[0, :, :, np.newaxis], dtype=np.uint8, order="F"))[0]
                for mask in masks
            ]
            for rle in rles:
                rle["counts"] = rle["counts"].decode("utf-8")

            coco_results.extend(
                [
                    {
                        "image_id": original_id,
                        "category_id": labels[k],
                        "segmentation": rle,
                        "score": scores[k],
                    }
                    for k, rle in enumerate(rles)
                ]
            )
        return coco_results

    def prepare_for_coco_keypoint(self, predictions):
        coco_results = []
        for original_id, prediction in predictions.items():
            if len(prediction) == 0:
                continue

            boxes = prediction["boxes"]
            boxes = convert_to_xywh(boxes).tolist()
            scores = prediction["scores"].tolist()
            labels = prediction["labels"].tolist()
            keypoints = prediction["keypoints"]
            keypoints = keypoints.flatten(start_dim=1).tolist()

            coco_results.extend(
                [
                    {
                        "image_id": original_id,
                        "category_id": labels[k],
                        'keypoints': keypoint,
                        "score": scores[k],
                    }
                    for k, keypoint in enumerate(keypoints)
                ]
            )
        return coco_results

3 mAP计算(yolo源码)

基于YOLO源码实现mAP @0.5:0.95计算(MeanAveragePrecsion)

  • 数据形式:
    • 预测结果:xmin,ymin,xmax,ymax,conf,class(绝对坐标)
    • 真实结果:class,xmin,ymin,xmax,ymax(绝对坐标)
  • 函数:
    • process_batch:实现预测结果和真实结果的匹配
    • calculate_ap_per_class: 计算每一类别的AP值
    • compute_pr_area:计算PR曲线的面积
class MeanAveragePrecison:
    def __init__(self, device="cpu"):
        '''
        计算mAP: mAP@0.5; mAP @0.5:0.95; mAP @0.75
        '''
        self.iouv = torch.linspace(0.5, 0.95, 10, device=device)  # 不同的IoU置信度 @0.5:0.95
        self.niou = self.iouv.numel()  # IoU置信度数量
        self.stats = []  # 存储预测结果
        self.device = device
    def process_batch(self, detections, labels):
        '''
        预测结果匹配(TP/FP统计)
        :param detections:(array[N,6]) x1,y1,x1,y1,conf,class (原图绝对坐标)
        :param labels:(array[M,5]) class,x1,y1,x2,y2 (原图绝对坐标)
        '''
        # 每一个预测结果在不同IoU下的预测结果匹配
        correct = np.zeros((detections.shape[0], self.niou)).astype(bool)
        if detections is None:
            self.stats.append((correct, *torch.zeros((2, 0), device=self.device), labels[:, 0]))
        else:
        # 计算标签与所有预测结果之间的IoU
            iou = box_iou(labels[:, 1:], detections[:, :4])
            # 计算每一个预测结果可能对应的实际标签
            correct_class = labels[:, 0:1] == detections[:, 5]
            for i in range(self.niou):  # 在不同IoU置信度下的预测结果匹配结果
                # 根据IoU置信度和类别对应得到预测结果与实际标签的对应关系
                x = torch.where((iou >= self.iouv[i]) & correct_class)
                # 若存在和实际标签相匹配的预测结果
                if x[0].shape[0]:  # x[0]:存在为True的索引(实际结果索引), x[1]当前所有True的索引(预测结果索引)
                    # [label, detect, iou]
                    matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy()
                    if x[0].shape[0] > 1:  # 存在多个与目标对应的预测结果
                        matches = matches[matches[:, 2].argsort()[::-1]]  # 根据IoU从高到低排序 [实际结果索引,预测结果索引,结果IoU]
                        matches = matches[np.unique(matches[:, 1], return_index=True)[1]]  # 每一个预测结果保留一个和实际结果的对应
                        matches = matches[np.unique(matches[:, 0], return_index=True)[1]]  # 每一个实际结果和一个预测结果对应
                    correct[matches[:, 1].astype(int), i] = True  # 表面当前预测结果在当前IoU下实现了目标的预测
            # 预测结果在不同IoU是否预测正确, 预测置信度, 预测类别, 实际类别
            self.stats.append((correct, detections[:, 4], detections[:, 5], labels[:, 0]))

    def calculate_ap_per_class(self, save_dir='.', names=(), eps=1e-16):
        stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*self.stats)]  # to numpy
        # tp:所有预测结果在不同IoU下的预测结果 [n, 10]
        # conf: 所有预测结果的置信度
        # pred_cls: 所有预测结果得到的类别
        # target_cls: 所有图片上的实际类别
        tp, conf, pred_cls, target_cls = stats[0], stats[1], stats[2], stats[3]
        # 根据类别置信度从大到小排序
        i = np.argsort(-conf)  # 根据置信度从大到小排序
        tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]

        # 得到所有类别及其对应数量(目标类别数)
        unique_classes, nt = np.unique(target_cls, return_counts=True)
        nc = unique_classes.shape[0]  # number of classes
 
        # ap: 每一个类别在不同IoU置信度下的AP, p:每一个类别的P曲线(不同类别置信度), r:每一个类别的R(不同类别置信度)
        ap, p, r = np.zeros((nc, tp.shape[1])), np.zeros((nc, 1000)), np.zeros((nc, 1000))
        for ci, c in enumerate(unique_classes):  # 对每一个类别进行P,R计算
            i = pred_cls == c
            n_l = nt[ci]  # number of labels 该类别的实际数量(正样本数量)
            n_p = i.sum()  # number of predictions 预测结果数量
            if n_p == 0 or n_l == 0:
                continue

            # cumsum:轴向的累加和, 计算当前类别在不同的类别置信度下的P,R
            fpc = (1 - tp[i]).cumsum(0)  # FP累加和(预测为负样本且实际为负样本)
            tpc = tp[i].cumsum(0)  # TP累加和(预测为正样本且实际为正样本)
            # 召回率计算(不同的类别置信度下)
            recall = tpc / (n_l + eps)
            # 精确率计算(不同的类别置信度下)
            precision = tpc / (tpc + fpc)


            # 计算不同类别置信度下的AP(根据P-R曲线计算)
            for j in range(tp.shape[1]):
                ap[ci, j], mpre, mrec = self.compute_ap(recall[:, j], precision[:, j])
        # 所有类别的ap值 @0.5:0.95
       	return ap


    def compute_ap(self, recall, precision):
        # 增加初始值(P=1.0 R=0.0) 和 末尾值(P=0.0, R=1.0)
        mrec = np.concatenate(([0.0], recall, [1.0]))
        mpre = np.concatenate(([1.0], precision, [0.0]))

        # Compute the precision envelope np.maximun.accumulate
        # (返回一个数组,该数组中每个元素都是该位置及之前的元素的最大值)
        mpre = np.flip(np.maximum.accumulate(np.flip(mpre)))

        # 计算P-R曲线面积
        method = 'interp'  # methods: 'continuous', 'interp'
        if method == 'interp':  # 插值积分求面积
            x = np.linspace(0, 1, 101)  # 101-point interp (COCO))
            # 积分(求曲线面积)
            ap = np.trapz(np.interp(x, mrec, mpre), x)
        elif method == 'continuous':  # 不插值直接求矩阵面积
            i = np.where(mrec[1:] != mrec[:-1])[0]  # points where x axis (recall) changes
            ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])  # area under curve

        return ap, mpre, mrec

4 计算方法对比(pycocotools和yolo源码)

  yolo源码计算得到的mAP会高于pycocotools计算得到的mAP,其主要表现在得到P-R曲线后的处理过程,如图4所示。
在这里插入图片描述

图4 coco和yolo中P-R曲线面积计算方法对比

4.1 插值方法

  在最终计算得到的mpre(P),mrec(R)中,通过插值的方法得到101个点,在两种计算方法中,所用的插值函数存在不同。

  • pycocotools:np.searchsorted
'''
np.searchsorted(a, v, side='left', sorter=None)-> inds
a:一维数组,当sorter为None时,其必须为升序数组
v:插值数组
side: 'left':a[i-1] < v <= a[i],第一个满足条件的; 'right':a[i-1] <= v < a[i],最后一个满足条件的
inds: 列表,对应v中元素插入a的位置
'''
recThrs = np.linspace(.0, 1.00, 101, endpoint=True)
inds = np.searchsorted(mrec, recThrs, side='left')   # 在横坐标(R)上插值得到新的横坐标
for ri, pi in enumerate(inds):
	q[ri] = mpre[pi]  # 新的纵坐标
mpre = np.array(q[ri])
  • yolo源码:np.interp
'''
numpy.interp(x, xp, fp, left=None, right=None, period=None)->p
x:计算插值的x坐标
xp:原数据的纵坐标
fp:原数据的横坐标
p:通过估计xp和fp的线性关系,得到插值
'''
recThrs = np.linspace(.0, 1.00, 101)
mpre = np.interp(recThrs, mrec, mpre)

4.2 面积计算方法(mAP)

  • pycocotools:np.mean(mpre)计算插值点的均值得到结果

  • yolo源码:np.tapz(mpre,recThrs)计算插值后P-R曲线积分(面积)得到结果

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

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

相关文章

6.2 声音编辑工具GoldWave5简介(7)

6.2.5其它常用功能 1&#xff0e;高低通 把录制的语音和背景音乐融合在一起时&#xff0c;可能会出现背景音乐音量过大&#xff0c;语音音量过小的现象&#xff0c;这时可以选择“低通”将背景音乐的音量降低一些。 (1)选择【效果】|【波波器】|【低通/高通】命令&#xff0…

开箱即用的企业级前后端分离【.NET Core6.0 Api + Vue 2.x + RBAC】权限框架-Blog.Core

前言 今天要给大家推荐一个开箱即用的企业级前后端分离【.NET Core6.0 Api Vue 2.x RBAC】权限框架&#xff08;提高生产效率&#xff0c;快速开发就选它&#xff09;&#xff1a;Blog.Core。 推荐原因 Blog.Core通过详细的文章和视频讲解&#xff0c;将知识点各个击破&…

2024-1-12 关于SVPWM的理解疑问

直流母线电压利用率是指逆变电路&#xff08;电机控制器&#xff09;所能输出的交流电压基波最大幅值U1m和直流母线电压之比。 电压利用率 SVPWM算法理解&#xff08;二&#xff09;——关于非零基本矢量幅值和线电压幅值的解释 因此我们在实际应用中提供的直流侧电压Udc&…

ssm基于Web的课堂管理系统设计与实现论文

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

【Linux】 系统目录结构

进入到根目录 cd /ls目录名具体作用/存放系统系统相关的目录文件/boot放置linux系统内核文件和启动时用到的一些引导文件/home包含linux系统上各用户的主目录&#xff0c;子目录名称默认以该用户名命名/root系统管理员root的家目录/bin包含常用的命令文件&#xff08;如ls 等&a…

STM32 CAN学习(一)

STM32 CAN CAN协议简介 CAN是控制器局域网络(Controller Area Network)的简称&#xff0c;它是由研发和生产汽车电子产品著称的德国BOSCH公司开发的&#xff0c;并最终成为国际标准&#xff08;ISO11519&#xff09;&#xff0c;是国际上应用最广泛的现场总线之一。CAN总线协…

Qat++,轻量级开源C++ Web框架

目录 一.简介 二.编译Oat 1.环境 2.编译/安装 三.试用 1.创建一个 CMake 项目 2.自定义客户端请求响应 3.将请求Router到服务器 4.用浏览器验证 一.简介 Oat是一个面向C的现代Web框架 官网地址&#xff1a;https://oatpp.io github地址&#xff1a;https://github.co…

JavaScript中alter、confrim、prompt的区别及使用

文章目录 一、alter1.什么是alert&#xff1f;2.alter的使用 二、confrim1.什么是confrim&#xff1f;2.confrim的使用 三、prompt1.什么是prompt&#xff1f;2.prompt的使用 四、总结alter、confrim、prompt的区别 一、alter 1.什么是alert&#xff1f; 在JavaScript中&…

ssm基于Vue的健身房会员管理系统+vue论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差&#x…

强化学习应用(四):基于Q-learning算法的无人车配送路径规划(提供Python代码)

一、Q-learning算法介绍 Q-learning是一种强化学习算法&#xff0c;用于解决基于环境的决策问题。它通过学习一个Q-table来指导智能体在不同状态下采取最优动作。下面是Q-learning算法的基本步骤&#xff1a; 1. 定义环境&#xff1a;确定问题的状态和动作空间&#xff0c;并…

1.5矩阵元素的引用

通过下标来引用矩阵的元素 A(3, 2)表示A矩阵第3行第2列的元素。 >> arr [1,2,3;4,5,6]; >> arr(4, 5) 10arr 1 2 3 0 04 5 6 0 00 0 0 0 00 0 0 0 10>> 如果引用元素超过矩阵的大小将自…

ssm基于spring和vue开发的web新闻流媒体平台论文

摘 要 如今的时代&#xff0c;是有史以来最好的时代&#xff0c;随着计算机的发展到现在的移动终端的发展&#xff0c;国内目前信息技术已经在世界上遥遥领先&#xff0c;让人们感觉到处于信息大爆炸的社会。信息时代的信息处理肯定不能用之前的手工处理这样的解决方法&#x…

隧道应用3-Cobalt Strike正反向连接多层内网

Cobalt Strike 正向连接多层内网&#xff1a; teamserver 不允许访问 B &#xff0c;但是服务器上A有权限&#xff08; A 与 B 在同一网段&#xff09;&#xff0c;若 A 服务上已经有了 cs 的后门&#xff0c;则可以通过 cs 的正向连接去连接 B &#xff0c;在 teamserver 通…

基于机器学习的高考志愿高校及专业分析系统

本项目在“基于 Python 的高考志愿高校及专业分析系统”基础上补充添加了机器学习算法对高考总问进行预测&#xff1b; 项目采用了网络爬虫技术&#xff0c;从指定的高考信息网站上抓取了各大高校的历年录取分数线数据。 通过精细的数据清洗过程&#xff0c;这些数据被存储于…

黑马程序员SpringBoot2-开发实用篇

视频连接&#xff1a;开发实用篇-67-手工启动热部署_哔哩哔哩_bilibili 热部署 手动启动热部署 热部署仅包含restart的过程。 自动启动热部署 按CtrlAltShift/打开下列界面。 禁用热部署 配置高级 ConfigurationProperties 宽松绑定/松散绑定 常用计量单位绑定 数据校验 设置…

阿里云优惠券介绍、种类、领取入口及使用教程

阿里云优惠券是阿里云提供的一种优惠活动&#xff0c;旨在帮助用户节省购买云服务产品的费用。本文将为大家详细介绍阿里云优惠券的相关信息&#xff0c;包括优惠券的介绍、种类、领取入口以及使用教程。 一、阿里云优惠券介绍 阿里云优惠券是阿里云提供给用户的一种优惠凭证&…

超强站群系统v9.0:最新蜘蛛池优化技术,一键安装,内容无缓存刷新,高效安全

安全、高效&#xff0c;化的优化利用php性能&#xff0c;使得运行流畅稳定 独创内容无缓存刷新不变&#xff0c;节省硬盘。防止搜索引擎识别蜘蛛池 蜘蛛池算法&#xff0c;轻松构建站点&#xff08;电影、资讯、图片、论坛等等&#xff09; 可以个性化每个网站的风格、内容、…

SpringFramework实战指南(二)

SpringFramework实战指南&#xff08;二&#xff09; 2.1 Spring 和 SpringFramework概念2.2 SpringFramework主要功能模块2.3 SpringFramework 主要优势 2.1 Spring 和 SpringFramework概念 Spring-ioc 广义的 Spring&#xff1a;Spring 技术栈&#xff08;全家桶&#xff0…

2.1 常用计算机网络体系结构

2.1 常用计算机网络体系结构 2.1.1 OSI体系结构 1、为了使不同体系结构的计算机网络都能够互联&#xff0c;国际标准化组织于1977年成立了专门机构研究该问题&#xff0c;不久他们就提出了一个试图使各种计算机在世界范围内都能够互连成网的标准框架&#xff0c;也就是著名的…

【基础数据结构】字符串

一、字符串输入 1.scanf("%s",str);分隔符为空格、制表符、回车 2.fgets(str,10,stdin);10为字符串char str[10]长度&#xff0c;可以读取空格字符的字符串&#xff0c;10代表最大读取长度&#xff0c;最多读取9个字符&#xff0c;这个函数自动在读取到换行符停止&…