【BEV 视图变换】Fast-Ray(2): 代码复现+画图解释 基于查找表LUT、多视角到单个三维体素转换

news2024/11/15 12:21:46

paper:Fast-BEV: A Fast and Strong Bird’s-Eye View Perception Baseline
code:https://github.com/Sense-GVT/Fast-BEV
致谢: 感谢我司傅同学提供的复现源码

一、完整复现代码(可一键运行)和效果图

Fast-Ray pipeline:
1.创建uv coord + semantic channels (2d image + 语义通道64)
2.构建离线LUT表(voxel coord -> uv coord, 3d->2d)(基于深度均匀假设,没做深度估计,多个3d点对应一个2d图像点)
(1) 逆体素化过程:根据世界范围划分和刻度实现 voxel coord -> world coord
(2)逆视锥化过程: 使用投影矩阵(相机内外参)实现 world coord -> uv coord
(3)构建LUT表
3.对LUT表进行在线查询(uv coord -> voxel coord, 2d->3d)
4.pool(voxel coord -> bev coord)(去掉Z轴)

在这里插入图片描述



import numpy as np
import matplotlib.pyplot as plt

# 查找表的特点:
    # 1.它不依赖于与数据相关的深度信息,因为摄像头位置和它们的内外参参数在感知系统构建时就已确定,并且对于每次输入都是相同的。
    # 2.因此,无需为每次输入重新计算投影索引,而是可以预先计算固定的投影索引并将其作为静态查找表存储起来。
    # 3.在推理(inference)过程中,可以通过查询这个查找表来获得投影索引,这是一个低成本的操作。
    # 4.无论是处理单帧还是多帧图像,都可以轻松预先计算相机的内外参数,并根据这些参数预先对齐到当前帧。
def build_LUT_CPU(n_voxels, voxel_size, orgin, projection, n_images, height, width):
    """
    构建一个查找表(LUT),将BEV空间中的每个体素反投影到图像空间中的像素。
    Args:
        n_voxels: BEV空间中每个维度上的体素数量,例如 [100,100,4]
        voxel_size: 每个体素的大小,例如[0.5,0.5,1.5]
        orgin: BEV空间的原点坐标,例如[0,0,0]
        projection: 相机投影矩阵,形状为(n_images,3,4)
        n_images: 图像数量
        height: 图像高度
        width: 图像宽度
    Returns:
        LUT:查找表,形状为(n_voxels[0],n_voxels[1],n_voxels[2],2)
        valid: 每个体素是否有效,形状为(n_voxels[0],n_voxels[1],n_voxels[2])
    """
    n_x_voxels, n_y_voxels, n_z_voxels = n_voxels # [100,100,4]
    size_x, size_y, size_z = voxel_size # [0.5,0.5,1.5]
    orgin_x, orgin_y, orgin_z = orgin # BEV空间的原点坐标

    nrof_voxels = n_x_voxels * n_y_voxels * n_z_voxels # voxel总数量

    LUT = np.full((nrof_voxels,2),-1,dtype=np.int32) # [400000,2]
    valid = np.zeros(nrof_voxels,dtype=np.int32) # [40000]

    offset = 0 # LUT中的偏移量
    count = 0

    # BEV --> cam --> uv图像上,如果超出图像大小的则,否则1,放在valid
    for zi in range(n_z_voxels): # 4
        for yi in range(n_y_voxels): # 100
            for xi in range(n_x_voxels): # 100
                for img_id in range(n_images):
                    # 逆体素化过程!  voxel coord -> world coord
                    # 将体素中心在BEV空间的X轴上的坐标上加上BEV原点在BEV空间的X轴上的坐标,得到体素中心在世界坐标系中的X坐标
                    pt = np.array([(xi-n_x_voxels/2)*size_x+orgin_x,
                                   (yi-n_y_voxels/2)*size_y+orgin_y,
                                   (zi-n_z_voxels/2)*size_z+orgin_z,
                                   1 # 齐次坐标
                                   ],
                                  )

                    # 逆视锥化! 使用投影矩阵(相机内外参)将点从 world coord -> uv coord
                    ar = projection[img_id] @ pt # (3*4) @ (4*1)
                    ar = ar[:3] / ar[2] # 将齐次坐标系下的 3D点投影到图像平面,并进行归一化。 u,v,1

                    u = int(round(ar[0])) # 检查投影点是否在图像范围内
                    v = int(round(ar[1]))
                    d = ar[2]

                    # 建立查找表
                    if(0 <= u <width and 0 <= v <height and d>0):
                        # LUT(look-up table)中第offset的值 代表 img中(u,v)点
                        LUT[offset] = [img_id, v*width + u] # 2
                        valid[offset] = 1
                        count += 1
                        break
                    # 一个voxel对应的多个image的uv,这里没有处理,直接覆盖了
                offset += 1
    return LUT, valid


