手把手写深度学习(27):如果获得相机位姿态的plücker embedding?以RealEstate10K为例

手把手写深度学习(0):专栏文章导航

前言:用plücker embedding表示相机的位姿是一种非常常用的方法,这篇博客以RealEstate10K数据集为例子,详细讲解如何从相机的轨迹坐标中获得plücker embedding,用于下一步模型的学习。

目录

初始化相机参数

计算相机的相对位姿

读取轨迹文件中的相机位姿信息

将位姿信息解析为Camera对象列表

计算目标图像与原始位姿图像的宽高比

构建相机内参矩阵

根据轨迹文件获取Plücker嵌入

完整代码

示例文件


初始化相机参数

class Camera(object):def __init__(self, entry):"""初始化相机参数。参数:- entry: 一个包含相机内参和外参信息的列表。该方法从entry中提取相机的焦距和光心参数,并将其存储为实例变量。同时,它还根据entry中的外参信息构建相机在世界坐标系下的变换矩阵,并计算其逆矩阵。"""# 解包entry列表的前四个元素,对应相机内参的fx, fy, cx, cyfx, fy, cx, cy = entry[1:5]# 将解包的相机内参赋值给实例变量self.fx = fxself.fy = fyself.cx = cxself.cy = cy# 从entry列表的第7个元素开始,解包出3x4的矩阵,表示相机在外的空间变换w2c_mat = np.array(entry[7:]).reshape(3, 4)# 构建4x4单位矩阵,并将前3行的变换矩阵赋值给它,得到完整的相机到世界坐标的变换矩阵w2c_mat_4x4 = np.eye(4)w2c_mat_4x4[:3, :] = w2c_mat# 存储相机到世界坐标的变换矩阵作为实例变量self.w2c_mat = w2c_mat_4x4# 计算世界到相机坐标的变换矩阵的逆,得到相机到世界坐标的变换矩阵self.c2w_mat = np.linalg.inv(w2c_mat_4x4)

计算相机的相对位姿

def get_relative_pose(cam_params, zero_first_frame_scale):"""计算相机的相对位姿。该函数根据一组相机参数和是否对第一帧进行缩放的标志,计算出所有相机帧相对第一帧的位姿。参数:- cam_params: 一个列表,包含每个相机帧的参数,每个参数包括世界到相机的矩阵(w2c_mat)和相机到世界的矩阵(c2w_mat)。- zero_first_frame_scale: 布尔值,指示是否忽略第一帧的缩放信息。返回:- ret_poses: 相对位姿矩阵的列表,数组类型为numpy.float32。"""# 提取所有相机帧的绝对世界到相机矩阵和相机到世界矩阵abs_w2cs = [cam_param.w2c_mat for cam_param in cam_params]abs_c2ws = [cam_param.c2w_mat for cam_param in cam_params]# 使用第一个相机帧作为源相机的相机到世界矩阵source_cam_c2w = abs_c2ws[0]# 根据zero_first_frame_scale参数决定cam_to_origin的距离if zero_first_frame_scale:# 如果标志为真,相机到原点的距离为0cam_to_origin = 0else:# 如果标志为假,计算相机到原点的距离cam_to_origin = np.linalg.norm(source_cam_c2w[:3, 3])# 构建目标相机的相机到世界矩阵target_cam_c2w = np.array([[1, 0, 0, 0],[0, 1, 0, -cam_to_origin],[0, 0, 1, 0],[0, 0, 0, 1]])# 计算绝对坐标系到相对坐标系的转换矩阵abs2rel = target_cam_c2w @ abs_w2cs[0]# 计算所有相机帧相对第一帧的位姿ret_poses = [target_cam_c2w, ] + [abs2rel @ abs_c2w for abs_c2w in abs_c2ws[1:]]# 将结果转换为numpy数组并返回ret_poses = np.array(ret_poses, dtype=np.float32)return ret_poses

读取轨迹文件中的相机位姿信息

    with open(trajectory_file, 'r') as f:poses = f.readlines()poses = [pose.strip().split(' ') for pose in poses[1:]]

