# GFTTDetector In OpenCV

这是使用imgproc.hpp中的goodFeaturesToTrack函数封装的类,其使用和goodFeaturesToTrack函数基本相似。

# GFTTDetector功能

GFTTDetector类用来提取对线的角点特征,角点检测(Corner Detection)也称为特征点检测,是图像处理和计算机视觉中用来获取图像局部特征点的一类方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模以及目标识别等领域中。

最常用的角点检测算法有梯度直方图HOG,Haar特征和Haris角点检测,上面这三种在之前都介绍过,

1.Haar特征 (opens new window)
2.梯度直方图HOG (opens new window)
3.HS角点检测 (opens new window)

这些方法都是使用了图像中的局部信息提取了局部特征。

如同在HS角点检测中介绍的,图像灰度的变化可以分成3种情况:

  • 在两个方向上灰度变化剧烈,角点
  • 在单个方向上灰度变化剧烈,边
  • 在两个方向上灰度变化都不大,平坦区域

如下图:

对于给定图像上一个宽高为patch窗口,计算该窗口平移一段微小距离时各个像素值差的平方和为:

E(μ,v)=xwyhω(x,y)[I(x+μ,y+v)I(x,y)]2

omega(x,y)是窗口函数,可以使用窗口中的像素均值或者使用高斯函数。

根据泰勒公式展开上式:

I(x+μ,y+v)I(x,y)+Ix(x,y)μ+Iy(x,y)v

故,

E(μ,v)[u,v]M(x,y)[μv]

其中,

M(x,y)=[Ix2IxIyIxIyIy2]=[ACCB]

的定义可以看到,对于角点有左右边沿或上下边沿组成,总有一个近似于0,因此对于角点有,

M(x,y)=[Ix200Iy2]

这里考虑的是左右上下边沿与图像高宽平行组成的角点,对于旋转和缩放的角点需要单独讨论。

在判断是否为角点时,为了减少运算量,通常并不会计算M的特征值,而使用M的行列式和迹来计算:

R=det(M)α(trace(M))2

是一个经验常数,用来控制检测到角点的数量,值越小检测到的角点越多,相应的质量也会下降。

  • 都很大时,取较大正值,说明是角点
  • 一大一小时,取较大负值,说明是边
  • 都很小时,绝对值较小,说明是平坦区域

GFTTDetector中使用的是Shi-Tomasi 角点检测器,其直接使用作为角点的度量,减少了超参数和运算量。

# OpenCV中GFTTDetector类

调用GFTTDetector类中的静态函数create可以创建cv::Ptr<GFTTDetector>

create函数参数为:


static Ptr<GFTTDetector> cv::GFTTDetector::create	(	
    int 	maxCorners = 1000,
    double 	qualityLevel = 0.01,
    double 	minDistance = 1,
    int 	blockSize = 3,
    bool 	useHarrisDetector = false,
    double 	k = 0.04 
)		
  • maxCorners控制最多检测到的角点数量
  • qualityLevel控制角的质量水平,例如最好的是1500, qualityLevel0.01,则quality measure小于1500*0.01的将被舍弃
  • minDistance角点之间的最小距离
  • blockSize计算梯度相关矩阵时使用的邻域大小
  • useHarrisDetector是否使用Harris角点检测
  • k,Harris角点检测的超参数

代码示例:

#include <memory>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/features2d.hpp>

class TestGFTTDetector
{
    public:
        typedef std::shared_ptr<TestGFTTDetector> Ptr;
        TestGFTTDetector();
        ~TestGFTTDetector() = default;
        void compute(cv::Mat &image);

    private:
        cv::Ptr<cv::GFTTDetector> gftt_ptr_;
        std::vector<cv::KeyPoint> keypoints_;
};

TestGFTTDetector::TestGFTTDetector()
{
    gftt_ptr_ = cv::GFTTDetector::create(1000, 0.1, 10);
}


void TestGFTTDetector::compute(cv::Mat &image)
{   
    cv::Mat mask(image.size(), CV_8UC1, 255);
    gftt_ptr_->detect(image, keypoints_, mask);
    for(auto &kp : keypoints_) {
        cv::circle(image, kp.pt, 3, cv::Scalar(255, 0, 0));
    }
    std::cout << "keypoints_.size: " << keypoints_.size() << std::endl;
    cv::imshow("gftt_detector_result", image);
    cv::waitKey(0);

    cv::goodFeaturesToTrack()
}

int main(int argc, char **argv)
{
    TestGFTTDetector::Ptr gftt = std::make_shared<TestGFTTDetector>();
    cv::Mat image = cv::imread(argv[1]);
    gftt->compute(image);
    return 0;
}

检测结果如下:

可以看到检测的结果还是很好的,不过中间大六边形上面的两个角点还是没有检测到,感兴趣可以改小的值试一下。

使用的图片在OpenCV代码仓库中opencv-4.5.5/samples/data/blox.jpg

# reference