【SVO】klt与极限搜索块匹配findEpipolarMatchDirect

Matcher::findEpipolarMatchDirect 函数逻辑与原理分析

核心目标

在极线上搜索参考帧特征点 ref_ftr 在当前帧 cur_frame 中的最佳匹配点,并通过三角化计算深度。


关键步骤解析

1. 极线端点计算
const BearingVector A = T_cur_ref.getRotation().rotate(ref_ftr.f) + T_cur_ref.getPosition() * d_min_inv;
const BearingVector B = T_cur_ref.getRotation().rotate(ref_ftr.f) + T_cur_ref.getPosition() * d_max_inv;
cur_frame.cam()->project3(A, &px_A);  // 投影到当前帧像素坐标
cur_frame.cam()->project3(B, &px_B);
epi_image_ = px_A - px_B;  // 极线方向向量
  • 原理:利用深度倒数范围 [d_min_inv, d_max_inv] 计算参考帧特征点对应的3D点在当前帧中的投影范围(px_A, px_B)。
  • 作用:确定极线搜索区间。
2. 仿射扭曲矩阵计算
warp::getWarpMatrixAffine(ref_frame.cam_, cur_frame.cam_, ref_ftr.px, ref_ftr.f,1.0 / d_estimate_inv, T_cur_ref, ref_ftr.level, &A_cur_ref_);
  • 原理:根据两帧间位姿变换 T_cur_ref 和深度估计值,计算参考帧到当前帧的仿射变换矩阵 A_cur_ref_
  • 作用:补偿视角变化导致的图像变形。
