关于TUM数据集

news2025/1/18 6:42:05

2、验证回环检测算法,需要有人工标记回环的数据集。然而人工标记回环是很不方便的,我们会考虑根据标准轨迹计算回环。即,如果轨迹中有两个帧的位姿非常相近,就认为它们是回环。请根据TUM数据集给出的标准轨迹,计算出一个数据集中的回环。这些回环的图像真的相似吗?

文章目录

      • TUM数据集资料_链接
      • TUM 数据集 使用Tips
      • 使用TUM数据集,并与标准轨迹进行比较
        • 数据集下载
        • 仅下载轨迹
        • !! 轨迹显示
          • 轨迹显示 Python3 仅处理了 位移信息
        • 根据标准轨迹计算回环
            • 新建 .txt文件 touch CMakeLists.txt
            • CMakeLists.txt文件 包含的内容

TUM数据集资料_链接

!!高翔博客上的相关内容

在这里插入图片描述
在这里插入图片描述

TUM数据集网址:https://cvg.cit.tum.de/data/datasets/rgbd-dataset/download

TUM 数据集 使用Tips

【Ctrl + ‘+’】放大字体。 博客园的字体有点小。

普通人; 赚钱花钱
乐趣:搞科研 + 码代码
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
associate.py

#!/usr/bin/python
# Software License Agreement (BSD License)
#
# Copyright (c) 2013, Juergen Sturm, TUM
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following
#    disclaimer in the documentation and/or other materials provided
#    with the distribution.
#  * Neither the name of TUM nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Requirements: 
# sudo apt-get install python-argparse

"""
The Kinect provides the color and depth images in an un-synchronized way. This means that the set of time stamps from the color images do not intersect with those of the depth images. Therefore, we need some way of associating color images to depth images.

For this purpose, you can use the ''associate.py'' script. It reads the time stamps from the rgb.txt file and the depth.txt file, and joins them by finding the best matches.
"""

import argparse
import sys
import os
import numpy


def read_file_list(filename):
    """
    Reads a trajectory from a text file. 
    
    File format:
    The file format is "stamp d1 d2 d3 ...", where stamp denotes the time stamp (to be matched)
    and "d1 d2 d3.." is arbitary data (e.g., a 3D position and 3D orientation) associated to this timestamp. 
    
    Input:
    filename -- File name
    
    Output:
    dict -- dictionary of (stamp,data) tuples
    
    """
    file = open(filename)
    data = file.read()
    lines = data.replace(","," ").replace("\t"," ").split("\n") 
    list = [[v.strip() for v in line.split(" ") if v.strip()!=""] for line in lines if len(line)>0 and line[0]!="#"]
    list = [(float(l[0]),l[1:]) for l in list if len(l)>1]
    return dict(list)

def associate(first_list, second_list,offset,max_difference):
    """
    Associate two dictionaries of (stamp,data). As the time stamps never match exactly, we aim 
    to find the closest match for every input tuple.
    
    Input:
    first_list -- first dictionary of (stamp,data) tuples
    second_list -- second dictionary of (stamp,data) tuples
    offset -- time offset between both dictionaries (e.g., to model the delay between the sensors)
    max_difference -- search radius for candidate generation

    Output:
    matches -- list of matched tuples ((stamp1,data1),(stamp2,data2))
    
    """
    first_keys = first_list.keys()
    second_keys = second_list.keys()
    potential_matches = [(abs(a - (b + offset)), a, b) 
                         for a in first_keys 
                         for b in second_keys 
                         if abs(a - (b + offset)) < max_difference]
    potential_matches.sort()
    matches = []
    for diff, a, b in potential_matches:
        if a in first_keys and b in second_keys:
            first_keys.remove(a)
            second_keys.remove(b)
            matches.append((a, b))
    
    matches.sort()
    return matches

if __name__ == '__main__':
    
    # parse command line
    parser = argparse.ArgumentParser(description='''
    This script takes two data files with timestamps and associates them   
    ''')
    parser.add_argument('first_file', help='first text file (format: timestamp data)')
    parser.add_argument('second_file', help='second text file (format: timestamp data)')
    parser.add_argument('--first_only', help='only output associated lines from first file', action='store_true')
    parser.add_argument('--offset', help='time offset added to the timestamps of the second file (default: 0.0)',default=0.0)
    parser.add_argument('--max_difference', help='maximally allowed time difference for matching entries (default: 0.02)',default=0.02)
    args = parser.parse_args()

    first_list = read_file_list(args.first_file)
    second_list = read_file_list(args.second_file)

    matches = associate(first_list, second_list,float(args.offset),float(args.max_difference))    

    if args.first_only:
        for a,b in matches:
            print("%f %s"%(a," ".join(first_list[a])))
    else:
        for a,b in matches:
            print("%f %s %f %s"%(a," ".join(first_list[a]),b-float(args.offset)," ".join(second_list[b])))
            
