一、概述
PF Alcantarilla等人2012 年提出 KAZE 特征,通过非线性扩散滤波利用非线性尺度空间。这使得图像中的模糊局部适应特征点,从而减少噪声并同时保留主题图像中区域的边界。KAZE 检测器基于Hessian 矩阵的尺度归一化行列式这是在多个尺度级别计算的。使用移动窗口将检测器响应的最大值作为特征点拾取。特征描述通过在每个检测到的特征周围的圆形邻域中找到主导方向来引入旋转不变性的特性。KAZE 特征对旋转、尺度、有限仿射具有不变性,并且在不同尺度上具有更多的独特性,但代价是计算时间适度增加。下面等式显示了标准的非线性扩散公式。
PF Alcantarilla等人。在 2013 年中提出了Accelerated-KAZE (AKAZE ) 算法,该算法也基于像 KAZE 一样的非线性扩散滤波,但其非线性尺度空间是使用称为快速显式扩散 (FED ) 的计算高效框架构建的。AKAZE 检测器基于Hessian 矩阵的行列式。使用Scharr 滤波器提高了旋转不变性质量。空间位置中检测器响应的最大值被拾取为特征点。AKAZE 的描述符基于修改的局部差分二进制(MLDB) 算法也是高效的。AKAZE 特征对尺度、旋转、有限仿射具有不变性,并且由于非线性尺度空间,在不同尺度上具有更多的独特性。
二、KAZE类参考
1、函数原型
static Ptr<KAZE> cv::KAZE::create ( bool extended = false,
bool upright = false,
float threshold = 0.001f,
int nOctaves = 4,
int nOctaveLayers = 4,
KAZE::DiffusivityType diffusivity = KAZE::DIFF_PM_G2
)
2、参数详解
extended | 设置以启用扩展(128 字节)描述符的提取。 |
upright | 设置为启用垂直描述符(非旋转不变)。 |
threshold | 接受点的检测器响应阈值 |
nOctaves | 图像的最大倍频程演化 |
nOctaveLayers | 每个比例级别的默认子级别数 |
diffusivity | 扩散型。 DIFF_PM_G1、DIFF_PM_G2、DIFF_WEICKERT 或 DIFF_CHARBONNIER |
三、AKAZE类参考
1、函数原型
static Ptr<AKAZE> cv::AKAZE::create ( AKAZE::DescriptorType descriptor_type = AKAZE::DESCRIPTOR_MLDB,
int descriptor_size = 0,
int descriptor_channels = 3,
float threshold = 0.001f,
int nOctaves = 4,
int nOctaveLayers = 4,
KAZE::DiffusivityType diffusivity = KAZE::DIFF_PM_G2
)
2、参数详解
descriptor_type | 提取描述符的类型:DESCRIPTOR_KAZE、DESCRIPTOR_KAZE_UPRIGHT、DESCRIPTOR_MLDB 或 DESCRIPTOR_MLDB_UPRIGHT。 |
descriptor_size | 描述符的大小(以位为单位)。 0 -> 全尺寸 |
descriptor_channels | 描述符中的通道数(1、2、3) |
threshold | 接受点的检测器响应阈值 |
nOctaves | 图像的最大倍频程演化 |
nOctaveLayers | 每个比例级别的默认子级别数 |
diffusivity | 扩散型。 DIFF_PM_G1、DIFF_PM_G2、DIFF_WEICKERT 或 DIFF_CHARBONNIER |
四、OpenCV源码
1、源码路径
opencv\modules\features2d\src\kaze.cpp
opencv\modules\features2d\src\akaze.cpp
2、源码代码
class KAZE_Impl CV_FINAL : public KAZE
{
public:
KAZE_Impl(bool _extended, bool _upright, float _threshold, int _octaves,
int _sublevels, KAZE::DiffusivityType _diffusivity)
: extended(_extended)
, upright(_upright)
, threshold(_threshold)
, octaves(_octaves)
, sublevels(_sublevels)
, diffusivity(_diffusivity)
{
}
virtual ~KAZE_Impl() CV_OVERRIDE {}
void setExtended(bool extended_) CV_OVERRIDE { extended = extended_; }
bool getExtended() const CV_OVERRIDE { return extended; }
void setUpright(bool upright_) CV_OVERRIDE { upright = upright_; }
bool getUpright() const CV_OVERRIDE { return upright; }
void setThreshold(double threshold_) CV_OVERRIDE { threshold = (float)threshold_; }
double getThreshold() const CV_OVERRIDE { return threshold; }
void setNOctaves(int octaves_) CV_OVERRIDE { octaves = octaves_; }
int getNOctaves() const CV_OVERRIDE { return octaves; }
void setNOctaveLayers(int octaveLayers_) CV_OVERRIDE { sublevels = octaveLayers_; }
int getNOctaveLayers() const CV_OVERRIDE { return sublevels; }
void setDiffusivity(KAZE::DiffusivityType diff_) CV_OVERRIDE{ diffusivity = diff_; }
KAZE::DiffusivityType getDiffusivity() const CV_OVERRIDE{ return diffusivity; }
// returns the descriptor size in bytes
int descriptorSize() const CV_OVERRIDE
{
return extended ? 128 : 64;
}
// returns the descriptor type
int descriptorType() const CV_OVERRIDE
{
return CV_32F;
}
// returns the default norm type
int defaultNorm() const CV_OVERRIDE
{
return NORM_L2;
}
void detectAndCompute(InputArray image, InputArray mask,
std::vector<KeyPoint>& keypoints,
OutputArray descriptors,
bool useProvidedKeypoints) CV_OVERRIDE
{
CV_INSTRUMENT_REGION();
cv::Mat img = image.getMat();
if (img.channels() > 1)
cvtColor(image, img, COLOR_BGR2GRAY);
Mat img1_32;
if ( img.depth() == CV_32F )
img1_32 = img;
else if ( img.depth() == CV_8U )
img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0);
else if ( img.depth() == CV_16U )
img.convertTo(img1_32, CV_32F, 1.0 / 65535.0, 0);
CV_Assert( ! img1_32.empty() );
KAZEOptions options;
options.img_width = img.cols;
options.img_height = img.rows;
options.extended = extended;
options.upright = upright;
options.dthreshold = threshold;
options.omax = octaves;
options.nsublevels = sublevels;
options.diffusivity = diffusivity;
KAZEFeatures impl(options);
impl.Create_Nonlinear_Scale_Space(img1_32);
if (!useProvidedKeypoints)
{
impl.Feature_Detection(keypoints);
}
if (!mask.empty())
{
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat());
}
if( descriptors.needed() )
{
Mat desc;
impl.Feature_Description(keypoints, desc);
desc.copyTo(descriptors);
CV_Assert((!desc.rows || desc.cols == descriptorSize()));
CV_Assert((!desc.rows || (desc.type() == descriptorType())));
}
}
void write(FileStorage& fs) const CV_OVERRIDE
{
writeFormat(fs);
fs << "extended" << (int)extended;
fs << "upright" << (int)upright;
fs << "threshold" << threshold;
fs << "octaves" << octaves;
fs << "sublevels" << sublevels;
fs << "diffusivity" << diffusivity;
}
void read(const FileNode& fn) CV_OVERRIDE
{
extended = (int)fn["extended"] != 0;
upright = (int)fn["upright"] != 0;
threshold = (float)fn["threshold"];
octaves = (int)fn["octaves"];
sublevels = (int)fn["sublevels"];
diffusivity = static_cast<KAZE::DiffusivityType>((int)fn["diffusivity"]);
}
bool extended;
bool upright;
float threshold;
int octaves;
int sublevels;
KAZE::DiffusivityType diffusivity;
};
Ptr<KAZE> KAZE::create(bool extended, bool upright,
float threshold,
int octaves, int sublevels,
KAZE::DiffusivityType diffusivity)
{
return makePtr<KAZE_Impl>(extended, upright, threshold, octaves, sublevels, diffusivity);
}
String KAZE::getDefaultName() const
{
return (Feature2D::getDefaultName() + ".KAZE");
}