# features+LUT -> volume    uv space + LUT-> voxel space
def backproject_LUT_CPU(features, LUT, volume, n_voxels):
    """
    使用LUT将图像特征投影到BEV空间中
    Args:
        features:图像特征, 形状为(n_images,height,width,n_channels)
        LUT: 查找表, 形状为(n_voxels[0]*n_voxels[1]*n_voxels[2], 2)
        volume: BEV空间中的体素,形状为(n_voxels[0]*n_voxels[1]*n_voxels[2],n_channels)
        n_voxels: BEV空间中每个维度上的体素数量, 例如[100,100,4]. 40000个BEV
    Returns:

    """
    n_x_voxels, n_y_voxels, n_z_voxels = n_voxels

    volume_count = n_x_voxels * n_y_voxels * n_z_voxels *2 # 计算BEV空间中体素的数量*2(因为LUT中每个体素对应两行), volume_count=80000=2*40000

    cnt = 0
    for offset in range(0,volume_count,2): # 循环遍历 LUT数组(BEV index), 每次迭代处理两个元素
        img_id = LUT[offset//2,0] # 获取当前体素对应的图像索引: 第几张图
        voxel_index = LUT[offset//2,1] # 获取当前体素对应的像素索引: v*width + u
        if img_id >=0:
            u = voxel_index // width # voxel_index, 需要 //width表示他在该尺度特征图上的index
            v = voxel_index % width
            # 64 sematic channels
            src = features[img_id, u, v] # 从对应图像中提取特征, pixel * c

            # 将uv图像特征复制到相应的体素空间
            volume[offset//2] = src
            volume[offset//2]/=2
            cnt+=1
    print("repeat cnt:",cnt)
    bev_volume = volume
    return bev_volume


def plot_uvd_frustum(frustum): # 41 8 22 3
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')

    # Convert frustum tensor to numpy array for visualization
    frustum_np = frustum

    # Extract x, y, d coordinates
    x = frustum_np[..., 0].flatten()
    y = frustum_np[..., 1].flatten()
    d = frustum_np[..., 2].flatten()

    # Plot the points in 3D space
    ax.scatter(x, y, d, c=d, cmap='viridis', marker='o')
    ax.set_xlabel('u')
    ax.set_ylabel('v')
    ax.set_zlabel('semantic channels')
    plt.show()

def plot_voxel(voxel_feat):
    # 创建一个3D图形
    fig = plt.figure()
    ax=fig.add_subplot(projection='3d')
    # 创建网格坐标
    x,y,z=np.indices(voxel_feat.shape)
    # 绘制网格
    ax.scatter(x.flatten(),y.flatten(),z.flatten(),c=voxel_feat.flatten(),cmap='viridis')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    plt.show()


def plot_bev(bev_feat):
    # 创建一个2d图形
    fig = plt.figure()
    ax=fig.add_subplot()
    # 创建网格坐标
    x,y=np.indices(bev_feat.shape)
    # 绘制网格
    ax.scatter(x.flatten(),y.flatten(),c=bev_feat.flatten(),cmap='viridis')
    ax.set_xlabel('u')
    ax.set_ylabel('v')
    plt.show()

# Fast-Ray 基于查找表LUT、多视角到单个三维体素转换
if __name__ == "__main__":
    n_voxels = [100,100,4]
    voxel_size = [0.5,0.5,1.5]

    orgin = [0,0,0]
    n_images = 6
    height = 232
    width = 400
    n_channels = 64

    # 创建投影矩阵
    projection = np.random.rand(n_images,3,4)

    # 构建LUT和valid数组 [40000,2] [40000]
    LUT,valid = build_LUT_CPU(n_voxels, voxel_size, orgin, projection, n_images, height, width)

    # 创建图像特征
    features = np.random.rand(n_images,height,width,n_channels)
    plot_uvd_frustum(features[0])

    # 创建BEV空间 # [40000,3] 3表示每个voxel的特征长度是3
    # [40000,64]
    volume = np.zeros((n_voxels[0]*n_voxels[1]*n_voxels[2],n_channels),dtype=np.float32)

    # 反投影特征到BEV空间
    voxel_feat = backproject_LUT_CPU(features,LUT,volume,n_voxels)
    voxel_feat = voxel_feat.reshape(n_voxels[0],n_voxels[1],n_voxels[2],n_channels)

    # print
    print('volume shape:',volume.shape) # [100,100,4,64]
    print('volume:', volume)
    print('dst:',voxel_feat.shape) # [100,100,4,64]

    # [100,100,4,64] -> [100,100,4]
    voxel_feat = voxel_feat.sum(axis=3)
    plot_voxel(voxel_feat)

    # [100,100,4] -> [100,100,1]
    bev_feat = voxel_feat.sum(axis=2)
    plot_bev(bev_feat)



二、逐步代码讲解+图解

完整流程:
1.创建uv coord + semantic channels (2d image + 语义通道64)
2.构建离线LUT表(voxel coord -> uv coord, 3d->2d)
(1) 逆体素化过程:根据世界范围划分和刻度实现 voxel coord -> world coord
(2)逆视锥化过程: 使用投影矩阵(相机内外参)实现 world coord -> uv coord
(3)构建LUT表
3.对LUT表进行在线查询(uv coord -> voxel coord, 2d->3d)
4.pool(voxel coord -> bev coord)(去掉Z轴)

1.创建uv coord+ semantic channels (2d image + 语义通道64)

    # 创建图像特征
    features = np.random.rand(n_images,height,width,n_channels)
    plot_uvd_frustum(features[0])

在这里插入图片描述

注意
坐标范围,u,v范围代表模型输入尺寸,semantic channels为64。

2.构建离线LUT表(voxel coord -> uv coord)

# 查找表的特点:
    # 1.它不依赖于与数据相关的深度信息,因为摄像头位置和它们的内外参参数在感知系统构建时就已确定,并且对于每次输入都是相同的。
    # 2.因此,无需为每次输入重新计算投影索引,而是可以预先计算固定的投影索引并将其作为静态查找表存储起来。
    # 3.在推理(inference)过程中,可以通过查询这个查找表来获得投影索引,这是一个低成本的操作。
    # 4.无论是处理单帧还是多帧图像,都可以轻松预先计算相机的内外参数,并根据这些参数预先对齐到当前帧。
def build_LUT_CPU(n_voxels, voxel_size, orgin, projection, n_images, height, width):
    """
    构建一个查找表(LUT),将BEV空间中的每个体素反投影到图像空间中的像素。
    Args:
        n_voxels: BEV空间中每个维度上的体素数量,例如 [100,100,4]
        voxel_size: 每个体素的大小,例如[0.5,0.5,1.5]
        orgin: BEV空间的原点坐标,例如[0,0,0]
        projection: 相机投影矩阵,形状为(n_images,3,4)
        n_images: 图像数量
        height: 图像高度
        width: 图像宽度
    Returns:
        LUT:查找表,形状为(n_voxels[0],n_voxels[1],n_voxels[2],2)
        valid: 每个体素是否有效,形状为(n_voxels[0],n_voxels[1],n_voxels[2])
    """
    n_x_voxels, n_y_voxels, n_z_voxels = n_voxels # [100,100,4]
    size_x, size_y, size_z = voxel_size # [0.5,0.5,1.5]
    orgin_x, orgin_y, orgin_z = orgin # BEV空间的原点坐标

    nrof_voxels = n_x_voxels * n_y_voxels * n_z_voxels # voxel总数量

    LUT = np.full((nrof_voxels,2),-1,dtype=np.int32) # [400000,2]
    valid = np.zeros(nrof_voxels,dtype=np.int32) # [40000]

    offset = 0 # LUT中的偏移量
    count = 0

    # BEV --> cam --> uv图像上,如果超出图像大小的则,否则1,放在valid
    for zi in range(n_z_voxels): # 4
        for yi in range(n_y_voxels): # 100
            for xi in range(n_x_voxels): # 100
                for img_id in range(n_images):
                    # 逆体素化过程!  voxel coord -> world coord
                    # 将体素中心在BEV空间的X轴上的坐标上加上BEV原点在BEV空间的X轴上的坐标,得到体素中心在世界坐标系中的X坐标
                    pt = np.array([(xi-n_x_voxels/2)*size_x+orgin_x,
                                   (yi-n_y_voxels/2)*size_y+orgin_y,
                                   (zi-n_z_voxels/2)*size_z+orgin_z,
                                   1 # 齐次坐标
                                   ],
                                  )

                    # 逆视锥化! 使用投影矩阵(相机内外参)将点从 world coord -> uv coord
                    ar = projection[img_id] @ pt # (3*4) @ (4*1)
                    ar = ar[:3] / ar[2] # 将齐次坐标系下的 3D点投影到图像平面,并进行归一化。 u,v,1

                    u = int(round(ar[0])) # 检查投影点是否在图像范围内
                    v = int(round(ar[1]))
                    d = ar[2]

                    # 建立查找表
                    if(0 <= u <width and 0 <= v <height and d>0):
                        # LUT(look-up table)中第offset的值 代表 img中(u,v)点
                        LUT[offset] = [img_id, v*width + u] # 2
                        valid[offset] = 1
                        count += 1
                        break
                    # 一个voxel对应的多个image的uv,这里没有处理,直接覆盖了
                offset += 1
    return LUT, valid

(1)逆体素化过程:根据世界范围划分和刻度实现 voxel coord -> world coord

# 将体素中心在BEV空间的X轴上的坐标上加上BEV原点在BEV空间的X轴上的坐标,得到体素中心在世界坐标系中的X坐标
pt = np.array([(xi-n_x_voxels/2)*size_x+orgin_x,
               (yi-n_y_voxels/2)*size_y+orgin_y,
               (zi-n_z_voxels/2)*size_z+orgin_z,
               1 # 齐次坐标
               ],
              )

(2)逆视锥化过程: 使用投影矩阵(相机内外参)实现 world coord -> uv coord

# 逆视锥化! 使用投影矩阵(相机内外参)将点从 world coord -> uv coord
ar = projection[img_id] @ pt # (3*4) @ (4*1)
ar = ar[:3] / ar[2] # 将齐次坐标系下的 3D点投影到图像平面,并进行归一化。 u,v,1

u = int(round(ar[0])) # 检查投影点是否在图像范围内
v = int(round(ar[1]))
d = ar[2]

(3)构建LUT表

                    # 建立查找表
                    if(0 <= u <width and 0 <= v <height and d>0):
                        # LUT(look-up table)中第offset的值 代表 img中(u,v)点
                        LUT[offset] = [img_id, v*width + u] # 2
                        valid[offset] = 1
                        count += 1
                        break
                    # 一个voxel对应的多个image的uv,这里没有处理,直接覆盖了
                offset += 1

基于深度均匀假设:基于深度均匀假设,没做深度估计,多个3d点对应一个2d图像点
在这里插入图片描述

3.对LUT表进行在线查询(uv coord -> voxel coord, 2d->3d)

在这里插入图片描述

def backproject_LUT_CPU(features, LUT, volume, n_voxels):
    """
    使用LUT将图像特征投影到BEV空间中
    Args:
        features:图像特征, 形状为(n_images,height,width,n_channels)
        LUT: 查找表, 形状为(n_voxels[0]*n_voxels[1]*n_voxels[2], 2)
        volume: BEV空间中的体素,形状为(n_voxels[0]*n_voxels[1]*n_voxels[2],n_channels)
        n_voxels: BEV空间中每个维度上的体素数量, 例如[100,100,4]. 40000个BEV
    Returns:

    """
    n_x_voxels, n_y_voxels, n_z_voxels = n_voxels

    volume_count = n_x_voxels * n_y_voxels * n_z_voxels *2 # 计算BEV空间中体素的数量*2(因为LUT中每个体素对应两行), volume_count=80000=2*40000

    cnt = 0
    for offset in range(0,volume_count,2): # 循环遍历 LUT数组(BEV index), 每次迭代处理两个元素
        img_id = LUT[offset//2,0] # 获取当前体素对应的图像索引: 第几张图
        target = LUT[offset//2,1] # 获取当前体素对应的像素索引: v*width + u
        if img_id >=0:
            u = target // width # target这个图像的一维索引是在原图的, 需要 //width表示他在该尺度特征图上的index
            v = target % width
            # 64 sematic channels
            src = features[img_id, u, v] # 从对应图像中提取特征, pixel * c

            # 将uv图像特征复制到相应的体素空间
            volume[offset//2] = src
            volume[offset//2]/=2
            cnt+=1
    print("repeat cnt:",cnt)
    bev_volume = volume
    return bev_volume

4.pool(voxel coord -> bev coord)(去掉Z轴)

# [100,100,4,64] -> [100,100,4]
voxel_feat = voxel_feat.sum(axis=3)
plot_voxel(voxel_feat)

# [100,100,4] -> [100,100,1]
bev_feat = voxel_feat.sum(axis=2)
plot_bev(bev_feat)

在这里插入图片描述

bev尺寸为100x100

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

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

相关文章

PHP项目中Vendor错误导致项目失败的解决方案

在PHP项目中&#xff0c;vendor目录通常用于存放通过Composer安装的依赖库。虽然这些依赖极大地提高了开发效率&#xff0c;但它们也可能成为项目失败的隐患。本文将探讨常见的Vendor错误及其解决方案。 #### 1. 常见的Vendor错误 ##### 1.1 版本不兼容 不同的依赖可能对PHP…

微软AI核电计划

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

如何养成好习惯

最近一直在玩黑神话悟空&#xff0c;加上有录制实况视频&#xff0c;还是花了快一个月才通关&#xff0c;现在可以回到正常的文章更新节奏了。 上次我们学习了读书笔记-《习惯的力量》&#xff0c;不过那毕竟是国外的、十多年前的书籍了。如今&#xff0c;我们的生活又发生了不…

如何在银河麒麟操作系统中关闭IPv6

如何在银河麒麟操作系统中关闭IPv6 1、临时关闭IPv62、永久关闭IPv6方法一&#xff1a;通过sysctl.conf方法二&#xff1a;通过GRUB配置 1、3、 验证IPv6是否已关闭 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在当前的网络环境中&#…

MVC、MVP和MVVM三种设计模式之间的区别是什么

区别&#xff1a; mvc表示“模型-视图-控制器”&#xff0c;mvp表示“模型-视图-演示者”&#xff0c;mvvm表示“模型-视图-视图模型”&#xff1b; mvp、mvvm都是由mvc衍生出的。mvc中&#xff0c;view会直接从model中读取数据&#xff1b;mvp中&#xff0c;view并不直接使用m…

如何使用智能代码编辑器改变编程体验

你是否曾经在深夜加班时&#xff0c;望着屏幕上密密麻麻的代码&#xff0c;感到无比疲惫&#xff1f;或者在处理复杂项目时&#xff0c;被繁琐的代码管理和调试过程折磨得头痛不已&#xff1f;如果是这样&#xff0c;那么你可能还没有发现编程世界中的一个秘密武器——智能代码…

《关键跃升》读书笔记10

发展靠规划 执⾏靠闭环&#xff0c;提⾼靠循环&#xff0c;其实讲的是短期和中期的事。短期内完成 任务靠闭环&#xff0c;经理有⽆数需要执⾏的事在⼿边&#xff0c;要靠闭环&#xff0c;不能有漏 洞&#xff0c;不能出现不了了之的情况&#xff1b;中期的团队成⻓靠循环&…

go 读取excel数据存储到mysql

一、安装依赖 go get github.com/go-sql-driver/mysql go get github.com/jmoiron/sqlx 二、main.go package mainimport ("fmt""github.com/jmoiron/sqlx""log" ) import "github.com/tealeg/xlsx" import _ "github.com/go-s…

并查集(上)

并查集简要介绍&#xff1a; 我们先讲并查集的一般使用场景&#xff0c;之后再讲并查集的具体细节以及原理。 并查集的使用一般是如下的场景&#xff1a; 一开始每个元素都拥有自己的集合&#xff0c;在自己的集合里只有这个元素自己。 f i n d ( i ) find(i) find(i)&#…

使命召唤游戏助手系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;玩家管理&#xff0c;游戏分类管理&#xff0c;道具种类管理&#xff0c;游戏道具处管理&#xff0c;战绩信息管理&#xff0c;水平评估管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统…

心觉:感恩何其重要,感恩之心如何培养

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作177/1000天 上篇文章我们讲了保持感恩之心&#xff0c;可以吸引更多的机会和财富 但是现实中很多人是缺乏感恩之心 这是由于他们…

Python画笔案例-057 绘制蜘蛛网

1、绘制蜘蛛网 通过 python 的turtle 库绘制 蜘蛛网&#xff0c;如下图&#xff1a; 2、实现代码 绘制蜘蛛网&#xff0c;以下为实现代码&#xff1a; """蜘蛛网.py """ import turtledef draw_circle(pos,r):"""pos:圆的中心点…

嘉立创新建元件并快速使用导入的AD封装,快速建立一个新元件

尝试的原因 在网上买了三块很新的蓝牙&#xff0c;这个导致没有封装&#xff0c;幸好商家给了封装图和别的电路资料&#xff0c;自己画了一个封装&#xff0c;虽然不是很难&#xff0c;但也是很费时间&#xff0c;需要查看数据和修改引脚位置等&#xff0c;所以尝试使用商家给…

7-51 7-52 两个有序链表序列并集 和 交集

7-51代码&#xff1a;&#xff08;map) #include<iostream> #include<map> using namespace std; map<int,int>mp; int cnt,cnttp; void scan(){while(1){int x; scanf("%d",&x);if(x-1) break;mp[x];cnt;} } int main(){scan();scan();if(!…

SwiftUI里的ForEach使用的注意事项

在用Swift编程语言的SwiftUI包设计苹果设备的程序时&#xff0c;经常会用到ForEach函数。这个函数的作用是将一个数据集里面的内容一条一条地取出&#xff0c;罗列在程序的页面上&#xff0c;使用方式的详解见[1]。 但ForEach和一般的循环不同之处在于它要求输入里面的数据集里…

了解云容器实例云容器实例(Cloud Container Instance)

1.什么是云容器实例&#xff1f; 云容器实例&#xff08;Cloud Container Instance&#xff0c; CCI&#xff09;服务提供 Serverless Container&#xff08;无服务器容器&#xff09;引擎&#xff0c;让您无需创建和管理服务器集群即可直接运行容器。 Serverless是一种架构理念…

【WEB】序列一下

1、 2、反序列化 <?phpclass Polar{public $url polarctf.com;public $ltsystem;public $bls /;function __destruct(){$a $this->lt;$a($this->b);} }$a new Polar(); echo serialize($a); ?>###O:5:"Polar":3:{s:3:"url";s:12:"…

山体滑坡检测系统源码分享

山体滑坡检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

【成品论文】2024年华为杯研赛E题25页高质量成品论文(后续会更新

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片链接&#xff0c;那是获取资料的入口&#xff01; 点击链接加入【2024华为杯研赛资料汇总】&#xff1a;https://qm.qq.com/q/Mxv2XNWxUc https://qm.qq.com/q/Mxv2XNWxUc 高速公路应急车道紧急启用模型…

OpenGL使用Glfw框架创建第一个窗体

code #include <iostream> /* glad必须先包含&#xff0c;后包含glfw */ #include "glad/glad.h" #include "glfw/glfw3.h"int main() {// 1 初始化GLFW基本环境glfwInit();// 1.1设置OpenGL主版本、次版本glfwWindowHint(GLFW_CONTEXT_VERSION_MAJ…