3. 边缘特征方向过滤
if (isEdgelet(ref_ftr.type) {const Eigen::Vector2d grad_cur = (A_cur_ref_ * ref_ftr.grad).normalized();const double cosangle = fabs(grad_cur.dot(epi_image_.normalized()));if (cosangle < options_.epi_search_edgelet_max_angle) return MatchResult::kFailAngle;  // 边缘方向与极线夹角过大
}
  • 原理:边缘特征的梯度方向应与极线方向一致(夹角小)。
  • 作用:过滤掉梯度方向与极线方向不一致的边缘特征,提升匹配鲁棒性。
4. 图像金字塔预处理
search_level_ = warp::getBestSearchLevel(A_cur_ref_, ref_frame.img_pyr_.size() - 1);
epi_length_pyramid_ = epi_image_.norm() / (1 << search_level_);
  • 原理:根据仿射矩阵尺度选择最佳金字塔层级 search_level_,并计算该层级的极线长度。
  • 作用:在粗分辨率上快速搜索,减少计算量。
5. 参考图像块扭曲
warp::warpAffine(A_cur_ref_, ref_frame.img_pyr_[ref_ftr.level], ...);
patch_utils::createPatchFromPatchWithBorder(...);  // 提取参考图像块
  • 原理:将参考帧中的图像块通过仿射变换 A_cur_ref_ 扭曲到当前帧视角。
  • 作用:生成用于匹配的模板图像块 patch_
6. 极线搜索策略
  • 情况1:极线过短(epi_length_pyramid_ < 2.0
    px_cur_ = (px_A + px_B) / 2.0;  // 取极线中点
    findLocalMatch(cur_frame, epi_dir_image, search_level_, px_cur_);  // 局部搜索
    
  • 情况2:极线较长
    PatchScore patch_score(patch_);  // 预计算参考图像块评分
    scanEpipolarLine(cur_frame, A, B, C, patch_score, ...);  // 沿极线扫描
    
  • 原理
    • 短极线:直接在极线中点附近局部搜索。
    • 长极线:在极线上滑动参考图像块,通过 ZMSSD(零均值平方和差) 计算匹配得分,选择得分最高的位置。
7. 匹配验证与优化
if (zmssd_best < PatchScore::threshold()) {if (options_.subpix_refinement) findLocalMatch(...);  // 亚像素优化cur_frame.cam()->backProject3(px_cur_, &f_cur_);  // 反投影到3DdepthFromTriangulation(T_cur_ref, ref_ftr.f, f_cur_, &depth);  // 三角化深度
}
  • 原理
    • 亚像素优化:在粗匹配位置附近进行高斯牛顿迭代,提升精度。
    • 三角化:利用两帧间位姿和匹配点光线,求解3D点深度。

失败处理

失败原因返回值触发条件
边缘特征方向与极线夹角过大MatchResult::kFailAngle夹角余弦值小于阈值 epi_search_edgelet_max_angle
图像块扭曲失败MatchResult::kFailWarpwarpAffine 返回失败
匹配得分不足MatchResult::kFailScore最佳 ZMSSD 得分超过阈值

关键算法与技巧

  1. 仿射光流(Affine Warping)
    • 补偿视角变化,使图像块在不同帧间保持形状一致。
  2. 金字塔搜索(Pyramid Search)
    • 在低分辨率图像上快速定位,逐步细化到高分辨率。
  3. 极线约束(Epipolar Constraint)
    • 将搜索范围从整幅图像压缩到一条直线,减少计算量。
  4. ZMSSD 匹配度量
    • 对光照变化鲁棒:通过减去图像块均值,消除亮度差异影响。
  5. 亚像素优化(Subpixel Refinement)
    • 通过二次拟合或高斯牛顿法,使匹配精度达到亚像素级别。

代码流程总结

在这里插入图片描述

此函数实现了高效且鲁棒的直接法特征匹配,适用于视觉里程计(VO)和SLAM系统中的特征跟踪与深度估计。

    Matcher::MatchResult Matcher::findEpipolarMatchDirect(const Frame& ref_frame,const Frame& cur_frame,const Transformation& T_cur_ref,const FeatureWrapper& ref_ftr,const double d_estimate_inv,const double d_min_inv,const double d_max_inv,double& depth){int zmssd_best = PatchScore::threshold();// Compute start and end of epipolar line in old_kf for match search, on image planeconst BearingVector A = T_cur_ref.getRotation().rotate(ref_ftr.f) + T_cur_ref.getPosition() * d_min_inv;const BearingVector B = T_cur_ref.getRotation().rotate(ref_ftr.f) + T_cur_ref.getPosition() * d_max_inv;Eigen::Vector2d px_A, px_B;cur_frame.cam()->project3(A, &px_A);cur_frame.cam()->project3(B, &px_B);epi_image_ = px_A - px_B;//LOG(INFO) << "A:" << A;//LOG(INFO) << "B:" << B;//LOG(INFO) << "px_A:" << px_A;//LOG(INFO) << "px_B:" << px_B;// Compute affine warp matrixwarp::getWarpMatrixAffine(ref_frame.cam_, cur_frame.cam_, ref_ftr.px, ref_ftr.f,1.0 / std::max(0.000001, d_estimate_inv), T_cur_ref, ref_ftr.level, &A_cur_ref_);// feature pre-selectionreject_ = false;if (isEdgelet(ref_ftr.type) && options_.epi_search_edgelet_filtering){const Eigen::Vector2d grad_cur = (A_cur_ref_ * ref_ftr.grad).normalized();const double cosangle = fabs(grad_cur.dot(epi_image_.normalized()));if (cosangle < options_.epi_search_edgelet_max_angle){reject_ = true;return MatchResult::kFailAngle;}}//LOG(INFO) << "A_cur_ref_: " << A_cur_ref_;// prepare for match//    - find best search level//    - warp the reference patchsearch_level_ = warp::getBestSearchLevel(A_cur_ref_, ref_frame.img_pyr_.size() - 1);// length and direction on SEARCH LEVELepi_length_pyramid_ = epi_image_.norm() / (1 << search_level_);GradientVector epi_dir_image = epi_image_.normalized();if (!warp::warpAffine(A_cur_ref_, ref_frame.img_pyr_[ref_ftr.level], ref_ftr.px,ref_ftr.level, search_level_, kHalfPatchSize + 1, patch_with_border_))return MatchResult::kFailWarp;patch_utils::createPatchFromPatchWithBorder(patch_with_border_, kPatchSize, patch_);// Case 1: direct search locally if the epipolar line is too shortif (epi_length_pyramid_ < 2.0){px_cur_ = (px_A + px_B) / 2.0;MatchResult res = findLocalMatch(cur_frame, epi_dir_image, search_level_, px_cur_);if (res != MatchResult::kSuccess)return res;cur_frame.cam()->backProject3(px_cur_, &f_cur_);f_cur_.normalize();return matcher_utils::depthFromTriangulation(T_cur_ref, ref_ftr.f, f_cur_, &depth);}// Case 2: search along the epipolar line for the best matchPatchScore patch_score(patch_); // precompute for reference patchBearingVector C = T_cur_ref.getRotation().rotate(ref_ftr.f) + T_cur_ref.getPosition() * d_estimate_inv;//LOG(INFO) << "C: " << C;//LOG(INFO) << "px_cur_: " << std::setprecision(15) << px_cur_.transpose();scanEpipolarLine(cur_frame, A, B, C, patch_score, search_level_, &px_cur_, &zmssd_best);//LOG(INFO) << "zmssd_best: " << zmssd_best;// check if the best match is good enoughif (zmssd_best < PatchScore::threshold()){if (options_.subpix_refinement){MatchResult res = findLocalMatch(cur_frame, epi_dir_image, search_level_, px_cur_);if (res != MatchResult::kSuccess)return res;}//LOG(INFO) << "BACK PROJECT";cur_frame.cam()->backProject3(px_cur_, &f_cur_);f_cur_.normalize();//LOG(INFO) << "f_cur_ NORM: " <<std::setprecision(15)<< f_cur_.x() <<" " << f_cur_.y() << " " << f_cur_.z();//LOG(INFO) << "T_cur_ref: \n" << std::setprecision(15) << T_cur_ref;//LOG(INFO) << "ref_ftr.f: " << std::setprecision(15) << ref_ftr.f.transpose();return matcher_utils::depthFromTriangulation(T_cur_ref, ref_ftr.f, f_cur_, &depth);}elsereturn MatchResult::kFailScore;}

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

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

相关文章

C 语言基础入门:基本数据类型与运算符详解

一、基本数据类型C 语言提供了丰富的基本数据类型&#xff0c;用于存储不同类型的数据&#xff0c;主要包括整数类型、浮点类型和布尔类型。1. 整数类型整数类型用于存储整数&#xff0c;根据是否带符号以及占用存储空间的不同&#xff0c;可进一步细分&#xff1a;类型名占用存…

应用在核电行业的虚拟现实解决方案

核能领域正处于创新与责任的交汇点。尽管核反应堆提供了高效且可持续的能源&#xff0c;但由于放射性物质的危险性&#xff0c;其也带来了独特挑战。虚拟现实&#xff08;VR&#xff09;技术正通过为远程操作、应急响应和放射性物质处理提供先进解决方案&#xff0c;彻底革新这…

CTF Web的数组巧用

PHP数组绕过intval和preg_match的CTF技巧 原题目 <?php include("flag.php"); // 引入flag文件&#xff0c;flag变量在这里定义 show_source("index.php"); // 显示index.php文件的源码&#xff08;方便选手查看&#xff09;// 判断是否通过GET方式传入…

vue2+elementui使用compressorjs压缩上传的图片

首先是npm install compressorjs 然后新建一个compressorjs.js的文件 import Compressor from "compressorjs";// 默认压缩配置 const DEFAULT_COMPRESS_OPTIONS {quality: 0.6, // 默认压缩质量 (0-1)maxWidth: 1920, // 最大宽度maxHeight: 1080, // 最大高度con…

GPIO详解:不仅仅是输入输出那么简单

GPIO详解&#xff1a;不仅仅是输入输出那么简单 “别小看一个小小的引脚&#xff0c;它可是 MCU 世界的社交之门。” &#x1f44b; 先打个招呼&#xff1a;什么是 GPIO&#xff1f; GPIO&#xff0c;全称是 General Purpose Input/Output —— 通用输入输出口。 简单说&…

深度学习5(深层神经网络 + 参数和超参数)

深层神经网络简介 深层神经网络是机器学习中一种重要的模型&#xff0c;它通过增加网络的“深度”&#xff08;即隐藏层的数量&#xff09;来提升模型对复杂数据的表示和学习能力。同浅层类似&#xff0c;也分为三个部分&#xff1a; 输入层&#xff1a;接收原始数据&#xff…

时间复杂度与空间复杂度分析

一、什么是复杂度&#xff1f; 1.1 为什么需要复杂度分析&#xff1f; 假设你写了两个程序来解决同一个问题&#xff0c;如何判断哪个程序更好&#xff1f;我们不能只看运行时间&#xff0c;因为&#xff1a; 不同电脑性能不同同一电脑在不同时刻状态也不同数据规模不同&#x…

上下文工程:从提示词到自动化流程的AI应用新范式

上下文工程&#xff1a;从提示词到自动化流程的 AI 应用新范式 一、背景与概述&#xff1a;从提示词工程到上下文工程的演进 随着大语言模型 (LLM) 技术的飞速发展&#xff0c;AI 应用开发正经历从 “提示词工程”(Prompt Engineering) 到 “上下文工程”(Context Engineerin…

HTML网页应用打包Android App 完整实践指南

技术准备与工具下载 必需工具清单 在开始之前&#xff0c;需要准备以下开发工具&#xff1a; Android Studio官网&#xff1a;https://developer.android.com/studio HBuilderX官网&#xff1a;https://www.dcloud.io/hbuilderx.html 离线SDK下载&#xff1a;https://nati…

简单 Python 爬虫程序设计

爬虫是获取网页数据的常用工具&#xff0c;我们一起来设计一个基于 requests 和 BeautifulSoup 的简单爬虫&#xff0c;它可以获取网页内容并提取文本信息。 所需库安装 首先需要安装两个必要的库&#xff1a; pip install requests beautifulsoup4 完整代码 import reques…

AUTOSAR图解==>AUTOSAR_AP_EXP_ARAComAPI

AUTOSAR ara::com API详解 自适应平台通信API技术详解 目录 1. 概述2. ara::com API架构 2.1 Proxy/Skeleton架构2.2 通信方式2.3 服务连接方式 3. 详细API说明 3.1 Proxy类3.2 Skeleton类3.3 实例标识符3.4 通信组 4. ara::com API状态管理 4.1 服务生命周期4.2 事件与方法状…

Spring Boot + 本地部署大模型实现:优化与性能提升

在将大语言模型集成到 Spring Boot 应用中时&#xff0c;性能优化是一个关键环节。本地部署的大模型虽然提供了强大的功能&#xff0c;但也可能带来一些性能挑战&#xff0c;如响应时间较长、资源占用较高等问题。本文将介绍如何在 Spring Boot 应用中优化本地部署大模型的性能…

QML 鼠标只响应左键处理方法

【1】问题描述 默认情况下qml支持左键&#xff0c;如果需要支持右键&#xff0c;甚至是中键那需要设置 【2】设置方法 MouseArea{ id: mouse anchors.fill: parent property int cx: 0 pr…

北方算网亮相2025全球数字经济大会|共绘数字友好城市建设

7月2日&#xff0c;以“建设数字友好城市”为主题的2025全球数字经济大会隆重开幕&#xff0c;为构建技术与人、城市与生态和谐共进的全球数字经济新生态提供交流合作平台。自7月3日开始&#xff0c;北方算网将在大会集中亮相&#xff0c;先后在多个论坛中发表主题演讲&#xf…

Android PNG/JPG图ARGB_8888/RGB_565‌解码形成Bitmap在物理内存占用大小的简单计算

Android PNG/JPG图ARGB_8888/RGB_565‌解码形成Bitmap在物理内存占用大小的简单计算 Android的Bitmap 是一个用于表示图像数据的核心类&#xff0c;代表一张图片在内存中的存储&#xff0c;Bitmap存储了图像的像素信息数据。 Bitmap把图像理解为像素点组成的二维矩阵&#xff…

力扣网编程55题:跳跃游戏之逆向思维

一. 简介 前面一篇文章使用贪心算法解决 力扣网55题&#xff1a;跳跃游戏&#xff0c;文章如下&#xff1a; 力扣网编程55题&#xff1a;跳跃游戏之贪心算法-CSDN博客 二. 力扣网编程55题&#xff1a;跳跃游戏之逆向思维 给你一个非负整数数组 nums &#xff0c;你最初位于数…

苍穹外卖--day12数据统计-Excel报表

1.工作台1.1实现思路工作台是系统运营的数据看板&#xff0c;并提供快捷操作入口&#xff0c;可以有效提高商家的工作效率。工作台展示的数据&#xff1a;①今日数据②订单管理③菜品总览④套餐总览⑤订单信息名词解释&#xff1a;①营业额&#xff1a;已经完成订单的总金额②有…

鸿蒙应用开发:从网络获取数据

一、网络状态概述上述任一指标的变化均可视为网络状态的改变 二、获取网络信息 创建网络对象 //创建网络对象 //?表示可传可不传 connection.createNetConnection(netSpecifier?:NetSpecifier,timeout?:number):NetConnection;获取默认激活网络及其能力 //获取默认激活网络 …

探索开源虚拟 Excel 函数模块:Python 中的 Excel 功能利器

在数据处理和分析的领域中&#xff0c;Excel 一直是一款备受青睐的工具&#xff0c;它提供了丰富多样的函数&#xff0c;帮助用户高效地完成各种数据操作。而现在&#xff0c;我&#xff08;董翔&#xff09;开发一个基于 Python 的虚拟 Excel 函数模块&#xff0c;它将 Excel …

开源 vGPU 方案 HAMi: corememory 隔离测试

本文主要对开源的 vGPU 方案 HAMi 的 GPU Core&Memory 隔离功能进行测试。 省流&#xff1a; HAMi vGPU 方案提供的 Core&Memory 隔离基本符合预期&#xff1a; Core 隔离&#xff1a;Pod 能使用的算力会围绕设定值波动&#xff0c;但是一段时间内平均下来和申请的 g…