OpenCV线特征提取

前言

最近想试着在ORB_SLAM2添加线特征,所以先学习了一下如何使用OpenCV提取LSD线特征。

一、OpenCV提取LSD(简单)

OpenCV在imgproc模块实现了一个LineSegmentDetector,实现原理就是常用的LSD算法,使用方法也很简单。

#include <iostream>
#include <string>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

int main() {
	// 换成自己的图像路径
    std::string image_1_dir = "../data/image1.png";
	// 以灰度图读取图像
    cv::Mat image_1 = cv::imread(image_1_dir, cv::IMREAD_GRAYSCALE);
	// 先看看图像有没有读取到
    if(image_1.empty()) {
        std::cout << "Unable to load " << image_1_dir << std::endl;
        return 1;
    }
	// 显示原图像
    cv::imshow("Source Image 1", image_1);
    
    // 创建LSD
    cv::Ptr<cv::LineSegmentDetector> lsd = createLineSegmentDetector(cv::LSD_REFINE_STD);
	
	// 创建一个4维向量的vector,作为后续lsd的输出
    std::vector<cv::Vec4f> lines_1;
    // lsd检测,检测出的线特征以一个4维向量表示
    // 向量中是线段起始端点和终点的坐标值
    // [x1, y1, x2, y2], 1是起始点,2是终点
    lsd->detect(image_1, lines_1);

    // 显示线特征,把原图拷贝下,当然不拷贝也行
    cv::Mat image_output = image_1.clone();
    // 显示线特征用到lsd中的drawSegment函数
    lsd->drawSegments(image_output, lines_1);

    cv::imshow("1", image_output);
    cv::waitKey(0);
    return 0;
}

显示结果
在这里插入图片描述

在这里插入图片描述

二、OpenCV提取LSD(复杂)

上面的方法,线特征只有两个端点的坐标,信息比较简单。而且这里面也没有LBD描述子相关的计算,这个时候,我们可以使用OpenCV_contrib中的line_descriptor模块。
OpenCV一般包含的是基本模块,而OpenCV_contrib模块中还包含了一些扩展模块,这些扩展模块中会包含一些带专利或收费的模块(当然我们用来学习不需要管这个收不收费),而line_descriptor就是在OpenCV_contrib,下面是这个模块的简介

This module shows how to extract line segments from an image by 2 different methods: First segmenting lines with Line Segment Detector LSDDetector and then (or just) using the Binary Descriptor to get the lines and give them a descriptor – BinaryDescriptor. Finally, we can then match line segments using the BinaryDescriptorMatcher class.

如何安装OpenCV_contrib,大家可以参照这个教程,简单点说就是先下载对应版本的OpenCV_contrib,比如我的是3.4.16版本,然后在OpenCV中cmake时可以指定额外模块的路径,把你的OpenCV_contrib的路径输入进入即可,为了方便,通常是直接把OpenCV_contrib放到OpenCV路径里,之后就可以在代码中正常导入line_descriptor了,代码如下

#include <iostream>
#include <string>

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

#include <opencv2/line_descriptor.hpp>

int main() {
    std::string image_1_dir = "../data/image1.png";

    cv::Mat image_1 = cv::imread(image_1_dir, cv::IMREAD_UNCHANGED);

    if(image_1.empty()) {
        std::cout << "Unable to load " << image_1_dir << std::endl;
        return 1;
    }

    cv::imshow("Source Image 1", image_1);
    // 上面读取图像代码和之前一样

    // 创建直线检测器
    cv::Ptr<cv::line_descriptor::LSDDetector> lsd = cv::line_descriptor::LSDDetector::createLSDDetector();
    // 这个看名字是计算描述子的,但其实里面也有直线检测器,但检测结果和上面那个有些区别,底层实现似乎是不一样的
    cv::Ptr<cv::line_descriptor::BinaryDescriptor> lbd = cv::line_descriptor::BinaryDescriptor::createBinaryDescriptor();

    // 存储检测出的直线
    std::vector<cv::line_descriptor::KeyLine> keylines_1;
    // 直线描述子,每一行表示一条直线的描述子
    cv::Mat descriptor_1;

    // 下面这两个都可以检测直线,但是lsd这个接口有金字塔分层和缩放系数的设置,但下面lbd这个没有,估计是不支持分层检测
    // 大家可以试试用这两个不同的检测器检测
    lsd->detect(image_1, keylines_1, 1.2, 1);
//    lbd->detect(image_1, keylines_1);

    // 计算描述子
    lbd->compute(image_1, keylines_1, descriptor_1);

    // 绘制直线,用蓝色绘制
    cv::Mat image_output = image_1.clone();
    cv::line_descriptor::drawKeylines(image_1, keylines_1, image_output, cv::Scalar(255, 0, 0));

    cv::imshow("1", image_output);

    cv::waitKey(0);
    return 0;
}

检测结果如下
在这里插入图片描述

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值