【论文解读】单目3D目标检测 LPCG(ECCV 2022)

news2025/2/26 1:55:58

本文分享单目3D目标检测,LPCG模型的论文解读,了解它的设计思路,论文核心观点,模型结构,以及效果和性能。

目录

一、LPCG 简介

二、论文核心观点

三、思路框架

四、核心观点——单目3D目标检测的标签中,3D位置是极其关键的

五、核心内容——低成本模式,点云数据生成粗略的3D标签

六、核心内容——高精度模式,小量标注数据生成精准标签

七、在自动驾驶中应用LPCG

八、实验分析


一、LPCG 简介

LPCG是一种用激光点云指导-单目3D目标检测的方法,通过点云数据生成海量粗略的3D标签,生成过程中不用对点云进行标注;降低3D标签的成本。

同时这些海量“粗略的3D标签”位置是准确的,只是尺寸和朝向有些偏差

所以如何通过点云数据,直接生成粗略的3D标签是LPCG论文亮点。

用这些海量“粗略的3D标签”,作为伪标签指导单目3D目标检测训练。这种方法可以应用到各种单目3D目标检测模型中,模型精度提升大,太强了~

论文地址:Lidar Point Cloud Guided Monocular 3D Object Detection

开源地址:https://github.com/SPengLiang/LPCG

二、论文核心观点

论文核心观点,主要有4点组成:

  • 1、在单目3D目标检测的标签中中心点位置准确性,是非常重要的;与标签的尺寸和朝向相比,3D位置是极其关键的。
  • 2、激光雷达的点云数据,具有准确的3D测量;获取点云数据,不用对点云数据进行标注,经过算法直接生成粗略的3D标签
  • 3、标注一小部分数据,监督训练点云3D目标检测模型,得到高精度的模型;模型预测的结果,作为较精准的3D标签
  • 4、用海量的粗略3D标签,和小量的较精准3D标签,一起形成伪标签,指导单目3D目标检测训练

三、思路框架

LPCG是一种用激光点云指导-单目3D目标检测的方法,可以应用到各种单目3D目标检测模型中,比如:MonoFlex、M3D-RPN等等。

思路框架如下图所示: 

第一步:生成伪标签

  • 低成本模式,获取点云数据,不用对点云数据进行标注,经过算法直接生成粗略的3D标签
  • 高精度模式,标注一小部分数据,监督训练点云3D目标检测模型,得到高精度的模型;模型预测的结果,作为较精准的3D标签
  • 整合低成本模型输出的海量的粗略3D标签高精度模型输出的较精准的3D标签,一起作为单目3D目标检测模型的标签。

第二步:训练单目3D模型

  • 得到伪标签,进行有监督训练,得到单目3D目标检测模型。

四、核心观点——单目3D目标检测的标签中,3D位置是极其关键的

作者对标签中中心位置尺寸朝向,进行干扰实验。通过在百分比范围内,随机移动相应的值来扰乱完美的手动注释标签。

受5%干扰的标签准确率,与完美标签的准确度相当。

当实施大干扰(10%和20%)时,可以看到位置(Location)主导性能(AP仅在干扰位置时显著降低)。

这表明,具有精确位置的粗略伪3D box标签,可以替代完美的带注释的3D box标签。即:发现手动标注的完美标签,对于单目3D检测是非必要的。

作者注意到激光点云可以提供有价值的3D Location信息,点云可以提供精确的深度测量,而周围精确的深度信息可以提供更加精确的物体位置,这对于3D物体检测至关重要。

点云可以由激光雷达设备轻松获取,允许离线收集大量点云,无需人工成本。

于是,使用点云生成3D伪标签,新生成的标签可用于训练单目3D检测器。

五、核心内容——低成本模式,点云数据生成粗略的3D标签

低成本模式,获取点云数据,不用对点云数据进行标注,经过算法直接生成粗略的3D标签。思路流程:

1、2D实例分割:采用2D实例分割模型,对图像进行分割,获得2D框和掩模mask。默认使用mask-rcnn模型。

2、提取ROI点云:结合实例分割结果mask,和相机平截头体camera frustums,提取每个对象选择相关的ROI点云。其中忽略了内部没有任何点云点的框。

3、点云聚类:位于同一平截头体中的激光雷达点由对象点和混合背景或遮挡点组成。为了消除不相关的点,作者用DBSCAN根据密度将RoI点云划分为不同的组。在3D空间中接近的点将聚集到一个簇中。

