rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究
我看的阅读的是中南大学FYT战队开源视觉代码
链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git
1.框架:
代码框架结构:readme有
现在看第一个文件rm_auto_aim
这个是自瞄部分代码。今天的目标就是整理阅读这部分代码,自瞄部分整体的流程
**自瞄系统全流程解析**#### **1. 图像预处理**
- **输入**:相机捕获的原始图像(RGB或灰度)。
- **预处理步骤**:1. **二值化**:根据设定的阈值(`binary_thres`)将图像转换为二值图像,突出装甲板的边缘。2. **去噪**:通过形态学操作(如开运算、闭运算)去除噪声和小区域干扰。3. **颜色过滤**:根据敌方颜色(红/蓝)过滤无关区域。#### **2. 灯条检测**
- **检测方法**:- 使用轮廓检测(`cv::findContours`)找到候选灯条。- 对每个轮廓拟合旋转矩形(`cv::RotatedRect`),并计算其长宽比、角度等特征。
- **筛选条件**:- 长宽比范围(`light_params.min_ratio` ~ `light_params.max_ratio`)。- 角度限制(`light_params.max_angle`),确保灯条接近垂直。#### **3. 装甲板匹配**
- **匹配规则**:- 将成对的灯条组合为装甲板候选区域。- 检查灯条间距(`armor_params.min_small_center_distance` ~ `armor_params.max_large_center_distance`)。- 计算装甲板水平角度(`armor_params.max_angle`),排除倾斜过大的组合。
- **分类**:根据大小区分小装甲板(`SMALL_ARMOR`)和大装甲板(`LARGE_ARMOR`)。#### **4. 目标识别(数字分类)**
- **模型输入**:从装甲板区域裁剪的数字图像。
- **模型功能**:使用训练好的分类器(如YOLO或CNN)识别装甲板编号(如`1`~`5`或`outpost`)。
- **输出**:装甲板编号和置信度。#### **5. 位姿解算(PnP + BA优化)**
- **PnP解算**:- 根据装甲板的3D-2D点对应关系,解算装甲板在相机坐标系下的位姿(旋转矩阵`R`和平移向量`t`)。- 使用OpenCV的`solvePnP`函数实现。
- **BA优化**:- 使用G2O或Ceres库优化装甲板的Yaw角度,最小化重投影误差。- 公式: \[\hat{\theta} = \arg\min_{\theta} \sum_i \| P^{det}_i - \frac{P^{img}_i}{P^{img}_i.z} \|^2\]- 其中,\( P^{img}_i \)是投影点,\( P^{det}_i \)是检测到的角点。#### **6. 目标跟踪(EKF滤波)**
- **状态向量**:包含目标中心位置、速度、Yaw角、角速度等。
- **预测**:根据运动模型预测下一帧目标状态。
- **更新**:用当前检测到的装甲板位置更新状态估计。
- **切换逻辑**:根据Yaw角速度(`target.v_yaw`)判断是否切换跟踪的装甲板。#### **7. 弹道补偿**
- **补偿器类型**:- 理想弹道模型(`IdealCompensator`):忽略空气阻力。- 手动补偿(`ManualCompensator`):根据经验设置固定偏移。
- **计算弹道下坠**:- 根据子弹初速(`bullet_speed`)、重力(`gravity`)和距离计算俯仰角偏移。- 公式: \[\Delta \theta = \arctan\left( \frac{0.5 \cdot g \cdot t^2}{d} \right)\]- 其中,\( t \)为飞行时间,\( d \)为水平距离。#### **8. 云台控制指令**
- **输出指令**:- 目标Yaw和Pitch角度(单位:度)。- 开火建议(`fire_advice`):当目标位于射击范围内时触发。
- **射击条件**:- 目标角度误差小于阈值(`shooting_range_w_`和`shooting_range_h_`)。- 跟踪稳定性高(连续多帧检测到目标)。#### **9. 数据发送**
- **消息类型**:通过ROS 2的`rm_interfaces/msg/GimbalCmd`发布云台指令。
- **字段**:- `yaw`:目标偏航角。- `pitch`:目标俯仰角。- `fire_advice`:是否开火。---### **关键代码文件**
1. **检测模块**:- `armor_detector.cpp`:实现灯条检测和装甲板匹配。- `armor_pose_estimator.cpp`:处理PnP和BA优化。
2. **跟踪模块**:- `armor_tracker.hpp`:EKF状态估计。
3. **解算模块**:- `armor_solver.cpp`:计算云台指令和弹道补偿。
里面弹道补偿的计算公式
各个文件包含的功能
armor_detector/
作用:装甲板检测模块,负责从图像中识别装甲板。
关键文件:
armor_detector.cpp:实现灯条检测、装甲板匹配和数字分类。
armor_pose_estimator.cpp:通过PnP和BA优化计算装甲板3D位姿。
types.hpp:定义装甲板、灯条的数据结构(如Armor、Light)和常量(如装甲板尺寸)。
输出:检测到的装甲板列表(位置、编号、类型)。
(2) armor_solver/
作用:解算模块,根据装甲板位姿计算云台控制指令。
关键文件:
armor_solver.cpp:核心算法,处理弹道补偿、目标选择和射击判断。
armor_tracker.hpp:扩展卡尔曼滤波(EKF)实现目标跟踪。
trajectory_compensator.hpp:弹道补偿器基类(支持理想弹道和手动补偿)。
输出:云台角度指令(Yaw/Pitch)和开火建议。
(3) armor_solver_node.cpp
作用:ROS 2节点入口,集成检测、跟踪、解算模块。
功能:
订阅相机图像和IMU数据。
调用检测和跟踪逻辑。
发布云台控制指令(rm_interfaces/msg/GimbalCmd)。
2. 接口与工具
(1) rm_interfaces/
作用:自定义ROS 2消息和服务,定义模块间通信协议。
关键消息:
Target.msg:目标信息(位置、速度、装甲板编号)。
GimbalCmd.msg:云台控制指令(Yaw/Pitch/开火标志)。
服务:用于动态参数配置(如调整检测阈值)。
(2) rm_utils/
作用:工具库,提供数学计算和日志功能。
关键内容:
math/utils.hpp:PnP解算、坐标转换等数学工具。
logger/:日志系统(基于spdlog封装)。
3. 配置文件与启动脚本
(1) config/
作用:存放参数配置文件(YAML格式)。
示例:
detector_params.yaml:灯条和装甲板的检测阈值。
solver_params.yaml:弹道补偿和跟踪参数。
(2) launch/
作用:ROS 2启动文件,用于一键启动模块。
示例:
bringup.launch.py:启动检测、解算节点和参数服务器。
4. 测试与调试
(1) test/
作用:单元测试和性能测试脚本。
示例:
test_armor_detector.cpp:测试装甲板检测的准确性和实时性。
(2) debug/
作用:调试工具和可视化脚本。
示例:
debug_detector.py:实时显示检测结果(灯条、装甲板框)。
5. 其他文件
CMakeLists.txt:定义模块的编译规则和依赖项。
README.md:模块的使用说明和依赖安装指南。
以上就是对自瞄整体框架的一个详细,描述
具体代码的实现
1.armor_detector_node.cpp:视觉节点订阅的文件
1.构造函数 ArmorDetectorNode::ArmorDetectorNode
作用:初始化ROS 2节点,加载参数,订阅/发布消息。
关键步骤:
声明参数(如检测阈值、相机内参路径)。
订阅相机图像话题(/camera/image_raw)。
发布装甲板检测结果(/detector/armors)和调试信息(/detector/debug)。
初始化TF2监听器(用于坐标系转换)ArmorDetectorNode::ArmorDetectorNode(const rclcpp::NodeOptions &options): Node("armor_detector", options) {// 参数声明binary_thres_ = declare_parameter("binary_thres", 160);// 订阅图像image_sub_ = create_subscription<sensor_msgs::msg::Image>("/camera/image_raw", 10,std::bind(&ArmorDetectorNode::imageCallback, this, _1));// 发布装甲板消息armors_pub_ = create_publisher<rm_interfaces::msg::Armors>("/detector/armors", 10);}
2. 图像回调函数 ArmorDetectorNode::imageCallback
作用:处理每一帧图像,执行检测流程。
流程:
获取图像:将ROS图像消息转换为OpenCV格式(cv_bridge)。
坐标系转换:通过TF2获取相机到IMU的变换(用于位姿解算)。
调用检测器:执行装甲板检测(detector_->detect)。
发布结果:将检测到的装甲板信息发布到ROS话题。void ArmorDetectorNode::imageCallback(const sensor_msgs::msg::Image::ConstSharedPtr img_msg) {// 转换图像格式cv::Mat img = cv_bridge::toCvShare(img_msg, "bgr8")->image;// 获取坐标系变换try {auto transform = tf2_buffer_->lookupTransform("imu_link", img_msg->header.frame_id, tf2::TimePointZero);// 提取旋转矩阵 R_imu_camera} catch (tf2::TransformException &ex) {RCLCPP_ERROR(get_logger(), "TF Error: %s", ex.what());return;}// 检测装甲板auto armors = detector_->detect(img);// 发布结果auto armors_msg = std::make_shared<rm_interfaces::msg::Armors>();armors_msg->header = img_msg->header;armors_pub_->publish(*armors_msg);}
3. 检测函数 Detector::detect(间接调用)
作用:实现装甲板检测的核心逻辑。
步骤:
预处理:二值化、颜色过滤。
灯条检测:轮廓查找 + 旋转矩形拟合。
装甲板匹配:配对灯条并筛选有效装甲板。
数字识别:调用分类器识别装甲板编号。
关键参数:
binary_thres:二值化阈值。
light_params:灯条长宽比、角度限制。
armor_params:装甲板间距、角度限制。
4. 调试函数 ArmorDetectorNode::publishDebugInfo
作用:发布调试信息(如检测框、灯条轮廓)。
实现:
绘制检测结果到图像(OpenCV绘图函数)。
通过ROS话题 /detector/debug 发布调试图像
5. 辅助函数
(1) ArmorDetectorNode::loadCameraInfo
作用:从YAML文件加载相机内参和畸变系数。
用途:初始化PnP解算器(ArmorPoseEstimator)。
(2) ArmorDetectorNode::createDetector
作用:根据参数创建装甲板检测器实例。
逻辑:选择检测算法(如传统图像处理或深度学习)。
关键ROS 2接口
订阅话题:
/camera/image_raw:输入图像。
发布话题:
/detector/armors:装甲板检测结果(位置、编号、类型)。
/detector/debug:调试图像(可视化检测框)。
总结
输入:相机图像 + 坐标系变换(TF2)。
处理:图像预处理 → 灯条检测 → 装甲板匹配 → 数字识别 → 位姿解算。
输出:装甲板位姿列表(ROS消息) + 调试图像。
2.armor_detector.cpp:视觉检测的主要文件
1. 构造函数 Detector::Detector
作用:初始化检测器参数和工具。
参数:
bin_thres:二值化阈值。
color:敌方颜色(红/蓝)。
light_params:灯条检测参数(长宽比、角度限制)。
armor_params:装甲板匹配参数(间距、角度限制)。
关键操作:
初始化分类器(数字识别模型)。
设置角点校正器(LightCornerCorrector)。
2. 核心检测函数 Detector::detect
作用:从输入图像中检测装甲板。
输入:cv::Mat 格式的RGB图像。
输出:std::vector<Armor>,包含所有检测到的装甲板信息。
流程:
预处理:调用 preprocessImage 生成二值图像。
灯条检测:调用 findLights 提取候选灯条。
装甲板匹配:调用 matchLights 配对灯条并筛选有效装甲板。
数字识别:对每个装甲板调用分类器识别编号。
3. 图像预处理 Detector::preprocessImage
作用:生成二值化图像,突出灯条区域。
步骤:1.转换为灰度图。2.根据敌方颜色提取红色或蓝色通道。3.二值化(阈值 binary_thres)。
4. 灯条检测 Detector::findLights
作用:从二值图像中提取灯条候选区域。
流程:
查找轮廓(cv::findContours)。
对每个轮廓拟合旋转矩形(cv::RotatedRect)。
过滤不符合条件的灯条(长宽比、角度)。
过滤条件:
长宽比:light_params.min_ratio < ratio < light_params.max_ratio。
角度:light_params.max_angle 限制灯条倾斜度。
输出:std::vector<Light>,包含灯条几何信息和颜色。5. 装甲板匹配 Detector::matchLights
作用:将灯条配对为装甲板候选。
匹配规则:
距离检查:灯条中心距需在 [min_small_center_distance, max_large_center_distance] 范围内。
角度检查:两灯条的倾斜角差小于 armor_params.max_angle。
长度比:两灯条长度相近(避免误匹配)。
装甲板类型判断:
小装甲板:SMALL_ARMOR(间距较小)。
大装甲板:LARGE_ARMOR(间距较大)。
输出:std::vector<Armor>,包含匹配后的装甲板。6. 灯条有效性判断 Detector::isLight
作用:验证旋转矩形是否为有效灯条。
检查项:
长宽比是否符合灯条特征。
面积是否过小(噪声过滤)。
角度是否接近垂直(light_params.max_angle)。
返回:bool,true 表示有效。7. 装甲板类型判断 Detector::isArmor
作用:根据灯条对判断装甲板类型(小/大/无效)。
逻辑:
计算两灯条中心距离 distance。
若 distance 在 [min_small, max_small] 范围内 → 小装甲板。
若在 [min_large, max_large] 范围内 → 大装甲板。
否则返回 INVALID。
8. 调试工具函数
(1) Detector::drawResults
作用:在图像上绘制检测结果(灯条框、装甲板框、编号)。
用途:可视化调试。
(2) Detector::getAllNumbersImage
作用:返回所有装甲板数字区域的拼接图像。
用途:验证数字分类器的输入质量。总结
输入:原始图像(cv::Mat)。
处理链:
预处理 → 灯条检测 → 装甲板匹配 → 数字识别 → 输出装甲板列表。
关键参数:通过 LightParams 和 ArmorParams 控制检测灵敏度。
3.armor_pose_estimator.cpp:将装甲板的2D像素坐标转换为3D位姿,并通过优化提高Yaw角度的精度。
1. 构造函数 ArmorPoseEstimator::ArmorPoseEstimator
作用:初始化位姿估计器,加载相机内参并配置PnP解算器。
输入:sensor_msgs::msg::CameraInfo::SharedPtr(相机内参和畸变系数)。
关键操作:
初始化PnP解算器(PnPSolver),设置小/大装甲板的3D模板点。
初始化BA优化器(BaSolver),用于优化装甲板Yaw角度。
设置相机-IMU的旋转矩阵 R_gimbal_camera_(默认单位矩阵)
2. 位姿解算主函数 ArmorPoseEstimator::extractArmorPoses
作用:对检测到的装甲板列表进行位姿解算。
输入:
const std::vector<Armor> &armors:检测到的装甲板。
const Eigen::Matrix3d &imu_to_camera:IMU到相机的旋转矩阵。
输出:std::vector<rm_interfaces::msg::Armor>,包含位姿信息的装甲板ROS消息。
流程:
遍历装甲板,调用 solveArmorPose 解算单个装甲板位姿。
转换坐标系(相机系 → IMU系)。
填充ROS消息(位置、姿态、编号等)。
3. 单装甲板位姿解算 ArmorPoseEstimator::solveArmorPose
作用:解算单个装甲板的3D位姿(位置 + 旋转)。
步骤:
PnP解算:根据装甲板角点的2D-3D对应关系,计算初始位姿(cv::solvePnP)。
BA优化:使用光束法平差(Bundle Adjustment)优化装甲板的Yaw角度。
位姿转换:将位姿从相机系转换到IMU系。
输出:rm_interfaces::msg::Armor,包含优化后的位姿和编号。
4. BA优化函数 BaSolver::optimize
作用:优化装甲板的Yaw角度,最小化重投影误差。
输入:
const Armor &armor:装甲板信息(角点、编号)。
cv::Mat &rvec, cv::Mat &tvec:PnP解算的初始旋转和平移向量。
const Eigen::Matrix3d &imu_to_camera:IMU到相机的旋转矩阵。
输出:优化后的Yaw角度(弧度)。
数学原理:
误差函数:\ e(\theta) = \sum_i \| P^{det}_i - \frac{K \cdot (R(\theta) \cdot P^{3D}_i + t)}{z} \|^2 \
使用Ceres或G2O库实现非线性优化。
5. 辅助函数
(1) Armor::buildObjectPoints
作用:生成装甲板的3D模板点(基于装甲板尺寸)。
输入:装甲板宽度和高度(单位:米)。
输出:std::vector<cv::Point3f>,四个角点的3D坐标(以装甲板中心为原点)。
(2) PnPSolver::solvePnP
作用:封装OpenCV的PnP解算,支持选择小/大装甲板模板。
输入:
const std::vector<cv::Point2f> &points:装甲板角点的2D像素坐标。
ArmorType type:装甲板类型(小/大)。
输出:旋转向量 rvec 和平移向量 tvec。6. 调试与验证函数
(1) ArmorPoseEstimator::visualizeResults
作用:在图像上绘制位姿解算结果(坐标系轴、角点投影)。
用途:验证PnP和BA优化的准确性。
(2) BaSolver::computeReprojectionError
作用:计算重投影误差,用于评估优化效果。
输出:平均像素误差。总结
核心功能:将装甲板的2D像素坐标转换为3D位姿,并通过优化提高Yaw角度的精度。
依赖项:
OpenCV(PnP解算)。
Ceres/G2O(BA优化)。
Eigen(坐标系转换)。
输出:装甲板在IMU坐标系下的位姿,供后续跟踪和云台控制使用。
4.ba_solver.cpp:通过非线性优化(BA)提高装甲板Yaw角的估计精度
1. 构造函数 BaSolver::BaSolver
作用:初始化BA优化器,配置相机内参和优化参数。
输入:
const std::array<double, 9> &K:相机内参矩阵(3x3)。
const std::vector<double> &D:相机畸变系数。
关键操作:
存储相机内参和畸变系数。
初始化优化器参数(如最大迭代次数、收敛阈值)。
2. 核心优化函数 BaSolver::optimize
作用:优化装甲板的Yaw角度,最小化重投影误差。
输入:
const Armor &armor:装甲板信息(角点、编号、类型)。
cv::Mat &rvec:PnP解算的初始旋转向量。
cv::Mat &tvec:PnP解算的初始平移向量。
const Eigen::Matrix3d &R_imu_camera:IMU到相机的旋转矩阵。
输出:优化后的Yaw角度(弧度)。
流程:
初始化优化变量:从 rvec 提取初始Yaw角。
构建优化问题:使用Ceres库定义残差块。
执行优化:调用Ceres求解器。
更新位姿:将优化后的Yaw角写回 rvec。
3. Yaw角提取函数 BaSolver::extractYawFromRvec
作用:从旋转向量 rvec 中提取Yaw角(绕Z轴的旋转)。
输入:
const cv::Mat &rvec:旋转向量(3x1)。
const Eigen::Matrix3d &R_imu_camera:IMU到相机的旋转矩阵。
输出:Yaw角(弧度)。
实现:
将 rvec 转换为旋转矩阵 R_camera_armor。
结合 R_imu_camera 计算IMU系下的Yaw角。
4. 旋转向量更新函数 BaSolver::updateRvecWithYaw
作用:将优化后的Yaw角更新到旋转向量 rvec 中。
输入:
cv::Mat &rvec:待更新的旋转向量。
double yaw:优化后的Yaw角。
const Eigen::Matrix3d &R_imu_camera:IMU到相机的旋转矩阵。
实现:
构造新的旋转矩阵(仅更新Yaw角)。
将旋转矩阵转换回旋转向量。
5. 残差计算类 YawReprojectionError
作用:定义Ceres优化的残差计算逻辑。
关键成员:
observed_point_:检测到的装甲板角点(2D像素坐标)。
object_point_:装甲板角点的3D模板坐标。
tvec_:平移向量。
K_, D_:相机内参和畸变系数。
重载 operator():
根据当前Yaw角计算重投影误差。
残差公式:\ e = \| p_{detected} - p_{projected} \| \。
6. 辅助函数 BaSolver::projectPoint
作用:将3D点投影到图像平面,考虑畸变。
输入:
const cv::Point3f &object_point:3D点坐标。
const Eigen::Matrix3d &R:旋转矩阵。
const cv::Mat &tvec:平移向量。
const std::array<double, 9> &K:相机内参。
const std::vector<double> &D:畸变系数。
输出:投影后的2D像素坐标。
实现:调用OpenCV的 projectPoints 函数。总结
核心功能:通过非线性优化(BA)提高装甲板Yaw角的估计精度。
依赖库:
Ceres Solver:用于高效的最小二乘优化。
Eigen:处理矩阵运算和坐标系转换。
OpenCV:提供PnP解算和投影功能。
输出:优化后的Yaw角,用于提升云台控制的准确性。
5.graph_optimizer.cpp
1. 顶点类 VertexYaw 的函数
(1) VertexYaw::setToOriginImpl
作用:初始化顶点的估计值(Yaw角)。
实现:将顶点值设为 0。
2) VertexYaw::oplusImpl
作用:更新顶点的Yaw角估计值。
输入:const double *update,增量(弧度)。
数学:\ \theta_{\text{new}} = \theta_{\text{old}} + \Delta \theta \。
2. 边类 EdgeProjection 的函数
(1) 构造函数 EdgeProjection::EdgeProjection
作用:初始化投影误差边,存储相机-IMU变换和相机参数。
输入:
R_camera_imu:相机到IMU的旋转矩阵(Sophus::SO3d)。
R_pitch:云台俯仰角的旋转矩阵。
t:平移向量(相机系到装甲板系)。
K:相机内参矩阵。
关键操作:存储参数到成员变量。(2) EdgeProjection::computeError
作用:计算重投影误差(2D像素误差)。
数学原理:
根据Yaw角(顶点)和3D点(顶点)计算投影点:误差:\ e = P_{\text{detected}} - \frac{P_{\text{img}}}{z} \(归一化像素坐标)。
3. 图优化主函数 GraphOptimizer::optimize
作用:执行图优化,优化装甲板的Yaw角。
输入:
const std::vector<cv::Point2f> &detected_points:检测到的装甲板角点(2D)。
const std::vector<cv::Point3f> &object_points:装甲板3D模板点。
double initial_yaw:初始Yaw角(弧度)。
输出:优化后的Yaw角。
流程:
初始化图优化器(g2o::SparseOptimizer)。
添加顶点:
Yaw角顶点(VertexYaw)。
3D点顶点(g2o::VertexPointXYZ)。
添加边:为每个角点添加投影误差边(EdgeProjection)。
执行优化:调用 optimizer.optimize()。
4. 辅助函数
(1) GraphOptimizer::setCameraParams
作用:设置相机-IMU变换和相机内参。
输入:
R_camera_imu:相机到IMU的旋转矩阵。
R_pitch:云台俯仰角旋转矩阵。
t:平移向量。
K:相机内参矩阵。
(2) GraphOptimizer::computeReprojectionError
作用:计算优化后的平均重投影误差(用于验证优化效果)。
输出:像素误差的均方根(RMSE)。总结
核心功能:通过图优化(G2O)优化装甲板的Yaw角,最小化重投影误差。
关键类:
VertexYaw:优化变量(Yaw角)。
EdgeProjection:定义误差计算逻辑。
依赖项:
G2O:图优化框架。
Sophus:处理旋转矩阵(SO3d)。
Eigen:矩阵运算。
输出:优化后的Yaw角,用于提升装甲板位姿估计的准确性。
6.light_corner_corrector.cpp:通过亚像素级优化提升灯条角点的检测精度,从而改善装甲板位姿解算的准确性。
1. 构造函数 LightCornerCorrector::LightCornerCorrector
作用:初始化角点校正器的参数和配置。
关键操作:
设置默认的角点搜索范围(search_radius_)。
初始化图像处理参数(如边缘检测阈值)。
2. 核心函数 LightCornerCorrector::correctCorner
作用:对灯条的角点位置进行亚像素级校正,提升检测精度。
输入:
const cv::Mat &image:原始图像(灰度或二值化)。
cv::Point2f &corner:待校正的角点坐标(输入输出参数)。
输出:校正后的角点坐标(直接修改 corner)。
流程:
提取局部ROI:以当前角点为中心,截取 search_radius_ 范围内的图像区域。
边缘检测:使用Sobel算子计算局部区域的梯度。
亚像素优化:调用OpenCV的 cornerSubPix 函数,基于梯度信息优化角点位置。
3. 批量校正函数 LightCornerCorrector::correctCorners
作用:对一组灯条的四个角点进行批量校正。
输入:
const cv::Mat &image:原始图像。
std::vector<cv::Point2f> &corners:灯条的四个角点(顺序:左上、右上、右下、左下)。
输出:校正后的角点坐标(直接修改 corners)。
实现:遍历每个角点,调用 correctCorner 逐个校正。
4. 参数设置函数 LightCornerCorrector::setSearchRadius
作用:调整角点搜索范围(单位:像素)。
输入:int radius,搜索半径(默认值通常为5~10像素)。
用途:根据图像分辨率或噪声水平动态调整搜索范围。
5. 边缘检测辅助函数 LightCornerCorrector::computeEdgeGradient
作用:计算局部区域的梯度幅值和方向(用于亚像素优化的权重)。
输入:const cv::Mat &patch,局部图像区域。
输出:梯度矩阵(cv::Mat)。
实现:使用Sobel算子计算x/y方向梯度,合并为幅值
6. 调试函数 LightCornerCorrector::drawCorrectionResult
作用:可视化校正前后的角点位置(用于调试)。
输入:
const cv::Mat &image:原始图像。
const std::vector<cv::Point2f> &corners_before:校正前角点。
const std::vector<cv::Point2f> &corners_after:校正后角点。
输出:绘制对比结果的图像(cv::Mat)。
总结
核心功能:通过亚像素级优化提升灯条角点的检测精度,从而改善装甲板位姿解算的准确性。
关键技术:
亚像素角点优化:基于图像梯度信息调整角点位置。
局部ROI处理:减少计算量,避免全局图像处理。
依赖项:OpenCV(cornerSubPix、Sobel算子、绘图函数)。
应用场景:在装甲板检测流程中,对灯条的四个角点进行后处理校正。
7.number_classifier.cpp :数字分类
1. 构造函数 NumberClassifier::NumberClassifier
作用:初始化数字分类器,加载预训练模型和分类标签。
关键操作:
加载模型文件(如ONNX或TensorRT格式)。
初始化预处理参数(归一化均值、标准差)。
加载类别标签(如["1", "2", "3", "4", "5", "outpost"])。
2. 分类函数 NumberClassifier::classify
作用:对装甲板数字区域进行分类,返回编号或类型。
输入:
const Armor &armor:装甲板信息(包含数字区域图像 number_img)。
输出:分类结果(字符串,如"1"、"outpost")。
流程:
预处理:调整大小、归一化、转换为Blob。
推理:调用模型前向传播。
后处理:提取置信度最高的类别。
3. 标签加载函数 NumberClassifier::loadLabels
作用:从文件加载分类标签。
输入:const std::string &label_path,标签文件路径(每行一个类别)。
输出:std::vector<std::string>,类别名称列表。
4. 预处理函数 NumberClassifier::preprocess
作用:标准化输入图像(归一化、通道分离等)。
输入:cv::Mat &image,原始数字区域图像。
输出:预处理后的图像(cv::Mat)。
关键步骤:
转换为浮点型并归一化到[0,1]。
应用ImageNet均值/标准差标准化。
5. 置信度阈值设置 NumberClassifier::setConfidenceThreshold
作用:设置分类结果的置信度阈值,低于阈值则视为无效。
输入:float threshold(默认值如0.7)。
影响:在classify函数中过滤低置信度结果。
6. 调试函数 NumberClassifier::visualize
作用:可视化分类结果(绘制类别文本和置信度)。
输入:
cv::Mat &image:原始图像。
const std::string &label:分类结果。
float confidence:置信度分数。
输出:绘制结果的图像(cv::Mat)。
7. 模型热更新 NumberClassifier::reloadModel
作用:动态加载新模型(无需重启程序)。
输入:const std::string &new_model_path。总结
核心功能:利用深度学习模型对装甲板数字区域进行分类。
关键技术:
OpenCV DNN模块:支持多种模型格式(ONNX/TensorRT)。
预处理标准化:提升模型泛化能力。
动态阈值过滤:平衡准确率与误检率。
性能优化点:
使用GPU加速推理(net_.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA))。
批量处理(若支持多输入)。
以上就是关于armor_detector文件的一些解释
下面是armor_solver代码的解释
1. armor_solver_node.cpp
1. 构造函数 ArmorSolverNode::ArmorSolverNode
作用:初始化ROS 2节点,加载参数,配置订阅/发布接口。
关键操作:
声明参数(如跟踪阈值、EKF噪声参数)。
订阅装甲板检测结果(/detector/armors)。
发布云台控制指令(/solver/gimbal_cmd)。
初始化跟踪器(Tracker)和扩展卡尔曼滤波器(EKF)。
2. 装甲板回调函数 ArmorSolverNode::armorsCallback
作用:处理检测到的装甲板消息,执行跟踪和位姿解算。
输入:rm_interfaces::msg::Armors::SharedPtr,包含装甲板列表。
流程:
目标跟踪:调用 tracker_->update(armors_msg) 更新跟踪状态。
EKF预测:根据运动模型预测目标状态。
位姿解算:调用 solver_->solve 计算云台指令。
发布指令:将指令发送到云台控制话题。
3. 云台指令解算函数 ArmorSolverNode::solveGimbalCmd
作用:根据目标状态计算云台控制指令(Yaw/Pitch/开火建议)。
输入:
const rm_interfaces::msg::Target &target:跟踪目标信息。
const rclcpp::Time &stamp:当前时间戳。
输出:rm_interfaces::msg::GimbalCmd,云台指令。
逻辑:
弹道补偿:根据目标距离和子弹速度计算俯仰角偏移。
射击判断:若目标位于射击范围内,设置 fire_advice=true。
4. EKF更新函数 ArmorSolverNode::updateEKF
作用:用当前装甲板观测值更新EKF状态估计。
输入:
const rm_interfaces::msg::Armor &armor:当前检测的装甲板。
const rclcpp::Time &stamp:时间戳。
实现:
将装甲板位姿转换为目标状态向量。
调用 ekf_->update(measurement) 更新状态。
5. 调试发布函数 ArmorSolverNode::publishDebugInfo
作用:发布调试信息(如跟踪状态、预测误差)。
输出话题:/solver/debug(自定义调试消息)。
内容:
目标预测位置与实际位置的误差。
EKF协方差矩阵的迹(反映估计不确定性)。
6. 工具函数 ArmorSolverNode::calculateShootDelay
作用:计算子弹飞行时间(用于弹道补偿)。
输入:目标距离 distance(米)。
总结
核心流程:
装甲板检测 → 目标跟踪 → EKF状态估计 → 位姿解算 → 云台控制
关键模块:
跟踪器:关联多帧检测结果,处理目标切换。
EKF:估计目标运动状态(位置、速度、Yaw角速度)。
解算器:综合弹道补偿和射击逻辑生成指令。
ROS 2接口:
输入:/detector/armors(装甲板检测结果)。
输出:/solver/gimbal_cmd(云台指令)、/solver/debug(调试信息)。
2.armor_solver_node.cpp
1. 构造函数 Solver::Solver
作用:初始化解算器,加载参数并创建弹道补偿器。
关键操作:
从ROS参数服务器读取配置(如弹道速度、重力、补偿器类型)。
初始化补偿器(IdealCompensator 或 ManualCompensator)。
设置默认跟踪状态(State::TRACKING_ARMOR)。
2. 核心解算函数 Solver::solve
作用:根据目标信息计算云台控制指令(Yaw/Pitch/开火建议)。
输入:
const rm_interfaces::msg::Target &target:目标信息(位置、速度、装甲板编号)。
const rclcpp::Time ¤t_time:当前时间戳。
std::shared_ptr<tf2_ros::Buffer> tf_buffer:TF2坐标变换工具。
输出:rm_interfaces::msg::GimbalCmd,云台指令。
流程:
预测目标位置:补偿子弹飞行时间(calculateFlyingTime)。
选择最优装甲板:调用 selectBestArmor(针对多装甲板目标)。
计算弹道补偿:根据距离和重力计算俯仰角偏移。
生成指令:设置Yaw/Pitch角度和开火建议。
3. 装甲板选择函数 Solver::selectBestArmor
作用:从多个装甲板中选择最佳射击目标(如平衡步兵的左右装甲板)。
输入:
const std::vector<Armor> &armors:装甲板列表。
const Eigen::Vector3d &target_pos:目标预测位置。
double target_yaw:目标Yaw角。
输出:最优装甲板索引(int)。
选择策略:
距离云台当前角度最近的装甲板。
排除被遮挡或超出射击范围的装甲板。
4. 射击判断函数 Solver::isOnTarget
作用:判断目标是否位于可射击范围内。
输入:
double yaw:云台当前Yaw角。
double pitch:云台当前Pitch角。
const Eigen::Vector3d &target_pos:目标位置。
输出:bool,true表示可射击。
判断逻辑:
计算目标与云台的角度偏差。
检查偏差是否小于阈值(shooting_range_w_ 和 shooting_range_h_)。
5. 弹道补偿函数 IdealCompensator::calculate
作用:计算理想弹道下的俯仰角补偿值(忽略空气阻力)。
输入:const Eigen::Vector3d &target_pos,目标位置。
6. 状态切换函数 Solver::updateState
作用:根据目标运动状态切换跟踪模式(如装甲板/中心点跟踪)。
触发条件:
目标Yaw角速度超过阈值(max_tracking_v_yaw_)→ 切换到中心点跟踪。
目标静止 → 切换回装甲板跟踪。
总结
核心功能:将目标位姿转换为云台控制指令,结合弹道补偿和射击逻辑。
关键模块:
目标预测:补偿子弹飞行时间和目标运动。
装甲板选择:动态切换跟踪目标。
弹道模型:支持理想弹道和手动补偿。
输出指令:Yaw/Pitch角度 + 开火建议,通过ROS 2话题发布。
3.armor_tracker.cpp
1. 构造函数 Tracker::Tracker
作用:初始化跟踪器参数和状态。
关键参数:
max_match_distance:同一目标装甲板的最大匹配距离(单位:米)。
max_match_yaw_diff:同一目标装甲板的最大Yaw角差(单位:弧度)。
初始化内容:
重置跟踪状态(LOST)。
设置跟踪阈值(tracking_thres、lost_thres)。
2. 初始化函数 Tracker::init
作用:在首次检测到目标时初始化跟踪器。
输入:const Armors::SharedPtr &armors_msg,检测到的装甲板消息。
流程:
选择距离图像中心最近的装甲板作为初始目标。
初始化EKF(扩展卡尔曼滤波)状态向量。
设置跟踪状态为 DETECTING。
3. 状态更新函数 Tracker::update
作用:根据新检测到的装甲板更新跟踪状态和目标信息。
输入:const Armors::SharedPtr &armors_msg,当前帧的装甲板消息。
核心逻辑:
匹配目标:调用 matchArmors 关联当前检测与历史跟踪目标。
状态机切换:
LOST → DETECTING:首次检测到目标。
DETECTING → TRACKING:连续多帧检测到目标。
TRACKING → TEMP_LOST:短暂丢失目标。
EKF更新:用匹配的装甲板更新状态估计。
4. 装甲板匹配函数 Tracker::matchArmors
作用:关联当前检测的装甲板与跟踪目标。
匹配策略:
距离过滤:仅考虑距离小于 max_match_distance_ 的装甲板。
角度过滤:Yaw角差小于 max_match_yaw_diff_。
ID匹配:优先匹配相同编号(如 "1"、"outpost")的装甲板。
输出:匹配成功的装甲板(std::optional<Armor>),若无匹配返回 std::nullopt。
6. 目标丢失处理函数 Tracker::handleLostArmor
作用:处理目标丢失情况,更新跟踪状态。
逻辑:
若丢失帧数超过 lost_thres_,状态置为 LOST。
否则状态为 TEMP_LOST,继续预测目标位置(EKF预测)。
7. 装甲板跳变处理函数 Tracker::handleArmorJump
作用:当目标切换装甲板(如平衡步兵旋转)时,更新跟踪信息。
触发条件:检测到同一目标的不同装甲板(如从左侧切换到右侧)。
操作:
更新跟踪的装甲板编号(tracked_id_)。
调整EKF状态中的Yaw角。
8. 工具函数 Tracker::convertArmorToMeasurement
作用:将装甲板信息转换为EKF的观测向量。
输入:const Armor &armor。
输出:Eigen::VectorXd
总结
核心功能:通过多状态机(LOST/DETECTING/TRACKING/TEMP_LOST)和EKF实现鲁棒的目标跟踪。
关键设计:
状态机管理:适应目标出现、持续跟踪、短暂丢失等场景。
EKF融合:结合运动模型和观测数据提高跟踪精度。
装甲板匹配:综合空间距离、角度和编号关联目标。
输出:稳定的目标状态(位置、速度、Yaw角),供后续解算模块使用。
目前来说,
rm_auto_aim下的rm_auto_aim这个文件夹暂时没有什么作用,以上就是所有关于自瞄的一个相关的解释,整体来看,代码非常完善, 相关功能集成度很高,鲁棒性很强,由此可见中南大学的视觉组的功力还是很深厚的,代码还需细细研读,还需要适配自己那套机器
只能说,需要学的还有太多了,写这个的目的是为了写个笔记,方便重新看的时候没有那么难受
相关文章:

rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...

高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...

负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...

算法—栈系列
一:删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...

leetcode73-矩阵置零
leetcode 73 思路 记录 0 元素的位置:遍历整个矩阵,找出所有值为 0 的元素,并将它们的坐标记录在数组zeroPosition中置零操作:遍历记录的所有 0 元素位置,将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...
ArcPy扩展模块的使用(3)
管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如,可以更新、修复或替换图层数据源,修改图层的符号系统,甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...

向量几何的二元性:叉乘模长与内积投影的深层联系
在数学与物理的空间世界中,向量运算构成了理解几何结构的基石。叉乘(外积)与点积(内积)作为向量代数的两大支柱,表面上呈现出截然不同的几何意义与代数形式,却在深层次上揭示了向量间相互作用的…...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...

Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...

Mac flutter环境搭建
一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...

[拓扑优化] 1.概述
常见的拓扑优化方法有:均匀化法、变密度法、渐进结构优化法、水平集法、移动可变形组件法等。 常见的数值计算方法有:有限元法、有限差分法、边界元法、离散元法、无网格法、扩展有限元法、等几何分析等。 将上述数值计算方法与拓扑优化方法结合&#…...

Linux-进程间的通信
1、IPC: Inter Process Communication(进程间通信): 由于每个进程在操作系统中有独立的地址空间,它们不能像线程那样直接访问彼此的内存,所以必须通过某种方式进行通信。 常见的 IPC 方式包括&#…...
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...

