使用kaliber与imu_utils进行IMU、相机+IMU联合标定

news2024/10/7 4:27:38

目录

1 标定工具编译

1.1 IMU标定工具 imu_utils

1.2 相机标定工具 kaliber

2 标定数据录制

3 开始标定

3.1 IMU标定

3.2 相机标定

3.3 相机+IMU联合标定

4 将参数填入ORBSLAM的文件中


1 标定工具编译

1.1 IMU标定工具 imu_utils

        标定IMU我们使用imu_utils软件进行标定:

        首先我们安装标定软件的依赖项:Eigen、Ceres

        通过命令行安装Eigen3.3.4即可

sudo apt-get install libdw-dev
sudo apt-get install libeigen3-dev

        安装Ceres1.14.0的依赖项:

sudo apt-get install liblapack-dev libblas-dev libeigen3-dev libgflags-dev libgoogle-glog-dev
sudo apt-get install liblapack-dev libsuitesparse-dev libcxsparse3 libgflags-dev libgoogle-glog-dev libgtest-dev

       安装Ceres1.14.0

wget -O ~/Downloads/ceres.zip https://github.com/ceres-solver/ceres-solver/archive/1.14.0.zip
cd ~/Downloads/ && unzip ceres.zip -d ~/Downloads/
cd ~/Downloads/ceres-solver-1.14.0
mkdir ceres-bin && cd ceres-bin
cmake ..
sudo make install -j4

        这些安装之后,我们开始安装imu_utils。

        首先为我们要先在ROS环境下编译code_utils,否则会报错:

cd ..catkin_imu/src
git clone https://github.com/gaowenliang/code_utils 
cd ..
catkin_make 

        运行这个步骤会报错,找不到backward.hpp这个头文件:

        解决方案:

        把src/code_utils/CMakeList.txt中,添加路径:include_directories(“include/code_utils”)

        如下图:

        安装imu_utils:

cd ..catkin_imu/src
git clone https://github.com/gaowenliang/imu_utils
cd ..
catkin_make #编译imu_utils

        这样就编译成功了:

1.2 相机标定工具 kaliber

        标定IMU+相机与相机的标定我们使用kaliber软件进行标定:

        先进行依赖安装:

sudo apt install python-setuptools python-rosinstall ipython libeigen3-dev libboost-all-dev doxygen libopencv-dev
sudo apt install ros-noetic-vision-opencv ros-noetic-image-transport-plugins ros-noetic-cmake-modules
sudo apt install python-software-properties software-properties-common libpoco-dev python-matplotlib python-scipy python-git python-pip ipython 
sudo apt install libtbb-dev libblas-dev liblapack-dev python-catkin-tools libv4l-dev 
sudo apt install build-essential python-dev libxml2 libxml2-dev zlib1g-dev bison flex libigraph0-dev texlive-binaries
sudo pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-igraph
sudo pip install python-igraph --upgrade
sudo apt-get install python-setuptools python-rosinstall ipython libeigen3-dev libboost-all-dev doxygen libopencv-dev ros-melodic-vision-opencv ros-melodic-image-transport-plugins ros-melodic-cmake-modules python-software-properties software-properties-common libpoco-dev python-matplotlib python-scipy python-git python-pip ipython libtbb-dev libblas-dev liblapack-dev python-catkin-tools libv4l-dev

        编译:

kaliber下载网站icon-default.png?t=N7T8https://gitcode.net/mirrors/ethz-asl/kalibr        从上述网址下载Kaliber,正常编译即可。不会出什么问题。

2 标定数据录制

        IMU数据:

        IMU静置2小时,周围不要有振动,录制完成后利用下面的脚本转化成rosbag的格式。

        这里是一个可以使用的转化脚本:将文本的IMU信息转化为了sensor_msgs/Imu的信息

"""
Function: convert rawdata into rosbag
Author: Yiheng Zhao
Date: 2023.10.11
"""
import math
import os
import cv2
import numpy as np
from vp_config import ROOT_PATH
from utility import ReadQapData, fix_filename

import rospy
import rosbag
from sensor_msgs.msg import Imu, Image
from cv_bridge import CvBridge
import openpyxl
import time