4、形成各个物体点云:将包含大多数点的簇视为与对象相对应的目标。

5、在BEV中形成2D框:为了简化解决3D边界框的问题,作者将点投影到BEV鸟瞰图上,减少了参数。得到BEV的中心点信息、长宽、朝向。

6、生成3D框信息:结合点云的高度,和BEV的中心点信息、长宽、朝向,得到完整的3D框信息(中心位置、长宽高、朝向)

这里再讲一下在BEV中形成2D框,使用物体点的凸包( the convex hull),然后使用旋转卡壳(rotating calipers)。

看一下2D实例分割的代码,默认使用mask-rcnn模型,进行实例分割。包含的类别的:

COCO_INSTANCE_CATEGORY_NAMES = [
    '__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
    'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
    'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
    'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
    'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
    'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
    'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
    'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table',
    'N/A', 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
    'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
    'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]

核心代码: 

if __name__ == '__main__':
    # pre_trained_mask_rcnn_path = '/private/pengliang/maskrcnn_resnet50_fpn.pth'
    # model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=False)
    # model.load_state_dict(torch.load(pre_trained_mask_rcnn_path))

    model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)
    model.cuda()
    model.eval()


    with torch.no_grad():
        for _, v in enumerate(tqdm(train_id)):
            img_file_path = os.path.join(img_dir, v+'.png')
            seg_mask_path = img_file_path.replace('image_2', 'seg_mask').replace('png', 'npz')
            seg_bbox_path = img_file_path.replace('image_2', 'seg_bbox').replace('png', 'txt')

            seg_mask_dir = os.path.dirname(seg_mask_path)
            seg_bbox_dir = os.path.dirname(seg_bbox_path)
            if not os.path.exists(seg_mask_dir):
                os.makedirs(seg_mask_dir)
            if not os.path.exists(seg_bbox_dir):
                os.makedirs(seg_bbox_dir)

            image = cv.imread(img_file_path)
            image_tensor = torchvision.transforms.functional.to_tensor(image)

            output = model([image_tensor.cuda()])[0]
            labels = output['labels'].cpu().numpy()

            '''for car'''
            ind = (labels == 3)
            scores = (output['scores'].cpu().numpy())
            score_ind = scores > 0.5
            ind = ind & score_ind

            bbox = (output['boxes'].cpu().numpy())[ind]
            masks = (output['masks'].cpu().numpy())[ind]
            scores = scores[ind]

            if bbox.shape[0] > 0:
                bbox2d = np.hstack([bbox.reshape(-1, 4), scores.reshape(-1, 1)])
                np.savetxt(seg_bbox_path, bbox2d, fmt='%f')
                np.savez(seg_mask_path, masks=masks[:, 0, ...])



看一下点云聚类的代码,默认使用DBSCAN算法:

import os
from tqdm import tqdm
import numpy as np
import cv2 as cv
from sklearn.cluster import DBSCAN
import yaml

import utils

kitti_cfg = yaml.load(open('./config/kitti.yaml', 'r'), Loader=yaml.Loader)
kitti_merge_data_dir = kitti_cfg['KITTI_merge_data_dir']
dst_low_cost_label_dir = os.path.join(kitti_cfg['root_dir'], 'low_cost/label_2')