# associate.py
python associate.py rgb.txt depth.txt

在这里插入图片描述

python associate.py rgb.txt depth.txt > associate.txt

在这里插入图片描述
在这里插入图片描述
draw_groundtruth.py

在这里插入图片描述

python draw_groundtruth.py

如何查找每个图像的真实位置呢?

python associate.py associate.txt groundtruth.txt > associate_with_groundtruth.txt

在这里插入图片描述

  • 存 associate.py
  • 试运行

使用TUM数据集,并与标准轨迹进行比较

数据集下载

TUM数据集网址:https://cvg.cit.tum.de/data/datasets/rgbd-dataset/download

在这里插入图片描述

参考链接2

在这里插入图片描述

wget https://cvg.cit.tum.de/rgbd/dataset/freiburg1/rgbd_dataset_freiburg1_room.tgz
tar -xf rgbd_dataset_freiburg1_room.tgz
仅下载轨迹

TUM数据集网址:https://cvg.cit.tum.de/data/datasets/rgbd-dataset/download
https://cvg.cit.tum.de/data/datasets/rgbd-dataset/download
在数据集下载界面往下拉 或
在这里插入图片描述
在这里插入图片描述
点击进去,另存为。

https://cvg.cit.tum.de/data/datasets/rgbd-dataset/download#freiburg1_room 或直接复制这个链接,另存即可。

需要把轨迹的.txt的前3行注释删掉
在这里插入图片描述

!! 轨迹显示

trajectory.txt每一行的内容为: t i m e , t x , t y , t z , q x , q y , q z time, t_x,t_y,t_z,q_x, q_y, q_z time,tx,ty,tz,qx,qy,qz
time: 该位姿的记录时间
t \bm{t} t: 平移
q \bm{q} q: 旋转四元数

plotTrajectory.cpp

#include <pangolin/pangolin.h>
#include <Eigen/Core>
#include <unistd.h>

// 本例演示了如何画出一个预先存储的轨迹

using namespace std;
using namespace Eigen;

// path to trajectory file
string trajectory_file = "../rgbd_dataset_freiburg1_desk-groundtruth.txt"; // 该文件和.cpp同一目录

void DrawTrajectory(vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>>);

int main(int argc, char **argv) {

  vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>> poses;
  ifstream fin(trajectory_file);
  if (!fin) {
    cout << "cannot find trajectory file at " << trajectory_file << endl;
    return 1;
  }

  while (!fin.eof()) {
    double time, tx, ty, tz, qx, qy, qz, qw;
    fin >> time >> tx >> ty >> tz >> qx >> qy >> qz >> qw;
    Isometry3d Twr(Quaterniond(qw, qx, qy, qz));
    Twr.pretranslate(Vector3d(tx, ty, tz));
    poses.push_back(Twr);
  }
  cout << "read total " << poses.size() << " pose entries" << endl;

  // draw trajectory in pangolin
  DrawTrajectory(poses);
  return 0;
}

/*******************************************************************************************/
void DrawTrajectory(vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>> poses) {
  // create pangolin window and plot the trajectory
  pangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  pangolin::OpenGlRenderState s_cam(
    pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
    pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
  );

  pangolin::View &d_cam = pangolin::CreateDisplay()
    .SetBounds(0.0, 1.0, 0.0, 1.0, -1024.0f / 768.0f)
    .SetHandler(new pangolin::Handler3D(s_cam));

  while (pangolin::ShouldQuit() == false) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    d_cam.Activate(s_cam);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glLineWidth(2);  //  修改 线的宽度
    for (size_t i = 0; i < poses.size(); i++) {
      // 画每个位姿的三个坐标轴
      Vector3d Ow = poses[i].translation();
      Vector3d Xw = poses[i] * (0.1 * Vector3d(1, 0, 0));
      Vector3d Yw = poses[i] * (0.1 * Vector3d(0, 1, 0));
      Vector3d Zw = poses[i] * (0.1 * Vector3d(0, 0, 1));
      glBegin(GL_LINES);
      glColor3f(1.0, 0.0, 0.0);
      glVertex3d(Ow[0], Ow[1], Ow[2]);
      glVertex3d(Xw[0], Xw[1], Xw[2]);
      glColor3f(0.0, 1.0, 0.0);
      glVertex3d(Ow[0], Ow[1], Ow[2]);
      glVertex3d(Yw[0], Yw[1], Yw[2]);
      glColor3f(0.0, 0.0, 1.0);
      glVertex3d(Ow[0], Ow[1], Ow[2]);
      glVertex3d(Zw[0], Zw[1], Zw[2]);
      glEnd();
    }
    // 画出连线
    for (size_t i = 0; i < poses.size(); i++) {
      glColor3f(0.0, 0.0, 0.0);
      glBegin(GL_LINES);
      auto p1 = poses[i], p2 = poses[i + 1];
      glVertex3d(p1.translation()[0], p1.translation()[1], p1.translation()[2]);
      glVertex3d(p2.translation()[0], p2.translation()[1], p2.translation()[2]);
      glEnd();
    }
    pangolin::FinishFrame();
    usleep(5000);   // sleep 5 ms
  }
}

