# SuperPoint-SuperGlue-TensorRT-CIUS
**Repository Path**: zhuangwu/SuperPoint-SuperGlue-TensorRT-CIUS
## Basic Information
- **Project Name**: SuperPoint-SuperGlue-TensorRT-CIUS
- **Description**: 转自github/SuperPoint-SuperGlue-TensorRT
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: grid
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 6
- **Created**: 2024-07-05
- **Last Updated**: 2024-07-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# CIUS SuperPoint + SuperGlue + TensorRT + **LK_flow**
## Demo
### Dual_channel (SuperPoint + SuperGlue + **LK_flow**) in Lab room
### Usage
Run the code after you install `TensorRT`, See the `CmakeLists.txt` to see the specification.
```sh
# On desktop
roslaunch super_point_glue_track desktop_real_slave.launch
roslaunch super_point_glue_track desktop_real_master.launch
roslaunch super_point_glue_track desktop_real_opti_grid.launch
```
---
1. zph台式机表现
- cuda-11.6,TensorRT-8.4.1.5
- 先删除原有engine,让其自己生成
- 可以build superpoint 和 superglue 的engine,
- 提取点1.7ms,匹配8.5ms
2. 笔记本表现
- cuda-11.6,TensorRT-8.4.1.5
- 先删除原有engine,让其自己生成
- 320*240图像提取250个点,只需要4ms。
3. NVIDIA NX表现
- Jetpack 5.1 cuda-11.4,TensorRT-8.5.2 cuDNN 8.6.0 OpenCV4.5.4
- 先删除原有engine,让其自己生成,耗时非常久,大约半小时
- 提取点14ms,匹配38ms
## 对比方法数据统计
zph台式机测试结果
- SURF
- ORB 匹配时间:提取60个ORB点,经过brute-force match,以及ransac过滤,用时15ms。
## 耗时统计
| Image Size: 640 x 480 | SuperPoint | SuperGlue | normal LK | Fast LK 6 |
|:---------------------:|:----------:|:---------:|:---------:|:---------:|
| NVIDIA NX | 26 | 50 | 4.2 | 27 |
| NVIDIA NX TensorRT | | | | |
## 多种匹配方式耗时统计
| | SSF | SS | SURF | ORB |
|------------|-----------|---------|----------|---------|
| point: 50 | (23+40)/2 | 34 + 20 | 85 + 10 | 27 + 34 |
| point: 100 | | 34 + 26 | 105 + 12 | 30 + 35 |
| point: 200 | | 37 + 33 | 110 + 15 | 30 + 38 |
| point: 500 | | 40 + 70 | 110 + 30 | 30 + 47 |
写point=500的平均耗时就可以,不同的keypoint点数可以放在曲线图中
在nvidia NX上 光流耗时 CPU:10ms ~ 20ms, CPU:1.5ms ~ 4ms
| SSF | SS | SURF | ORB |
|:---------------------:|:----------:|:---------:|:---------:|:---------:|
| NVIDIA NX | 26 | 50 | 4.2 | 27 |
## 准确性统计
| Accuracy | Super | normal LK | Fast LK 3 | Fast LK 5 |
|:----------------------------:|:-------:|:---------:|:----------:|:---------:|
| Gazebo | 1.04 MS | MS | | |
| Meta_count | 1.03 MS | 13.32 MS | | |
| indoor | 7.47 MS | 58.83 MS | | |
| outdoor | 7.47 MS | 58.83 MS | | |
## 测试流程
### 由slave进行匹配方案 slave_core
1. `super_track_master_broadcast.cpp`发布带有深度信息的superpoint消息, 以及对应图像(用于演示match效果)
2. `super_track_slave_match.cpp`
- 接收来自master的 带有深度信息的superpoint消息 以及 master的图像(用于演示match效果)
- 进行superGlue匹配,并展示匹配效果
- 发布匹配好的`MKPTS_XYZ`
3. `super_track_slave_opti.cpp`把`MKPTS_XYZ`和`master`以及`slave`的彩色图像接收,发现深度图不能实时获取,也就作罢
4. **结论**:在使用光流追踪时由于需要master的深度图信息,所以最好还是把匹配过程留在master上做。slave将图片和提取的superpoint发布出来
### 由master匹配方案 master_core
1. `super_track_slave_broadcast.cpp`发布带有深度信息的superpoint消息
2. `super_track_master_match.cpp`
- 接收来自slave的 带有深度信息的superpoint消息
- 进行superGlue匹配
- 发布匹配好的`MKPTS_XYZ`
3. `super_track__opti.cpp`把`MKPTS_XYZ`和`master`以及`slave`的彩色图像接收,以及`master`的深度图信息
- 进行光流加速融合。
## 经验
- `keypoint_threshold`对应特征点的score分数,正常场景在0.1~0.7之间,越高的分数,在superpoint集合中点的排列随score呈降序。
## 光流追踪程序思路
1. 对不断传入的img0和img1彩色图片进行`FuseToImgPairs()`进行配对,把图片对作为一组放在map中,并用时间戳索引。
2. 对传来的mkpts数据进行ID关联
2.1. 首先寻找这次引导数据的时间戳和图片队列中那个时间戳最近,然后依据此时间戳删除图片队列之前的图片对。
2.2. 判断引导数据是首次还是后续,若是首次则直接给mkpts赋予ID,若是后续,则也是赋予临时ID,都是从0开始,到引导数目为止。
3. 在引导数据下,对存储图片后续队列持续追踪
3.1. 使用for循环,从队列中依次取出一对图片
3.2. 若是首次,则进行正常光流跟踪并输出匹配点对; 若是第二次引导,则进入fast track光流,并在后面进行特征引导融合。
4. 特征引导融合
4.1. 上次追踪的点在`kpts0_map`和`kpts1_map`中,本次引导点在`kpts0_map_temp`和`kpts1_map_temp`中
4.2. 对img0和img1分别 遍历所有`引导点`,对每个引导点检查上次`追踪点集`中是否有 临近点(8个像素范围以内),若落入临近则认为是`增强点集`。并从`追踪点集`中暂时删除这些点,也暂时删除对应的`引导点`。
4.3. 然后将剩下`追踪点集`中的没有临近的点称为`衰退点集`,本版本处理中是直接清空这些点集,避免光流跟踪一直保留着这些点。
4.4. 对`引导点`和`增强点集`都进行0和1的ID交叉检查,删除不一致的ID。
4.5. 将`引导点`和`增强点集`都加入到最新点集中,作为下一次的`追踪点集`
5. 在没有引导帧的间隔期,对新增图像持续追踪点
5.1. 由于图像队列一直在塞入新图像,所以用当前时间戳再去队列找,并作为起点,向后续图像队列开始做追踪。并更新当前时间戳。
6. 可视化匹配效果,检查当前深度图并发布消息。
## 计算匹配正确率的方法
使用SuperGlue中提供的`match_pairs.py`,本质是提供两个相机的匹配点`mkpts0`,`mkpts1`,加上cam2相对于cam1的在图像坐标系下相对位姿`T_0_1`,以及两个相机内参`K0`,`K1`
计算特征点对的对极极线误差。最重要的是`model/utils.py`中的`compute_epipolar_error`
使用
```shell
roslaunch super_point_glue_track wirte_image_with_pose.launch
```
可以产生带有图片名称对以及真实相对位姿的txt文件,同时将rostopic的对应图片消息写入磁盘。方便调用匹配正确率的python脚本。
使用superglue匹配示例计算如下
```shell
python match_pairs_changed.py --input_pairs /home/zph/hard_disk/rosbag/match_test/match_accelerate/img_kun01-image-mocap_successful-2023-03-05-16-27-37/image_pairs_with_pose_small_sample.txt --input_dir /home/zph/hard_disk/rosbag/match_test/match_accelerate/img_kun01-image-mocap_successful-2023-03-05-16-27-37/img_assets_small_sample --output_dir /home/zph/hard_disk/rosbag/match_test/match_accelerate/img_kun01-image-mocap_successful-2023-03-05-16-27-37/dump_match_pairs_small_sample --eval --viz --fast_viz
```
或者使用原生的`SuperGluePretrainedNetwork`项目中的
```shell
./match_pairs.py --eval --viz --fast_viz
```
## RoadMap
- [x] 使用cuda::cv进行光流计算加速,参考`https://github.com/pjrambo/VINS-Fusion-gpu`
- [ ] 针对A与B在光流追踪中因一方追踪失败而删除的点,由于再下次检测到该点时会以一个新的ID命名,这样不利于对点的追踪长度的累积统计。以A为主,以B为辅。
拟采用对因为B追踪失败而对应删除A的中的点归为`track_lost`std::map,我们在`Normal_track`中继续对这些点保持追踪,并在一个新的`guide`到来fusion的时机,
我们检查新检测的匹配点是否有和`track_lost`距离相近的点,若判定是同一点则以旧的ID命名,若不是同一点,则以新的ID命名。
**实验结果**发现很少有点是因为B中跟踪失误而导致A中删除的,反而这些消失的点再次出现时可以继续继承之前的ID,让我怀疑是因为最大数量和有效深度对特征点进行了截取,导致时而是有效匹配,时而不是有效匹配。
## Trouble Known
当刚关闭Gazebo后,可能roscore被占用,或未知状态。此时直接进行slave, master, opti的话。并不能运行。必须重新开一个roscore。
---
# SuperPoint SuperGlue TensorRT
SuperPoint and SuperGlue with TensorRT.
## Demo
* This demo was tested on the Quadro P620 GPU.
## Baseline
| Image Size: 320 x 240 | RTX3080 | Quadro P620 |
|:----------------------:|:-------:|:-----------:|
| SuperPoint (250 points)| 1.04 MS | 13.61 MS |
| SuperPoint (257 points)| 1.03 MS | 13.32 MS |
| SuperGlue (256 dims) | 7.47 MS | 58.83 MS |
| FPS (superpoint one time + superglue one time) | $\approx$ 117 FPS | $\approx$ 13 FPS |
## Docker(Recommand)
```bash
docker pull yuefan2022/tensorrt-ubuntu20.04-cuda11.6:latest
docker run -it --env DISPLAY=$DISPLAY --volume /tmp/.X11-unix:/tmp/.X11-unix --privileged --runtime nvidia --gpus all --volume ${PWD}:/workspace --workdir /workspace --name tensorrt yuefan2022/tensorrt-ubuntu20.04-cuda11.6:latest /bin/bash
```
## Environment required
* CUDA==11.6
* TensorRT==8.4.1.5
* OpenCV>=4.0
* EIGEN
* yaml-cpp
## Convert model(Optional)
The converted model is already provided in the [weights](./weights) folder, if you are using the pretrained model officially provided by [SuperPoint and SuperGlue](https://github.com/magicleap/SuperGluePretrainedNetwork), you do not need to go through this step.
```bash
python convert2onnx/convert_superpoint_to_onnx.py --weight_file superpoint_pth_file_path --output_dir superpoint_onnx_file_dir
python convert2onnx/convert_superglue_to_onnx.py --weight_file superglue_pth_file_path --output_dir superglue_onnx_file_dir
```
## Build and run
```bash
git clone https://github.com/yuefanhao/SuperPoint-SuperGlue-TensorRT.git
cd SuperPoint-SuperGlue-TensorRT
mkdir build
cd build
cmake ..
make
# test on image pairs 100 times, the output image will be saved in the build dir
./superpointglue_image ../config/config.yaml ../weights/ ${PWD}/../image/image0.png ${PWD}/../image/image1.png
# test on the folder with image sequence, output images will be saved in the param assigned dir
./superpointglue_sequence ../config/config.yaml ../weights/ ${PWD}/../image/freiburg_sequence/ ${PWD}/../image/freiburg_sequence/match_images/
```
The default image size param is 320x240, if you need to modify the image size in the config file, you should delete the old .engine file in the weights dir.
## Samples
```c++
#include "super_point.h"
#include "super_glue.h"
// read image
cv::Mat image0 = cv::imread("../image/image0.png", cv::IMREAD_GRAYSCALE);
cv::Mat image1 = cv::imread("../image/image1.png", cv::IMREAD_GRAYSCALE);
// read config from file
Configs configs("../config/config.yaml", "../weights/");
// create superpoint detector and superglue matcher
auto superpoint = std::make_shared(configs.superpoint_config);
auto superglue = std::make_shared(configs.superglue_config);
// build engine
superpoint->build();
superglue->build();
// infer superpoint
Eigen::Matrix feature_points0, feature_points1;
superpoint->infer(image0, feature_points0);
superpoint->infer(image1, feature_points1);
// infer superglue
std::vector superglue_matches;
superglue->matching_points(feature_points0, feature_points1, superglue_matches);
```
## Acknowledgements
[SuperPoint](https://github.com/magicleap/SuperPointPretrainedNetwork) [SuperGlue](https://github.com/magicleap/SuperGluePretrainedNetwork) [TensorRT](https://github.com/NVIDIA/TensorRT) [AirVO](https://github.com/xukuanHIT/AirVO)