KAZE系列笔记:

1.  OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

2.  OpenCV学习笔记(28)KAZE 算法原理与源码分析(二)非线性尺度空间构建

3.  OpenCV学习笔记(29)KAZE 算法原理与源码分析(三)特征检测与描述

4.OpenCV学习笔记(30)KAZE 算法原理与源码分析(四)KAZE特征的性能分析与比较

5.  OpenCV学习笔记(31)KAZE 算法原理与源码分析(五)KAZE的性能优化及与SIFT的比较

KAZE算法资源:

1.  论文:  http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla12eccv.pdf

2.  项目主页:http://www.robesafe.com/personal/pablo.alcantarilla/kaze.html

3.  作者代码:http://www.robesafe.com/personal/pablo.alcantarilla/code/kaze_features_1_4.tar 
(需要boost库,另外其计时函数的使用比较复杂,可以用OpenCV的cv::getTickCount代替)

4.  Computer Vision Talks的评测:http://computer-vision-talks.com/2013/03/porting-kaze-features-to-opencv/

5.  Computer Vision Talks 博主Ievgen Khvedchenia将KAZE集成到OpenCV的cv::Feature2D类,但需要重新编译OpenCV,并且没有实现算法参数调整和按Mask过滤特征点的功能:https://github.com/BloodAxe/opencv/tree/kaze-features

6.  我在Ievgen的项目库中提取出KAZE,封装成继承cv::Feature2D的类,无需重新编译OpenCV,实现了参数调整和Mask过滤的功能:https://github.com/yuhuazou/kaze_opencv (2013-03-28更新,对KAZE代码进行了优化)

7.  Matlab 版的接口程序,封装了1.0版的KAZE代码:https://github.com/vlfeat/vlbenchmarks/blob/unstable/%2BlocalFeatures/Kaze.m

2.3 与其他特征算法的比较

2.3.1 与OpenCV API的融合

KAZE算法作者在其项目主页提供了源码,其中包括KAZE的核心算法库以及KAZE特征的提取、匹配和比较等例程,是基于OpenCV实现的。Computer Vision Talks的博主Ievgen Khvedchenia不久前将KAZE代码融合到OpenCV的cv::Feature2D API中,不过他是OpenCV项目的维护者之一,他的目标是在未来的OpenCV版本中加入KAZE。使用他的KAZE类需要重新编译OpenCV,并且目前只是简单地嵌入、还不能调整KAZE类的参数,也不支持Mask过滤。

因为想尽快测试和比较KAZE算法的性能,又不想重新编译OpenCV,我在Ievgen的项目库中将KAZE相关的代码抽离出来,改造为一个相对独立的cv::KAZE类,继承于cv::Feature2D类。这样就可以方便地在OpenCV中使用,并能够通过一致的接口与其它特征算法进行比较。cv::KAZE类包括如下文件:

[plain]  view plain copy
  1. |--KAZE
  2. |   kaze_features.cpp               // Class that warps KAZE to cv::Feature2D
  3. |   kaze_features.h
  4. |   kaze.cpp                        // Implementation of KAZE
  5. |   kaze.h
  6. |   kaze_config.cpp                 // Configuration variables and options
  7. |   kaze_config.h
  8. |   kaze_ipoint.cpp                 // Class that defines a point of interest
  9. |   kaze_ipoint.h
  10. |   kaze_nldiffusion_functions.cpp  // Functions for non-linear diffusion applications
  11. |   kaze_nldiffusion_functions.h
  12. |   kaze_utils.cpp                  // Some useful functions
  13. |   kaze_utils.h

其中kaze_feature.h和kaze_feature.cpp是继承cv::Feature2D的cv::KAZE类,通过这个类将KAZE核心算法库与OpenCV的Feature2D类关联起来。其具体代码如下:

[cpp]  view plain copy
  1. #ifndef _KAZE_FEATURES_H_
  2. #define _KAZE_FEATURES_H_
  3. // Extract from ..\opencv\modules\features2d\src\precomp.hpp
  4. //
  5. #ifdef HAVE_CVCONFIG_H
  6. #include "cvconfig.h"
  7. #endif
  8. #include "opencv2/features2d/features2d.hpp"
  9. #include "opencv2/imgproc/imgproc.hpp"
  10. #include "opencv2/imgproc/imgproc_c.h"
  11. #include "opencv2/core/internal.hpp"
  12. #include <algorithm>
  13. #ifdef HAVE_TEGRA_OPTIMIZATION
  14. #include "opencv2/features2d/features2d_tegra.hpp"
  15. #endif
  16. //
  17. #include "kaze_config.h"
  18. /*!
  19. KAZE features implementation.
  20. !! Note that it has NOT been warped to cv::Algorithm in oder to avoid rebuilding OpenCV
  21. So most functions of cv::Algorithm can not be used in cv::KAZE
  22. http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla12eccv.pdf
  23. */
  24. namespace cv
  25. {
  26. class CV_EXPORTS_W KAZE : public Feature2D
  27. {
  28. public:
  29. CV_WRAP explicit KAZE();
  30. KAZE(toptions &_options);
  31. // returns the descriptor size in bytes
  32. int descriptorSize() const;
  33. // returns the descriptor type
  34. int descriptorType() const;
  35. // Compute the KAZE features and descriptors on an image
  36. void operator()( InputArray image, InputArray mask, vector<KeyPoint>& keypoints,
  37. OutputArray descriptors, bool useProvidedKeypoints=false ) const;
  38. // Compute the KAZE features with mask
  39. void operator()(InputArray image, InputArray mask, vector<KeyPoint>& keypoints) const;
  40. // Compute the KAZE features and descriptors on an image WITHOUT mask
  41. void operator()(InputArray image, vector<KeyPoint>& keypoints, OutputArray descriptors) const;
  42. //AlgorithmInfo* info() const;
  43. protected:
  44. void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;
  45. // !! NOT recommend to use because KAZE descriptors ONLY work with KAZE features
  46. void computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) const;
  47. CV_PROP_RW int nfeatures;
  48. private:
  49. toptions options;
  50. };
  51. typedef KAZE KazeFeatureDetector;
  52. //typedef KAZE KazeDescriptorExtractor; // NOT available because KAZE descriptors ONLY work with KAZE features
  53. }
  54. #endif