if __name__ == "__main__":
    ###########################
    ## rosbag config
    ###########################
    save_path = os.path.join(ROOT_PATH, "imu.bag")
    bag = rosbag.Bag(save_path, 'w')
    
    ###########################
    ## main function
    ###########################
    ## read data
    workbook = openpyxl.load_workbook(r'D:\projectslam\off_data_zhuan_ros\raw_data\20231010_180949.xlsx')
    sheet = workbook.active
    ## begin frame by frame process
    i = 0
    for row in sheet.iter_rows(values_only=True):
        #create new message
        imu_msg = Imu()
        imu_msg.header.frame_id = "base_link"
        imu_msg.header.seq = i

        timestamp = time.time()
        formatted_timestamp = "{:.9f}".format(timestamp)
        secs = int(formatted_timestamp.split('.')[0])
        nsecs = int(formatted_timestamp.split('.')[1])
        imu_msg.header.stamp.secs = secs
        imu_msg.header.stamp.nsecs = nsecs


        imu_msg.linear_acceleration.x = float(row[9])
        imu_msg.linear_acceleration.y = float(row[10])
        imu_msg.linear_acceleration.z = float(row[11])

        print("acceleration x is %f" % imu_msg.linear_acceleration.x)
        print("acceleration y is %f" % imu_msg.linear_acceleration.y)
        print("acceleration z is %f" % imu_msg.linear_acceleration.z)

        imu_msg.angular_velocity.x = ( float(row[6])/ 180.0 * 3.1415926)
        imu_msg.angular_velocity.y = ( float(row[7])/ 180.0 * 3.1415926)
        imu_msg.angular_velocity.z = ( float(row[8])/ 180.0 * 3.1415926)

        print("angular x is %f" % imu_msg.angular_velocity.x)
        print("angular y is %f" % imu_msg.angular_velocity.y)
        print("angular z is %f" % imu_msg.angular_velocity.z)

        bag.write(topic="/imu/data_raw", msg=imu_msg)
        i += 1

        time.sleep(0.033)

    bag.close()

        我们得到了一个仅含IMU数据的bag。

        相机数据录制:

        缓慢移动相机,且相机和IMU之间不要发生相对运动,将相机左右移动、上下移动、旋转移动充分激励IMU,录制三分钟左右即可。

        我们得到一个bag,包含IMU和相机数据:

        下面这个脚本是合并IMU、相机图像数据的脚本:

"""
Function: convert rawdata into rosbag
Author: Yiheng Zhao
Date: 2023.10.11
"""
import math
import os
import cv2
import numpy as np
from vp_config import ROOT_PATH
from utility import ReadQapData, fix_filename

import rospy
import rosbag
from sensor_msgs.msg import Imu, Image
from cv_bridge import CvBridge
import openpyxl
import time

if __name__ == "__main__":
    ###########################
    ## rosbag config
    ###########################
    save_path = os.path.join(ROOT_PATH, "imu_cam.bag")
    bag = rosbag.Bag(save_path, 'w')

    ###########################
    ## main function
    ###########################
    ## read data image
    # 指定存储图片的目录路径
    image_directory = r'D:\projectslam\off_data_zhuan_ros\qap_out_data\image'
    # 初始化一个空列表来存储图片路径
    image_paths = []
    # 遍历目录下的所有文件
    for root, dirs, files in os.walk(image_directory):
        for file in files:
            # 检查文件扩展名是否为图片格式(例如,这里假设是以.jpg、.png、.jpeg为扩展名的图片)
            if file.lower().endswith(('.jpg', '.png', '.jpeg')):
                # 使用os.path.join()将目录和文件名组合成完整的文件路径
                image_path = os.path.join(root, file)
                # 将图片路径添加到列表中
                image_paths.append(image_path)
    print(image_paths)
    ## read data  imu
    workbook = openpyxl.load_workbook(r'D:\projectslam\off_data_zhuan_ros\qap_out_data\imu.xlsx')
    sheet = workbook.active
    ## begin frame by frame process
    i = 0
    for row in sheet.iter_rows(values_only=True):

        # create new message
        imu_msg = Imu()
        imu_msg.header.frame_id = "base_link"
        imu_msg.header.seq = i

        timestamp = time.time()
        formatted_timestamp = "{:.9f}".format(timestamp)
        secs = int(formatted_timestamp.split('.')[0])
        nsecs = int(formatted_timestamp.split('.')[1])
        imu_msg.header.stamp.secs = secs
        imu_msg.header.stamp.nsecs = nsecs

        imu_msg.linear_acceleration.x = float(row[9])
        imu_msg.linear_acceleration.y = float(row[10])
        imu_msg.linear_acceleration.z = float(row[11])

        print("acceleration x is %f" % imu_msg.linear_acceleration.x)
        print("acceleration y is %f" % imu_msg.linear_acceleration.y)
        print("acceleration z is %f" % imu_msg.linear_acceleration.z)

        imu_msg.angular_velocity.x = (float(row[6]) / 180.0 * 3.1415926)
        imu_msg.angular_velocity.y = (float(row[7]) / 180.0 * 3.1415926)
        imu_msg.angular_velocity.z = (float(row[8]) / 180.0 * 3.1415926)

        print("angular x is %f" % imu_msg.angular_velocity.x)
        print("angular y is %f" % imu_msg.angular_velocity.y)
        print("angular z is %f" % imu_msg.angular_velocity.z)

        # 图像 msg
        image = cv2.imread(image_paths[i])
        my_bridge = CvBridge()
        img_msg = my_bridge.cv2_to_imgmsg(cvim=image)
        img_msg.header.frame_id = "base_link"
        img_msg.header.seq = i

        img_msg.header.stamp.secs = secs
        img_msg.header.stamp.nsecs = nsecs
        bag.write(topic="/image/data_raw", msg=img_msg)
        bag.write(topic="/imu/data_raw", msg=imu_msg)
        i += 1

        time.sleep(0.033)

    bag.close()

        下面开始标定。

