关于OpenCV的学习,敬请关注专栏: 一步步学习OpenCV2
=================分割线=================
原文发布时间:2012年8月18日
=================以下是对原文翻译部分=================
我认为从事对象识别,图像注册和使用关键点提取的其他领域的开发人员和研究人员可以发现这个帖子很有用。最近(从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功能比较报告。
========================分割线==============================