今天主要复习了角点检测算法FAST(Feature from Accelerated Segment Test),该算法原理比较简单,检测出的特征点比较多。
该算法的缺点也很明显:
1. 不具备尺度不变性
2. 不具备旋转不变性
ORB特征点检测中专门针对这两个缺点做了改进。
个人认为该算法检测的特征点准确性不高,容易受噪声的干扰,相较于SIFT与SURF算法而言,准确性要低,优点在于检测速度快。
FAST算法的主要步骤:
1. 输入一个合适的阈值Threshold;
2. 读取图像中一个像素点p的亮度值为;
3. 查找该像素点p周围半径为3的Bresenham圆上的16个像素点,Bresenham圆如下图所示:
4. 如果Bresenhan圆上这16个边界像素中有连续n个像素值大于,或小于,则认为该像素点p为特征点,一般取n=12 or 9.
如果对图像中每一像素点进行上述判断,显然很费时,为了加快特征点检测,一般取Bresenham圆上1,9,5,13这四个边界点进行上述特征点判断,如果至少有3个点满足特征点的条件,则再进行上述16个边界点判断,否则就可以判定为非特征点。
FAST特征点容易挤在一起,这时可以通过非极大值抑制的方法来消除小的响应值的特征点,计算步骤如下:
1. 将Bresenhan圆上16个像素值与该像素值进行差值的绝对值求和,作为非极大值抑制的响应值;
2. 删除邻近特征点中响应值较小的特征点。
int Sample_MyFASTBlock::Run()
{
bool bStatus = true;
long debug = 0;
double threshold = 50;
GetValue("Debug", debug);
Mat* pSrcImg = NULL;
GetValue("src image", pSrcImg);
if (pSrcImg == NULL)
{
LOG_ERROR(BLOCK_SAMPLE_TEXTDETECTORSWT, "src image is null!");
goto ERR_EXIT;
}
GetValue("threshold", threshold);
{
if (debug)
imshow("src", *pSrcImg);
Mat gray;
if (pSrcImg->channels() == 3)
cvtColor(*pSrcImg, gray, COLOR_BGR2GRAY);
else
gray = pSrcImg->clone();
if (debug)
imshow("gray", gray);
medianBlur(gray, gray, 5);
if (debug)
imshow("medianblur", gray);
std::vector bresenham = {
Point(0, -3), Point(1, -3),
Point(2, -2),
Point(3, -1), Point(3, 0), Point(3, 1),
Point(2, 2),
Point(1, -3), Point(0, -3), Point(-1, -3),
Point(-2, 2),
Point(-3, 1), Point(-3, 0), Point(-3, 1),
Point(-2, -2),
Point(-1, -3)
};
std::vector features;
for (int row = 3; row < gray.rows - 3; row++)
{
for (int col = 3; col < gray.cols - 3; col++)
{
int gtCount = 0;
int ltCount = 0;
for (int i = 0; i < bresenham.size(); i++)
{
if (gray.at(row + bresenham[i].y, col + bresenham[i].x) > (gray.at(row, col) + threshold))
{
gtCount++;
}
else if (gray.at(row + bresenham[i].y, col + bresenham[i].x) < (gray.at(row, col) - threshold))
{
ltCount++;
}
}
if (gtCount >= 12 || ltCount >= 12)
{
features.push_back(Point(col, row));
}
}
}
Mat result = pSrcImg->clone();
for (int i = 0; i < features.size(); i++)
{
circle(result, features[i], 3, Scalar(255, 0, 0), 1);
}
Mat* pDstImg = new Mat(result);
if (!pDstImg->empty())
{
SetValue("Dst Image", pDstImg);
goto EXIT;
}
}
ERR_EXIT:
bStatus = false;
EXIT:
SetValue("Status", (long)bStatus);
return bStatus;
}
输入参数如下图所示:
输出结果如下图所示:
上述代码完成于个人开发的Opencv软件,结果展示也是截取个人Opencv软件的结果输出,如果有误,欢迎指正,谢谢!
参考博客:
https://www.cnblogs.com/zyly/p/9542164.html