基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(一)---UnrealCV获取深度+分割图像
前言
- 本系列教程旨在使用
UE5
配置一个具备激光雷达
+深度摄像机
的仿真小车,并使用通过跨平台的方式进行ROS2
和UE5
仿真的通讯,达到小车自主导航的目的。 - 本教程使用的环境:
- ubuntu 22.04 ros2 humble
- windows11 UE5.4.3
- python8
- 本系列教程将涉及以下内容:
- UE仿真环境和简易小车的搭建
- UE仿真雷达数据和RGBD深度相机数据的获取
- 使用ROS2和UE5进行通讯
- 使用ROS2导航Nav2及其相关模块对小车进行自主通讯
- UE5部分C++编写和ROS2C++代码编写
- 部分插件使用python进行编写
- 本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客
UE介绍
UE5(Unreal Engine5)
是由Epic Games开发的一款功能强大、跨平台的最新版的游戏开发引擎,以其高质量的实时渲染效果、多编程语言支持、丰富的市场资源和活跃的社区而闻名,广泛应用于游戏、影视、建筑等多个领域,不断推动着数字内容产业的发展。- 目前
Unreal Engine(UE)
主要支持以下编程语言:-
- C++:
- C++是UE的核心编程语言,用于编写引擎的底层架构和游戏逻辑。
- 它提供了最高的性能和灵活性,允许开发者直接访问和修改引擎的各个组件。
- C++在UE中通过自定义的反射系统与蓝图系统紧密集成,使得C++类和函数可以在蓝图可视化编程环境中被使用。
- 蓝图(Blueprint):
- 蓝图是UE的一种可视化脚本系统,它允许开发者通过拖拽连接节点的方式来创建逻辑和功能,无需编写传统的代码。
- 蓝图降低了编程的入门门槛,使得非程序员也能参与到游戏和应用的开发中。
- 蓝图可以与C++代码无缝交互,使得开发者可以根据需要选择最适合的编程方法。
-
安装
-
本系列教程将使用最新版的
UE5.4.3
作为教程使用 -
在下载
UE
需要先安装Epic Games Launcher,下载链接 -
下载完后初次进入会要求注册
Epic
账号,注册好后选择虚幻引擎的库选项,选择“+”号在下拉的菜单栏中选择5.4.3
即可完成下载 -
注意下载可能需要根据个人需求安装对应的编辑器,这里我们使用的是
VisualStudio2022
-
完成安装后我们选择创建一个全新的C++空白模板项目
-
创建完项目打开我们会得到以下的画面,这样就完成
UE5.4版本的安装
UnrealCV
插件
-
UnrealCV是一个开源项目,旨在将Unreal Engine(UE)与计算机视觉(CV)领域结合起来。它允许开发者利用UE的高质量渲染能力来生成用于机器学习和计算机视觉研究的数据集和场景。UnrealCV提供了一个Python接口,允许用户通过Python脚本控制UE引擎,从而实现自动化场景渲染、数据采集和交互。
-
更多内容->UnrealCV官网
安装
-
这里来介绍以下如何为
UE5
配置UnrealCV
插件插件 -
首先我们先登录
UnrealCV
的github仓库,由于官方提供的二进制release目前只支持到UE4.16版本,所以这里我们选择源码安装 -
注意选择5.2分支,目前
UnrealCV
已经支持到UE5.4版本
-
git clone
后我们会得到一个unrealcv
的文件夹,文件夹内容大致如下 -
找到你的项目文件夹(该文件夹下有一个以
.uproject
结尾的项目文件),创建一个名为Plugins
的文件夹 -
把上述你下载的
unrealcv
文件夹整个移动到Plugins
文件交下,然后重新打开这个项目,项目会弹出UnrealCV插件
是否进行编译的提示,选择是,然后就会进行编译 -
安装好后,在
UE5
界面左上角的编辑
,在下拉菜单找到插件
,搜索UnrealCV
-
返回UE主界面,找到
绿色箭头
开始运行此关卡(请务必记得这一步!!!) -
在左下方的
控制台
输入vget /unrealcv/status
确认插件配置情况 -
在左侧
输出日志
得到如下输出则表示插件配置成功
报错指南
-
控制台
输入vget /unrealcv/status
后UE
直接闪退 -
检查是否进行
绿色箭头
开始运行此关卡此步骤(八成问题) -
检查
UE
下载是否完全,检查UE
版本是否为5.4.3
,检查unrealcv
下载的分支是否为5.2
使用python对Unreal客户端与服务器进行连接通讯
-
UnrealCV 实现了在游戏和计算机视觉算法之间的进程间通信 (IPC)。这种通信可以用下图来总结。由
UE
创建的游戏将通过加载UnrealCV服务器
作为其模块来扩展。当游戏启动时,UnrealCV
将启动一个TCP 服务器
并等待命令。任何程序都可以使用UnrealCV客户端
代码发送纯文本 UnrealCV 命令来控制场景或检索信息。 -
下面我们来简单的写一段代码进行通讯测试,默认的
UnrealCV服务器
运行在本地的9000端口,我们通过简单的配置完成下述代码
from unrealcv import Client
client = Client(('localhost', 9000)) # 连接到 UnrealCV 服务器
if client.connect(): print('UnrealCV connected successfully')
else: print('UnrealCV is not connected') exit() response = client.request('vget /unrealcv/status')
print(response)
# 断开连接
client.disconnect()
- 上述运行结果将会输出和我们在UE控制台同样的内容输出,即视为通讯连接成功,此过程中确保UE允许了UnrealCV插件且UE处于运行此关卡中
使用UnrealCV
进深度和分割图像的获取
-
这里我们介绍
UnrealCV
的一些基础用法,首先我们使用UE
简单在摄像机视角前搭建一些简单物体 -
为相机添加初始位置,这里我们假定设置相机的位置为0,0,0(运行此关卡默认的摄像头视角就是0,0,0),注意这里必须设置,否则后面拍摄的深度和分割图像可能无法正确拍摄。
camera_settings = { 'location': {'x': 0, 'y': 0, 'z': 0}, # 相机位置 'rotation': {'pitch': 0, 'yaw': 0, 'roll': 0} # 相机旋转
}
# 使用 vset 命令设置相机的位置
client.request('vset /camera/0/location {x} {y} {z}'.format(**camera_settings['location'])) # 使用 vset 命令设置相机的旋转
client.request('vset /camera/0/rotation {pitch} {yaw} {roll}'.format(**camera_settings['rotation']))
- 然后我们在上述连接的基础上添加如下代码,下述的代码将保存
- lit:摄像机原始图像
- object_mask:物体分割图像
- depth:深度图像(注意这里深度图像保存为
npy格式
)
client.request('vget /camera/0/lit C:/Users/lzh/Desktop/UE5_ROS2_project/camera/lit.png')
client.request('vget /camera/0/object_mask C:/Users/lzh/Desktop/UE5_ROS2_project/camera/object_mask.png')
client.request('vget /camera/0/depth C:/Users/lzh/Desktop/UE5_ROS2_project/camera/depth.npy')
- 我们简单对图像进行展示,便得到以下图像
# 加载图像
lit_img = plt.imread(r'C:/Users/lzh/Desktop/UE5_ROS2_project/camera/lit.png')
object_mask_img = plt.imread(r'C:/Users/lzh/Desktop/UE5_ROS2_project/camera/object_mask.png')
depth_img = np.load(r'C:\Users\lzh\Desktop\UE5_ROS2_project\camera\depth.npy') # 创建图形和子图
fig, axes = plt.subplots(1, 3, figsize=(15, 5)) # 显示 lit 图像
axes[0].imshow(lit_img)
axes[0].set_title('Lit Image')
axes[0].axis('off') # 显示 object_mask 图像
axes[1].imshow(object_mask_img, cmap='gray')
axes[1].set_title('Object Mask')
axes[1].axis('off') # 显示 depth 图像
axes[2].imshow(depth_img, cmap='gray', vmin=0, vmax=1300)
axes[2].set_title('Depth Image')
axes[2].axis('off') # 显示图形
plt.tight_layout()
plt.show()
实时进行图像读取与显示
- 上面我们进行了单张文件的保存,下面我们来介绍如何进行实时读取,这里我们介绍核心函数,通过下述三个函数,我们就能实时返回读取到的图像数据,为此我们需要进行解码
data=client.request('vget /camera/0/lit png')
data=client.request('vget /camera/0/object_mask png')
data=client.request('vget /camera/0/depth npy')
- 对于普通图像和分割图像,我们只需要
lit_img = cv2.imdecode(np.frombuffer(self.data, np.uint8), cv2.IMREAD_COLOR)
object_mask_img = cv2.imdecode(np.frombuffer(self.data, np.uint8), cv2.IMREAD_COLOR)
- 对于深度图像,如果我们希望使用
opencv-python
进行展示,我们需要进行转换
import io
def read_npy(self,res): return np.load(io.BytesIO(res))
depth_img = self.read_npy(self.data)
gray_depth = cv2.convertScaleAbs(depth_img, alpha=(255.0 / 1300.0))
# 使用cv2.applyColorMap将灰度图转换为伪彩色图
colored_depth = cv2.applyColorMap(gray_depth, cv2.COLORMAP_JET)
- 通过上述核心代码,我们只需要简单写一个循环,进行展示即可
- 在不额外添加移动物体以及移动摄像机的前提下,我们移动观测者小球,便能得到以下实时画面
封装
- 为了后续教程我们方便使用,我们封装以下整个流程
from unrealcv import Client
import cv2 # OpenCV
import numpy as np
import io
import time
class UE5CameraCenter: def __init__(self): self._client = Client(('localhost', 9000)) self._connection_check() self._camera_init() self._lit_image=LitImage() self._object_mask=ObjectMaskImage() self._depth_mask=DepthImage() def __del__(self): self._client.disconnect() def _connection_check(self): '''检查是否连接''' if self._client.connect(): print('UnrealCV connected successfully') else: print('UnrealCV is not connected') exit() def set_camera_pose(self,x,y,z,pitch,yaw,roll): '''设置摄像头位置''' camera_settings = { 'location': {'x': x, 'y': y, 'z': z}, # 相机位置 'rotation': {'pitch': pitch, 'yaw': yaw, 'roll': roll} # 相机旋转 } # 设置相机的位置 self._client.request('vset /camera/0/location {x} {y} {z}'.format(**camera_settings['location'])) # 设置相机的旋转 self._client.request('vset /camera/0/rotation {pitch} {yaw} {roll}'.format(**camera_settings['rotation'])) def _camera_init(self): '''摄像头初始化''' self.set_camera_pose(0,0,0,0,0,0) def get_camera_data(self, camera_type): valid_types = {'lit', 'object_mask', 'depth'} # 检查 camera_type 是否在有效类型中 if camera_type not in valid_types: raise ValueError(f"Invalid camera type. Expected one of {valid_types}, but got '{camera_type}'.") # 根据camera_type获取相应的数据 if camera_type == 'lit': return self._lit_image.get_image(self._client) elif camera_type == 'object_mask': return self._object_mask.get_image(self._client) elif camera_type == 'depth': return self._depth_mask.get_image(self._client) def test(self): while True : self._lit_image.get_image(self._client) self._object_mask.get_image(self._client) self._depth_mask.get_image(self._client) self._lit_image.display() self._object_mask.display() self._depth_mask.display() class Image: def __init__(self): self.data_np = None def get_image(self,client): pass def display(self): pass class LitImage(Image): def __init__(self): self.data_np = None def get_image(self,client): data = client.request('vget /camera/0/lit png') self.data_np=cv2.imdecode(np.frombuffer(data, np.uint8), cv2.IMREAD_COLOR) def display(self): cv2.imshow("lit_img", self.data_np) key = cv2.waitKey(1)
class ObjectMaskImage(Image): def __init__(self): self.data_np = None def get_image(self,client): data=client.request('vget /camera/0/object_mask png') self.data_np=cv2.imdecode(np.frombuffer(data, np.uint8), cv2.IMREAD_COLOR) def display(self): cv2.imshow("object_mask_data", self.data_np) key = cv2.waitKey(1)
class DepthImage(Image): def __init__(self): self.data_np = None def get_image(self,client): data=client.request('vget /camera/0/depth npy') self.data_np = self.read_npy(data) def display(self): gray_depth = cv2.convertScaleAbs(self.data_np, alpha=(255.0 / 1300.0)) # 使用cv2.applyColorMap将灰度图转换为伪彩色图 colored_depth = cv2.applyColorMap(gray_depth, cv2.COLORMAP_JET) cv2.imshow("depth_img", colored_depth) def read_npy(self,res): return np.load(io.BytesIO(res)) def main(): ue5_cam_center=UE5CameraCenter() ue5_cam_center.test()
if __name__ =='__main__': main()
- 并预留三个接口
- 设置摄像机位置
def set_camera_pose(self,x,y,z,pitch,yaw,roll):
- 获取摄像机图像
def get_camera_data(self, camera_type):
- 测试(显示摄像机画面)
def test(self):
- 设置摄像机位置
UnrealCV
指令大全
通用命令
vget /unrealcv/status
:获取 UnrealCV 插件的状态。vget /unrealcv/help
:列出所有可用的命令及其帮助信息。vget /unrealcv/version
:获取 UnrealCV 的版本信息。vget /scene/name
:获取当前场景的名称。vget /level/name
:获取当前级别的名称。
对象命令
vget /objects
:获取场景中所有对象的名称。vset /objects/spawn_cube
:在场景中生成一个用于调试的立方体。vget /object/[str]/location
:获取指定对象的坐标位置。vset /object/[str]/location [float] [float] [float]
:设置指定对象的坐标位置。vget /object/[str]/rotation
:获取指定对象的旋转。vset /object/[str]/rotation [float] [float] [float]
:设置指定对象的旋转。vset /object/[str]/color [uint] [uint] [uint]
:设置指定对象的颜色。vset /object/[str]/destroy
:销毁指定对象。
相机命令
vget /cameras
:列出场景中所有传感器(相机)。vset /camera/[uint]/location [float] [float] [float]
:设置指定相机的位置。vset /camera/[uint]/rotation [float] [float] [float]
:设置指定相机的旋转。vget /camera/[uint]/lit [str]
:从指定相机获取光照图像。vget /camera/[uint]/depth [str]
:从指定相机获取深度图像。vget /camera/[uint]/normal [str]
:从指定相机获取表面法线图像。vget /camera/[uint]/object_mask [str]
:从指定相机获取对象掩码图像。vset /camera/[uint]/fov [float]
:设置指定相机的视场角。
视图模式命令
vset /viewmode [str]
:设置视图模式,如lit
(光照)、normal
(法线)、depth
(深度)、object_mask
(对象掩码)等。vget /viewmode
:获取当前的视图模式。
其他命令
vrun [str]
:运行 Unreal 引擎内置的命令。vexec [str]
:运行 Unreal 引擎蓝图函数。vbp [str]
:运行 Unreal 引擎蓝图函数。
小结
- 本节介绍了如何使用
UnrealCV
插件在UE
中获取原始,深度,分割图像,并实时进行读取 - 下一节我们将进行跨平台实现图像数据的传输
- 感谢大家对本教程的支持,如有错误,欢迎指出~
相关文章:

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(一)---UnrealCV获取深度+分割图像
前言 本系列教程旨在使用UE5配置一个具备激光雷达深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程使用的环境: ubuntu 22.04 ros2 humblewindows11 UE5.4.3python8 本系列教程将涉及以…...

Java算法解析一:二分算法及其衍生出来的问题
这个算法的前提是,数组是升序排列的 算法描述: i和j是指针可以表示查找范围 m为中间值 当目标值targat比m大时,设置查找范围在m右边:i m-1 当目标值targat比m小时,设置查找范围在m左边:j m1 当targat的…...

数学建模预测类—【一元线性回归】
每日格言:行动是治愈恐惧的良药,而犹豫拖延将不断滋养恐惧. 目录 前言 一、什么是回归分析? 1.概念理解 2.分类和一般步骤 二、一元线性回归(Matlab算法) 1.利用regress函数 2、例题讲解 总结 前言 在具体讲述线性回归…...
配置更加美观的 Swagger UI
//注册Swagger服务 private static void AddSwaggerService(IServiceCollection services){services.AddSwaggerGen(opt >{opt.SwaggerDoc("Push", new OpenApiInfo{Version "v1",Title "Push API",Description "Push API 文档"…...
软件测试 - 基础(软件测试的生命周期、测试报告、bug的级别、与开发人员产生争执的调解方式)
一、软件测试的生命周期 测试贯穿软件的整个生命周期 软件测试的生命周期: 需求分析 →测试计划→ 测试设计、测试开发→ 测试执行→ 测试评估->上线->运行维护 需求分析:判断用户的需求是否合理,是否可实现 测试计划:计划项…...

RTX 4070 GDDR6显存曝光:性能与成本的平衡之选
近期,关于NVIDIA RTX 4070新显卡的信息曝光,这款显卡将配备较为缓慢的GDDR6显存,而非更高性能的GDDR6X。这一配置的选择引发了业内的广泛关注,特别是在性能与成本的平衡问题上。 新版RTX 4070 OC 2X的核心特点 **1.显存类型与带…...

canvas的基础使用
canvas的基础使用 一、画一条直线二、线的属性设置三、防止多次绘制的样式污染四、闭合五、快捷绘制矩形六、绘制圆形七、绘制文字八、绘制图片js版dom版图片截取 一、画一条直线 画一条直线需要用到三个方法:cxt.moveTo、cxt.lineTo、cxt.stroke <canvas id&qu…...

Windows 常用网络命令之 telnet(测试端口是否连通)
文章目录 1 概述1.1 启用 telnet 2 常用命令2.1 ping:测试网络是否连通2.2 telnet:测试端口是否连通 3 扩展3.1 进入 cmd 命令3.2 cls 清屏命令 1 概述 1.1 启用 telnet telnet ip:port // 格式 telnet 10.0.24.154:8001若出现上述提示&…...
x264 编码器像素运算系列:asd8函数
x264 编码器中像素间运算 在 x264 编码器中有多种像素间的运算,如下: sad 计算:SAD(Sum of Absolute Differences,绝对差值和)是一种在图像处理和视频编码中常用的度量,用于计算两个图像块之间的差异。SAD值越小,表示两个图像块越相似。hadamard_ac计算:用于计算Hadam…...

什么是AR、VR、MR、XR?
时代背景 近年来随着计算机图形学、显示技术等的发展,视觉虚拟化技术得到了广泛的发展,并且越来越普及化,慢慢的也走入人们的视野。目前市场上视觉虚拟化技术的主流分为这几种 VR、AR、MR、XR。这几项技术并不是最近才出现的,VR的…...

Epic Games 商店面向欧盟 iPhone 用户上线
Epic Games Store 终于在欧盟推出,为玩家提供了不通过 App Store 就能在 iPhone上访问游戏的途径。在经历了漫长而昂贵的关于支付和竞争对手应用程序店面的法律战,以及公证方面的麻烦之后,Epic Games 成功地为App Store 带来了一个数字店面。…...
【计算机毕设项目】2025级计算机专业小程序项目推荐 (小程序+后台管理)
以下项目选题适合计算机专业大部分专业,技术栈主要为:前端小程序,后端Java语言,数据库MySQL 后台免费获取源码,可提供远程调试、环境安装配置服务。(文末有联系方式) 以下是本次部分项目推荐1…...

Fast API + LangServe快速搭建 LLM 后台
如果快速搭建一个 LLM 后台 API,使前端可以快速接入 LLM API。LangChain 或者 LlamaIndex 架构都可以快速集成各种大语言模型,本文将讲述如何通过 Fast API LangServe 快速的搭建一个后台 Rest API 服务。LLM 这些框架现在主打一个就是快速,…...

CSS继承、盒子模型、float浮动、定位、diaplay
一、CSS继承 1.文字相关的样式会被子元素继承。 2.布局样式相关的不会被子元素继承。(用inherit可以强行继承) 实现效果: 二、盒子模型 每个标签都有一个盒子模型,有内容区、内边距、边框、外边距。 从内到外:cont…...

使用百度文心智能体创建AI旅游助手
百度文心智能体平台为你开启。百度文心智能体平台,创建属于自己的智能体应用。百度文心智能体平台是百度旗下的智能AI平台,集成了先进的自然语言处理技术和人工智能技术,可以用来创建属于自己的智能体应用,访问官网链接࿱…...
斗破C++编程入门系列之四:运算符和表达式
鸡啄米C 记住首页不迷路: http://www.jizhuomi.com/software/129.html 斗破观看顺序: https://v.haohuitao.cc/yhplay/336-1-2.html 第一季☞第二季前2集☞特别篇1☞第二季3~12集☞特别篇2沙之澜歌☞第三季☞第四季☞三年之约☞缘起☞年番…...

CVPR2024 | PromptAD: 仅使用正常样本进行小样本异常检测的学习提示
PromptAD: 仅使用正常样本进行小样本异常检测的学习提示 论文名称:PromptAD: Learning Prompts with only Normal Samples for Few-Shot Anomaly Detection 论文地址:https://arxiv.org/pdf/2404.05231 研究背景 异常检测(Anomaly Detecti…...

文件批量上传,oss使用时间戳解决同名问题 以及一些sql bug
1.文件批量上传 ApiOperation(value "文件批量上传")PostMapping("/multipleImageUpload")Transactional(rollbackFor Exception.class)public Result multipleImageUpload(ApiParam(name "files",value "文件",required true) R…...
机器学习——线性回归(sklearn)
目录 一、认识线性回归 1. 介绍 2. 多元线性回归的基本原理(LinearRegression) 二、多重共线性 1. 介绍 2. 多重共线性详细解释 三、岭回归(解决多重共线性问题) 1. 模型推导 2. 选取最佳的正则化参数取值 四、Lasso&am…...
Go 语言切片(Slice) 15
在 Go 语言中,切片(Slice)是一种可以容纳多个值的数据结构,它可以被视为一个可变的数组。切片是一个引用类型,它可以容纳任意类型的值,可以是整数、字符串、浮点数、结构体等。 切片的声明方式是使用 [] 语法,例如&am…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...

边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...