Line Slam 项目中线段匹配里面的计算线段特征距离DescriptorDistance()函数的理解
·
理解线段特征的匹配的距离计算(不是原理方面的理解,是加速方面计算)
先看两段代码(都是计算两个线特征的距离),其中前一段是Line slam的代码(ORB-slam也有类似的代码),后一段代码是用opencv自带的函数来计算两个线特征距离的方法。
一)Line slam的代码(ORB-slam也有类似的代码):
int LSDmatcher::DescriptorDistance(const Mat &a, const Mat &b)
{
const int *pa = a.ptr<int32_t>();
const int *pb = b.ptr<int32_t>();
int dist=0;
for(int i=0; i<8; i++, pa++, pb++)
{
unsigned int v = *pa ^ *pb;
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
dist += (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
return dist;
}
特点(优点)
- 性能极高(比 cv::norm 更快,尤其在大规模匹配时)。
- 无 OpenCV 调用开销,完全在 CPU 内部执行。
- 用 手写 bit-count 算法(类似于 popcount)。
- 设计上假设每个描述子长度为 256 bits (32 bytes)(典型 ORB/BRIEF/BRISK)。
⚠️ 缺点
- 不通用:写死了循环 8 次(= 8 × 4 bytes = 32 bytes)。如果描述子长度变化(如 512 bits 的 LDB / FREAK),需要手动改循环次数。
- 对 Mat 类型有隐含要求:必须是 CV_32S(即 int32_t),否则指针类型会出错。
- 没有输入检查,调试难度大
二)用opencv自带的函数来计算两个线特征距离的方法:
// Descriptor distance using Hamming distance (for binary descriptors)
int LSDmatcher::DescriptorDistance(const cv::Mat& desc1, const cv::Mat& desc2)
{ // Ensure descriptors are of type CV_8U (binary)
if (desc1.type() != CV_8U || desc2.type() != CV_8U)
{
std::cerr << "Error: Descriptors must be binary!" << std::endl; return -1;
}
// Use cv::norm with NORM_HAMMING for binary descriptors
return cv::norm(desc1, desc2, cv::NORM_HAMMING);
}
特点
- 简洁、安全、可读性高。
- 自动处理不同长度(支持 256, 512 bit 描述子)。
- 自动检查类型,避免内存错误。
- 调试方便、易扩展。
⚠️ 缺点
- 性能略低(调用了 OpenCV 封装函数,会有函数调用开销)。
- 在匹配非常多的线特征时(例如上千条线段),比手写版本慢 10–20%
因此这两个版本的 DescriptorDistance() 都能计算二进制描述子的汉明距离(Hamming distance),但适用的场景和性能差别比较明显。综合上述优缺点,可以采用自动选择两个函数的做法:这种“自动切换版本”的设计在工程中非常实用。下面是一个自动选择机制的完整实现示例,它能根据编译宏(例如 USE_FAST_HAMMING)在两种版本之间自由切换:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cassert>
namespace ORB_SLAM3 {
class LSDmatcher {
public:
static int DescriptorDistance(const cv::Mat& a, const cv::Mat& b);
};
int LSDmatcher::DescriptorDistance(const cv::Mat& a, const cv::Mat& b)
{
// 基础检查(两种版本都适用)
assert(a.cols == b.cols && a.rows == b.rows);
assert(a.type() == CV_8U && b.type() == CV_8U);
#ifdef USE_FAST_HAMMING
// -------------------------
// 🔥 高速版本(手写 XOR)
// -------------------------
const int* pa = a.ptr<int32_t>();
const int* pb = b.ptr<int32_t>();
int dist = 0;
// 假设每个描述子为 256 bits(= 32 bytes = 8×int)
for (int i = 0; i < 8; i++, pa++, pb++)
{
unsigned int v = *pa ^ *pb;
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
dist += (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
return dist;
#else
// -------------------------
// 🧩 安全版本(OpenCV 原生)
// -------------------------
return cv::norm(a, b, cv::NORM_HAMMING);
#endif
}
} // namespace ORB_SLAM3
这只是工程方面理解,希望对大家有用
更多推荐



所有评论(0)