[cpp]  view plain copy
  1. /*********************************************************************
  2. * Software License Agreement (BSD License)
  3. *
  4. *  Copyright (c) 2009, Willow Garage, Inc.
  5. *  All rights reserved.
  6. *
  7. *  Redistribution and use in source and binary forms, with or without
  8. *  modification, are permitted provided that the following conditions
  9. *  are met:
  10. *
  11. *   * Redistributions of source code must retain the above copyright
  12. *     notice, this list of conditions and the following disclaimer.
  13. *   * Redistributions in binary form must reproduce the above
  14. *     copyright notice, this list of conditions and the following
  15. *     disclaimer in the documentation and/or other materials provided
  16. *     with the distribution.
  17. *   * Neither the name of the Willow Garage nor the names of its
  18. *     contributors may be used to endorse or promote products derived
  19. *     from this software without specific prior written permission.
  20. *
  21. *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29. *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. *  POSSIBILITY OF SUCH DAMAGE.
  33. *********************************************************************/
  34. /** Authors: Ievgen Khvedchenia */
  35. /** Modified: Yuhua Zou, 2013-03-20 */
  36. #include <iterator>
  37. #include "kaze_features.h"
  38. #include "kaze.h"
  39. #define DEGREE_TO_RADIAN(x) ((x) * CV_PI / 180.0)
  40. #define RADIAN_TO_DEGREE(x) ((x) * 180.0 / CV_PI)
  41. namespace cv
  42. {
  43. /***
  44. *  Convertions between cv::Keypoint and KAZE::Ipoint
  45. */
  46. static inline void convertPoint(const cv::KeyPoint& kp, Ipoint& aux)
  47. {
  48. aux.xf = kp.pt.x;
  49. aux.yf = kp.pt.y;
  50. aux.x = fRound(aux.xf);
  51. aux.y = fRound(aux.yf);
  52. //cout << "SURF size: " << kpts_surf1_[i].size*.5 << endl;
  53. aux.octave = kp.octave;
  54. // Get the radius for visualization
  55. aux.scale = kp.size*.5/2.5;
  56. aux.angle = DEGREE_TO_RADIAN(kp.angle);
  57. //aux.descriptor_size = 64;
  58. }
  59. static inline void convertPoint(const Ipoint& src, cv::KeyPoint& kp)
  60. {
  61. kp.pt.x = src.xf;
  62. kp.pt.y = src.yf;
  63. kp.angle    = RADIAN_TO_DEGREE(src.angle);
  64. kp.response = src.dresponse;
  65. kp.octave = src.octave;
  66. kp.size = src.scale;
  67. }
  68. /***
  69. *  runByPixelsMask() for KAZE Ipoint
  70. */
  71. class MaskPredicate
  72. {
  73. public:
  74. MaskPredicate( const Mat& _mask ) : mask(_mask) {}
  75. bool operator() (const Ipoint& key_pt) const
  76. {
  77. return mask.at<uchar>( (int)(key_pt.yf + 0.5f), (int)(key_pt.xf + 0.5f) ) == 0;
  78. }
  79. private:
  80. const Mat mask;
  81. MaskPredicate& operator=(const MaskPredicate&);
  82. };
  83. void runByPixelsMask( std::vector<Ipoint>& keypoints, const Mat& mask )
  84. {
  85. if( mask.empty() )
  86. return;
  87. keypoints.erase(std::remove_if(keypoints.begin(), keypoints.end(), MaskPredicate(mask)), keypoints.end());
  88. }
  89. /***
  90. *  Implementation of cv::KAZE
  91. */
  92. KAZE::KAZE()
  93. {
  94. }
  95. KAZE::KAZE(toptions &_options)
  96. {
  97. options = _options;
  98. }
  99. int KAZE::descriptorSize() const
  100. {
  101. return options.extended ? 128 : 64;
  102. }
  103. int KAZE::descriptorType() const
  104. {
  105. return CV_32F;
  106. }
  107. void KAZE::operator()(InputArray _image, InputArray _mask, vector<KeyPoint>& _keypoints,
  108. OutputArray _descriptors, bool useProvidedKeypoints) const
  109. {
  110. bool do_keypoints = !useProvidedKeypoints;
  111. bool do_descriptors = _descriptors.needed();
  112. if( (!do_keypoints && !do_descriptors) || _image.empty() )
  113. return;
  114. cv::Mat img1_8, img1_32;
  115. // Convert to gray scale iamge and float image
  116. if (_image.getMat().channels() == 3)
  117. cv::cvtColor(_image, img1_8, CV_RGB2GRAY);
  118. else
  119. _image.getMat().copyTo(img1_8);
  120. img1_8.convertTo(img1_32, CV_32F, 1.0/255.0,0);
  121. // Construct KAZE
  122. toptions opt = options;
  123. opt.img_width = img1_32.cols;
  124. opt.img_height = img1_32.rows;
  125. ::KAZE kazeEvolution(opt);
  126. // Create nonlinear scale space
  127. kazeEvolution.Create_Nonlinear_Scale_Space(img1_32);
  128. // Feature detection
  129. std::vector<Ipoint> kazePoints;
  130. if (do_keypoints)
  131. {
  132. kazeEvolution.Feature_Detection(kazePoints);
  133. if (!_mask.empty())
  134. {
  135. runByPixelsMask(kazePoints, _mask.getMat());
  136. }
  137. }
  138. else
  139. {
  140. kazePoints.resize(_keypoints.size());
  141. for (size_t i = 0; i < kazePoints.size(); i++)
  142. {
  143. convertPoint(_keypoints[i], kazePoints[i]);
  144. }
  145. }
  146. // Descriptor generation
  147. if (do_descriptors)
  148. {
  149. kazeEvolution.Feature_Description(kazePoints);
  150. cv::Mat& descriptors = _descriptors.getMatRef();
  151. descriptors.create(kazePoints.size(), descriptorSize(), descriptorType());
  152. for (size_t i = 0; i < kazePoints.size(); i++)
  153. {
  154. std::copy(kazePoints[i].descriptor.begin(), kazePoints[i].descriptor.end(), (float*)descriptors.row(i).data);
  155. }
  156. }
  157. // Transfer from KAZE::Ipoint to cv::KeyPoint
  158. if (do_keypoints)
  159. {
  160. _keypoints.resize(kazePoints.size());
  161. for (size_t i = 0; i < kazePoints.size(); i++)
  162. {
  163. convertPoint(kazePoints[i], _keypoints[i]);
  164. }
  165. }
  166. }
  167. void KAZE::operator()(InputArray image, InputArray mask, vector<KeyPoint>& keypoints ) const
  168. {
  169. (*this)(image, mask, keypoints, noArray(), false);
  170. }
  171. void KAZE::operator()(InputArray image, vector<KeyPoint>& keypoints, OutputArray descriptors) const
  172. {
  173. (*this)(image, noArray(), keypoints, descriptors, false);
  174. }
  175. void KAZE::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const
  176. {
  177. (*this)(image, mask, keypoints, noArray(), false);
  178. }
  179. void KAZE::computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors) const
  180. {
  181. (*this)(image, Mat(), keypoints, descriptors, false);       // Regenerate keypoints no matter keypoints is empty or not
  182. }
  183. }

