https://github.com/floatpigeon/Meteor-Long-Exposure
绑定组件rmcs_hero_lob/src/lob_vsison_core.cpp 输入:
- 相机图像和帧号:InputInterface camera_frame_;
- 发射信号:InputInterface bullet_fired_; 处理:
- 使用一个队列存放历史图像,每4帧放一次,然后队列最大长度为15(对应的是过去0.5s内的图像,视频采集帧率120) 收到发射信号后:
- 选择参考帧:使用当前历史图像队列里的图像,做一个中值法提取背景,将这个作为参考帧
- 触发后的60帧不参与后续流程,从触发后的61帧开始处理,到触发后的300帧,起始可配置
- 其余流程保持不变、
- 不得阻塞主线程
目的:消除视频帧间的相机抖动,将所有帧对齐到参考帧坐标系
算法:基于 ORB 特征的透视变换配准
步骤:
-
特征提取:
- 将参考帧和当前帧转换为灰度图
- 使用 ORB 检测器提取特征点(默认最多 200 个特征)
- 排除左上角区域(避免天空等无关区域)
- 可选降采样以提高性能(默认 0.5 倍缩放)
-
特征匹配:
- 使用 BFMatcher(汉明距离)进行 KNN 匹配(K=2)
- 应用比率测试(阈值 0.75)筛选优质匹配
- 要求最少 10 个优质匹配点
-
变换估计:
- 使用 RANSAC 算法估计单应性矩阵 H
- 重投影误差阈值:3.0 像素
- 若匹配不足或估计失败,使用单位变换(不配准)
-
图像变换:
- 使用估计的单应性矩阵对当前帧进行透视变换
- 输出缩放比例:0.5 倍(减少计算量)
目的:从配准后的帧中提取运动前景(移动物体)
算法:基于帧差法的运动检测
步骤:
-
差分计算:
- 将参考帧和配准后的当前帧转换为灰度图
- 计算绝对差值:
diff = |ref_gray - cur_gray|
-
掩码生成:
- 亮度掩码:当前帧灰度值 > 128(过滤暗区)
- 差分掩码:差值 > 24(过滤静止区域)
- 候选掩码:
candidate_mask = diff_mask & bright_mask
-
形态学处理:
- 开运算(3×3 椭圆核):去除小噪点
- 闭运算(5×5 椭圆核):填补小空洞
目的:将前景运动轨迹累积到轨迹层中,生成长曝光效果
算法:基于连通域分析的轨迹追踪与累积
步骤:
-
连通域检测:
- 使用
connectedComponentsWithStats检测前景连通域 - 过滤面积小于 5 像素的小区域
- 获取每个连通域的质心和边界框
- 使用
-
轨迹匹配与速度估计:
- 将当前帧的连通域与上一帧的连通域进行匹配
- 匹配准则:质心距离 < 120 像素
- 计算原始速度:
v = (current_centroid - previous_centroid) / dt - 速度平滑:
v_smooth = α * v_raw + (1-α) * v_previous(α=0.6)
-
累积决策:
- 新出现的连通域:直接累积
- 已匹配的连通域:检查运动方向
- 运动方向判断:
angle = |atan2(vx, vy)| * 180/π - 垂直运动半角阈值:40°(过滤垂直方向的抖动)
-
轨迹累积:
- 将前景像素累积到轨迹层(
trajectory_layer += masked_bgr) - 更新曝光计数矩阵(
exposure_count += mask) - 使用掩码确保只累积前景区域
- 将前景像素累积到轨迹层(
目的:将累积的轨迹层与参考帧合成,生成最终的长曝光图像
算法:CLAHE 增强 + 图像融合
步骤:
-
归一化处理:
- 计算轨迹层的平均曝光:
layer = trajectory_layer / exposure_count - 使用 99% 百分位数进行归一化(避免极值影响)
- 缩放因子:0.6(控制轨迹亮度)
- 计算轨迹层的平均曝光:
-
对比度增强:
- 转换到 Lab 颜色空间
- 对 L 通道应用 CLAHE(对比度限制自适应直方图均衡化)
- 参数:clipLimit=2.0,tileGridSize=8×8
- 转换回 BGR 颜色空间
-
图像融合:
- 将增强后的轨迹层与参考帧相加
- 输出图像 = 参考帧 + 增强轨迹层
目的:调整输出图像尺寸,减小文件大小
处理:
- 使用区域插值(INTER_AREA)进行下采样
- 默认输出尺寸:288×216 像素
- OutputInterfacecv::Mat latest_shooting_background_; 输出第一步中值法得到的背景
- OutputInterfacecv::Mat latest_shooting_track_; 输出轨迹层
- OutputInterfacecv::Mat latest_shooting_exposure_image_; 输出拼合后的图像