def obtain_cluster_box(l_3d, l_2d, seg_bbox_path, seg_mask_path, P2, wh_range, mask_conf):
    bbox2d = np.loadtxt(seg_bbox_path).reshape(-1, 5)
    bbox_mask = (np.load(seg_mask_path))['masks']

    _, h, w = bbox_mask.shape
    fov_ind = (l_3d[:, 2] > 0) & (l_2d[:, 0] > 0) & (l_2d[:, 1] > 0) & (l_2d[:, 0] < w-1) & (l_2d[:, 1] < h-1)
    l_3d, l_2d = l_3d[fov_ind], l_2d[fov_ind]

    label = []
    for index, b in enumerate(bbox2d):
        if b[-1] < mask_conf:
            continue

        bbox2d_2 = bbox_mask[index]
        bbox2d_2[bbox2d_2 < 0.7] = 0
        bbox2d_2[bbox2d_2 >= 0.7] = 1

        ind = bbox2d_2[l_2d[:, 1], l_2d[:, 0]].astype(np.bool)
        cam_points = l_3d[ind]

        if len(cam_points) < 10:
            continue

        cluster_index = DBSCAN(eps=0.8, min_samples=10, n_jobs=-1).fit_predict(cam_points)

        cam_points = cam_points[cluster_index > -1]
        cluster_index = cluster_index[cluster_index > -1]

        if len(cam_points) < 10:
            continue

        cluster_set = set(cluster_index[cluster_index > -1])
        cluster_sum = np.array([len(cam_points[cluster_index == i]) for i in cluster_set])
        cam_points = cam_points[cluster_index == np.argmax(cluster_sum)]

        rect = cv.minAreaRect(np.array([(cam_points[:, [0, 2]]).astype(np.float32)]))
        (l_t_x, l_t_z), (w, l), rot = rect

        if w > l:
            w, l = l, w
            rot = 90 + rot

        if w > wh_range[0] and w < wh_range[1] and l > wh_range[2] and l < wh_range[3]:
            rect = ((l_t_x, l_t_z), (w, l), rot)
            box = cv.boxPoints(rect)

            h = np.max(cam_points[:, 1]) - np.min(cam_points[:, 1])
            y_center = np.mean(cam_points[:, 1])
            y = y_center + h / 2

            x, z = np.mean(box[:, 0]), np.mean(box[:, 1])
            Ry = (-(np.pi / 2 - (-rot) / 180 * np.pi)) % (np.pi*2)
            if Ry > np.pi:
                Ry -= np.pi*2
            if Ry < -np.pi:
                Ry += np.pi*2

            c_3d = utils.corner_3d([h, w, l, x, y, z, Ry])
            c_2d = utils.convert_to_2d(c_3d, P2)
            bbox = [np.min(c_2d[:, 0]), np.min(c_2d[:, 1]),
                    np.max(c_2d[:, 0]), np.max(c_2d[:, 1])]

            res = np.array([bbox[0], bbox[1], bbox[2], bbox[3],
                              h, w, l, np.mean(box[:, 0]), y, np.mean(box[:, 1]), Ry])
            res = np.round(res, 2)

            label.append(['Car', '0', '0', '0'] + list(res))
    return np.array(label)


if __name__ == '__main__':
    wh_range = [1.2, 1.8, 3.2, 4.2]
    mask_conf = 0.9

    root_dir = kitti_merge_data_dir
    if not os.path.exists(dst_low_cost_label_dir):
        os.makedirs(dst_low_cost_label_dir)

    calib_dir = os.path.join(root_dir, 'calib')
    lidar_dir = os.path.join(root_dir, 'velodyne')
    seg_box_dir = os.path.join(root_dir, 'seg_bbox')
    seg_mask_dir = os.path.join(root_dir, 'seg_mask')
    train_id_path = os.path.join(root_dir, 'split/train.txt')
    train_id = np.loadtxt(train_id_path, dtype=str)

    for i, v in enumerate(tqdm(train_id)):
        lidar_path = os.path.join(lidar_dir, v+'.bin')
        calib_path = os.path.join(calib_dir, v+'.txt')
        seg_bbox_path = os.path.join(seg_box_dir, v+'.txt')
        seg_mask_path = os.path.join(seg_mask_dir, v+'.npz')
        dst_low_cost_label_path = os.path.join(dst_low_cost_label_dir, v+'.txt')

        # obtain and transform lidar points
        l_3d = np.fromfile(lidar_path, dtype=np.float32, count=-1).reshape([-1, 4])[:, :3]
        calibs = utils.parse_calib('3d', calib_path)
        l_3d = (calibs['l2i'] @ (np.concatenate([l_3d, np.ones_like(l_3d[:, :1])], axis=1)).T).T
        l_2d = (utils.convert_to_2d(l_3d, calibs['P2'])).astype(np.int32)

        if not os.path.exists(seg_bbox_path):
            np.savetxt(dst_low_cost_label_path, np.array([]), fmt='%s')
            continue

        low_cost_label = obtain_cluster_box(l_3d, l_2d, seg_bbox_path, seg_mask_path, calibs['P2'], wh_range, mask_conf)
        np.savetxt(dst_low_cost_label_path, low_cost_label, fmt='%s')

六、核心内容——高精度模式,小量标注数据生成精准标签