下面是基于cv::KAZE类的特征提取与图像匹配例程及结果图:

[cpp]  view plain copy
  1. // KazeOpenCV.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "predep.h"
  4. #include "opencv2/imgproc/imgproc.hpp"
  5. #include "opencv2/highgui/highgui.hpp"
  6. #include "opencv2/calib3d/calib3d.hpp"
  7. #include "KAZE/kaze_features.h"
  8. #pragma comment( lib, cvLIB("core") )
  9. #pragma comment( lib, cvLIB("imgproc") )
  10. #pragma comment( lib, cvLIB("highgui") )
  11. #pragma comment( lib, cvLIB("flann") )
  12. #pragma comment( lib, cvLIB("features2d") )
  13. #pragma comment( lib, cvLIB("calib3d") )
  14. using namespace std;
  15. using namespace cv;
  16. int main(int argc, char** argv[])
  17. {
  18. Mat img_1 = imread("box.png");
  19. Mat img_2 = imread("box_in_scene.png");
  20. std::vector<KeyPoint> keypoints_1, keypoints_2;
  21. Mat descriptors_1, descriptors_2;
  22. toptions opt;
  23. opt.extended = true;        // 1 - 128-bit vector, 0 - 64-bit vector, default: 0
  24. opt.verbosity = true;       // 1 - show detail information while caculating KAZE, 0 - unshow, default: 0
  25. KAZE detector_1(opt);
  26. KAZE detector_2(opt);
  27. double t2 = 0.0, t1 = 0.0, tkaze = 0.0;
  28. int64 start_t1 = cv::getTickCount();
  29. //-- Detect keypoints and calculate descriptors
  30. detector_1(img_1, keypoints_1, descriptors_1);
  31. detector_2(img_2, keypoints_2, descriptors_2);
  32. t2 = cv::getTickCount();
  33. tkaze = 1000.0 * (t2 - start_t1) / cv::getTickFrequency();
  34. cout << "\n\n-- Total detection time (ms): " << tkaze << endl;
  35. printf("-- Keypoint number of img_1 : %d \n", keypoints_1.size() );
  36. printf("-- Keypoint number of img_2 : %d \n", keypoints_2.size() );
  37. //-- Matching descriptor vectors using FLANN matcher
  38. FlannBasedMatcher matcher;
  39. vector< DMatch > matches;
  40. matcher.match( descriptors_1, descriptors_2, matches );
  41. double max_dist = 0; double min_dist = 100;
  42. //-- Quick calculation of max and min distances between keypoints
  43. for( int i = 0; i < descriptors_1.rows; i++ )
  44. {
  45. double dist = matches[i].distance;
  46. if( dist < min_dist ) min_dist = dist;
  47. if( dist > max_dist ) max_dist = dist;
  48. }
  49. //-- Find initial good matches (i.e. whose distance is less than 2*min_dist )
  50. vector< DMatch > good_matches, inliers;
  51. for( int i = 0; i < descriptors_1.rows; i++ )
  52. {
  53. if( matches[i].distance < 2*min_dist )
  54. {
  55. good_matches.push_back( matches[i]);
  56. }
  57. }
  58. cout << "-- Computing homography (RANSAC)..." << endl;
  59. //-- Get the keypoints from the good matches
  60. vector<Point2f> points1( good_matches.size() );
  61. vector<Point2f> points2( good_matches.size() );
  62. for( size_t i = 0; i < good_matches.size(); i++ )
  63. {
  64. points1[i] = keypoints_1[ good_matches[i].queryIdx ].pt;
  65. points2[i] = keypoints_2[ good_matches[i].trainIdx ].pt;
  66. }
  67. //-- Computing homography (RANSAC) and find inliers
  68. vector<uchar> flags(points1.size(), 0);
  69. Mat H = findHomography( points1, points2, CV_RANSAC, 3.0, flags );
  70. //cout << H << endl << endl;
  71. for (int i = 0; i < good_matches.size(); i++)
  72. {
  73. if (flags[i])
  74. {
  75. inliers.push_back( good_matches[i] );
  76. }
  77. }
  78. //-- Draw Keypoints
  79. Mat img_1k, img_2k;
  80. drawKeypoints(img_1, keypoints_1, img_1k, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
  81. drawKeypoints(img_2, keypoints_2, img_2k, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
  82. //-- Draw inliers
  83. Mat img_matches;
  84. drawMatches( img_1, keypoints_1, img_2, keypoints_2,
  85. inliers, img_matches, Scalar::all(-1), Scalar::all(-1),
  86. vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
  87. printf("-- Number of Matches : %d \n", good_matches.size() );
  88. printf("-- Number of Inliers : %d \n", inliers.size() );
  89. printf("-- Match rate : %f \n", inliers.size() / (float)good_matches.size() );
  90. //-- Localize the object
  91. //-- Get the corners from the image_1 ( the object to be "detected" )
  92. vector<Point2f> obj_corners;
  93. obj_corners.push_back( Point2f(0,0) );
  94. obj_corners.push_back( Point2f(img_1.cols,0) );
  95. obj_corners.push_back( Point2f(img_1.cols,img_1.rows) );
  96. obj_corners.push_back( Point2f(0,img_1.rows) );
  97. if (!H.empty())
  98. {
  99. vector<Point2f> scene_corners;
  100. perspectiveTransform(obj_corners, scene_corners, H);
  101. //-- Draw lines between the corners (the mapped object in the scene - image_2 )
  102. int npts = scene_corners.size();
  103. for (int i=0; i<npts; i++)
  104. line( img_matches, scene_corners[i] + Point2f( img_1.cols, 0),
  105. scene_corners[(i+1)%npts] + Point2f( img_1.cols, 0), Scalar(0,0,255), 2 );
  106. }
  107. //-- Show detected matches
  108. cout << "-- Show detected matches." << endl;
  109. namedWindow("Image 1",CV_WINDOW_NORMAL);
  110. namedWindow("Image 2",CV_WINDOW_NORMAL);
  111. namedWindow("Good Matches",CV_WINDOW_NORMAL);
  112. imshow( "Image 1", img_1k );
  113. imshow( "Image 2", img_2k );
  114. imshow( "Good Matches", img_matches );
  115. waitKey(0);
  116. destroyAllWindows();
  117. return 0;
  118. }

2.3.2 KAZE特征的性能测试与比较

KAZE论文中给出了若干实验图表数据,与SURF、SIFT和STAR相比,KAZE有更好的尺度和旋转不变性,并且稳定、可重复检测。主要的实验包括:

(1)   重复检测试验

这里主要从旋转缩放、视角变换、噪声干扰、模糊图像、压缩图像等方面进行了测试,可以看出KAZE的可重复性明显优于其它特征。

(2)   特征检测与匹配试验

这里也是从旋转缩放、视角变换、噪声干扰、模糊图像、压缩图像等方面进行了测试,给出了特征匹配的Precision-Recall图。使用的匹配算法是最近邻匹配。这里可以看出,在图像模糊、噪声干扰和压缩重构等造成的信息丢失的情况下,KAZE特征的鲁棒性明显优于其它特征。

(3)   表面形变目标的特征匹配

这里可以看出基于g2传导函数的KAZE特征性能最好。

(4)   检测效率测试

这里可以看出KAZE的特征检测时间高于SURF和STAR,但与SIFT相近。这里比较花时间的是非线性尺度空间的构建。

作者提出通过多线程并行计算进行AOS求解的方法来加快运行速度,在实现代码中,他们用boost/thread库进行AOS求解和寻找局部极大值点。不过我通过测试发现这并没有明显提高运行速度,可能是因为他们的代码中,分发的多个线程最后要用thread.join()等待所有计算线程结束,然后才能继续后续运算。这个join的使用反而可能会降低运行速度。

Computer Vision Talks博客不久前对KAZE算法进行了评测,并与其它特征进行了性能比较。这里我根据Ievgen在github上的OpenCV-Features-Comparison代码进行了更深入的测试,进一步显示了KAZE特征在尺度缩放、旋转变换、亮度变化和高斯模糊等情况下的优良性能。

(1) Percent of correct matches

(2) Percent of matches

(3) Match ratio

(4) Mean distance

(5) Homography error

不过KAZE在运行时间上的短板的确很明显,远高于其他特征。特别是,论文的实验显示KAZE和SIFT的检测速度相差并不大。但在我的实验中,KAZE的检测时间是SIFT的10倍,而且SIFT比SURF还快一倍!这可能是OpenCV的实现代码中对SIFT做了较大的优化。具体还需要再研究下OpenCV的代码。

最后分享一下上述图表的Matlab代码:

[plain]  view plain copy
  1. %%
  2. % MATLAB script for the visualization of the results of OpenCV-Features-Comparison
  3. % Copyright (c) by Yuhua Zou.
  4. % Email: yuhuazou AT gmail DOT com OR chenyusiyuan AT 126 DOT com
  5. %
  6. close all;
  7. clear all;
  8. clc;
  9. % workroot: directory which contains files as follows:
  10. %     HomographyError.txt
  11. %     MatchingRatio.txt
  12. %     MeanDistance.txt
  13. %     PercentOfCorrectMatches.txt
  14. %     PercentOfMatches.txt
  15. %     Performance.txt
  16. %
  17. workroot='.\5\';
  18. files=dir([workroot,'*.txt']);
  19. % use the file name as the figure name, stored in a cell 'nameFigure'
  20. nameFigure = cell(1,length(files));
  21. for i=1:length(files),
  22. % get file name and create a correspoinding figure
  23. filename = files(i,1).name;
  24. nameFigure{i} = filename(1:end-4);
  25. figure('Name',nameFigure{i},'Position',[20 40 1240 780]);
  26. % initialize 2 cells to store title name and legends of each plot
  27. nameTitle{1} = '';
  28. nameLegend{1} = '';
  29. % open file
  30. file = fullfile(workroot,filename);
  31. fid = fopen(file,'r');
  32. % process 'Performance.txt' individually
  33. if strcmp(nameFigure{i},'Performance') ,
  34. nl = 0;
  35. data = 0;
  36. %% analyze each line
  37. tline = fgetl(fid);
  38. while ischar(tline),
  39. nl = nl + 1;
  40. tline(tline == '"') = '';
  41. if nl == 1,
  42. nameTitle{ 1 } = tline;
  43. elseif nl == 2,
  44. args = regexp(tline,'\t','split');
  45. nameLegend = args(2:end);
  46. elseif ~isempty(tline),
  47. args = regexp(tline,'\t','split');
  48. cols = length(args) - 1;
  49. tick = args{1};
  50. nameTick{nl-2} = tick;
  51. for n = 1:cols, data(nl-2,n) = str2num( args{n+1} ); end
  52. end
  53. tline = fgetl(fid);
  54. end
  55. % plotting
  56. for k=1:2,
  57. subplot(2,1,k);
  58. [data_sorted,idx] = sort(data(:,k),'ascend');
  59. h = barh( data_sorted ); % get the handle to change bar color
  60. xlabel('Time (ms)'); ylabel('Algorithms');
  61. title(nameLegend{ k }, 'FontWeight', 'bold');
  62. set(gca, 'yticklabel', nameTick(idx), 'FontSize', 7);
  63. %             set(gca,'yticklabel','','FontSize',7); % unshow y-axis ticks
  64. %% attach the value to the right side of each bar
  65. x = get(h, 'XData');
  66. y = get(h, 'YData');
  67. horiGap = 0.01 * ( max(y) - min(y) );
  68. for c=1:length(x),
  69. text( y(c) + horiGap, x(c), num2str(y(c), '%0.3f'),...
  70. 'HorizontalAlignment','left','VerticalAlignment','middle',...
  71. 'FontSize',7);
  72. end
  73. %% Change the color of each bar
  74. ch = get(h,'Children'); % get children of the bar group
  75. fvd = get(ch,'Faces'); % get faces data
  76. fvcd = get(ch,'FaceVertexCData'); % get face vertex cdata
  77. %             [zs, izs] = sortrows(datak,1); % sort the rows ascending by first columns
  78. for c = 1:length(data_sorted)
  79. fvcd(fvd(c,:)) = idx(c); % adjust the face vertex cdata to be that of the row
  80. end
  81. set(ch,'FaceVertexCData',fvcd) % set to new face vertex cdata
  82. % you can search 'FaceVertexCData' in MATLAB Help for more info.
  83. end
  84. else
  85. %% process other documents
  86. nDataRow = 0;   % rows of numerical data in each plot
  87. nPlot = 0;      % number of plots
  88. data{1} = 0;    % all numerical data in current document
  89. %% analyze each line
  90. tline = fgetl(fid);
  91. while ischar(tline) && ~strcmp(tline, -1),
  92. % split the line into strings by '\t'
  93. args = regexp(tline,'\t','split');
  94. if strcmp(args{end},''), args = args(1:end-1); end; % remove the last empty one
  95. % the line which contains only one string
  96. % is recognized as the beginning of a new plot
  97. % the string is stored as plot title
  98. % which represents the transformation type
  99. if length(args) == 1,
  100. nDataRow = 0;
  101. nPlot = nPlot + 1;
  102. tline(tline == '"') = '';
  103. nameTitle{ nPlot } = tline;
  104. else
  105. % the line with several '"'s under the 'plot title' line
  106. % stores legends of the plot
  107. % which represent feature methods
  108. if ~isempty( find( tline=='"', 1 ) ),
  109. tline(tline == '"') = '';
  110. nameLegend{ nPlot } = args(2:end);
  111. else
  112. % the line without '""'s contains numerical data
  113. % which represent experiment data
  114. nDataRow = nDataRow + 1;
  115. for n = 1:length(args),
  116. data{ nPlot }(nDataRow,n) = str2double( args{n} );
  117. end
  118. end
  119. end
  120. tline = fgetl(fid);
  121. end
  122. %% plotting
  123. cmap = colormap( jet( length( nameLegend{1} ) ) ); % cmap: table of line color
  124. for p = 1:nPlot,
  125. subplot(ceil(nPlot/2), 2, p);
  126. xdata = data{p}(:,1);
  127. ydata = data{p}(:,2:end);
  128. for r=1:size(ydata,2)
  129. plot(xdata, ydata(:,r), 'Color', cmap(r,:), 'LineWidth',2); hold on; % draw each line with different color
  130. end
  131. title(nameTitle{p},'FontWeight','bold');
  132. if p == 1, legend(nameLegend{p},'Location','Best','FontSize',7); end
  133. xlim([min(xdata(:)-0.1*max(xdata(:))), 1.1*max(xdata(:))]);
  134. ylim([0, 1.1*max(ydata(:))]);
  135. end
  136. end
  137. fclose(fid);
  138. end

其中bar的颜色设置参考自: http://www.mathworks.cn/support/solutions/en/data/1-4LDEEP/index.html?solution=1-4LDEEP

KAZE特征分析的系列笔记到此暂告一段落了,我觉得如果能够在非线性尺度空间的构建和特征检测方面对算法做出优化和改进、提高其实时性,KAZE 将大有用武之地。笔记仓促写完,还有很多不足和问题,欢迎大家指正和讨论,谢谢!

KAZE FEATURES相关推荐

  1. OpenCV + CPP 系列(卅三)图像特征提取(Harris角点检测、Shi-Tomasi角点检测、自定义角点检测)

    文章目录 一.常用图像特征描述 二.Harris角点检测 演示Harris角点检测 三.Shi-Tomasi角点检测 四.自定义角点检测器 一.常用图像特征描述 SIFT.SURF.HOG.Haar. ...

  2. LIFT: Learned Invariant Feature Transform详细笔记

    LIFT: Learned Invariant Feature Transform Paper: LIFT: Learned Invariant Feature Transform | Springe ...

  3. OpenCV3 和 Qt5 计算机视觉:6~10

    原文:Computer Vision with OpenCV 3 and Qt5 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自[ApacheCN 计算机视觉 译文集],采用译后编辑(MT ...

  4. OpenCV——KAZE、AKAZE特征检测、匹配与对象查找

      AKAZE是KAZE的加速版 特征点查找和绘制:把surf中的surf改成KAZE或AKAZE即可 1 #include <opencv2/opencv.hpp> 2 #include ...

  5. kaze算法的图像配准研究(2)-匹配

    在特征点检测过后,完成图像间特征点的匹配是非常重要的.对于图像配准工作而言.特征点匹配的准确度是最值得关注的点,宁愿少匹配,也不能误匹配. 我在此图像配准中使用的是KNN匹配: 下面引用自百度百科. ...

  6. PyTorch加载模型model.load_state_dict()问题,Unexpected key(s) in state_dict: “module.features..,Expected .

    希望将训练好的模型加载到新的网络上.如上面题目所描述的,PyTorch在加载之前保存的模型参数的时候,遇到了问题. Unexpected key(s) in state_dict: "mod ...

  7. OpenCV中的SURF(Speeded-Up Robust Features 加速鲁棒特征)

    OpenCV中的SURF(加速健壮功能) 1. 效果图 2. 原理 2.1 为什么SURF比SIFT快? 2.3 怎样获取SIFT与SURF? 3. 源码 参考 上一篇博客介绍了用于关键点检测和描述的 ...

  8. OpenCV中的快速特征检测——FAST(Features from Accelerated Segment Test)

    OpenCV中的快速特征检测--FAST(Features from Accelerated Segment Test) 1. 效果图 2. 源码 参考 OpenCV中的尺度不变特征变换(SIFT S ...

  9. keras系列︱图像多分类训练与利用bottleneck features进行微调(三)

    引自:http://blog.csdn.net/sinat_26917383/article/details/72861152 中文文档:http://keras-cn.readthedocs.io/ ...

最新文章

  1. 智源出品 | 超大规模智能模型产业发展报告(附下载)
  2. 练习1: Python基本语法元素 (第1周)
  3. import org.apache.commons.codec.digest.DigestUtils; 未导入
  4. Eclipse中显示文件字符乱码
  5. hadoop yarn 获取日志_「大数据」「Hadoop」-安装及数据目录
  6. WF4.0 基础篇 (一)开始使用WF
  7. 语言编奇数和合偶数和_Go语言基础(三)
  8. Excel在统计分析中的应用—第十章—方差分析-方差分析表
  9. Python-Django框架学习笔记——第一课:Hello World
  10. Intel(R) 6 Series/C200 Series Chipset Family USB Enhanced Host Controller - 1C26出现感叹号,USB无法使用
  11. 电路杂谈——硬件经典面试题
  12. turtle绘制皮卡丘
  13. NewStarCTF 公开赛赛道 WEEK2 pwn 砍一刀
  14. python常用的表达式有关系表达式_数学关系式 表示成正确的 Python表达式为_________。_学小易找答案...
  15. 上传大文件解决方案方法
  16. CSS查漏补缺(一)—页面内容不足铺满屏幕高度和有滚动条时,footer始终保持底部显示
  17. 重温数据结构:二叉排序树的查找、插入、删除
  18. Windows10 修改host文件(windows 设置ip别名)
  19. CNN入门+猫狗大战(Dogs vs. Cats)+PyTorch入门
  20. #pragma comment 的使用方法

热门文章

  1. Linux关机时执行指定脚本
  2. 7.2 一次产品异常复位引发的质量提升经历
  3. .NET6 使用 AutoFac (落地)
  4. VS shortcuts
  5. 2022年全球市场次氯酸钠总体规模、主要生产商、主要地区、产品和应用细分研究报告
  6. 毕业生必看:获取就业信息的主要渠道(收藏起来,以免丢失)
  7. 淘宝推广方法大全,教你如何做淘宝(转)
  8. 12864图片显示操作
  9. 幸运大转盘-jQuery+Java实现的抽奖程序
  10. 层压结构及参数(PCB板层厚度)收集