KAZE局部特征检测与匹配 KAZE是日语音译过来的
AOS 构造尺度空间(非线性方式构造,得到的keypoints也就更准确) 尺度不变性
Hessian矩阵特征点检测
方向指定,基于一阶微分图像 旋转不变性
描述子生成 归一化处理,光照不变性
AKAZE局部特征检测与匹配 A表示Accelerated(加速的)
与SIFT、 SUFR比较:
更加稳定
非线性尺度空间
AKAZE速度更加快
代码
#include "../common/common.hpp"
void main(int argc, char** argv)
{
Mat src = imread(getCVImagesPath("images/test1_3.png"), IMREAD_GRAYSCALE);
imshow("src2-23", src);
// kaze detection
Ptr<KAZE> detector_kaze = KAZE::create(); // KAZE局部特征检测类
vector<KeyPoint> keypoints_kaze; // 保存检测到的特征点
double t1 = getTickCount();
detector_kaze->detect(src, keypoints_kaze, Mat()); // AKAZE局部特征检测
double t2 = getTickCount();
double tkaze = 1000 * (t2 - t1) / getTickFrequency(); // 乘以1000,转换成毫秒
printf("KAZE Time consume(ms) : %f\n", tkaze); // KAZE Time consume(ms) : 1523.385317
Mat keypointImg_kaze;
drawKeypoints(src, keypoints_kaze, keypointImg_kaze, Scalar::all(-1), DrawMatchesFlags::DEFAULT); // 绘制显示
imshow("kaze key points", keypointImg_kaze);
// akaze detection
Ptr<AKAZE> detector_akaze = AKAZE::create(); // AKAZE局部特征检测类,比KAZE速度要快
vector<KeyPoint> keypoints_akaze; // 保存检测到的特征点
t1 = getTickCount();
detector_akaze->detect(src, keypoints_akaze, Mat()); // AKAZE局部特征检测
t2 = getTickCount();
tkaze = 1000 * (t2 - t1) / getTickFrequency(); // 乘以1000,转换成毫秒
printf("AKAZE Time consume(ms) : %f\n", tkaze); // AKAZE Time consume(ms) : 665.136977
Mat keypointImg_akaze;
drawKeypoints(src, keypoints_akaze, keypointImg_akaze, Scalar::all(-1), DrawMatchesFlags::DEFAULT); // 绘制显示
imshow("akaze key points", keypointImg_akaze);
waitKey(0);
}
效果图
代码
#include "../common/common.hpp"
void main(int argc, char** argv)
{
Mat img1 = imread(getCVImagesPath("images/box.png"), IMREAD_GRAYSCALE);
Mat img2 = imread(getCVImagesPath("images/box_in_scene.png"), IMREAD_GRAYSCALE);
imshow("box image", img1);
imshow("scene image", img2);
// extract akaze features
Ptr<AKAZE> detector = AKAZE::create(); // AKAZE局部特征检测类
vector<KeyPoint> keypoints_obj; // 保存检测到的特征点
vector<KeyPoint> keypoints_scene;
Mat descriptor_obj, descriptor_scene; // 保存生成的特征描述子
double t1 = getTickCount();
detector->detectAndCompute(img1, Mat(), keypoints_obj, descriptor_obj); // AKAZE特征检测,并且计算生成特征描述子
detector->detectAndCompute(img2, Mat(), keypoints_scene, descriptor_scene);
cout << "keypoints_obj.size=" << keypoints_obj.size() << endl; // keypoints_obj.size=460
cout << "keypoints_scene.size=" << keypoints_scene.size() << endl; // keypoints_scene.size = 970
// descriptor_obj depth = 0, type = 0, size = [61 x 460] CV_8U 单通道 每个关键点用61来描述?
cout << "descriptor_obj depth=" << descriptor_obj.depth() << ", type=" << descriptor_obj.type() << ", size=" << descriptor_obj.size() << endl;
// descriptor_scene depth = 0, type = 0, size = [61 x 970]
cout << "descriptor_scene depth=" << descriptor_scene.depth() << ", type=" << descriptor_scene.type() << ", size=" << descriptor_scene.size() << endl;
double t2 = getTickCount();
double tkaze = 1000 * (t2 - t1) / getTickFrequency(); // 乘以1000,转换成毫秒
printf("AKAZE Time consume(ms) : %f\n", tkaze); // AKAZE Time consume(ms) : 2205.513233
// matching 还可以使用BFMatcher matcher(NORM_L2);
// 如果直接使用 FlannBasedMatcher matcher; 会报错,因为其默认方式支持的特征描述子的数据类型是float型,而AKAZE的特征描述子的数据类型为uchar
FlannBasedMatcher matcher(new flann::LshIndexParams(20, 10, 2)); // new flann::LshIndexParams(20, 10, 2) 使Flann支持uchar类型的特征匹配
//BFMatcher matcher(NORM_L2);
vector<DMatch> matches;
matcher.match(descriptor_obj, descriptor_scene, matches);
cout << "matches.size=" << matches.size() << endl; // matches.size=460 长度与要查询的特征描述子一致
// draw matches(key points)
Mat akazeMatchesImg;
drawMatches(img1, keypoints_obj, img2, keypoints_scene, matches, akazeMatchesImg);
imshow("akaze match result", akazeMatchesImg);
// 筛选匹配都高的匹配值
vector<DMatch> goodMatches;
double minDist = 100000, maxDist = 0;
for (int i = 0; i < descriptor_obj.rows; i++) {
double dist = matches[i].distance;
if (dist < minDist) {
minDist = dist;
}
if (dist > maxDist) {
maxDist = dist;
}
}
printf("min distance : %f\n", minDist); // min distance : 37.000000
printf("max distance : %f\n", maxDist); // max distance : 168.000000
for (int i = 0; i < descriptor_obj.rows; i++) {
double dist = matches[i].distance;
if (dist < max(1.5*minDist, 0.02)) {
goodMatches.push_back(matches[i]);
}
}
cout << "goodMatches.size=" << goodMatches.size() << endl; // goodMatches.size=11
drawMatches(img1, keypoints_obj, img2, keypoints_scene, goodMatches, akazeMatchesImg, Scalar::all(-1),
Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); // 不绘制单独的点
imshow("good match result", akazeMatchesImg);
Mat drawSinglePoints;
drawMatches(img1, keypoints_obj, img2, keypoints_scene, goodMatches, akazeMatchesImg);
imshow("drawSinglePoints", akazeMatchesImg);
waitKey(0);
}
效果图