将位姿信息解析为Camera对象列表

    cam_params = [[float(x) for x in pose] for pose in poses]cam_params = [Camera(cam_param) for cam_param in cam_params]

计算目标图像与原始位姿图像的宽高比

    # 计算目标图像与原始位姿图像的宽高比,并据此调整相机参数sample_wh_ratio = image_width / image_heightpose_wh_ratio = original_pose_width / original_pose_heightif pose_wh_ratio > sample_wh_ratio:resized_ori_w = image_height * pose_wh_ratiofor cam_param in cam_params:cam_param.fx = resized_ori_w * cam_param.fx / image_widthelse:resized_ori_h = image_width / pose_wh_ratiofor cam_param in cam_params:cam_param.fy = resized_ori_h * cam_param.fy / image_height

构建相机内参矩阵

    intrinsic = np.asarray([[cam_param.fx * image_width,cam_param.fy * image_height,cam_param.cx * image_width,cam_param.cy * image_height]for cam_param in cam_params], dtype=np.float32)K = torch.as_tensor(intrinsic)[None]  # [1, 1, 4]

根据轨迹文件获取Plücker嵌入

def get_plucker_embedding(trajectory_file, image_width, image_height, original_pose_width, original_pose_height, device='cpu'):"""根据轨迹文件获取Plücker嵌入。参数:- trajectory_file: 轨迹文件路径,文件中包含相机的位姿信息。- image_width: 目标图像的宽度。- image_height: 目标图像的高度。- original_pose_width: 原始位姿图像的宽度。- original_pose_height: 原始位姿图像的高度。- device: 计算设备,默认为'cpu'。返回:- plucker_embedding: Plücker嵌入张量。"""# 读取轨迹文件中的相机位姿信息with open(trajectory_file, 'r') as f:poses = f.readlines()poses = [pose.strip().split(' ') for pose in poses[1:]]# 将位姿信息解析为Camera对象列表cam_params = [[float(x) for x in pose] for pose in poses]cam_params = [Camera(cam_param) for cam_param in cam_params]# 计算目标图像与原始位姿图像的宽高比,并据此调整相机参数sample_wh_ratio = image_width / image_heightpose_wh_ratio = original_pose_width / original_pose_heightif pose_wh_ratio > sample_wh_ratio:resized_ori_w = image_height * pose_wh_ratiofor cam_param in cam_params:cam_param.fx = resized_ori_w * cam_param.fx / image_widthelse:resized_ori_h = image_width / pose_wh_ratiofor cam_param in cam_params:cam_param.fy = resized_ori_h * cam_param.fy / image_height# 构建相机内参矩阵intrinsic = np.asarray([[cam_param.fx * image_width,cam_param.fy * image_height,cam_param.cx * image_width,cam_param.cy * image_height]for cam_param in cam_params], dtype=np.float32)K = torch.as_tensor(intrinsic)[None]  # [1, 1, 4]# 获取相机间的相对位姿,并转换为张量c2ws = get_relative_pose(cam_params, zero_first_frame_scale=True)c2ws = torch.as_tensor(c2ws)[None]  # [1, n_frame, 4, 4]# 计算Plücker嵌入,并调整张量维度顺序及存储连续性plucker_embedding = ray_condition(K, c2ws, image_height, image_width, device=device)       # b f h w 6plucker_embedding = plucker_embedding.permute(0, 1, 4, 2, 3).contiguous().to(device=device)return plucker_embedding

完整代码

