三个描述符的比较:SURF,FREAK和BRISK

关于OpenCV的学习,敬请关注专栏: 一步步学习OpenCV2


=================分割线=================


原文发布时间:2012年8月18日

原文地址:https://computer-vision-talks.com/post/2012-08-18-a-battle-of-three-descriptors-surf-freak-and-brisk/


=================以下是对原文翻译部分=================

我认为从事对象识别,图像注册和使用关键点提取的其他领域的开发人员和研究人员可以发现这个帖子很有用。最近(从2.4.2),一个新的特征描述符算法被添加到OpenCV库中。据称FREAK描述符优于ORB和SURF描述符,但速度非常快(与ORB相当)。也有人在我的博客上的评论提到BRISK描述符,这是比SURF更新,更高效。那么,最后我找到一个时间来比较他们,并发表我的研究成果。

介绍

这篇文章与我过去的OpenCV比较报告非常相似虽然这些报告是多年前发表的,但它们还是有些实际的。对于这个测试,我决定从头开始重写整个测试框架。源代码即将可用。但现在,让我解释我做了什么来找到最好的三种算法。将图像转换为描述符的主要目标是什么?从像素域移动到更紧凑的表示形式相同的数据。此外,我们希望我们的表示是旋转和比例不变的(例如,当源图像旋转或缩放时,表示保持不变或略微变化)。SURF,FREAK和BRISK描述符宣称它们是旋转和尺度不变的。

========================分割线==============================

转换

就像在OpenCV比较报告中一样,测试应用程序与测试模式图像一起工作。我们有四个基本的转换:旋转,缩放,模糊和亮度调整。这里是如何旋转转换类看起来像:

class ImageRotationTransformation : public ImageTransformation
{
public:
    ImageRotationTransformation(float startAngleInDeg, float endAngleInDeg, float step, cv::Point2f rotationCenterInUnitSpace)
    : ImageTransformation("Rotation")
    , m_startAngleInDeg(startAngleInDeg)
    , m_endAngleInDeg(endAngleInDeg)
    , m_step(step)
    , m_rotationCenterInUnitSpace(rotationCenterInUnitSpace)
    {
        // Fill the arguments
        for (float arg = startAngleInDeg; arg < = endAngleInDeg; arg += step)
            m_args.push_back(arg);
    }

    virtual std::vector getX() const
    {
        return m_args;
    }

    virtual void transform(float t, const cv::Mat& source, cv::Mat& result) const
    {
        cv::Point2f center(source.cols * m_rotationCenterInUnitSpace.x, source.cols * m_rotationCenterInUnitSpace.y);
        cv::Mat rotationMat = cv::getRotationMatrix2D(center, t, 1);
        cv::warpAffine(source, result, rotationMat, source.size());
    }

private:
    float m_startAngleInDeg;
    float m_endAngleInDeg;
    float m_step;

    cv::Point2f m_rotationCenterInUnitSpace;

    std::vector m_args;
};

其他类型的转换看起来相似。但它显示了这个想法。

========================分割线==============================

FeatureAlgorithm

正如你可能知道的,当处理描述符时我们需要三个组件:

  • 特征检测器 - 从cv :: FeatureDetector派生的类,实现特定的检测算法。例如,cv :: SurfFeatureDetector实现SURF文件中描述的检测算法。
  • 描述符提取器 - 从cv :: DescriptorExtractor派生的类。它从传递的关键点计算描述符。cv :: SurfDescriptorExtractor将计算机的SURF描述符。
  • 描述符匹配器 - cv :: FlannBasedMatcher类的cv :: BFMatcher的一个实例用于匹配两组描述符。我们将这三个对象存储在FeatureAlgorithm类中: 
class FeatureAlgorithm
{
public:
    FeatureAlgorithm(std::string name, cv::FeatureDetector* d, cv::DescriptorExtractor* e, cv::DescriptorMatcher* m);

    std::string name;

    bool knMatchSupported;

    bool extractFeatures(const cv::Mat& image, Keypoints& kp, Descriptors& desc) const;

    void matchFeatures(const Descriptors& train, const Descriptors& query, Matches& matches) const;
    void matchFeatures(const Descriptors& train, const Descriptors& query, int k, std::vector& matches) const;

private:
    cv::FeatureDetector*     detector;
    cv::DescriptorExtractor* extractor;
    cv::DescriptorMatcher*   matcher;
};

========================分割线==============================

测试程序

主要测试功能采用FeatureAlgorithm,Transformation和测试图像。作为输出,我们返回每个运行的匹配统计信息列表。这是一个简短的序列:

  • 将输入图像转换为灰度
  • 检测关键点并从输入灰度图像中提取描述符
  • 使用传递的转换算法生成所有变换的图像
  • 对于每个变换的图像:
    • 检测关键点并提取描述符
    • 匹配列车描述符和查询
    • 使用单应性估计将分段匹配到内点和外点
    • 计算统计数据(消耗时间,匹配百分比,正确匹配的百分比等)主循环使用OpenMP并行,在我的四核酷睿i5上,在测试的同时加载100%的所有内核。特征算法: 
algorithms.push_back(FeatureAlgorithm("SURF/BRISK/BF",
        new cv::SurfFeatureDetector(),
        new cv::BriskDescriptorExtractor(),
        new cv::BFMatcher(cv::NORM_HAMMING, true)));

algorithms.push_back(FeatureAlgorithm("SURF/FREAK/BF",
        new cv::SurfFeatureDetector(),
        new cv::FREAK(),
        new cv::BFMatcher(cv::NORM_HAMMING, true)));

algorithms.push_back(FeatureAlgorithm("SURF/SURF/BF",
        new cv::SurfFeatureDetector(),
        new cv::SurfDescriptorExtractor(),
        new cv::BFMatcher(cv::NORM_L2, true)));

图像转换:
transformations.push_back(new GaussianBlurTransform(9));
transformations.push_back(new BrightnessImageTransform(-127, +127, 10));
transformations.push_back(new ImageRotationTransformation(0, 360, 10, cv::Point2f(0.5f,0.5f)));
transformations.push_back(new ImageScalingTransformation(0.25f, 2.0f, 0.1f));

========================分割线==============================

度量

计算以下指标:

  • 匹配百分比 - 分割匹配的商数计算关键点的最小值,以两个百分数计算。
  • 正确匹配的百分比 - 分配正确匹配的商数以百分比计总匹配数。
  • 匹配比例 - 匹配百分比*正确匹配百分比。在所有图表中,我将使用Y轴的“匹配比率”(百分比)值。
========================分割线==============================

统计

运行所有测试后,我们收集每个转换和算法的统计信息。特定转换算法的报表如下所示:

Argument SURF/BRISK/BF    SURF/FREAK/BF    SURF/SURF/BF
       1           100          88.5965         82.6752
       2           100          86.9608         79.1689
       3           100          85.6069         70.6731
       4           100          85.0897         64.9057
       5           100          83.1528         59.4776
       6           100          85.1648         58.9763
       7           100          88.6447         59.3066
       8           100          94.9109         64.8019
       9           100          95.9707         69.1154

为了制作图表,我使用Google Spreadsheets导入CSV表格并生成图表。您可以在这里找到这个电子表格:  OpenCV 2.4.9功能比较报告

========================分割线==============================

结果



=========================分割线==============================
说明:原博文打开慢,请耐心等待,可能话需要翻墙。
===========================END============================

猜你喜欢

转载自blog.csdn.net/sinat_36264666/article/details/78854152