门静脉高压——表现
一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构:由肠系膜上静脉和脾静脉汇合构成,是肝脏血液供应的主要来源。淤血后果:门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血,引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...
React核心概念:State是什么?如何用useState管理组件自己的数据?
系列回顾: 在上一篇《React入门第一步》中,我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目,并修改了App.jsx组件,让页面显示出我们想要的文字。但是,那个页面是“死”的,它只是静态…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...

【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
Java并发编程实战 Day 11:并发设计模式
【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能…...

DeepSeek越强,Kimi越慌?
被DeepSeek吊打的Kimi,还有多少人在用? 去年,月之暗面创始人杨植麟别提有多风光了。90后清华学霸,国产大模型六小虎之一,手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水,单月光是投流就花费2个亿。 疯…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...

医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...
跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践
在电商行业蓬勃发展的当下,多平台运营已成为众多商家的必然选择。然而,不同电商平台在商品数据接口方面存在差异,导致商家在跨平台运营时面临诸多挑战,如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...
字符串哈希+KMP
P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!
今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等,设置经线、纬线都以10间隔显示。 2、需要插入背会归线…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
boost::filesystem::path文件路径使用详解和示例
boost::filesystem::path 是 Boost 库中用于跨平台操作文件路径的类,封装了路径的拼接、分割、提取、判断等常用功能。下面是对它的使用详解,包括常用接口与完整示例。 1. 引入头文件与命名空间 #include <boost/filesystem.hpp> namespace fs b…...