import torch
import numpy as np
from packaging import version as pverclass Camera(object):def __init__(self, entry):"""初始化相机参数。参数:- entry: 一个包含相机内参和外参信息的列表。该方法从entry中提取相机的焦距和光心参数,并将其存储为实例变量。同时,它还根据entry中的外参信息构建相机在世界坐标系下的变换矩阵,并计算其逆矩阵。"""# 解包entry列表的前四个元素,对应相机内参的fx, fy, cx, cyfx, fy, cx, cy = entry[1:5]# 将解包的相机内参赋值给实例变量self.fx = fxself.fy = fyself.cx = cxself.cy = cy# 从entry列表的第7个元素开始,解包出3x4的矩阵,表示相机在外的空间变换w2c_mat = np.array(entry[7:]).reshape(3, 4)# 构建4x4单位矩阵,并将前3行的变换矩阵赋值给它,得到完整的相机到世界坐标的变换矩阵w2c_mat_4x4 = np.eye(4)w2c_mat_4x4[:3, :] = w2c_mat# 存储相机到世界坐标的变换矩阵作为实例变量self.w2c_mat = w2c_mat_4x4# 计算世界到相机坐标的变换矩阵的逆,得到相机到世界坐标的变换矩阵self.c2w_mat = np.linalg.inv(w2c_mat_4x4)def custom_meshgrid(*args):if pver.parse(torch.__version__) < pver.parse('1.10'):return torch.meshgrid(*args)else:return torch.meshgrid(*args, indexing='ij')def get_relative_pose(cam_params, zero_first_frame_scale):"""计算相机的相对位姿。该函数根据一组相机参数和是否对第一帧进行缩放的标志,计算出所有相机帧相对第一帧的位姿。参数:- cam_params: 一个列表,包含每个相机帧的参数,每个参数包括世界到相机的矩阵(w2c_mat)和相机到世界的矩阵(c2w_mat)。- zero_first_frame_scale: 布尔值,指示是否忽略第一帧的缩放信息。返回:- ret_poses: 相对位姿矩阵的列表,数组类型为numpy.float32。"""# 提取所有相机帧的绝对世界到相机矩阵和相机到世界矩阵abs_w2cs = [cam_param.w2c_mat for cam_param in cam_params]abs_c2ws = [cam_param.c2w_mat for cam_param in cam_params]# 使用第一个相机帧作为源相机的相机到世界矩阵source_cam_c2w = abs_c2ws[0]# 根据zero_first_frame_scale参数决定cam_to_origin的距离if zero_first_frame_scale:# 如果标志为真,相机到原点的距离为0cam_to_origin = 0else:# 如果标志为假,计算相机到原点的距离cam_to_origin = np.linalg.norm(source_cam_c2w[:3, 3])# 构建目标相机的相机到世界矩阵target_cam_c2w = np.array([[1, 0, 0, 0],[0, 1, 0, -cam_to_origin],[0, 0, 1, 0],[0, 0, 0, 1]])# 计算绝对坐标系到相对坐标系的转换矩阵abs2rel = target_cam_c2w @ abs_w2cs[0]# 计算所有相机帧相对第一帧的位姿ret_poses = [target_cam_c2w, ] + [abs2rel @ abs_c2w for abs_c2w in abs_c2ws[1:]]# 将结果转换为numpy数组并返回ret_poses = np.array(ret_poses, dtype=np.float32)return ret_posesdef get_plucker_embedding(trajectory_file, image_width, image_height, original_pose_width, original_pose_height, device='cpu'):"""根据轨迹文件获取Plücker嵌入。参数:- trajectory_file: 轨迹文件路径,文件中包含相机的位姿信息。- image_width: 目标图像的宽度。- image_height: 目标图像的高度。- original_pose_width: 原始位姿图像的宽度。- original_pose_height: 原始位姿图像的高度。- device: 计算设备,默认为'cpu'。返回:- plucker_embedding: Plücker嵌入张量。"""# 读取轨迹文件中的相机位姿信息with open(trajectory_file, 'r') as f:poses = f.readlines()poses = [pose.strip().split(' ') for pose in poses[1:]]# 将位姿信息解析为Camera对象列表cam_params = [[float(x) for x in pose] for pose in poses]cam_params = [Camera(cam_param) for cam_param in cam_params]# 计算目标图像与原始位姿图像的宽高比,并据此调整相机参数sample_wh_ratio = image_width / image_heightpose_wh_ratio = original_pose_width / original_pose_heightif pose_wh_ratio > sample_wh_ratio:resized_ori_w = image_height * pose_wh_ratiofor cam_param in cam_params:cam_param.fx = resized_ori_w * cam_param.fx / image_widthelse:resized_ori_h = image_width / pose_wh_ratiofor cam_param in cam_params:cam_param.fy = resized_ori_h * cam_param.fy / image_height# 构建相机内参矩阵intrinsic = np.asarray([[cam_param.fx * image_width,cam_param.fy * image_height,cam_param.cx * image_width,cam_param.cy * image_height]for cam_param in cam_params], dtype=np.float32)K = torch.as_tensor(intrinsic)[None]  # [1, 1, 4]# 获取相机间的相对位姿,并转换为张量c2ws = get_relative_pose(cam_params, zero_first_frame_scale=True)c2ws = torch.as_tensor(c2ws)[None]  # [1, n_frame, 4, 4]# 计算Plücker嵌入,并调整张量维度顺序及存储连续性plucker_embedding = ray_condition(K, c2ws, image_height, image_width, device=device)       # b f h w 6plucker_embedding = plucker_embedding.permute(0, 1, 4, 2, 3).contiguous().to(device=device)return plucker_embeddingif __name__ == "__main__":trajectory_file = "assets/pose_files/0f47577ab3441480_svd.txt"image_width = 576image_height = 320original_pose_width = 1280original_pose_height = 720plucker_embedding = get_plucker_embedding(trajectory_file, image_width, image_height, original_pose_width, original_pose_height)print("plucker_embedding: ", plucker_embedding.size())