CMakeLists.txt

include_directories("/usr/include/eigen3")

find_package(Pangolin REQUIRED)
include_directories(${Pangolin_INCLUDE_DIRS})
add_executable(plotTrajectory plotTrajectory.cpp)
target_link_libraries(plotTrajectory ${Pangolin_LIBRARIES})
mkdir build && cd build
cmake ..
make 
./plotTrajectory

GIF获取步骤

rgbd_dataset_freiburg1_room-groundtruth.txt
在这里插入图片描述
包含了 旋转信息

rgbd_dataset_freiburg1_desk-groundtruth.txt
desk TXT数据连接

xwininfo
byzanz-record -x 72 -y 64 -w 1848 -h 893  -d 10 --delay=5 -c  /home/xixi/myGIF/test.gif

在这里插入图片描述

轨迹显示 Python3 仅处理了 位移信息

draw_groundtruth.py

#!/usr/bin/env python
# coding=utf-8

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d

f = open("./rgbd_dataset_freiburg1_room-groundtruth.txt")
x = []
y = []
z = []
for line in f:
    if line[0] == '#': # 这里跳过了 注释行
        continue
    data = line.split() 
    x.append( float(data[1] ) )
    y.append( float(data[2] ) )
    z.append( float(data[3] ) )
ax = plt.subplot( 111, projection='3d')
ax.plot(x,y,z)
plt.show()

命令行:

python3 draw_groundtruth.py

在这里插入图片描述

根据标准轨迹计算回环

tum.cpp

在这里插入图片描述

#include <pangolin/pangolin.h>
#include <Eigen/Core>
#include <Eigen/Geometry> 
#include <unistd.h>

using namespace std;
using namespace Eigen;

// path to groundtruth file    ***记得删掉轨迹txt的前3行注释。保证首行即为轨迹数据 ***
string groundtruth_file = "../rgbd_dataset_freiburg1_room-groundtruth.txt"; //  且.txt文件和.cpp在同一目录
// 设置检测的间隔,使得检测具有稀疏性的同时覆盖整个环境
int delta = 15;   // 这里的值要是不适合,有时测不到回环
// 齐次变换矩阵差的范数,小于该值时认为位姿非常接近
double threshold = 0.4; 