标注一小部分数据,监督训练点云3D目标检测模型,得到高精度的模型;模型预测的结果,作为较精准的3D标签。

  1. 首先使用LiDAR点云和相关的3D box注释,从头开始训练基于LiDAR的3D检测器。
  2. 然后利用预训练的基于激光雷达的3D检测器,来推断其他未标记激光雷达点云上的3D box。
  3. 这样的3D box结果被当作伪标签来训练单目3D检测器

作者将伪标签与手动注释的完美标签进行了比较。由于精确的3D位置测量,基于LiDAR的3D探测器预测的伪标签相当准确,可以直接用于单目3D检测器的训练

由生成的伪标签训练的单目3D检测器显示出接近的性能,只需要少量的3D注释框就足以推动单目方法实现高性能。

看一下高精度模式和低成本模式的效果对比:

 

 在LiDAR的3D检测器中,默认使用的是OpenPCDet开源库中 PV-RCNN模型。还有许多其他点云3D目标检测模型可以换的

OpenPCDet库具有统一点云坐标的数据模型分离,可轻松扩展到自定义数据集。

统一3D框定义:(x、y、z、dx、dy、dz、航向)。

OpenPCDet开源库:GitHub - open-mmlab/OpenPCDet: OpenPCDet Toolbox for LiDAR-based 3D Object Detection.

在KITTI数据集的val集上,3D检测性能为中等难度:

training timeCar@R11Pedestrian@R11Cyclist@R11download
PointPillar~1.2 hours77.2852.2962.68model-18M
SECOND~1.7 hours78.6252.9867.15model-20M
SECOND-IoU-79.0955.7471.31model-46M
PointRCNN~3 hours78.7054.4172.11model-16M
PointRCNN-IoU~3 hours78.7558.3271.34model-16M
Part-A2-Free~3.8 hours78.7265.9974.29model-226M
Part-A2-Anchor~4.3 hours79.4060.0569.90model-244M
PV-RCNN~5 hours83.6157.9070.47model-50M
Voxel R-CNN (Car)~2.2 hours84.54--model-28M
Focals Conv - F~4 hours85.66--model-30M

七、在自动驾驶中应用LPCG

 在自动驾驶中,下图说明了数据收集策略。

  • 大多数自动驾驶系统可以轻松地同步收集大量未标记的LiDAR点云数据和RGB图像。
  • 该数据由多个序列构成,其中每个序列通常指向特定场景并包含多个连续帧。
  • 由于现实世界中时间和资源有限,仅选择一些序列进行注释,以训练网络,如Waymo。
  • 此外,为了降低高注释成本,仅对所选序列中的一些关键帧进行注释,例如KITTI。因此,在实际应用程序中仍然存在大量未标记的数据。

考虑到LPCG可以充分利用未标记的数据,在现实世界的自动驾驶系统中使用是很自然的。

  • 高精度模式,只需要少量标记数据。
  • 在低成本模式,从单目3D检测器的剩余未标记数据中,生成高质量的训练数据,以提高准确性。

低成本模式不需要任何3D注释框,仍然可以提供准确的3D框伪标签;生成的3D box伪标签对于单目3D检测器来说是很不错的。

八、实验分析

KITTI 测试集上实现分析的。 使用红色表示最高结果,蓝色表示第二高结果,青色表示第三高结果。

‡ 表示我们使用的基线检测器,改进是相对于基线检测器而言的。相对于MonoFlex模型,在简单场景的AP3D提升了5.62,达到25.56。

DD3D 采用大型私有 DDAD15M 数据集(包含大约 15M 帧)和KITTI 深度数据集(包含大约 26K 帧)。

KITTI 深度数据集提供大约 26K 样本来训练深度估计器(对于大多数基于深度图的方法),或为单目 3D 检测器 (LPCG) 生成额外的训练样本。

LPCG训练的 M3D-RPN的结果。 绿色:真实框。 红色:预测框。 白色:来自 M3D-RPN 的原始预测。

鸟瞰图中方框的粗体一侧指的是方向,可以看到LPCG的预测更加准确,一些预测框与真实框重叠。还展示了失败案例,这些案例包含在灰色虚线圆圈中。 

分享完成~

 单目3D目标检测专栏,大家可以参考一下

【综述篇】

单目3D目标检测 方法综述——直接回归方法、基于深度信息方法、基于点云信息方法-CSDN博客 

 【数据集】单目3D目标检测:

3D目标检测数据集 KITTI(标签格式解析、3D框可视化、点云转图像、BEV鸟瞰图)_kitti标签_一颗小树x的博客-CSDN博客

3D目标检测数据集 DAIR-V2X-V_一颗小树x的博客-CSDN博客

【论文解读】单目3D目标检测:

【论文解读】SMOKE 单目相机 3D目标检测(CVPR2020)_相机smoke-CSDN博客

【论文解读】单目3D目标检测 CUPNet(ICCV 2021)-CSDN博客

【论文解读】单目3D目标检测 DD3D(ICCV 2021)-CSDN博客

【论文解读】单目3D目标检测 MonoDLE(CVPR2021)_一颗小树x的博客-CSDN博客

【论文解读】单目3D目标检测 MonoFlex(CVPR 2021)-CSDN博客

【论文解读】单目3D目标检测 MonoCon(AAAI2022)_一颗小树x的博客-CSDN博客

【实践应用】

单目3D目标检测——SMOKE 环境搭建|模型训练_一颗小树x的博客-CSDN博客

单目3D目标检测——SMOKE 模型推理 | 可视化结果-CSDN博客

单目3D目标检测——MonoDLE 模型训练 | 模型推理_一颗小树x的博客-CSDN博客

单目3D目标检测——MonoCon 模型训练 | 模型推理-CSDN博客

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

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

相关文章

MySQL数据库 #5

文章目录 一、Python操作MySQL1.pymysql的基本操作2.pymysql补充说明1.查看补充2. 增删改&#xff0c;自动确认 3.SQL注入问题1.输入对的用户名就可登录2.输入错的用户名也可以登录针对上述的SQL注入问题&#xff0c;核心在于手动拼接了关键数据 二、视图1.什么是视图2. 为什么…

RPC与HTTP的关系

首选理清楚关系 RPC与HTTP是两个不同维度的东西 HTTP 协议&#xff08;Hyper Text Transfer Protocol&#xff09;&#xff0c;又叫做超文本传输协议&#xff0c;是一种传输协议&#xff0c;平时通过浏览器浏览网页网页&#xff0c;用到的就是 HTTP 协议。 而 RPC&#xff0…

全能数字音乐工作站(DAW)编曲FL Studio21.2.0官方中文版

FL Studio21.2.0官方中文版重磅发布纯正简体中文支持&#xff0c;更快捷的音频剪辑及素材管理器&#xff0c;多样主题随心换&#xff01;Mac版新增对苹果M2/1家族芯片原生支持。全能数字音乐工作站&#xff08;DAW&#xff09;编曲、剪辑、录音、混音&#xff0c;26余年的技术积…

LeetCode题:88合并两个有序数组,283移动零,448找到所有数组中消失的数字

目录 88合并两个有序数组 1、题目要求 2、解题思路 &#xff08;1&#xff09;、暴力解法&#xff1a; &#xff08;2&#xff09;、双指针&#xff0c;使用第三数组的解法&#xff1a; 3、代码展示 &#xff08;1&#xff09;、暴力解法&#xff1a; &#xff08;2&am…

ITSource 分享 第6期【网址云收藏系统】

项目介绍 本期给大家介绍一个 网址云收藏系统.。 你是否因为上网过程中收藏了很多网址找不到而发愁&#xff0c;如果浏览器没有登录账号开启同步的情况下&#xff0c;换个电脑&#xff0c;换个浏览器&#xff0c;以前收藏的网址就找不到了。 本期给大家推荐一个可以在线随时随地…

jmeter BeanShell预处理程序:报错Error invoking bsh method: eval...

1、jmeter运行报错&#xff1a; ERROR o.a.j.u.BeanShellInterpreter: Error invoking bsh method: eval In file: inline evaluation of: " . . . Encountered "" at line 13, column 23. WARN o.a.j.m.BeanShellPreProcessor: Problem in BeanShell scri…

[毕设记录]@学术技能积累:学位论文查询与下载

文章目录 ProQuest国外学位论文中国集团全文检索平台OATD.org&#xff08;Open Access Theses and Dissertations&#xff09;DART-EuropeTUDelft 在上一篇blog里面看的那些论文&#xff0c;感觉看起来收获太小了… 不如去看硕士或者博士的学位论文 于是我先去调研一下哪里方便…

如何将SAP数据集成到任意云平台