3 开始标定

3.1 IMU标定

        对于6轴的IMU,我们修改这个文件:

        /bag/catkin_imu/src/imu_utils/launch/tum.launch

        修改内容如下:

        修改我们IMU的录制时间IMU话题

<launch>

    <node pkg="imu_utils" type="imu_an" name="imu_an" output="screen">
        <param name="imu_topic" type="string" value= "/imu/data_raw"/>
        <param name="imu_name" type="string" value= "custom_imu_nrxdwcs"/>
        <param name="data_save_path" type="string" value= "$(find imu_utils)/imu666/"/>
        <param name="max_time_min" type="int" value= "90"/>
        <param name="max_cluster" type="int" value= "50"/>
    </node>


</launch>

        修改imu_topic为我们包的IMU录制话题:

        修改imu_name为我们IMU的名字:这里我随便起得名,和客户名字有关系.....

        修改max_time_min为我们IMU录制的时间:我这里是从09:55 - 11:30,我选择取前90分钟的数据。

        修改max_cluster为采样频率,由于我录制不够2小时,因此修改采样频率为50HZ(增大了采样频率)。

        修改data_save_path为我们标定完成的路径,即标定文件存放的位置。

        下面开始标定:

        打开标定IMU的ROS节点:

liuhongwei@liuhongwei-Legion-Y9000P-IRX8H:~/Downloads$ cd /bag/catkin_imu/
liuhongwei@liuhongwei-Legion-Y9000P-IRX8H:/bag/catkin_imu$ source devel/setup.bash 
liuhongwei@liuhongwei-Legion-Y9000P-IRX8H:/bag/catkin_imu$ roslaunch imu_utils tum.launch 

        打开节点后,我们以200倍速度播包。

 rosbag play imu.bag -r 200

        播包完毕后,我们IMU标定就完成了。

        标定文件存储在我们指定的路径中。

        第一个文件就是我们需要的IMU参数。

3.2 相机标定

        我们先需要下载标定版,这里我推荐带编码信息的棋盘格标定板:

标定版下载链接icon-default.png?t=N7T8https://doc-08-5c-docs.googleusercontent.com/docs/securesc/2nlhb7mn3rh7ilhvic8i1i0lcg6lvbo5/kcic7lcag2vqbkks6cg7sa20rnhoqc5r/1696916775000/08341388560495021951/08634034057607032407/1DqKWgePodCpAKJCd_Bz-hfiEQOSnn_k0?e=download&ax=AA75yW7BQ9IbcKRqN7F30tCa7QeNZmYUtrGfL0rCKL3H-BPWurSVMZ8SlMyN7l7mcABbUuU4t6LKNh1GUv6oaKYdz8fhFhpvrys81_Tr-LK6b6VaHTYZrKdK1Xl-7jalz-zRTbOGJI0B_pxlK-zYjlJ5qptj6eJa12S-A520-9oO-QwEJa2FTA10ED_NooTkPqK2nYqfulra1G-7X7By1KB5iB1aK6goViNqPnnFNBWaSyNKb2GBEDPdMgTphe8yFZ9OSGtrzNW9zdbAdM-Ohm-JP34_llYMgTzRxwqKX9ltC34xf4bCU83vDIOfrjqZHos9XkPmWahZuxtJxZGuRDWIBKhOb1P8y6qOVpvRP-hNZB4z8uPyiQ-Qu8q5xqGH1oT6kuQONiCAm1kDI0c0wp4lBi0DMV_5HHBnOrS7x26nTrsWYFAsqdjcx0awomsAlDtSVMc4zZ8pQJDeoV7Qa19VAC-9BidANzgAca2TyLven2FHj3ogrAz-2nlHDOK6OHT3Rzjdd9I5UNRg3ZQUP5g8SEXUo3qHDM0u1n1PKoaZKoRlFaYTYyZKMTqnhOBiBuyjqNB8LRCIteoBC335dRHdjRSzwlOD79bLwQGjXw_ItlDo_6YUV1ZM8nep9kzzcLNP34d_MUMNp6rSBHyfug5jobqcdtHmcWFgJuf2b0u6H2UWHP-0WRmjbHWfdbDQKK8vEmgRlndGnk6gxL8HqL_PQYO0yJ6ddagbHBztZZCZbXSl_KUPYDVd212u-vsoc6BsgYoj200XU7vQE3AfekgV0RLJNzeL0RCIT7ghfHQIBNXFmfTq8Y4byyh5-wnlqTvHi5WgCsF6x9_2sC6FVdZtvOxmpBlufS_eT9FaWu-cNk30Kor_OnQUv8RMLO9mcJbtzw&uuid=51452ed9-1b64-4adc-88d9-65bedb46fdfc&authuser=0&nonce=5kor9vi5br1lg&user=08634034057607032407&hash=7qn0q7b6strcok04upeb271oq7qcpf6c        我们需要制作参数文档,参数文档的数学信息如下:

原始pdf的格子参数是:
6*6的格子
大格子边长:5.5cm
小格子边长:1.65cm
小格子与大格子边长比例:0.3

调整后的格子参数是:
大格子边长:2.2cm
小格子边长:0.66cm
小格子与大格子边长比例:0.3

        然后如果你是打印成了A4纸的形式,可以参考我的参数文档:A4.yaml

target_type: 'aprilgrid' #gridtype
tagCols: 6               #number of apriltags
tagRows: 6               #number of apriltags
tagSize: 0.021           #size of apriltag, edge to edge [m]
tagSpacing: 0.285714285714   #ratio of space between tags to tagSize
codeOffset: 0            #code offset for the first tag in the aprilboard

        现在我们进行针孔相机的标定:

rosrun kalibr kalibr_calibrate_cameras --target '/bag/catkin_kaliber/src/Kalibr/a4.yaml' --bag /home/liuhongwei/Desktop/imu_cam.bag --models pinhole-radtan --topics /image/data_raw --bag-from-to 10 100 --show-extraction 

        然后就开始了标定工作:

        解释一下具体的参数:

        --target:标定版的参数,就是我们刚才写的那个

        --bag:包的路径

        --models:针孔相机模型选这个

        --topics:图像信息的话题

        --bag-from-to:选取10-100s的图像进行标定,这个可以按照自己需求改,一般都是前几秒比较模糊就不要了

        --show-extraction:展示图形化界面

        标定完成后,会输出几个文件:

        这个就是我们相机的内参了。

        标定时可能会遇到这个问题,这是因为相机焦距太大了,我们需要设置个初始值:

Initialization of focal length failed. You can enable manual input by setting ‘KALIBR_MANUAL_FOCAL_LENGTH_INIT’.

        遇到这种情况,我们先终端中设置变量 KALIBR_MANUAL_FOCAL_LENGTH_INIT = 1 然后程序运行时手动给相机设置初始焦距。