示例文件

assets/pose_files/0f47577ab3441480_svd.txt 文件:

https://www.youtube.com/watch?v=in69BD2eZqg
196429567 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.998043656 -0.008898078 0.061884791 0.025798442 0.009229627 0.999944508 -0.005073697 0.590754668 -0.061836209 0.005634944 0.998070419 -0.233247137
196696500 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.997390270 -0.009296595 0.071597412 0.013903395 0.009683816 0.999940276 -0.005063088 0.639742116 -0.071546070 0.005743211 0.997420788 -0.192511620
196996800 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.996610820 -0.009389835 0.081723645 0.001640113 0.009820240 0.999939919 -0.004866215 0.671455284 -0.081673041 0.005652268 0.996643126 -0.133688656
197263733 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.996082366 -0.010138805 0.087847337 -0.016342035 0.010684925 0.999926388 -0.005748684 0.672634560 -0.087782584 0.006664804 0.996117353 -0.063974549
197564033 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.995849669 -0.009882330 0.090475440 -0.039230446 0.010261126 0.999940395 -0.003722523 0.652124926 -0.090433262 0.004635453 0.995891750 0.029309661
197830967 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.995805681 -0.010101050 0.090933874 -0.063966908 0.010504867 0.999936998 -0.003963242 0.612482840 -0.090888113 0.004901868 0.995849073 0.150119615
198131267 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.995871365 -0.010241830 0.090195827 -0.078531843 0.010570447 0.999939144 -0.003166437 0.555611063 -0.090157904 0.004106774 0.995918989 0.288647339
198398200 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.996041775 -0.010097718 0.088310808 -0.082279252 0.010292084 0.999945521 -0.001745854 0.514557838 -0.088288367 0.002647846 0.996091425 0.410873608
198698500 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.997259557 -0.009423457 0.073379643 -0.066031947 0.009896892 0.999932468 -0.006090916 0.457751923 -0.073317289 0.006800454 0.997285485 0.567670483
198965433 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.998894870 -0.008021683 0.046310849 -0.031951124 0.008127374 0.999964774 -0.002094371 0.405029944 -0.046292417 0.002468442 0.998924911 0.707543520
199265733 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.999987304 -0.004264246 -0.002686474 -0.003940793 0.004252980 0.999982178 -0.004185534 0.350251174 0.002704274 0.004174056 0.999987602 0.860228697
199532667 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.998511136 0.001477750 -0.054528367 0.001275705 -0.001786051 0.999982715 -0.005605645 0.289542627 0.054519139 0.005694689 0.998496473 1.006409043
199832967 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.991945446 0.009338647 -0.126321211 -0.042639243 -0.010065611 0.999936223 -0.005117786 0.198872046 0.126265362 0.006348064 0.991976202 1.178174631
200133267 0.507650910 0.902490531 0.500000000 0.500000000 0.000000000 0.000000000 0.973961055 0.020193946 -0.225814342 -0.167000046 -0.021393530 0.999767005 -0.002866175 0.129793413 0.225703865 0.007622509 0.974166155 1.328984423

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

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