int main(int argc, char **argv) {

  vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>> poses;
  vector<string> times;
  
  ifstream fin(groundtruth_file);
  if (!fin) {
    cout << "cannot find trajectory file at " << groundtruth_file << endl;
    return 1;
  }
  
  int num = 0;
  
  while (!fin.eof()) {
    string time_s;
    double tx, ty, tz, qx, qy, qz, qw;
    fin >> time_s >> tx >> ty >> tz >> qx >> qy >> qz >> qw;
    Isometry3d Twr(Quaterniond(qw, qx, qy, qz));
    Twr.pretranslate(Vector3d(tx, ty, tz));
    // 相当于从第150个位姿开始,这是因为标准轨迹的记录早于照片拍摄(前120个位姿均无对应照片)
    if (num > 120 && num % delta == 0){
      times.push_back(time_s);
      poses.push_back(Twr);
    }
    num++;
  }
  cout << "read total " << num << " pose entries" << endl;
  cout << "selected total " << poses.size() << " pose entries" << endl;
  

  //设置检测到回环后重新开始检测图片间隔数量
  cout << "**************************************************" << endl;
  cout << "Detection Start!!!" << endl;
  cout << "**************************************************" << endl;
  for (size_t i = 0 ; i < poses.size() - delta; i += delta){
    for (size_t j = i + delta ; j < poses.size() ; j++){
      Matrix4d Error = (poses[i].inverse() * poses[j]).matrix() - Matrix4d::Identity();
      if (Error.norm() < threshold){
	cout << "第" << i << "张照片与第" << j << "张照片构成回环" << endl;
	cout << "位姿误差为" << Error.norm() << endl;
	cout << "第" << i << "张照片的时间戳为" << endl << times[i] << endl;
	cout << "第" << j << "张照片的时间戳为" << endl << times[j] << endl;
	cout << "**************************************************" << endl;
	break;
      }
    } 
  }
  cout << "Detection Finish!!!" << endl;
  cout << "**************************************************" << endl;
  return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(tum)  # 输出文件名 

include_directories("/usr/include/eigen3")
find_package(Pangolin REQUIRED)
include_directories(${Pangolin_INCLUDE_DIRS})

add_executable(tum tum.cpp)
target_link_libraries(tum ${Pangolin_LIBRARIES})



命令行窗口指令:

mkdir build  # 若是已建有,跳过这步
cd build
cmake ..
make 
./tum 

轨迹.txt文件里的时间和图片的不太一致,暂时不清楚怎么对应。
delta = 15:
在这里插入图片描述

delta = 20:
在这里插入图片描述

delta = 10: 获得更多组结果。

在这里插入图片描述
在这里插入图片描述
由于 图片读取间隔的原因,图片名称不完全对应。。

新建 .txt文件 touch CMakeLists.txt

在待创建.txt文件的目录下打开命令行窗口。

touch CMakeLists.txt

其它类型文件 亦可用。

CMakeLists.txt文件 包含的内容

在这里插入图片描述

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

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

相关文章

Flink中的状态一致性

1.概念 一致性其实就是结果的正确性。对于分布式系统而言&#xff0c;从不同节点读取时总能得到相同的值&#xff1b;而对于事务而言&#xff0c;是要求提交更新操作后&#xff0c;能够读取到新的数据。 有状态的流处理&#xff0c;内部每个算子任务都可以有自己的状态。对于流…

域环境介绍

一、概述 内网也指局域网&#xff0c;指的是某个区域由多台计算机互连而成的计算机组&#xff0c;范围通常在数千米以内&#xff0c;在局域网中&#xff0c;可以实现文件管理&#xff0c;应用软件共享&#xff0c;打印机共享、工作组内的日程安排、电子邮件和传真通信服务等&a…

【微服务保护】

文章目录 Sentinel 微服务雪崩问题&#xff1a; 微服务中&#xff0c;服务间调用关系错综复杂&#xff0c;一个微服务往往依赖于多个其它微服务。服务D有 故障进而导致服务A有故障&#xff0c;进而导致服务雪崩。 解决雪崩问题的常见方式有四种&#xff1a; 超时处理&#xff1…

iPhone苹果手机复制粘贴内容提示弹窗如何取消关闭提醒?

经常使用草柴APP查询淘宝、天猫、京东商品优惠券拿购物返利的iPhone苹果手机用户&#xff0c;复制商品链接后打开草柴APP粘贴商品链接查券时总是弹窗提示粘贴内容&#xff0c;为此很多苹果iPhone手机用户联系客服询问如何关闭iPhone苹果手机复制粘贴内容弹窗提醒功能的方法如下…

毛玻璃态按钮悬停效果

效果展示 页面结构组成 通过上述的效果展示可以看出如下几个效果 毛玻璃的按钮按钮上斜边背景及动画按钮上下边缘的小按钮和小按钮动画 CSS3 知识点 backdrop-filter 属性transition 属性transform 属性 实现基础按钮结构 <div class"btn"><a href&qu…

第三章 C运算符和控制语句

几乎每一个程序都需要进行运算&#xff0c;对数据进行加工处理&#xff0c;否则程序就没有意义了。要进行运算&#xff0c;就需规定可以使用的运算符。 C语言的运算符范围很宽&#xff0c;把除了控制语句和输人输出以外的几乎所有的基本操作都作为运算符处理。 运算符分类1 除…

【Linux】—— 详解动态库和静态库

前言&#xff1a; 本期我将要给大家讲解的是有关 动态库和静态库 的相关知识&#xff01;&#xff01;&#xff01; 目录 序言 见一见库 为什么要有库 &#xff08;一&#xff09;动态库&#xff08;.so&#xff09; 1.基本概念 2.命名规则 3.制作动态库 &#xff0…

No155.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

【KingbaseES】银河麒麟V10 ARM64架构_安装人大金仓数据库KingbaseES_V8R6(CentOS8)

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

C# 类型、变量与对象

变量一共7种&#xff1a; 静态变量&#xff08;静态字段&#xff09;、实例变量&#xff08;成员变量、字段&#xff09;、数组元素、值参数、引用参数、输出形参、局部变量 狭义的变量就是局部变量 内存的最小单位是比特&#xff08;byte&#xff09;&#xff0c;8个比特为…

【数据结构】【C++】封装哈希表模拟实现unordered_map和unordered_set容器

【数据结构】&&【C】封装哈希表模拟实现unordered_map和unordered_set容器 一.哈希表的完成二.改造哈希表(泛型适配)三.封装unordered_map和unordered_set的接口四.实现哈希表迭代器(泛型适配)五.封装unordered_map和unordered_set的迭代器六.解决key不能修改问题七.实…

Stm32_标准库_5_呼吸灯_按键控制

Stm32按键和输出差不多 PA1为LED供给正电&#xff0c;PB5放置按键&#xff0c;按键一端接PB5,另一端接负极 void Key_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //APB2总线连接着GPIOBGPIO_InitStructur.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructur.…

Java下对象的序列化和反序列化(写出和读入)

代码如下&#xff1a; public class MyWork {public static void main(String[] args) throws IOException, ClassNotFoundException {//序列化File f new File("testFile/testObject.txt");ObjectOutputStream oos new ObjectOutputStream(new FileOutputStream(…

数据结构:堆的实现和堆排序及TopK问题

文章目录 1. 堆的概念和性质1.1 堆的概念1.2 堆的性质1.3 堆的作用 2. 堆的声明3. 堆的实现3.1 堆的插入3.2 删除堆顶元素3.3 利用数组建堆3.4 完整代码 4. 堆的应用4.1 堆排序4.2 TopK问题代码实现 物理结构有顺序结构存储和链式结构存储两种,二叉树理所应当也是可以顺序结构存…

实时通信协议

本文旨在简要解释如何在Web上实现客户端/服务器和客户端/客户端之间的实时通信&#xff0c;以及它们的内部工作原理和最常见的用例。 TCP vs UDP TCP和UDP都位于OSI模型的传输层&#xff0c;负责在网络上传输数据包。它们之间的主要区别在于&#xff0c;TCP在传输数据之前会打开…

26960-2011 半自动捆扎机 学习笔记

声明 本文是学习GB-T 26960-2011 半自动捆扎机. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了半自动捆扎机(以下简称"捆扎机")的术语和定义、型号、型式与基本参数、技术要求、 试验方法、检验规则及标志、包装、运…

Python变量的三个特征

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 我们来看这些代码 x 10 print(x) # 获取变量的变量值 print(id(x)) # 获取变量的id&#xff0c;可以理解成变量在内存中的地址python的内置功能id()&#xff0c;内存地址不一样&#xff0c;则id()后打印的结果不一样&…

【HTML】表格行和列的合并

概述 当我们需要在 HTML 表格中展示复杂的数据时&#xff0c;行和列的合并可以帮助我们实现更灵活的布局和结构。通过合并行和列&#xff0c;我们可以创建具有更多层次和结构的表格&#xff0c;使数据更易于理解和分析。 在 HTML 表格中&#xff0c;我们可以使用 rowspan 和 …

【Spring Cloud】深入探索 Nacos 注册中心的原理,服务的注册与发现,服务分层模型,负载均衡策略,微服务的权重设置,环境隔离

文章目录 前言一、初识 Nacos 注册中心1.1 什么是 Nacos1.2 Nacos 的安装&#xff0c;配置&#xff0c;启动 二、服务的注册与发现三、Nacos 服务分层模型3.1 Nacos 的服务分级存储模型3.2 服务跨集群调用问题3.3 服务集群属性设置3.4 修改负载均衡策略为集群策略 四、根据服务…

【JUC】一文弄懂@Async的使用与原理

文章目录 1. Async异步任务概述2. 深入Async的底层2.1 Async注解2.2 EnableAsync注解2.3 默认线程池 1. Async异步任务概述 在Spring3.X的版本之后&#xff0c;内置了Async解决了多个任务同步进行导致接口响应迟缓的情况。 使用Async注解可以异步执行一个任务&#xff0c;这个…