3.3 相机+IMU联合标定

        这个我们事先制作几个文件:

        1.imu的配置信息,我们取名为imu.yaml,这个就是我们把我们之前标定的IMU信息写入这个文件就行:

rostopic: /imu/data_raw
update_rate: 30.0 #Hz

accelerometer_noise_density: 1.7640241083260223e-03
accelerometer_random_walk: 4.6133140085614272e-05
gyroscope_noise_density: 1.2287169549703986e-05
gyroscope_random_walk: 8.1951127134973680e-07

        图像的话题还有IMU的频率不要忘记修改。

        2.相机的内参标定信息:

        这个是3.2节中生成的文件imu_cam-camchain.yaml:

cam0:
  cam_overlaps: []
  camera_model: pinhole
  distortion_coeffs: [-0.34038923175502456, 0.06977055299360228, 0.015293838790916657, -0.010372561499554008]
  distortion_model: radtan
  intrinsics: [1685.169877633105, 1656.9322836449144, 997.1304121813936, 474.3184148435317]
  resolution: [1920, 1080]
  rostopic: /image/data_raw

        3.标定版文件,就是3.2中我们自己写的

target_type: 'aprilgrid' #gridtype
tagCols: 6               #number of apriltags
tagRows: 6               #number of apriltags
tagSize: 0.021           #size of apriltag, edge to edge [m]
tagSpacing: 0.285714285714   #ratio of space between tags to tagSize
codeOffset: 0            #code offset for the first tag in the aprilboard

        执行下面代码进行标定:

rosrun kalibr kalibr_calibrate_imu_camera --bag '/home/liuhongwei/Desktop/imu_cam.bag' --target '/bag/catkin_kaliber/src/Kalibr/a4.yaml'  --cam '/bag/catkin_kaliber/src/Kalibr/imu_cam-camchain.yaml'  --imu '/bag/catkin_kaliber/src/Kalibr/imu.yaml' --show-extraction

        参数列表含义如下:

        --bag:数据包路径

        --target:标定版文件路径(A4.yaml)

        --cam:相机内参文件路径(mu_cam-camchain.yaml)

        --imu:IMU标定文件路径(imu.yaml)

        --show-extraction:显示标定过程

        执行如下:

        标定结束:

        结束后生成标定文件imu_cam-results-imucam.txt:

        标定完毕。

4 将参数填入ORBSLAM的文件中

        根据上述我们的标定结果,我们的yaml文件为:

%YAML:1.0

#--------------------------------------------------------------------------------------------
# Camera Parameters. Adjust them!
#--------------------------------------------------------------------------------------------
File.version: "1.0"

Camera.type: "PinHole"

# Camera calibration and distortion parameters (OpenCV) 
Camera1.fx: 1685.16987763
Camera1.fy: 1656.93228364
Camera1.cx: 997.13041218
Camera1.cy: 474.31841484

Camera1.k1: -0.34038923175502456
Camera1.k2: 0.06977055299360228
Camera1.p1: 0.015293838790916657
Camera1.p2: -0.010372561499554008

# Camera resolution
Camera.width: 1920
Camera.height: 1080

Camera.newWidth: 600
Camera.newHeight: 350

# Camera frames per second 
Camera.fps: 30

# Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale)
Camera.RGB: 1

# Transformation from camera to body-frame (imu)
IMU.T_b_c1: !!opencv-matrix
   rows: 4
   cols: 4
   dt: f
   data: [0.94880513, 0.12309341, 0.27236458, 0.00027046,
         0.12309341, 0.98136615, 0.14754149, -0.00012572,
        -0.29088973, -0.10646184, 0.95081494, 0.00034056,
         0.0, 0.0, 0.0, 1.0]

# IMU noise
IMU.NoiseGyro: 1.2287169549703986e-05 #1.6968e-04
IMU.NoiseAcc: 1.7640241083260223e-03 #2.0e-3
IMU.GyroWalk: 8.1951127134973680e-07
IMU.AccWalk: 4.6133140085614272e-05 # 3e-03
IMU.Frequency: 30.0

#--------------------------------------------------------------------------------------------
# ORB Parameters
#--------------------------------------------------------------------------------------------

# ORB Extractor: Number of features per image
ORBextractor.nFeatures: 1000 # 1000

# ORB Extractor: Scale factor between levels in the scale pyramid 	
ORBextractor.scaleFactor: 1.2

