OpenCV每日函数 特征检测和描述模块(7) AGAST类 (提取关键点和计算描述符)

一、概述

        AGAST是一种计算二元决策树(角检测器)的技术,该技术是通用的,并且不必适应新环境。根据定义,它是完整的(没有假阳性或假阴性响应),唯一的参数是内存访问时间来加权各种像素比较。该树对于 AST 掩码中相似像素的某个概率是最优的。

        通过组合两棵树,角点检测器自动适应环境,并为图像区域提供最有效的决策树,只有一个像素延迟(见下图)。因此,它产生了一个角检测器,该检测器速度更快且无需进行训练,同时保持与(完整)FAST 角检测器相同的角响应和可重复性。我们将此检测器称为 AGAST,它代表 Adaptive and Generic Accelerated Segment Test。

        AGAST 所基于的 AST 是由 Edward Rosten(等人)开发的,在AGAST中,只有构建和使用 AST 的决策树的方式得到了显着改进。 AGAST 也使用与 FAST 相同的非最大抑制。

二、类参考

1、函数原型


void cv::AGAST	(	InputArray 	image,
    std::vector< KeyPoint > & 	keypoints,
    int 	threshold,
    bool 	nonmaxSuppression,
    AgastFeatureDetector::DetectorType 	type 
)	

2、参数详解 

image 检测到关键点(角)的灰度图像。
keypoints 在图像上检测到的关键点。
threshold 中心像素的强度与围绕该像素的圆的像素之间的差异阈值。
nonmaxSuppression 如果为真,则对检测到的角点(关键点)应用非最大抑制。
type 论文中定义的四个邻域之一:AgastFeatureDetector::AGAST_5_8、AgastFeatureDetector::AGAST_7_12d、AgastFeatureDetector::AGAST_7_12s、AgastFeatureDetector::OAST_9_16

三、OpenCV源码

1、源码路径

opencv\modules\features2d\src\agast.cpp

2、源码代码

        部分代码

class AgastFeatureDetector_Impl CV_FINAL : public AgastFeatureDetector
{
public:
    AgastFeatureDetector_Impl( int _threshold, bool _nonmaxSuppression, DetectorType _type )
    : threshold(_threshold), nonmaxSuppression(_nonmaxSuppression), type(_type)
    {}

    void detect( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask ) CV_OVERRIDE
    {
        CV_INSTRUMENT_REGION();

        if(_image.empty())
        {
            keypoints.clear();
            return;
        }

        Mat mask = _mask.getMat(), grayImage;
        UMat ugrayImage;
        _InputArray gray = _image;
        if( _image.type() != CV_8U )
        {
            _OutputArray ogray = _image.isUMat() ? _OutputArray(ugrayImage) : _OutputArray(grayImage);
            cvtColor( _image, ogray, COLOR_BGR2GRAY );
            gray = ogray;
        }
        keypoints.clear();
        AGAST( gray, keypoints, threshold, nonmaxSuppression, type );
        KeyPointsFilter::runByPixelsMask( keypoints, mask );
    }

    void set(int prop, double value)
    {
        if(prop == THRESHOLD)
            threshold = cvRound(value);
        else if(prop == NONMAX_SUPPRESSION)
            nonmaxSuppression = value != 0;
        else
            CV_Error(Error::StsBadArg, "");
    }

    double get(int prop) const
    {
        if(prop == THRESHOLD)
            return threshold;
        if(prop == NONMAX_SUPPRESSION)
            return nonmaxSuppression;
        CV_Error(Error::StsBadArg, "");
        return 0;
    }

    void setThreshold(int threshold_) CV_OVERRIDE { threshold = threshold_; }
    int getThreshold() const CV_OVERRIDE { return threshold; }

    void setNonmaxSuppression(bool f) CV_OVERRIDE { nonmaxSuppression = f; }
    bool getNonmaxSuppression() const CV_OVERRIDE { return nonmaxSuppression; }

    void setType(DetectorType type_) CV_OVERRIDE{ type = type_; }
    DetectorType getType() const CV_OVERRIDE{ return type; }

    int threshold;
    bool nonmaxSuppression;
    DetectorType type;
};

Ptr<AgastFeatureDetector> AgastFeatureDetector::create( int threshold, bool nonmaxSuppression, AgastFeatureDetector::DetectorType type )
{
    return makePtr<AgastFeatureDetector_Impl>(threshold, nonmaxSuppression, type);
}

void AGAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, AgastFeatureDetector::DetectorType type)
{
    CV_INSTRUMENT_REGION();

    std::vector<KeyPoint> kpts;

    // detect
    switch(type) {
      case AgastFeatureDetector::AGAST_5_8:
        AGAST_5_8(_img, kpts, threshold);
        break;
      case AgastFeatureDetector::AGAST_7_12d:
        AGAST_7_12d(_img, kpts, threshold);
        break;
      case AgastFeatureDetector::AGAST_7_12s:
        AGAST_7_12s(_img, kpts, threshold);
        break;
      case AgastFeatureDetector::OAST_9_16:
        OAST_9_16(_img, kpts, threshold);
        break;
    }

    cv::Mat img = _img.getMat();

    // score
    int pixel_[16];
    makeAgastOffsets(pixel_, (int)img.step, type);

    std::vector<KeyPoint>::iterator kpt;
    for(kpt = kpts.begin(); kpt != kpts.end(); ++kpt)
    {
        switch(type) {
          case AgastFeatureDetector::AGAST_5_8:
            kpt->response = (float)agast_cornerScore<AgastFeatureDetector::AGAST_5_8>
                (&img.at<uchar>((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold);
            break;
          case AgastFeatureDetector::AGAST_7_12d:
            kpt->response = (float)agast_cornerScore<AgastFeatureDetector::AGAST_7_12d>
                (&img.at<uchar>((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold);
            break;
          case AgastFeatureDetector::AGAST_7_12s:
            kpt->response = (float)agast_cornerScore<AgastFeatureDetector::AGAST_7_12s>
                (&img.at<uchar>((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold);
            break;
          case AgastFeatureDetector::OAST_9_16:
            kpt->response = (float)agast_cornerScore<AgastFeatureDetector::OAST_9_16>
                (&img.at<uchar>((int)kpt->pt.y, (int)kpt->pt.x), pixel_, threshold);
            break;
        }
    }

    // suppression
    if(nonmax_suppression)
    {
        size_t j;
        size_t curr_idx;
        size_t lastRow = 0, next_lastRow = 0;
        size_t num_Corners = kpts.size();
        size_t lastRowCorner_ind = 0, next_lastRowCorner_ind = 0;

        std::vector<int> nmsFlags;
        std::vector<KeyPoint>::const_iterator currCorner;

        currCorner = kpts.begin();

        nmsFlags.resize((int)num_Corners);

        // set all flags to MAXIMUM
        for(j = 0; j < num_Corners; j++)
            nmsFlags[j] = -1;

        for(curr_idx = 0; curr_idx < num_Corners; curr_idx++)
        {
            int t;
            // check above
            if(lastRow + 1 < currCorner->pt.y)
            {
                lastRow = next_lastRow;
                lastRowCorner_ind = next_lastRowCorner_ind;
            }
            if(next_lastRow != currCorner->pt.y)
            {
                next_lastRow = (size_t) currCorner->pt.y;
                next_lastRowCorner_ind = curr_idx;
            }
            if(lastRow + 1 == currCorner->pt.y)
            {
                // find the corner above the current one
                while( (kpts[lastRowCorner_ind].pt.x < currCorner->pt.x)
                    && (kpts[lastRowCorner_ind].pt.y == lastRow) )
                    lastRowCorner_ind++;

                if( (kpts[lastRowCorner_ind].pt.x == currCorner->pt.x)
                 && (lastRowCorner_ind != curr_idx) )
                {
                    size_t w = lastRowCorner_ind;
                    // find the maximum in this block
                    while(nmsFlags[w] != -1)
                        w = nmsFlags[w];

                    if(kpts[curr_idx].response < kpts[w].response)
                        nmsFlags[curr_idx] = (int)w;
                    else
                        nmsFlags[w] = (int)curr_idx;
                }
            }

            // check left
            t = (int)curr_idx - 1;
            if( (curr_idx != 0) && (kpts[t].pt.y == currCorner->pt.y)
             && (kpts[t].pt.x + 1 == currCorner->pt.x) )
            {
                int currCornerMaxAbove_ind = nmsFlags[curr_idx];
                // find the maximum in that area
                while(nmsFlags[t] != -1)
                    t = nmsFlags[t];
                // no maximum above
                if(currCornerMaxAbove_ind == -1)
                {
                    if((size_t)t != curr_idx)
                    {
                        if ( kpts[curr_idx].response < kpts[t].response )
                            nmsFlags[curr_idx] = t;
                        else
                            nmsFlags[t] = (int)curr_idx;
                    }
                }
                else // maximum above
                {
                    if(t != currCornerMaxAbove_ind)
                    {
                        if(kpts[currCornerMaxAbove_ind].response < kpts[t].response)
                        {
                            nmsFlags[currCornerMaxAbove_ind] = t;
                            nmsFlags[curr_idx] = t;
                        }
                        else
                        {
                            nmsFlags[t] = currCornerMaxAbove_ind;
                            nmsFlags[curr_idx] = currCornerMaxAbove_ind;
                        }
                    }
                }
            }
            ++currCorner;
        }

        // collecting maximum corners
        for(curr_idx = 0; curr_idx < num_Corners; curr_idx++)
        {
            if (nmsFlags[curr_idx] == -1)
                keypoints.push_back(kpts[curr_idx]);
        }
    } else
    {
      keypoints = kpts;
    }
}

String AgastFeatureDetector::getDefaultName() const
{
    return(Feature2D::getDefaultName() + ".AgastFeatureDetector");
}

四、效果图像示例

猜你喜欢

转载自blog.csdn.net/bashendixie5/article/details/125332986