相关文章

Java面试复习总结03

Java面试复习总结03 1、什么是SPI&#xff1f;2、SPI和API有什么区别&#xff1f;3、使用SPI机制的原因&#xff1f;4、SPI机制的优缺点&#xff1f; 1、什么是SPI&#xff1f; SPI 即 Service Provider Interface &#xff0c;字面意思就是&#xff1a;“服务提供者的接口”&…

Arduino library for proteus 下载 安装 测试

Arduino library include: https://drive.google.com/uc?exportdownload&id1P4VtXaomJ4lwcGJOZwR_25oeon9Zzvwb 第一步&#xff1a; 也可从我的共享网盘当中下载&#xff1a; 第2步&#xff1a;解压文件&#xff1a; 第3步&#xff1a; copy lib and idx 到对应的…

java宠物商城网站系统的设计与实现

springboot508基于Springboot宠物商城网站系统 题目&#xff1a;宠物商城网站系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往…

PHP一站式班级解决方案班级管家系统小程序源码

一站式班级解决方案 —— 班级管家系统 &#x1f393;【开篇&#xff1a;班级管理的烦恼&#xff0c;你中招了吗&#xff1f;】&#x1f393; 作为班主任或班级管理者&#xff0c;你是否经常为繁琐的班级事务而头疼&#xff1f;从日常通知的发布到作业的收集&#xff0c;从班…

TOGAF之架构标准规范-架构愿景

TOGAF标准规范中&#xff0c;架构愿景阶段的主要工作包括定义企业架构的范围、确认企业架构的利益相关者、创建企业架构愿景、获得利益相关者的批准。 如上所示&#xff0c;架构愿景&#xff08;Architecture Vision&#xff09;在TOGAF标准规范中处于A阶段 如上所示&#xff0…

SpringBoot学习(4)(yml配置信息书写和获取)(SpringEL表达式语言)

目录 1、yml配置信息的书写和获取介绍 2、案例学习 &#xff08;1&#xff09;配置信息的书写注意事项 &#xff08;2&#xff09;配置信息的获取 &#xff08;3&#xff09;注解Value &#xff08;4&#xff09;相同层级的共同前缀&#xff0c;可以使用下面这个注解 3、…

Great Wall长城工作站安装银河麒麟V10(SP1)-ARM版桌面操作系统

长城工作站安装银河麒麟V10(SP1)桌面操作系统 1. 硬件信息 [1]. Great Wall 长城台式微型计算机 产品型号&#xff1a;世恒TD120A2 型号代码&#xff1a;世恒TD120A2-019 电源&#xff1a;220V~3A 50Hz [2]. 芯片型号 架构&#xff1a; aarch64 CPU 运行模式&#xff1a…

2024.9.3 作业

自己实现栈和队列 代码&#xff1a; /*******************************************/ 文件名&#xff1a;sq.h /*******************************************/ #ifndef SQ_H #define SQ_H #include <iostream> #include<cstring>using namespace std; class …

秋招突击——算法练习——8/26——图论——200-岛屿数量、994-腐烂的橘子、207-课程表、208-实现Trie

文章目录 引言正文200-岛屿数量个人实现 994、腐烂的橘子个人实现参考实现 207、课程表个人实现参考实现 208、实现Trie前缀树个人实现参考实现 总结 引言 正文 200-岛屿数量 题目链接 个人实现 我靠&#xff0c;这道题居然是腾讯一面的类似题&#xff0c;那道题是计算最…

