FAST 算法:矩形中无角点检测
FAST Algorithm : No Corner Detection in Rectangular shapes
我正在尝试按照 OpenCV 教程在 C++ 中实现我自己的 FAST 算法。作为算法 says :
The pixel p is a corner if there exists a set of n contiguous
pixels in the circle (of 16 pixels) which are all brighter than I_p +
t, or all darker than I_p − t. (Shown as white dash lines in the above
image). n was chosen to be 12.
A high-speed test was proposed to exclude a large number of
non-corners. This test examines only the four pixels at 1, 9, 5 and 13
(First 1 and 9 are tested if they are too brighter or darker. If so,
then checks 5 and 13). If p is a corner, then at least three of these
must all be brighter than I_p + t or darker than I_p − t. If neither
of these is the case, then p cannot be a corner. The full segment test
criterion can then be applied to the passed candidates by examining
all pixels in the circle. This detector in itself exhibits high
performance
我将我的 FAST 输出与阈值为 100 的 OpenCV 的 FAST 输出进行了比较。我意识到我的未能检测到所有角落:
当我将 n 减少到 0 时(尽管 n 应该 >12 以获得最佳结果),我在这种类型的图像测试中得到了(仅)相同的结果,但它仍然没有检测到矩形的角一般而言:
这是我的完整代码:
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <iostream>
#include <opencv2/features2d/features2d.hpp>
using namespace std;
using namespace cv;
#define THRESHOLD 100
/*
** Compares intensity of pixels 1,5,9,13 of the circle surrounding a pixel at (i,j) of an image with its intensity ip.
** If 3 out of 4 satisfy the threshold FAST constraints : bright (i>ip+t) & dark (i<ip-t),
** the pixel at (i,j) is considered a possible key point
*/
bool couldBeKeyPoint(Mat imageIn, int i, int j, int threshold) {
uchar ip = imageIn.at<unsigned char>(i, j); //intensity of the potential key point
uchar ip9 = imageIn.at<unsigned char>(i, j - 3); //intensity of pixel 1 of the surrounding circle
uchar ip1 = imageIn.at<unsigned char>(i, j + 3); //intensity of pixel 9 of the surrounding circle
uchar ip5 = imageIn.at<unsigned char>(i + 3, j); //intensity of pixel 5 of the surrounding circle
uchar ip13 = imageIn.at<unsigned char>(i - 3, j); //intensity of pixel 13 of the surrounding circle
//checking FAST bright constraints on these 4 surrounding pixels
bool b1 = (ip1 >= ip + threshold);
bool b9 = (ip9 >= ip + threshold);
bool b5 = (ip5 >= ip + threshold);
bool b13 = (ip13 >= ip + threshold);
//cout << b1+b9+b5+b13 ;
//at least three of these must all be brighter than I_p + t.
if (b1+b9+b5+b13 >=3)
return true;
bool d1 = (ip1 <= ip - threshold);
bool d9 = (ip9 <= ip - threshold);
bool d5 = (ip5 <= ip - threshold);
bool d13 = (ip13 <= ip - threshold);
//cout << d1+d9+d5+d13 << "\n" ;
//at least three of these must all be darker than I_p − t.
if (d1+d9+d5+d13 >=3)
return true;
return false;
}
bool isKeyPoint(Mat imageIn, int i, int j, int threshold, int numberPixelsToCheck){
cout << "iskeypoint";
vector<unsigned char> pixelSurroundings;
pixelSurroundings.push_back(imageIn.at<unsigned char>(i, j));//the potential key point
pixelSurroundings.push_back(imageIn.at<unsigned char>(i, j + 3));//pixel 1
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 1, j + 3 3));//pixel 2
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 2, j + 2));//pixel 3
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 3, j + 1));//pixel 4
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 3, j));//pixel 5
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 3, j - 1));//pixel 6
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 2, j - 2));//pixel 7
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 1, j - 3));//pixel 8
pixelSurroundings.push_back(imageIn.at<unsigned char>(i, j - 3));//pixel 9
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 1, j - 3));//pixel 10
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 2, j - 2));//pixel 11
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 3, j - 1));//pixel 12
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 3, j));//pixel 13
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 3, j + 1));//pixel 14
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 2, j + 2));//pixel 15
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 1, j + 3));//pixel 16
if (numberPixelsToCheck > 16){
numberPixelsToCheck = 12; //The author have used N=12 in the first version of the algorithm
cout << "Error number of surrounding pixels to check should not exceed 16! Value 12 was used instead. " << std::endl ;
}
unsigned char ip = pixelSurroundings[0];
int brightScore = 0;
int darkScore = 0;
bool d = false,e=false;
for(int j=1;j<pixelSurroundings.size();j++){
unsigned char i = pixelSurroundings[j];
d = (i >= ip + (unsigned char ) threshold);
e = (i <= ip - (unsigned char ) threshold);
brightScore += d;
darkScore += e;
}
cout << darkScore << " DARKSCORE \n";
cout << brightScore << " BRIGHTSCORE \n";
if (darkScore >= numberPixelsToCheck || brightScore >= numberPixelsToCheck){
//cout << darkScore << " DARKSCORE \n";
//cout << brightScore << " BRIGHTSCORE \n";
return true; //the pixel is a key point
}
return false;
}
//renvoit un ensemble de détections
//inputarray image
vector<KeyPoint> FAST(Mat imageIn, vector<KeyPoint> keypoints, int threshold){
if(!imageIn.data ) // Check for invalid input
{
cout << "Could not open or find the image" << std::endl ;
//return {};
}
keypoints.clear();
int i, j, count =0;
for (i = 3; i < imageIn.rows - 3; i++)
{
for (j = 3; j < imageIn.cols - 3; j++)
{
if (couldBeKeyPoint(imageIn, i, j, threshold)){
if (isKeyPoint(imageIn, i, j, threshold, 0)){
keypoints.push_back(KeyPoint(j, i ,1));
count++;
cout << "keypoint found at " << i << " " << j << "\n";
}
}
}
}
cout << "NUMBER OF KEYPOINTS :" << keypoints.size() << "\n";
return keypoints;
}
int main(int argc, char** argv){
vector<KeyPoint> keypointsMyFast;
vector<KeyPoint> keypointsOpenCvFast;
Mat src, destMyFast, destOpenCvFast;
//src= imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
//src= imread(argv[1], CV_8UC3);
src= imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
imshow( "ORGINAL",src);
waitKey(1);
keypointsMyFast = FAST(src, keypointsMyFast,THRESHOLD);
drawKeypoints(src, keypointsMyFast, destMyFast, Scalar(255,0,0));
imshow( "MYFAST",destMyFast);
waitKey(1);
FAST(src,keypointsOpenCvFast,THRESHOLD,false);
cout << "NUMBER OF open cv KEYPOINTS :" << keypointsOpenCvFast.size() << "\n";
drawKeypoints(src, keypointsOpenCvFast, destOpenCvFast, Scalar(255,0,0));
imshow( "Display window",destOpenCvFast);
waitKey(0);
}
知道什么会导致算法无法检测矩形角点吗?
特别是:如何使用 imread
正确加载图像? (改变第二个参数给出不同的结果)
非常感谢
问题出现在初始的 couldBeKeyPoint 函数中。此函数检查顶部、底部、左侧、右侧位置的候选关键点位置,如果中心点 bright/darker 比周围点中的 3 个要 bright/darker 则 returns 为真。
这个假设对于直角正方形或矩形不成立,因为 square/rectangle 的边永远不会满足条件。您需要通过减少周围点的数量来放宽函数的条件以满足2.
我正在尝试按照 OpenCV 教程在 C++ 中实现我自己的 FAST 算法。作为算法 says :
The pixel p is a corner if there exists a set of n contiguous pixels in the circle (of 16 pixels) which are all brighter than I_p + t, or all darker than I_p − t. (Shown as white dash lines in the above image). n was chosen to be 12.
A high-speed test was proposed to exclude a large number of non-corners. This test examines only the four pixels at 1, 9, 5 and 13 (First 1 and 9 are tested if they are too brighter or darker. If so, then checks 5 and 13). If p is a corner, then at least three of these must all be brighter than I_p + t or darker than I_p − t. If neither of these is the case, then p cannot be a corner. The full segment test criterion can then be applied to the passed candidates by examining all pixels in the circle. This detector in itself exhibits high performance
我将我的 FAST 输出与阈值为 100 的 OpenCV 的 FAST 输出进行了比较。我意识到我的未能检测到所有角落:
当我将 n 减少到 0 时(尽管 n 应该 >12 以获得最佳结果),我在这种类型的图像测试中得到了(仅)相同的结果,但它仍然没有检测到矩形的角一般而言:
这是我的完整代码:
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <iostream>
#include <opencv2/features2d/features2d.hpp>
using namespace std;
using namespace cv;
#define THRESHOLD 100
/*
** Compares intensity of pixels 1,5,9,13 of the circle surrounding a pixel at (i,j) of an image with its intensity ip.
** If 3 out of 4 satisfy the threshold FAST constraints : bright (i>ip+t) & dark (i<ip-t),
** the pixel at (i,j) is considered a possible key point
*/
bool couldBeKeyPoint(Mat imageIn, int i, int j, int threshold) {
uchar ip = imageIn.at<unsigned char>(i, j); //intensity of the potential key point
uchar ip9 = imageIn.at<unsigned char>(i, j - 3); //intensity of pixel 1 of the surrounding circle
uchar ip1 = imageIn.at<unsigned char>(i, j + 3); //intensity of pixel 9 of the surrounding circle
uchar ip5 = imageIn.at<unsigned char>(i + 3, j); //intensity of pixel 5 of the surrounding circle
uchar ip13 = imageIn.at<unsigned char>(i - 3, j); //intensity of pixel 13 of the surrounding circle
//checking FAST bright constraints on these 4 surrounding pixels
bool b1 = (ip1 >= ip + threshold);
bool b9 = (ip9 >= ip + threshold);
bool b5 = (ip5 >= ip + threshold);
bool b13 = (ip13 >= ip + threshold);
//cout << b1+b9+b5+b13 ;
//at least three of these must all be brighter than I_p + t.
if (b1+b9+b5+b13 >=3)
return true;
bool d1 = (ip1 <= ip - threshold);
bool d9 = (ip9 <= ip - threshold);
bool d5 = (ip5 <= ip - threshold);
bool d13 = (ip13 <= ip - threshold);
//cout << d1+d9+d5+d13 << "\n" ;
//at least three of these must all be darker than I_p − t.
if (d1+d9+d5+d13 >=3)
return true;
return false;
}
bool isKeyPoint(Mat imageIn, int i, int j, int threshold, int numberPixelsToCheck){
cout << "iskeypoint";
vector<unsigned char> pixelSurroundings;
pixelSurroundings.push_back(imageIn.at<unsigned char>(i, j));//the potential key point
pixelSurroundings.push_back(imageIn.at<unsigned char>(i, j + 3));//pixel 1
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 1, j + 3 3));//pixel 2
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 2, j + 2));//pixel 3
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 3, j + 1));//pixel 4
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 3, j));//pixel 5
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 3, j - 1));//pixel 6
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 2, j - 2));//pixel 7
pixelSurroundings.push_back(imageIn.at<unsigned char>(i + 1, j - 3));//pixel 8
pixelSurroundings.push_back(imageIn.at<unsigned char>(i, j - 3));//pixel 9
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 1, j - 3));//pixel 10
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 2, j - 2));//pixel 11
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 3, j - 1));//pixel 12
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 3, j));//pixel 13
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 3, j + 1));//pixel 14
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 2, j + 2));//pixel 15
pixelSurroundings.push_back(imageIn.at<unsigned char>(i - 1, j + 3));//pixel 16
if (numberPixelsToCheck > 16){
numberPixelsToCheck = 12; //The author have used N=12 in the first version of the algorithm
cout << "Error number of surrounding pixels to check should not exceed 16! Value 12 was used instead. " << std::endl ;
}
unsigned char ip = pixelSurroundings[0];
int brightScore = 0;
int darkScore = 0;
bool d = false,e=false;
for(int j=1;j<pixelSurroundings.size();j++){
unsigned char i = pixelSurroundings[j];
d = (i >= ip + (unsigned char ) threshold);
e = (i <= ip - (unsigned char ) threshold);
brightScore += d;
darkScore += e;
}
cout << darkScore << " DARKSCORE \n";
cout << brightScore << " BRIGHTSCORE \n";
if (darkScore >= numberPixelsToCheck || brightScore >= numberPixelsToCheck){
//cout << darkScore << " DARKSCORE \n";
//cout << brightScore << " BRIGHTSCORE \n";
return true; //the pixel is a key point
}
return false;
}
//renvoit un ensemble de détections
//inputarray image
vector<KeyPoint> FAST(Mat imageIn, vector<KeyPoint> keypoints, int threshold){
if(!imageIn.data ) // Check for invalid input
{
cout << "Could not open or find the image" << std::endl ;
//return {};
}
keypoints.clear();
int i, j, count =0;
for (i = 3; i < imageIn.rows - 3; i++)
{
for (j = 3; j < imageIn.cols - 3; j++)
{
if (couldBeKeyPoint(imageIn, i, j, threshold)){
if (isKeyPoint(imageIn, i, j, threshold, 0)){
keypoints.push_back(KeyPoint(j, i ,1));
count++;
cout << "keypoint found at " << i << " " << j << "\n";
}
}
}
}
cout << "NUMBER OF KEYPOINTS :" << keypoints.size() << "\n";
return keypoints;
}
int main(int argc, char** argv){
vector<KeyPoint> keypointsMyFast;
vector<KeyPoint> keypointsOpenCvFast;
Mat src, destMyFast, destOpenCvFast;
//src= imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
//src= imread(argv[1], CV_8UC3);
src= imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
imshow( "ORGINAL",src);
waitKey(1);
keypointsMyFast = FAST(src, keypointsMyFast,THRESHOLD);
drawKeypoints(src, keypointsMyFast, destMyFast, Scalar(255,0,0));
imshow( "MYFAST",destMyFast);
waitKey(1);
FAST(src,keypointsOpenCvFast,THRESHOLD,false);
cout << "NUMBER OF open cv KEYPOINTS :" << keypointsOpenCvFast.size() << "\n";
drawKeypoints(src, keypointsOpenCvFast, destOpenCvFast, Scalar(255,0,0));
imshow( "Display window",destOpenCvFast);
waitKey(0);
}
知道什么会导致算法无法检测矩形角点吗?
特别是:如何使用 imread
正确加载图像? (改变第二个参数给出不同的结果)
非常感谢
问题出现在初始的 couldBeKeyPoint 函数中。此函数检查顶部、底部、左侧、右侧位置的候选关键点位置,如果中心点 bright/darker 比周围点中的 3 个要 bright/darker 则 returns 为真。
这个假设对于直角正方形或矩形不成立,因为 square/rectangle 的边永远不会满足条件。您需要通过减少周围点的数量来放宽函数的条件以满足2.