十年前就在使用SAP的客户询问我当时突然出现的新事物&#xff1a;大数据。五年前&#xff0c;变成了数据湖和机器学习。现在一切都是关于数据集成&#xff0c;当然还有人工智能。有时处理数据的基本方法已经改变或者发展。有时只是名字的改变。例如&#xff0c;在过去十年中&am…

测试大佬的压箱绝技:教你app 自动化测试如何实现多设备并发

appiumpython appiumpython 实现单设备的 app 自动化测试 启动 appium server&#xff0c;占用端口 4723 电脑与一个设备连接&#xff0c;通过 adb devices 获取已连接的设备 在 python 代码当中&#xff0c;编写启动参数&#xff0c;通过 pytest 编写测试用例&#xff0c;来…

代码审计-锐捷EG易网关 cli.php 远程命令执行

首先登录到后台中(可以组合 锐捷EG易网关 管理员账号密码泄露漏洞) 关键部分代码为 使用 exec 函数执行传递的命令 构造payload&#xff1a; /cli.php?ashell notdelaytrue&commandid漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教…

【C语言】内存的动态分配与释放

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 ​ 目录 什么是内存的动态分配? 内存动态分配函数 &#x1f38f;malloc() &#x1f38f;calloc() &#x1f38f;realloc() 动态内存释放函数 &#x1f38f;free() 常见的…

轻量封装WebGPU渲染系统示例<5>-多重纹理(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/version-1.01/src/voxgpu/sample/MultiTexturedCube.ts 此示例渲染系统实现的特性: 1. 用户态与系统态隔离。 2. 高频调用与低频调用隔离。 3. 面向用户的易用性封装。 4. 渲染数据和渲染机制分离。 …

【2023Mathorcup大数据】B题 电商零售商家需求预测及库存优化问题 python代码解析

【2023Mathorcup大数据】B题 电商零售商家需求预测及库存优化问题 python代码解析 1 题目 2023 年MathorCup 高校数学建模挑战赛——大数据竞赛赛道B&#xff1a;电商零售商家需求预测及库存优化问题电商平台存在着上千个商家&#xff0c;他们会将商品货物放在电商配套的仓库…

ChineseChess1 2023.10.29

中国象棋残局 中国象棋残局模拟器ChineseChess1 2023.10.29 原来圈粉丝&#xff0c;钓鱼&#xff0c;只要不要脸就OK&#xff01;&#xff01;

洛谷趣题【过河卒】参考题解

背景 今天逛洛谷才注意到这道题&#xff0c;原题连接【P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)】 对于爱下棋的我来说&#xff0c;当然是必刷之题。 题意 小卒起始点在左上角(0,0)处&#xff0c;我们的程序将接收两个坐标&#xff1…

解决历史图片创建时间错误(批量修改文件创建时间)

最近在整理历史文件&#xff0c;发现很多历史图片&#xff0c;截图&#xff0c;微信拍照等途径创建的图片没有创建时间和修改时间&#xff0c;导致在相册时间轴错误。集中出现在整理的当天。 这些图片基本在文件名都含有创建时间&#xff0c;大多格式如下&#xff1a; 对于其中…

集成Swagger

基于knife4j集成swagger 集成的步骤 1添加依赖 2配置包扫描 3给每个Controller配置API 4给每个方法&#xff08;接口&#xff09;配置入参、返回值的说明 5针对入参的实体、返回类型VO做配置 添加依赖 <dependency><groupId>com.github.xiaoymin</groupId…

web前端JS基础-----制作进度条

1&#xff0c;参考代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><progress id"pro" max"100" value"0"></progress><scrip…

hive 函数使用详解

一、前言 在任何一种编程语言中,函数可以说是必不可少的,像mysql、oracle中,提供了很多内置函数,或者通过自定义函数的方式进行定制化使用,而hive作为一门数据分析软件,随着版本的不断更新迭代,也陆续出现了很多函数,以满足日常数据查询与分析的各种场景。 二、hive 函…

阻塞队列.

目录 ♫什么是阻塞队列 ♫什么是生产-消费者模式 ♫实现一个阻塞队列 ♫BlockingQueue ♫什么是阻塞队列 阻塞队列是一种特殊的队列&#xff0c;它除了具备队列的先进先出的特点外&#xff0c;还具有以下特点&#xff1a; ♩.如果队列为空时&#xff0c;执行出队列操作&#xf…