在opencv4中,SIFT和SURF不在发布的release版本中了,这些方法被放入了opencv_contrib中,如果想使用需要自己编译到opencv,编译方法参考
https://blog.youkuaiyun.com/Gordon_Wei/article/details/85775328
代码实现
void Demo::SURF_demo(Mat &image1, Mat &image2) {
//创建提取特征点方法
Ptr<xfeatures2d::SURF> surf = xfeatures2d::SURF::create(2000);
//Ptr<ORB> surf = ORB::create(2000);
//Ptr<SIFT> surf = SIFT::create(2000);
//特征点
vector<KeyPoint> keyPoint1;
vector<KeyPoint> keyPoint2;
//提取特征点
surf->detect(image1, keyPoint1);
surf->detect(image2, keyPoint2);
//绘制特征点
Mat keyPointImage1, keyPointImage2;
drawKeypoints(image1, keyPoint1, keyPointImage1, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
drawKeypoints(image2, keyPoint2, keyPointImage2, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//namedWindow("kp1", WINDOW_AUTOSIZE);
//namedWindow("kp2", WINDOW_AUTOSIZE);
//imshow("kp1", keyPointImage1);
//imshow("kp2", keyPointImage2);
//提取特征点并计算特征描述子
Mat desp1, desp2;
surf->detectAndCompute(image1, Mat(), keyPoint1, desp1);
surf->detectAndCompute(image2, Mat(), keyPoint2, desp2);
//Struct for DMatch: query descriptor index, train descriptor index, train image index and distance between descriptors.
//int queryIdx –>是测试图像的特征点描述符(descriptor)的下标,同时也是描述符对应特征点(keypoint)的下标。
//int trainIdx –> 是样本图像的特征点描述符的下标,同样也是相应的特征点的下标。
//int imgIdx –>当样本是多张图像的话有用。
//float distance –>代表这一对匹配的特征点描述符(本质是向量)的欧氏距离,数值越小也就说明两个特征点越相像。
vector<DMatch> matches;
if (desp1.type() != CV_32F || desp2.type() != CV_32F) {
desp1.convertTo(desp1, CV_32F);
desp2.convertTo(desp2, CV_32F);
}
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased");
matcher->match(desp1, desp2, matches);
//计算特征点距离的最大值
double maxDist = 0;
for (int i = 0; i < desp1.rows; i++) {
double dist = matches[i].distance;
if (dist > maxDist)
maxDist = dist;
}
//挑选好的匹配点
vector<DMatch>good_matches;
for (int i = 0; i < desp1.rows; i++)
{
if (matches[i].distance < 0.5*maxDist) {
good_matches.push_back(matches[i]);
}
}
Mat imageout;
drawMatches(image1, keyPoint1, image2, keyPoint2, good_matches, imageout);
namedWindow("picture match");
imshow("picture match", imageout);
}
要点解析
- 大致流程
- 获得提取特征点的方法
- 分别为两张图片建立特征点数组
- 特征点匹配
- 计算特征点距离最大值
- 筛选匹配点
- 绘制匹配线段
- 提取特征点方法时,create括号内的参数是Hessian阈值,也是SURF算法的核心。在数学中,Hessian矩阵是一个自变量为向量的实值函数的二阶偏导数组成的方块矩阵,即每一个像素点都可以求出一个2x2的Hessian矩阵,可计算出其行列式detH,可以利用行列式取值正负来判别该点是或不是极值点来将所有点分类。在SURF算法中,选用二阶标准高斯函数作为滤波器,通过特定核间的卷积计算二阶偏导数,从而计算出Hessian矩阵,但是由于特征点需要具备尺度无关性,所以在进行Hessian矩阵构造前,需要对其进行高斯滤波,即与以方差为自变量的高斯函数的二阶导数进行卷积。通过这种方法可以为图像中每个像素计算出其H的行列式的决定值,并用这个值来判别特征点。一般来说,参数越大,得到的特征点越少,但不代表越精准。
- KeyPoint参数,一个为特征点检测而生的数据结构,用于表示特征点
inline KeyPoint::KeyPoint(Point2f _pt, float _size, float _angle, float _response, int _octave, int _class_id) : pt(_pt), size(_size), angle(_angle), response(_response), octave(_octave), class_id(_class_id) {}
pt(x,y):关键点的点坐标;
size():该关键点邻域直径大小;
angle:角度,表示关键点的方向,值为[零,三百六十),负值表示不使用。
response:响应强度
octacv:从哪一层金字塔得到的此关键点。
class_id:当要对图片进行分类时,用class_id对每个关键点进行区分,默认为-1。 -
绘制关键点——drawKeypoints函数。
void drawKeypoints(const Mat&image, const vector& keypoints,Mat& outImage,const Scalar& color=Scalar::all(-1),int flags=DrawMatchesFlags::DEFAULT)
Mat&image:输入图像
vector& keypoints:根据源图像得到的特征点,它是一个输出参数。
Mat& outImage:输出图像,其内容决定于第五个参数标识符flags。
Scalar& color=Scalar::all(-1):关键点的颜色,默认值Scalar::all(-1),表示颜色是随机生成的。。
int flags=DrawMatchesFlags::DEFAULT:绘制关键点的特征标识符,默认值DrawMatchesFlags::DEFAULT。 -
提取特征点并计算特征描述子
detectAndCompute(InputArray image, InputArray mask,&Keypoint,OutputArray image)
InputArray image:输入图像
InputArray mask:mask
&Keypoint:关键点
,OutputArray image:输出图像 -
DMatch,包含四个参数
int queryIdx:是测试图像的特征点描述符(descriptor)的下标,同时也是描述符对应特征点(keypoint)的下标。
int trainIdx:是样本图像的特征点描述符的下标,同样也是相应的特征点的下标。
int imgIdx:当样本是多张图像的话有用。
float distance:代表这一对匹配的特征点描述符(本质是向量)的欧氏距离,数值越小也就说明两个特征点越相像。