理解线段特征的匹配的距离计算(不是原理方面的理解,是加速方面计算)

先看两段代码(都是计算两个线特征的距离),其中前一段是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;
 }

特点(优点)

  1. 性能极高(比 cv::norm 更快,尤其在大规模匹配时)。
  2. 无 OpenCV 调用开销,完全在 CPU 内部执行。
  3. 用 手写 bit-count 算法(类似于 popcount)。
  4. 设计上假设每个描述子长度为 256 bits (32 bytes)(典型 ORB/BRIEF/BRISK)。

⚠️ 缺点

  1. 不通用:写死了循环 8 次(= 8 × 4 bytes = 32 bytes)。如果描述子长度变化(如 512 bits 的 LDB / FREAK),需要手动改循环次数。
  2. 对 Mat 类型有隐含要求:必须是 CV_32S(即 int32_t),否则指针类型会出错。
  3. 没有输入检查,调试难度大

二)用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); 
}

特点

  1. 简洁、安全、可读性高。
  2. 自动处理不同长度(支持 256, 512 bit 描述子)。
  3. 自动检查类型,避免内存错误。
  4. 调试方便、易扩展。

⚠️ 缺点

  1. 性能略低(调用了 OpenCV 封装函数,会有函数调用开销)。
  2. 在匹配非常多的线特征时(例如上千条线段),比手写版本慢 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

这只是工程方面理解,希望对大家有用

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