# ORB Extractor: Number of levels in the scale pyramid	
ORBextractor.nLevels: 8

# ORB Extractor: Fast threshold
# Image is divided in a grid. At each cell FAST are extracted imposing a minimum response.
# Firstly we impose iniThFAST. If no corners are detected we impose a lower value minThFAST
# You can lower these values if your images have low contrast			
ORBextractor.iniThFAST: 20
ORBextractor.minThFAST: 7

#--------------------------------------------------------------------------------------------
# Viewer Parameters
#--------------------------------------------------------------------------------------------
Viewer.KeyFrameSize: 0.05
Viewer.KeyFrameLineWidth: 1.0
Viewer.GraphLineWidth: 0.9
Viewer.PointSize: 2.0
Viewer.CameraSize: 0.08
Viewer.CameraLineWidth: 3.0
Viewer.ViewpointX: 0.0
Viewer.ViewpointY: -0.7
Viewer.ViewpointZ: -3.5 # -1.8
Viewer.ViewpointF: 500.0

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

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

相关文章

kepler.gl 笔记:地图样式

1 设置地图样式 2 调整layer的上下顺序 3 地图图层 Label&#xff1a;显示城市、社区等的标签。Road&#xff1a;显示半透明的道路线图层。Border&#xff1a;显示州和大陆边界。Building&#xff1a;显示建筑物轮廓。Water&#xff1a;显示水体。Land&#xff1a;显示公园、山…

Excel 函数大全应用,包含各类常用函数

Excel 函数大全应用&#xff0c;各类函数应用与案例实操。 AIGC ChatGPT 职场案例 AI 绘画 与 短视频制作&#xff0c; Power BI 商业智能 68集&#xff0c; 数据库Mysql8.0 54集 数据库Oracle21C 142集&#xff0c; Office 2021实战&#xff0c; Python 数据分析&#xff0…

批量文件重命名软件 A Better Finder Rename 11汉化for mac

A Better Finder Rename 11是一款功能强大的文件重命名工具&#xff0c;可在Mac操作系统上使用。它提供了简单而直观的界面&#xff0c;帮助用户快速批量重命名文件和文件夹&#xff0c;提高文件管理和组织效率。 以下是A Better Finder Rename 11可能提供的一些主要功能和特点…

U盘怎么设置为只读?U盘怎么只读加密?

当将U盘设置为只读模式时&#xff0c;将只能查看其中数据&#xff0c;无法对其中数据进行编辑、复制、删除等操作。那么&#xff0c;怎么将U盘设置成只读呢&#xff1f; U盘如何设置成只读&#xff1f; 有些U盘带有写保护开关&#xff0c;当打开时&#xff0c;U盘就会处于只读…

摩尔信使MThings设备管理

设备是通信目标设备的本地镜像或服务对象&#xff0c;设备是进行一切MThings功能的基础。通过这种设备集成方法&#xff0c;MThings才具备了多设备、多协议、多通道的调试能力。 1、添加设备 1. 添加设备入口&#xff1b; 2. 选择添加设备所在的通道&#xff1b; 3. 选择添加…

AI智能网关在工业物联网领域有哪些应用优势

随着工业物联网规模的持续扩大&#xff0c;监测个控制需求的增加&#xff0c;传统工业网关越来越难以满足工业物联网的发展步伐。针对规模庞大、设备复杂、自动化智能化水平要求高的工业物联网应用&#xff0c;佰马科技推出了多款搭载AI智能网关&#xff0c;依托强劲处理器性能…

c++视觉----使用多边形包围轮廓

外部矩形边界:boundingRect()函数 #include <opencv2/opencv.hpp> #include <iostream> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp>using namespace std; using namespace cv; #include <iostream> #incl…

美创科技三重数据安全韧性,杜绝删库跑路

从删库到跑路&#xff0c;教训很多&#xff0c;但类似事件近年来总在重复上演&#xff0c;有运维部为此连夜鏖战恢复&#xff0c;更有企业陷入“至暗时刻”&#xff0c;经济受损、名誉蒙尘。 组织单位应该采取怎样的策略和积极主动的方法&#xff0c;避免酿成严重的后果&#x…

视频太大怎么压缩变小?超过1G的视频这样压缩