[数据集][目标检测]智慧牧场猪只检测数据集VOC+YOLO格式16245张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;16245 标注数量(xml文件个数)&#xff1a;16245 标注数量(txt文件个数)&#xff1a;16245 标…

vue使用html2Canvas导出图片 input文字向上偏移

vue使用html2Canvas导出图片 input文字向上偏移 图中 用的是element的输入框 行高 32px,经常测试 你使用原生的input 还是会出现偏移。 解决方法&#xff1a;修改css样式 1.怎么实现导出 网上随便找很多 2.在第一步 获取你要导出的元素id 克隆后 修改他的样式或者 你直接在你需…

基于单片机的水箱水质监测系统设计

本设计基于STM32F103C8T6为核心控制器设计了水质监测系统&#xff0c;选用DS18B20温度传感器对水箱水体温度进行采集&#xff1b;E-201-C PH传感器获取水体PH值&#xff1b;选用TS-300B浊度传感器检测水体浊度&#xff1b;采用YW01液位传感器获取水位&#xff0c;当检测水位低于…

宽带和带宽分不清楚

如何理解带宽 我们平时经常听到的带宽其实是宽带&#xff0c;举个栗子&#xff1a;我家用的是xx运营商提供的&#xff0c;号称1000M宽带&#xff0c;这其实指是的网络数据传输的速率是&#xff1a;1000Mbs&#xff08;即125MBps&#xff09;。 那么既然有宽带&#xff0c;就有…

MCU官方IDE软件安装及学习教程集合 — STM32CubeIDE(STM32)

简介 各MCU厂商为保证产品的市场地位以及用户体验&#xff0c;不断的完善自己的产品配套&#xff0c;搭建自己的开发生态&#xff0c;像国外ST公司&#xff0c;国内的GD&#xff08;兆易创新&#xff09;&#xff0c;AT&#xff08;雅特力&#xff09;等等。目前就开发生态而言…

09.定时器02

#include "reg52.h"sbit led P3^6;void delay10ms() { //1. 配置定时器0工作模式位16位计时TMOD 0x01;//2. 给初值&#xff0c;定一个10ms出来TL00x00;TH00xDC;//3. 开始计时TR0 1;TF0 0; } void main() {int cnt 0;led 1;while(1){if(TF0 1)//当爆表的时候&a…

【Qt】QLCDNumber | QProgressBar | QCalendarWidget

文章目录 QLCDNumber —— 显示数字QLCDNumber 的属性QLCDNumber 的使用 QProgressBar —— 进度条QProgressBar 的属性创建一个进度条修改为 红色的进度条 QCalendarWidget —— 日历QCalendarWidget 的属性QCalendarWidget 的使用 QLCDNumber —— 显示数字 QLCDNumber 的属…

UE4_后期处理_后期处理材质及后期处理体积一

后期处理效果 在渲染之前应用于整个渲染场景的效果。 后期处理效果&#xff08;Post-processing effect&#xff09;使美术师和设计师能够对影响颜色、色调映射、光照的属性和功能进行组合选择&#xff0c;从而定义场景的整体外观。要访问这些功能&#xff0c;可以将一种称为…

多角度解读WMS:探寻仓库管理系统的核心功能

多角度解读 WMS 仓库管理系统 1. 概述 WMS 在数字化工厂中具有举足轻重的地位&#xff0c;它不仅提高了仓储管理的效率与准确性&#xff0c;还能优化整个供应链的管理&#xff0c;支持灵活生产模式&#xff0c;并提供决策支持的关键数据。通过现代前后端技术的架构设计&#xf…

【Spring Boot 3】自定义拦截器

【Spring Boot 3】自定义拦截器 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或…

Prometheus_0基础_学习笔记

一、基本概念 Prometheus是由golang语言开发的一套开源的监控、报警、时间序列数据库的组合&#xff0c;是一款基于时序数据库的开源监控告警系统。 时间序列数据库&#xff1a;时间序列数据库&#xff08;Time Serires Database , TSDB&#xff09;不同于传统的关系型数据库。…