视频已经成为了我们日常生活中不可或缺的一部分&#xff0c;然而&#xff0c;很多时候&#xff0c;我们可能会遇到视频文件过大&#xff0c;无法在某些平台上传或保存的问题。那么&#xff0c;如何将过大的视频文件压缩变小呢&#xff1f; 下面就给大家分享三款实用的工具&…

python写一个文本处理器

gpt给的latex在xmind中有时候会多出写红色的括号在xmind中会报红&#xff0c;影响观感&#xff0c;用python写一个自动删除],[,(,)的文本处理器&#xff0c;并且带有图形界面&#xff0c;本次程序用来解决gpt发来的latex问题&#xff0c;&#xff1a; import tkinter as tkdef…

MOS管在户用储能上的应用-REASUNOS瑞森半导体

一、前言 户用储能又称家庭储能系统&#xff0c;类似于微型储能电站&#xff0c;是分布式能源&#xff08;DER&#xff09;的重要组成部分&#xff0c;其运行不受城市供电压力影响。户用储能产品系统通常由电池组、电池管理系统&#xff08;BMS&#xff09;、储能变流器&…

聊聊Maven的依赖传递、依赖管理、依赖作用域

1. 依赖传递 在Maven中&#xff0c;依赖是会传递的&#xff0c;假如在业务项目中引入了spring-boot-starter-web依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>…

qt5.14.2+VS源码调试记录

在对qt使用时&#xff0c;有时需要对源代码进行调试&#xff0c;方便进行问题定位和debug&#xff0c;但直接安装的qt不能进入qt源码&#xff0c;需要进行一定的操作才能进行源码调试和定位。 源码调试需要对应版本的pdb文件&#xff0c;可以在官网下载&#xff0c;也可找其它…

Linux文件特殊权限与特殊属性

Linux特殊权限 一、粘滞位权限: 功能: 为目录添加粘滞位后该目录中创建的文件和目录只有创建者和超级管理员可以删除。使用场景: 粘滞位权限用于公共目录和临时目录等场景,它提供了一种限制删除和重命名操作的机制,以保护文件的安全性和完整性示例: passwd 程序,允许普…

ESP32-S3上手开发

1、搭建开发环境 首先搭建开发环境&#xff0c;这里采用了windows下集成开发环境ide进行开发&#xff0c;具体的安装方法&#xff1a;ESP-IDF安装配置 这里使用的乐鑫的esp32s3&#xff0c;N16R8 2、esp32s3模块 从上面图中可以看到&#xff0c;N16R8这里使用了外扩16M的fl…

CustomShapes/自定义形状, CustomCurves/自定义曲线, AnimateableData/数据变化动画 的使用

1. CustomShapes 自定义形状视图 1.1 资源图文件 therock.png 1.2 创建自定义形状视图 CustomShapesBootcamp.swift import SwiftUI/// 三角形 struct Triangle: Shape{func path(in rect: CGRect) -> Path {Path { path inpath.move(to: CGPoint(x: rect.midX, y: rect.mi…

Element UI怎么安装呢?

安装 :::warning 注意 后续演示将会在 Vue CLI 搭建的 Vue 项目上进行操作。如需要请查看 Vue CLI 安装 ::: 通过 YARN 命令安装 $ yarn add element-ui完整引入 代表一次性引入所有组件&#xff0c;比较省心省事&#xff0c;但是项目的打包体积也会跟着变大。 // main.js…

python flask接口字段存在性校验函数(http接口字段校验)(返回提示缺少的字段信息)validate_fields()

文章目录 字段存在性校验示例 字段存在性校验 from flask import Flask, request, jsonifyapp Flask(__name__)def validate_fields(data, fields):missing_fields [field for field in fields if field not in data]if missing_fields:return False, f"缺少以下字段: …

c++多态的使用

为什么要使用多态 项目需求&#xff1a; 因为各种不确定原因&#xff0c;包括人为原因&#xff0c;ODU设备会自动的切换到其它类型的设备&#xff0c;而切换后的设备&#xff0c;和原设备有很多不同的地方。如何完美的实现这个切换呢&#xff1f; 解决方案&#xff1a; 使用…

python opencv 深度学习 指纹识别算法实现 计算机竞赛

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python opencv 深度学习 指纹识别算法实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;4分创新点&#xff1a;4分 该项目较为新颖…