mirror of https://github.com/opencv/opencv.git
Merge pull request #2673 from BloodAxe:kaze
commit
8bd1efa523
17 changed files with 5122 additions and 2 deletions
@ -0,0 +1,232 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2008, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
/*
|
||||
OpenCV wrapper of reference implementation of |
||||
[1] Fast Explicit Diffusion for Accelerated Features in Nonlinear Scale Spaces. |
||||
Pablo F. Alcantarilla, J. Nuevo and Adrien Bartoli. |
||||
In British Machine Vision Conference (BMVC), Bristol, UK, September 2013 |
||||
http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla13bmvc.pdf
|
||||
@author Eugene Khvedchenya <ekhvedchenya@gmail.com> |
||||
*/ |
||||
|
||||
#include "precomp.hpp" |
||||
#include "akaze/AKAZEFeatures.h" |
||||
|
||||
namespace cv |
||||
{ |
||||
AKAZE::AKAZE() |
||||
: descriptor(DESCRIPTOR_MLDB) |
||||
, descriptor_channels(3) |
||||
, descriptor_size(0) |
||||
{ |
||||
} |
||||
|
||||
AKAZE::AKAZE(DESCRIPTOR_TYPE _descriptor_type, int _descriptor_size, int _descriptor_channels) |
||||
: descriptor(_descriptor_type) |
||||
, descriptor_channels(_descriptor_channels) |
||||
, descriptor_size(_descriptor_size) |
||||
{ |
||||
|
||||
} |
||||
|
||||
AKAZE::~AKAZE() |
||||
{ |
||||
|
||||
} |
||||
|
||||
// returns the descriptor size in bytes
|
||||
int AKAZE::descriptorSize() const |
||||
{ |
||||
switch (descriptor) |
||||
{ |
||||
case cv::AKAZE::DESCRIPTOR_KAZE: |
||||
case cv::AKAZE::DESCRIPTOR_KAZE_UPRIGHT: |
||||
return 64; |
||||
|
||||
case cv::AKAZE::DESCRIPTOR_MLDB: |
||||
case cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT: |
||||
// We use the full length binary descriptor -> 486 bits
|
||||
if (descriptor_size == 0) |
||||
{ |
||||
int t = (6 + 36 + 120) * descriptor_channels; |
||||
return (int)ceil(t / 8.); |
||||
} |
||||
else |
||||
{ |
||||
// We use the random bit selection length binary descriptor
|
||||
return (int)ceil(descriptor_size / 8.); |
||||
} |
||||
|
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
// returns the descriptor type
|
||||
int AKAZE::descriptorType() const |
||||
{ |
||||
switch (descriptor) |
||||
{ |
||||
case cv::AKAZE::DESCRIPTOR_KAZE: |
||||
case cv::AKAZE::DESCRIPTOR_KAZE_UPRIGHT: |
||||
return CV_32F; |
||||
|
||||
case cv::AKAZE::DESCRIPTOR_MLDB: |
||||
case cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT: |
||||
return CV_8U; |
||||
|
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
// returns the default norm type
|
||||
int AKAZE::defaultNorm() const |
||||
{ |
||||
switch (descriptor) |
||||
{ |
||||
case cv::AKAZE::DESCRIPTOR_KAZE: |
||||
case cv::AKAZE::DESCRIPTOR_KAZE_UPRIGHT: |
||||
return cv::NORM_L2; |
||||
|
||||
case cv::AKAZE::DESCRIPTOR_MLDB: |
||||
case cv::AKAZE::DESCRIPTOR_MLDB_UPRIGHT: |
||||
return cv::NORM_HAMMING; |
||||
|
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
|
||||
void AKAZE::operator()(InputArray image, InputArray mask, |
||||
std::vector<KeyPoint>& keypoints, |
||||
OutputArray descriptors, |
||||
bool useProvidedKeypoints) const |
||||
{ |
||||
cv::Mat img = image.getMat(); |
||||
if (img.type() != CV_8UC1) |
||||
cvtColor(image, img, COLOR_BGR2GRAY); |
||||
|
||||
Mat img1_32; |
||||
img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0); |
||||
|
||||
cv::Mat& desc = descriptors.getMatRef(); |
||||
|
||||
AKAZEOptions options; |
||||
options.descriptor = static_cast<DESCRIPTOR_TYPE>(descriptor); |
||||
options.descriptor_channels = descriptor_channels; |
||||
options.descriptor_size = descriptor_size; |
||||
options.img_width = img.cols; |
||||
options.img_height = img.rows; |
||||
|
||||
AKAZEFeatures impl(options); |
||||
impl.Create_Nonlinear_Scale_Space(img1_32); |
||||
|
||||
if (!useProvidedKeypoints) |
||||
{ |
||||
impl.Feature_Detection(keypoints); |
||||
} |
||||
|
||||
if (!mask.empty()) |
||||
{ |
||||
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat()); |
||||
} |
||||
|
||||
impl.Compute_Descriptors(keypoints, desc); |
||||
|
||||
CV_Assert((!desc.rows || desc.cols == descriptorSize())); |
||||
CV_Assert((!desc.rows || (desc.type() == descriptorType()))); |
||||
} |
||||
|
||||
void AKAZE::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const |
||||
{ |
||||
cv::Mat img = image.getMat(); |
||||
if (img.type() != CV_8UC1) |
||||
cvtColor(image, img, COLOR_BGR2GRAY); |
||||
|
||||
Mat img1_32; |
||||
img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0); |
||||
|
||||
AKAZEOptions options; |
||||
options.descriptor = static_cast<DESCRIPTOR_TYPE>(descriptor); |
||||
options.descriptor_channels = descriptor_channels; |
||||
options.descriptor_size = descriptor_size; |
||||
options.img_width = img.cols; |
||||
options.img_height = img.rows; |
||||
|
||||
AKAZEFeatures impl(options); |
||||
impl.Create_Nonlinear_Scale_Space(img1_32); |
||||
impl.Feature_Detection(keypoints); |
||||
|
||||
if (!mask.empty()) |
||||
{ |
||||
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat()); |
||||
} |
||||
} |
||||
|
||||
void AKAZE::computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const |
||||
{ |
||||
cv::Mat img = image.getMat(); |
||||
if (img.type() != CV_8UC1) |
||||
cvtColor(image, img, COLOR_BGR2GRAY); |
||||
|
||||
Mat img1_32; |
||||
img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0); |
||||
|
||||
cv::Mat& desc = descriptors.getMatRef(); |
||||
|
||||
AKAZEOptions options; |
||||
options.descriptor = static_cast<DESCRIPTOR_TYPE>(descriptor); |
||||
options.descriptor_channels = descriptor_channels; |
||||
options.descriptor_size = descriptor_size; |
||||
options.img_width = img.cols; |
||||
options.img_height = img.rows; |
||||
|
||||
AKAZEFeatures impl(options); |
||||
impl.Create_Nonlinear_Scale_Space(img1_32); |
||||
impl.Compute_Descriptors(keypoints, desc); |
||||
|
||||
CV_Assert((!desc.rows || desc.cols == descriptorSize())); |
||||
CV_Assert((!desc.rows || (desc.type() == descriptorType()))); |
||||
} |
||||
} |
@ -0,0 +1,109 @@ |
||||
/**
|
||||
* @file AKAZEConfig.h |
||||
* @brief AKAZE configuration file |
||||
* @date Feb 23, 2014 |
||||
* @author Pablo F. Alcantarilla, Jesus Nuevo |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
/* ************************************************************************* */ |
||||
// OpenCV
|
||||
#include "precomp.hpp" |
||||
#include <opencv2/features2d.hpp> |
||||
|
||||
/* ************************************************************************* */ |
||||
/// Lookup table for 2d gaussian (sigma = 2.5) where (0,0) is top left and (6,6) is bottom right
|
||||
const float gauss25[7][7] = { |
||||
{ 0.02546481f, 0.02350698f, 0.01849125f, 0.01239505f, 0.00708017f, 0.00344629f, 0.00142946f }, |
||||
{ 0.02350698f, 0.02169968f, 0.01706957f, 0.01144208f, 0.00653582f, 0.00318132f, 0.00131956f }, |
||||
{ 0.01849125f, 0.01706957f, 0.01342740f, 0.00900066f, 0.00514126f, 0.00250252f, 0.00103800f }, |
||||
{ 0.01239505f, 0.01144208f, 0.00900066f, 0.00603332f, 0.00344629f, 0.00167749f, 0.00069579f }, |
||||
{ 0.00708017f, 0.00653582f, 0.00514126f, 0.00344629f, 0.00196855f, 0.00095820f, 0.00039744f }, |
||||
{ 0.00344629f, 0.00318132f, 0.00250252f, 0.00167749f, 0.00095820f, 0.00046640f, 0.00019346f }, |
||||
{ 0.00142946f, 0.00131956f, 0.00103800f, 0.00069579f, 0.00039744f, 0.00019346f, 0.00008024f } |
||||
}; |
||||
|
||||
/* ************************************************************************* */ |
||||
/// AKAZE configuration options structure
|
||||
struct AKAZEOptions { |
||||
|
||||
/// AKAZE Diffusivities
|
||||
enum DIFFUSIVITY_TYPE { |
||||
PM_G1 = 0, |
||||
PM_G2 = 1, |
||||
WEICKERT = 2, |
||||
CHARBONNIER = 3 |
||||
}; |
||||
|
||||
AKAZEOptions() |
||||
: omax(4) |
||||
, nsublevels(4) |
||||
, img_width(0) |
||||
, img_height(0) |
||||
, soffset(1.6f) |
||||
, derivative_factor(1.5f) |
||||
, sderivatives(1.0) |
||||
, diffusivity(PM_G2) |
||||
|
||||
, dthreshold(0.001f) |
||||
, min_dthreshold(0.00001f) |
||||
|
||||
, descriptor(cv::AKAZE::DESCRIPTOR_MLDB) |
||||
, descriptor_size(0) |
||||
, descriptor_channels(3) |
||||
, descriptor_pattern_size(10) |
||||
|
||||
, kcontrast(0.001f) |
||||
, kcontrast_percentile(0.7f) |
||||
, kcontrast_nbins(300) |
||||
{ |
||||
} |
||||
|
||||
int omax; ///< Maximum octave evolution of the image 2^sigma (coarsest scale sigma units)
|
||||
int nsublevels; ///< Default number of sublevels per scale level
|
||||
int img_width; ///< Width of the input image
|
||||
int img_height; ///< Height of the input image
|
||||
float soffset; ///< Base scale offset (sigma units)
|
||||
float derivative_factor; ///< Factor for the multiscale derivatives
|
||||
float sderivatives; ///< Smoothing factor for the derivatives
|
||||
DIFFUSIVITY_TYPE diffusivity; ///< Diffusivity type
|
||||
|
||||
float dthreshold; ///< Detector response threshold to accept point
|
||||
float min_dthreshold; ///< Minimum detector threshold to accept a point
|
||||
|
||||
cv::AKAZE::DESCRIPTOR_TYPE descriptor; ///< Type of descriptor
|
||||
int descriptor_size; ///< Size of the descriptor in bits. 0->Full size
|
||||
int descriptor_channels; ///< Number of channels in the descriptor (1, 2, 3)
|
||||
int descriptor_pattern_size; ///< Actual patch size is 2*pattern_size*point.scale
|
||||
|
||||
float kcontrast; ///< The contrast factor parameter
|
||||
float kcontrast_percentile; ///< Percentile level for the contrast factor
|
||||
int kcontrast_nbins; ///< Number of bins for the contrast factor histogram
|
||||
}; |
||||
|
||||
/* ************************************************************************* */ |
||||
/// AKAZE nonlinear diffusion filtering evolution
|
||||
struct TEvolution { |
||||
|
||||
TEvolution() { |
||||
etime = 0.0f; |
||||
esigma = 0.0f; |
||||
octave = 0; |
||||
sublevel = 0; |
||||
sigma_size = 0; |
||||
} |
||||
|
||||
cv::Mat Lx, Ly; // First order spatial derivatives
|
||||
cv::Mat Lxx, Lxy, Lyy; // Second order spatial derivatives
|
||||
cv::Mat Lflow; // Diffusivity image
|
||||
cv::Mat Lt; // Evolution image
|
||||
cv::Mat Lsmooth; // Smoothed image
|
||||
cv::Mat Lstep; // Evolution step update
|
||||
cv::Mat Ldet; // Detector response
|
||||
float etime; // Evolution time
|
||||
float esigma; // Evolution sigma. For linear diffusion t = sigma^2 / 2
|
||||
size_t octave; // Image octave
|
||||
size_t sublevel; // Image sublevel in each octave
|
||||
size_t sigma_size; // Integer sigma. For computing the feature detector responses
|
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,65 @@ |
||||
/**
|
||||
* @file AKAZE.h |
||||
* @brief Main class for detecting and computing binary descriptors in an |
||||
* accelerated nonlinear scale space |
||||
* @date Mar 27, 2013 |
||||
* @author Pablo F. Alcantarilla, Jesus Nuevo |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
/* ************************************************************************* */ |
||||
// Includes
|
||||
#include "precomp.hpp" |
||||
#include "AKAZEConfig.h" |
||||
|
||||
/* ************************************************************************* */ |
||||
// AKAZE Class Declaration
|
||||
class AKAZEFeatures { |
||||
|
||||
private: |
||||
|
||||
AKAZEOptions options_; ///< Configuration options for AKAZE
|
||||
std::vector<TEvolution> evolution_; ///< Vector of nonlinear diffusion evolution
|
||||
|
||||
/// FED parameters
|
||||
int ncycles_; ///< Number of cycles
|
||||
bool reordering_; ///< Flag for reordering time steps
|
||||
std::vector<std::vector<float > > tsteps_; ///< Vector of FED dynamic time steps
|
||||
std::vector<int> nsteps_; ///< Vector of number of steps per cycle
|
||||
|
||||
/// Matrices for the M-LDB descriptor computation
|
||||
cv::Mat descriptorSamples_; // List of positions in the grids to sample LDB bits from.
|
||||
cv::Mat descriptorBits_; |
||||
cv::Mat bitMask_; |
||||
|
||||
public: |
||||
|
||||
/// Constructor with input arguments
|
||||
AKAZEFeatures(const AKAZEOptions& options); |
||||
|
||||
/// Scale Space methods
|
||||
void Allocate_Memory_Evolution(); |
||||
int Create_Nonlinear_Scale_Space(const cv::Mat& img); |
||||
void Feature_Detection(std::vector<cv::KeyPoint>& kpts); |
||||
void Compute_Determinant_Hessian_Response(void); |
||||
void Compute_Multiscale_Derivatives(void); |
||||
void Find_Scale_Space_Extrema(std::vector<cv::KeyPoint>& kpts); |
||||
void Do_Subpixel_Refinement(std::vector<cv::KeyPoint>& kpts); |
||||
|
||||
// Feature description methods
|
||||
void Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc); |
||||
|
||||
static void Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vector<TEvolution>& evolution_); |
||||
}; |
||||
|
||||
/* ************************************************************************* */ |
||||
// Inline functions
|
||||
|
||||
// Inline functions
|
||||
void generateDescriptorSubsample(cv::Mat& sampleList, cv::Mat& comparisons, |
||||
int nbits, int pattern_size, int nchannels); |
||||
float get_angle(float x, float y); |
||||
float gaussian(float x, float y, float sigma); |
||||
void check_descriptor_limits(int& x, int& y, int width, int height); |
||||
int fRound(float flt); |
@ -0,0 +1,183 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2008, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
/*
|
||||
OpenCV wrapper of reference implementation of |
||||
[1] KAZE Features. Pablo F. Alcantarilla, Adrien Bartoli and Andrew J. Davison. |
||||
In European Conference on Computer Vision (ECCV), Fiorenze, Italy, October 2012 |
||||
http://www.robesafe.com/personal/pablo.alcantarilla/papers/Alcantarilla12eccv.pdf
|
||||
@author Eugene Khvedchenya <ekhvedchenya@gmail.com> |
||||
*/ |
||||
|
||||
#include "precomp.hpp" |
||||
#include "kaze/KAZEFeatures.h" |
||||
|
||||
namespace cv |
||||
{ |
||||
KAZE::KAZE() |
||||
: extended(false) |
||||
, upright(false) |
||||
{ |
||||
} |
||||
|
||||
KAZE::KAZE(bool _extended, bool _upright) |
||||
: extended(_extended) |
||||
, upright(_upright) |
||||
{ |
||||
|
||||
} |
||||
KAZE::~KAZE() |
||||
{ |
||||
|
||||
} |
||||
|
||||
// returns the descriptor size in bytes
|
||||
int KAZE::descriptorSize() const |
||||
{ |
||||
return extended ? 128 : 64; |
||||
} |
||||
|
||||
// returns the descriptor type
|
||||
int KAZE::descriptorType() const |
||||
{ |
||||
return CV_32F; |
||||
} |
||||
|
||||
// returns the default norm type
|
||||
int KAZE::defaultNorm() const |
||||
{ |
||||
return NORM_L2; |
||||
} |
||||
|
||||
void KAZE::operator()(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const |
||||
{ |
||||
detectImpl(image, keypoints, mask); |
||||
} |
||||
|
||||
void KAZE::operator()(InputArray image, InputArray mask, |
||||
std::vector<KeyPoint>& keypoints, |
||||
OutputArray descriptors, |
||||
bool useProvidedKeypoints) const |
||||
{ |
||||
cv::Mat img = image.getMat(); |
||||
if (img.type() != CV_8UC1) |
||||
cvtColor(image, img, COLOR_BGR2GRAY); |
||||
|
||||
Mat img1_32; |
||||
img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0); |
||||
|
||||
cv::Mat& desc = descriptors.getMatRef(); |
||||
|
||||
KAZEOptions options; |
||||
options.img_width = img.cols; |
||||
options.img_height = img.rows; |
||||
options.extended = extended; |
||||
options.upright = upright; |
||||
|
||||
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()); |
||||
} |
||||
|
||||
impl.Feature_Description(keypoints, desc); |
||||
|
||||
CV_Assert((!desc.rows || desc.cols == descriptorSize())); |
||||
CV_Assert((!desc.rows || (desc.type() == descriptorType()))); |
||||
} |
||||
|
||||
void KAZE::detectImpl(InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask) const |
||||
{ |
||||
Mat img = image.getMat(); |
||||
if (img.type() != CV_8UC1) |
||||
cvtColor(image, img, COLOR_BGR2GRAY); |
||||
|
||||
Mat img1_32; |
||||
img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0); |
||||
|
||||
KAZEOptions options; |
||||
options.img_width = img.cols; |
||||
options.img_height = img.rows; |
||||
options.extended = extended; |
||||
options.upright = upright; |
||||
|
||||
KAZEFeatures impl(options); |
||||
impl.Create_Nonlinear_Scale_Space(img1_32); |
||||
impl.Feature_Detection(keypoints); |
||||
|
||||
if (!mask.empty()) |
||||
{ |
||||
cv::KeyPointsFilter::runByPixelsMask(keypoints, mask.getMat()); |
||||
} |
||||
} |
||||
|
||||
void KAZE::computeImpl(InputArray image, std::vector<KeyPoint>& keypoints, OutputArray descriptors) const |
||||
{ |
||||
cv::Mat img = image.getMat(); |
||||
if (img.type() != CV_8UC1) |
||||
cvtColor(image, img, COLOR_BGR2GRAY); |
||||
|
||||
Mat img1_32; |
||||
img.convertTo(img1_32, CV_32F, 1.0 / 255.0, 0); |
||||
|
||||
cv::Mat& desc = descriptors.getMatRef(); |
||||
|
||||
KAZEOptions options; |
||||
options.img_width = img.cols; |
||||
options.img_height = img.rows; |
||||
options.extended = extended; |
||||
options.upright = upright; |
||||
|
||||
KAZEFeatures impl(options); |
||||
impl.Create_Nonlinear_Scale_Space(img1_32); |
||||
impl.Feature_Description(keypoints, desc); |
||||
|
||||
CV_Assert((!desc.rows || desc.cols == descriptorSize())); |
||||
CV_Assert((!desc.rows || (desc.type() == descriptorType()))); |
||||
} |
||||
} |
@ -0,0 +1,83 @@ |
||||
/**
|
||||
* @file KAZEConfig.h |
||||
* @brief Configuration file |
||||
* @date Dec 27, 2011 |
||||
* @author Pablo F. Alcantarilla |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
// OpenCV Includes
|
||||
#include "precomp.hpp" |
||||
#include <opencv2/features2d.hpp> |
||||
|
||||
//*************************************************************************************
|
||||
|
||||
struct KAZEOptions { |
||||
|
||||
enum DIFFUSIVITY_TYPE { |
||||
PM_G1 = 0, |
||||
PM_G2 = 1, |
||||
WEICKERT = 2 |
||||
}; |
||||
|
||||
KAZEOptions() |
||||
: diffusivity(PM_G2) |
||||
|
||||
, soffset(1.60f) |
||||
, omax(4) |
||||
, nsublevels(4) |
||||
, img_width(0) |
||||
, img_height(0) |
||||
, sderivatives(1.0f) |
||||
, dthreshold(0.001f) |
||||
, kcontrast(0.01f) |
||||
, kcontrast_percentille(0.7f) |
||||
, kcontrast_bins(300) |
||||
|
||||
, use_fed(true) |
||||
, upright(false) |
||||
, extended(false) |
||||
|
||||
, use_clipping_normalilzation(false) |
||||
, clipping_normalization_ratio(1.6f) |
||||
, clipping_normalization_niter(5) |
||||
{ |
||||
} |
||||
|
||||
DIFFUSIVITY_TYPE diffusivity; |
||||
|
||||
float soffset; |
||||
int omax; |
||||
int nsublevels; |
||||
int img_width; |
||||
int img_height; |
||||
float sderivatives; |
||||
float dthreshold; |
||||
float kcontrast; |
||||
float kcontrast_percentille; |
||||
int kcontrast_bins; |
||||
|
||||
bool use_fed; |
||||
bool upright; |
||||
bool extended; |
||||
|
||||
bool use_clipping_normalilzation; |
||||
float clipping_normalization_ratio; |
||||
int clipping_normalization_niter; |
||||
}; |
||||
|
||||
struct TEvolution { |
||||
cv::Mat Lx, Ly; // First order spatial derivatives
|
||||
cv::Mat Lxx, Lxy, Lyy; // Second order spatial derivatives
|
||||
cv::Mat Lflow; // Diffusivity image
|
||||
cv::Mat Lt; // Evolution image
|
||||
cv::Mat Lsmooth; // Smoothed image
|
||||
cv::Mat Lstep; // Evolution step update
|
||||
cv::Mat Ldet; // Detector response
|
||||
float etime; // Evolution time
|
||||
float esigma; // Evolution sigma. For linear diffusion t = sigma^2 / 2
|
||||
float octave; // Image octave
|
||||
float sublevel; // Image sublevel in each octave
|
||||
int sigma_size; // Integer esigma. For computing the feature detector responses
|
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,90 @@ |
||||
|
||||
/**
|
||||
* @file KAZE.h |
||||
* @brief Main program for detecting and computing descriptors in a nonlinear |
||||
* scale space |
||||
* @date Jan 21, 2012 |
||||
* @author Pablo F. Alcantarilla |
||||
*/ |
||||
|
||||
#ifndef KAZE_H_ |
||||
#define KAZE_H_ |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
// Includes
|
||||
#include "KAZEConfig.h" |
||||
#include "nldiffusion_functions.h" |
||||
#include "fed.h" |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
// KAZE Class Declaration
|
||||
class KAZEFeatures { |
||||
|
||||
private: |
||||
|
||||
KAZEOptions options; |
||||
|
||||
// Parameters of the Nonlinear diffusion class
|
||||
std::vector<TEvolution> evolution_; // Vector of nonlinear diffusion evolution
|
||||
|
||||
// Vector of keypoint vectors for finding extrema in multiple threads
|
||||
std::vector<std::vector<cv::KeyPoint> > kpts_par_; |
||||
|
||||
// FED parameters
|
||||
int ncycles_; // Number of cycles
|
||||
bool reordering_; // Flag for reordering time steps
|
||||
std::vector<std::vector<float > > tsteps_; // Vector of FED dynamic time steps
|
||||
std::vector<int> nsteps_; // Vector of number of steps per cycle
|
||||
|
||||
// Some auxiliary variables used in the AOS step
|
||||
cv::Mat Ltx_, Lty_, px_, py_, ax_, ay_, bx_, by_, qr_, qc_; |
||||
|
||||
public: |
||||
|
||||
// Constructor
|
||||
KAZEFeatures(KAZEOptions& options); |
||||
|
||||
// Public methods for KAZE interface
|
||||
void Allocate_Memory_Evolution(void); |
||||
int Create_Nonlinear_Scale_Space(const cv::Mat& img); |
||||
void Feature_Detection(std::vector<cv::KeyPoint>& kpts); |
||||
void Feature_Description(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc); |
||||
|
||||
static void Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vector<TEvolution>& evolution_, const KAZEOptions& options); |
||||
|
||||
private: |
||||
|
||||
// Feature Detection Methods
|
||||
void Compute_KContrast(const cv::Mat& img, const float& kper); |
||||
void Compute_Multiscale_Derivatives(void); |
||||
void Compute_Detector_Response(void); |
||||
void Determinant_Hessian_Parallel(std::vector<cv::KeyPoint>& kpts); |
||||
void Find_Extremum_Threading(const int& level); |
||||
void Do_Subpixel_Refinement(std::vector<cv::KeyPoint>& kpts); |
||||
|
||||
// AOS Methods
|
||||
void AOS_Step_Scalar(cv::Mat &Ld, const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); |
||||
void AOS_Rows(const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); |
||||
void AOS_Columns(const cv::Mat &Ldprev, const cv::Mat &c, const float& stepsize); |
||||
void Thomas(const cv::Mat &a, const cv::Mat &b, const cv::Mat &Ld, cv::Mat &x); |
||||
|
||||
}; |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
// Inline functions
|
||||
float getAngle(const float& x, const float& y); |
||||
float gaussian(const float& x, const float& y, const float& sig); |
||||
void checkDescriptorLimits(int &x, int &y, const int& width, const int& height); |
||||
void clippingDescriptor(float *desc, const int& dsize, const int& niter, const float& ratio); |
||||
int fRound(const float& flt); |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
#endif // KAZE_H_
|
@ -0,0 +1,192 @@ |
||||
//=============================================================================
|
||||
//
|
||||
// fed.cpp
|
||||
// Authors: Pablo F. Alcantarilla (1), Jesus Nuevo (2)
|
||||
// Institutions: Georgia Institute of Technology (1)
|
||||
// TrueVision Solutions (2)
|
||||
// Date: 15/09/2013
|
||||
// Email: pablofdezalc@gmail.com
|
||||
//
|
||||
// AKAZE Features Copyright 2013, Pablo F. Alcantarilla, Jesus Nuevo
|
||||
// All Rights Reserved
|
||||
// See LICENSE for the license information
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* @file fed.cpp |
||||
* @brief Functions for performing Fast Explicit Diffusion and building the |
||||
* nonlinear scale space |
||||
* @date Sep 15, 2013 |
||||
* @author Pablo F. Alcantarilla, Jesus Nuevo |
||||
* @note This code is derived from FED/FJ library from Grewenig et al., |
||||
* The FED/FJ library allows solving more advanced problems |
||||
* Please look at the following papers for more information about FED: |
||||
* [1] S. Grewenig, J. Weickert, C. Schroers, A. Bruhn. Cyclic Schemes for |
||||
* PDE-Based Image Analysis. Technical Report No. 327, Department of Mathematics, |
||||
* Saarland University, Saarbrücken, Germany, March 2013 |
||||
* [2] S. Grewenig, J. Weickert, A. Bruhn. From box filtering to fast explicit diffusion. |
||||
* DAGM, 2010 |
||||
* |
||||
*/ |
||||
#include "precomp.hpp" |
||||
#include "fed.h" |
||||
|
||||
using namespace std; |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
/**
|
||||
* @brief This function allocates an array of the least number of time steps such |
||||
* that a certain stopping time for the whole process can be obtained and fills |
||||
* it with the respective FED time step sizes for one cycle |
||||
* The function returns the number of time steps per cycle or 0 on failure |
||||
* @param T Desired process stopping time |
||||
* @param M Desired number of cycles |
||||
* @param tau_max Stability limit for the explicit scheme |
||||
* @param reordering Reordering flag |
||||
* @param tau The vector with the dynamic step sizes |
||||
*/ |
||||
int fed_tau_by_process_time(const float& T, const int& M, const float& tau_max, |
||||
const bool& reordering, std::vector<float>& tau) { |
||||
// All cycles have the same fraction of the stopping time
|
||||
return fed_tau_by_cycle_time(T/(float)M,tau_max,reordering,tau); |
||||
} |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
/**
|
||||
* @brief This function allocates an array of the least number of time steps such |
||||
* that a certain stopping time for the whole process can be obtained and fills it |
||||
* it with the respective FED time step sizes for one cycle |
||||
* The function returns the number of time steps per cycle or 0 on failure |
||||
* @param t Desired cycle stopping time |
||||
* @param tau_max Stability limit for the explicit scheme |
||||
* @param reordering Reordering flag |
||||
* @param tau The vector with the dynamic step sizes |
||||
*/ |
||||
int fed_tau_by_cycle_time(const float& t, const float& tau_max, |
||||
const bool& reordering, std::vector<float> &tau) { |
||||
int n = 0; // Number of time steps
|
||||
float scale = 0.0; // Ratio of t we search to maximal t
|
||||
|
||||
// Compute necessary number of time steps
|
||||
n = (int)(ceilf(sqrtf(3.0f*t/tau_max+0.25f)-0.5f-1.0e-8f)+ 0.5f); |
||||
scale = 3.0f*t/(tau_max*(float)(n*(n+1))); |
||||
|
||||
// Call internal FED time step creation routine
|
||||
return fed_tau_internal(n,scale,tau_max,reordering,tau); |
||||
} |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
/**
|
||||
* @brief This function allocates an array of time steps and fills it with FED |
||||
* time step sizes |
||||
* The function returns the number of time steps per cycle or 0 on failure |
||||
* @param n Number of internal steps |
||||
* @param scale Ratio of t we search to maximal t |
||||
* @param tau_max Stability limit for the explicit scheme |
||||
* @param reordering Reordering flag |
||||
* @param tau The vector with the dynamic step sizes |
||||
*/ |
||||
int fed_tau_internal(const int& n, const float& scale, const float& tau_max, |
||||
const bool& reordering, std::vector<float> &tau) { |
||||
float c = 0.0, d = 0.0; // Time savers
|
||||
vector<float> tauh; // Helper vector for unsorted taus
|
||||
|
||||
if (n <= 0) { |
||||
return 0; |
||||
} |
||||
|
||||
// Allocate memory for the time step size
|
||||
tau = vector<float>(n); |
||||
|
||||
if (reordering) { |
||||
tauh = vector<float>(n); |
||||
} |
||||
|
||||
// Compute time saver
|
||||
c = 1.0f / (4.0f * (float)n + 2.0f); |
||||
d = scale * tau_max / 2.0f; |
||||
|
||||
// Set up originally ordered tau vector
|
||||
for (int k = 0; k < n; ++k) { |
||||
float h = cosf((float)CV_PI * (2.0f * (float)k + 1.0f) * c); |
||||
|
||||
if (reordering) { |
||||
tauh[k] = d / (h * h); |
||||
} |
||||
else { |
||||
tau[k] = d / (h * h); |
||||
} |
||||
} |
||||
|
||||
// Permute list of time steps according to chosen reordering function
|
||||
int kappa = 0, prime = 0; |
||||
|
||||
if (reordering == true) { |
||||
// Choose kappa cycle with k = n/2
|
||||
// This is a heuristic. We can use Leja ordering instead!!
|
||||
kappa = n / 2; |
||||
|
||||
// Get modulus for permutation
|
||||
prime = n + 1; |
||||
|
||||
while (!fed_is_prime_internal(prime)) { |
||||
prime++; |
||||
} |
||||
|
||||
// Perform permutation
|
||||
for (int k = 0, l = 0; l < n; ++k, ++l) { |
||||
int index = 0; |
||||
while ((index = ((k+1)*kappa) % prime - 1) >= n) { |
||||
k++; |
||||
} |
||||
|
||||
tau[l] = tauh[index]; |
||||
} |
||||
} |
||||
|
||||
return n; |
||||
} |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
/**
|
||||
* @brief This function checks if a number is prime or not |
||||
* @param number Number to check if it is prime or not |
||||
* @return true if the number is prime |
||||
*/ |
||||
bool fed_is_prime_internal(const int& number) { |
||||
bool is_prime = false; |
||||
|
||||
if (number <= 1) { |
||||
return false; |
||||
} |
||||
else if (number == 1 || number == 2 || number == 3 || number == 5 || number == 7) { |
||||
return true; |
||||
} |
||||
else if ((number % 2) == 0 || (number % 3) == 0 || (number % 5) == 0 || (number % 7) == 0) { |
||||
return false; |
||||
} |
||||
else { |
||||
is_prime = true; |
||||
int upperLimit = (int)sqrt(1.0f + number); |
||||
int divisor = 11; |
||||
|
||||
while (divisor <= upperLimit ) { |
||||
if (number % divisor == 0) |
||||
{ |
||||
is_prime = false; |
||||
} |
||||
|
||||
divisor +=2; |
||||
} |
||||
|
||||
return is_prime; |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
#ifndef FED_H |
||||
#define FED_H |
||||
|
||||
//******************************************************************************
|
||||
//******************************************************************************
|
||||
|
||||
// Includes
|
||||
#include <vector> |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
// Declaration of functions
|
||||
int fed_tau_by_process_time(const float& T, const int& M, const float& tau_max, |
||||
const bool& reordering, std::vector<float>& tau); |
||||
int fed_tau_by_cycle_time(const float& t, const float& tau_max, |
||||
const bool& reordering, std::vector<float> &tau) ; |
||||
int fed_tau_internal(const int& n, const float& scale, const float& tau_max, |
||||
const bool& reordering, std::vector<float> &tau); |
||||
bool fed_is_prime_internal(const int& number); |
||||
|
||||
//*************************************************************************************
|
||||
//*************************************************************************************
|
||||
|
||||
#endif // FED_H
|
@ -0,0 +1,437 @@ |
||||
//=============================================================================
|
||||
//
|
||||
// nldiffusion_functions.cpp
|
||||
// Author: Pablo F. Alcantarilla
|
||||
// Institution: University d'Auvergne
|
||||
// Address: Clermont Ferrand, France
|
||||
// Date: 27/12/2011
|
||||
// Email: pablofdezalc@gmail.com
|
||||
//
|
||||
// KAZE Features Copyright 2012, Pablo F. Alcantarilla
|
||||
// All Rights Reserved
|
||||
// See LICENSE for the license information
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* @file nldiffusion_functions.cpp |
||||
* @brief Functions for non-linear diffusion applications: |
||||
* 2D Gaussian Derivatives |
||||
* Perona and Malik conductivity equations |
||||
* Perona and Malik evolution |
||||
* @date Dec 27, 2011 |
||||
* @author Pablo F. Alcantarilla |
||||
*/ |
||||
|
||||
#include "nldiffusion_functions.h" |
||||
|
||||
// Namespaces
|
||||
using namespace std; |
||||
using namespace cv; |
||||
|
||||
/* ************************************************************************* */ |
||||
|
||||
namespace cv { |
||||
namespace details { |
||||
namespace kaze { |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function smoothes an image with a Gaussian kernel |
||||
* @param src Input image |
||||
* @param dst Output image |
||||
* @param ksize_x Kernel size in X-direction (horizontal) |
||||
* @param ksize_y Kernel size in Y-direction (vertical) |
||||
* @param sigma Kernel standard deviation |
||||
*/ |
||||
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma) { |
||||
|
||||
int ksize_x_ = 0, ksize_y_ = 0; |
||||
|
||||
// Compute an appropriate kernel size according to the specified sigma
|
||||
if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0) { |
||||
ksize_x_ = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f))); |
||||
ksize_y_ = ksize_x_; |
||||
} |
||||
|
||||
// The kernel size must be and odd number
|
||||
if ((ksize_x_ % 2) == 0) { |
||||
ksize_x_ += 1; |
||||
} |
||||
|
||||
if ((ksize_y_ % 2) == 0) { |
||||
ksize_y_ += 1; |
||||
} |
||||
|
||||
// Perform the Gaussian Smoothing with border replication
|
||||
GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_REPLICATE); |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function computes image derivatives with Scharr kernel |
||||
* @param src Input image |
||||
* @param dst Output image |
||||
* @param xorder Derivative order in X-direction (horizontal) |
||||
* @param yorder Derivative order in Y-direction (vertical) |
||||
* @note Scharr operator approximates better rotation invariance than |
||||
* other stencils such as Sobel. See Weickert and Scharr, |
||||
* A Scheme for Coherence-Enhancing Diffusion Filtering with Optimized Rotation Invariance, |
||||
* Journal of Visual Communication and Image Representation 2002 |
||||
*/ |
||||
void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder) { |
||||
Scharr(src, dst, CV_32F, xorder, yorder, 1.0, 0, BORDER_DEFAULT); |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function computes the Perona and Malik conductivity coefficient g1 |
||||
* g1 = exp(-|dL|^2/k^2) |
||||
* @param Lx First order image derivative in X-direction (horizontal) |
||||
* @param Ly First order image derivative in Y-direction (vertical) |
||||
* @param dst Output image |
||||
* @param k Contrast factor parameter |
||||
*/ |
||||
void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) { |
||||
cv::exp(-(Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), dst); |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function computes the Perona and Malik conductivity coefficient g2 |
||||
* g2 = 1 / (1 + dL^2 / k^2) |
||||
* @param Lx First order image derivative in X-direction (horizontal) |
||||
* @param Ly First order image derivative in Y-direction (vertical) |
||||
* @param dst Output image |
||||
* @param k Contrast factor parameter |
||||
*/ |
||||
void pm_g2(const cv::Mat &Lx, const cv::Mat& Ly, cv::Mat& dst, float k) { |
||||
dst = 1.0f / (1.0f + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k)); |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function computes Weickert conductivity coefficient gw |
||||
* @param Lx First order image derivative in X-direction (horizontal) |
||||
* @param Ly First order image derivative in Y-direction (vertical) |
||||
* @param dst Output image |
||||
* @param k Contrast factor parameter |
||||
* @note For more information check the following paper: J. Weickert |
||||
* Applications of nonlinear diffusion in image processing and computer vision, |
||||
* Proceedings of Algorithmy 2000 |
||||
*/ |
||||
void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) { |
||||
Mat modg; |
||||
cv::pow((Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), 4, modg); |
||||
cv::exp(-3.315f / modg, dst); |
||||
dst = 1.0f - dst; |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function computes Charbonnier conductivity coefficient gc |
||||
* gc = 1 / sqrt(1 + dL^2 / k^2) |
||||
* @param Lx First order image derivative in X-direction (horizontal) |
||||
* @param Ly First order image derivative in Y-direction (vertical) |
||||
* @param dst Output image |
||||
* @param k Contrast factor parameter |
||||
* @note For more information check the following paper: J. Weickert |
||||
* Applications of nonlinear diffusion in image processing and computer vision, |
||||
* Proceedings of Algorithmy 2000 |
||||
*/ |
||||
void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k) { |
||||
Mat den; |
||||
cv::sqrt(1.0f + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), den); |
||||
dst = 1.0f / den; |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function computes a good empirical value for the k contrast factor |
||||
* given an input image, the percentile (0-1), the gradient scale and the number of |
||||
* bins in the histogram |
||||
* @param img Input image |
||||
* @param perc Percentile of the image gradient histogram (0-1) |
||||
* @param gscale Scale for computing the image gradient histogram |
||||
* @param nbins Number of histogram bins |
||||
* @param ksize_x Kernel size in X-direction (horizontal) for the Gaussian smoothing kernel |
||||
* @param ksize_y Kernel size in Y-direction (vertical) for the Gaussian smoothing kernel |
||||
* @return k contrast factor |
||||
*/ |
||||
float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y) { |
||||
|
||||
int nbin = 0, nelements = 0, nthreshold = 0, k = 0; |
||||
float kperc = 0.0, modg = 0.0, lx = 0.0, ly = 0.0; |
||||
float npoints = 0.0; |
||||
float hmax = 0.0; |
||||
|
||||
// Create the array for the histogram
|
||||
std::vector<int> hist(nbins, 0); |
||||
|
||||
// Create the matrices
|
||||
Mat gaussian = Mat::zeros(img.rows, img.cols, CV_32F); |
||||
Mat Lx = Mat::zeros(img.rows, img.cols, CV_32F); |
||||
Mat Ly = Mat::zeros(img.rows, img.cols, CV_32F); |
||||
|
||||
// Perform the Gaussian convolution
|
||||
gaussian_2D_convolution(img, gaussian, ksize_x, ksize_y, gscale); |
||||
|
||||
// Compute the Gaussian derivatives Lx and Ly
|
||||
Scharr(gaussian, Lx, CV_32F, 1, 0, 1, 0, cv::BORDER_DEFAULT); |
||||
Scharr(gaussian, Ly, CV_32F, 0, 1, 1, 0, cv::BORDER_DEFAULT); |
||||
|
||||
// Skip the borders for computing the histogram
|
||||
for (int i = 1; i < gaussian.rows - 1; i++) { |
||||
for (int j = 1; j < gaussian.cols - 1; j++) { |
||||
lx = *(Lx.ptr<float>(i)+j); |
||||
ly = *(Ly.ptr<float>(i)+j); |
||||
modg = sqrt(lx*lx + ly*ly); |
||||
|
||||
// Get the maximum
|
||||
if (modg > hmax) { |
||||
hmax = modg; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Skip the borders for computing the histogram
|
||||
for (int i = 1; i < gaussian.rows - 1; i++) { |
||||
for (int j = 1; j < gaussian.cols - 1; j++) { |
||||
lx = *(Lx.ptr<float>(i)+j); |
||||
ly = *(Ly.ptr<float>(i)+j); |
||||
modg = sqrt(lx*lx + ly*ly); |
||||
|
||||
// Find the correspondent bin
|
||||
if (modg != 0.0) { |
||||
nbin = (int)floor(nbins*(modg / hmax)); |
||||
|
||||
if (nbin == nbins) { |
||||
nbin--; |
||||
} |
||||
|
||||
hist[nbin]++; |
||||
npoints++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Now find the perc of the histogram percentile
|
||||
nthreshold = (int)(npoints*perc); |
||||
|
||||
for (k = 0; nelements < nthreshold && k < nbins; k++) { |
||||
nelements = nelements + hist[k]; |
||||
} |
||||
|
||||
if (nelements < nthreshold) { |
||||
kperc = 0.03f; |
||||
} |
||||
else { |
||||
kperc = hmax*((float)(k) / (float)nbins); |
||||
} |
||||
|
||||
return kperc; |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function computes Scharr image derivatives |
||||
* @param src Input image |
||||
* @param dst Output image |
||||
* @param xorder Derivative order in X-direction (horizontal) |
||||
* @param yorder Derivative order in Y-direction (vertical) |
||||
* @param scale Scale factor for the derivative size |
||||
*/ |
||||
void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder, int scale) { |
||||
Mat kx, ky; |
||||
compute_derivative_kernels(kx, ky, xorder, yorder, scale); |
||||
sepFilter2D(src, dst, CV_32F, kx, ky); |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief Compute derivative kernels for sizes different than 3 |
||||
* @param _kx Horizontal kernel values |
||||
* @param _ky Vertical kernel values |
||||
* @param dx Derivative order in X-direction (horizontal) |
||||
* @param dy Derivative order in Y-direction (vertical) |
||||
* @param scale_ Scale factor or derivative size |
||||
*/ |
||||
void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, int dx, int dy, int scale) { |
||||
|
||||
int ksize = 3 + 2 * (scale - 1); |
||||
|
||||
// The standard Scharr kernel
|
||||
if (scale == 1) { |
||||
getDerivKernels(_kx, _ky, dx, dy, 0, true, CV_32F); |
||||
return; |
||||
} |
||||
|
||||
_kx.create(ksize, 1, CV_32F, -1, true); |
||||
_ky.create(ksize, 1, CV_32F, -1, true); |
||||
Mat kx = _kx.getMat(); |
||||
Mat ky = _ky.getMat(); |
||||
|
||||
float w = 10.0f / 3.0f; |
||||
float norm = 1.0f / (2.0f*scale*(w + 2.0f)); |
||||
|
||||
for (int k = 0; k < 2; k++) { |
||||
Mat* kernel = k == 0 ? &kx : &ky; |
||||
int order = k == 0 ? dx : dy; |
||||
std::vector<float> kerI(ksize, 0.0f); |
||||
|
||||
if (order == 0) { |
||||
kerI[0] = norm, kerI[ksize / 2] = w*norm, kerI[ksize - 1] = norm; |
||||
} |
||||
else if (order == 1) { |
||||
kerI[0] = -1, kerI[ksize / 2] = 0, kerI[ksize - 1] = 1; |
||||
} |
||||
|
||||
Mat temp(kernel->rows, kernel->cols, CV_32F, &kerI[0]); |
||||
temp.copyTo(*kernel); |
||||
} |
||||
} |
||||
|
||||
class Nld_Step_Scalar_Invoker : public cv::ParallelLoopBody |
||||
{ |
||||
public: |
||||
Nld_Step_Scalar_Invoker(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float _stepsize) |
||||
: _Ld(&Ld) |
||||
, _c(&c) |
||||
, _Lstep(&Lstep) |
||||
, stepsize(_stepsize) |
||||
{ |
||||
} |
||||
|
||||
virtual ~Nld_Step_Scalar_Invoker() |
||||
{ |
||||
|
||||
} |
||||
|
||||
void operator()(const cv::Range& range) const |
||||
{ |
||||
cv::Mat& Ld = *_Ld; |
||||
const cv::Mat& c = *_c; |
||||
cv::Mat& Lstep = *_Lstep; |
||||
|
||||
for (int i = range.start; i < range.end; i++) |
||||
{ |
||||
for (int j = 1; j < Lstep.cols - 1; j++) |
||||
{ |
||||
float xpos = ((*(c.ptr<float>(i)+j)) + (*(c.ptr<float>(i)+j + 1)))*((*(Ld.ptr<float>(i)+j + 1)) - (*(Ld.ptr<float>(i)+j))); |
||||
float xneg = ((*(c.ptr<float>(i)+j - 1)) + (*(c.ptr<float>(i)+j)))*((*(Ld.ptr<float>(i)+j)) - (*(Ld.ptr<float>(i)+j - 1))); |
||||
float ypos = ((*(c.ptr<float>(i)+j)) + (*(c.ptr<float>(i + 1) + j)))*((*(Ld.ptr<float>(i + 1) + j)) - (*(Ld.ptr<float>(i)+j))); |
||||
float yneg = ((*(c.ptr<float>(i - 1) + j)) + (*(c.ptr<float>(i)+j)))*((*(Ld.ptr<float>(i)+j)) - (*(Ld.ptr<float>(i - 1) + j))); |
||||
*(Lstep.ptr<float>(i)+j) = 0.5f*stepsize*(xpos - xneg + ypos - yneg); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private: |
||||
cv::Mat * _Ld; |
||||
const cv::Mat * _c; |
||||
cv::Mat * _Lstep; |
||||
float stepsize; |
||||
}; |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function performs a scalar non-linear diffusion step |
||||
* @param Ld2 Output image in the evolution |
||||
* @param c Conductivity image |
||||
* @param Lstep Previous image in the evolution |
||||
* @param stepsize The step size in time units |
||||
* @note Forward Euler Scheme 3x3 stencil |
||||
* The function c is a scalar value that depends on the gradient norm |
||||
* dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy |
||||
*/ |
||||
void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize) { |
||||
|
||||
cv::parallel_for_(cv::Range(1, Lstep.rows - 1), Nld_Step_Scalar_Invoker(Ld, c, Lstep, stepsize)); |
||||
|
||||
for (int j = 1; j < Lstep.cols - 1; j++) { |
||||
float xpos = ((*(c.ptr<float>(0) + j)) + (*(c.ptr<float>(0) + j + 1)))*((*(Ld.ptr<float>(0) + j + 1)) - (*(Ld.ptr<float>(0) + j))); |
||||
float xneg = ((*(c.ptr<float>(0) + j - 1)) + (*(c.ptr<float>(0) + j)))*((*(Ld.ptr<float>(0) + j)) - (*(Ld.ptr<float>(0) + j - 1))); |
||||
float ypos = ((*(c.ptr<float>(0) + j)) + (*(c.ptr<float>(1) + j)))*((*(Ld.ptr<float>(1) + j)) - (*(Ld.ptr<float>(0) + j))); |
||||
*(Lstep.ptr<float>(0) + j) = 0.5f*stepsize*(xpos - xneg + ypos); |
||||
} |
||||
|
||||
for (int j = 1; j < Lstep.cols - 1; j++) { |
||||
float xpos = ((*(c.ptr<float>(Lstep.rows - 1) + j)) + (*(c.ptr<float>(Lstep.rows - 1) + j + 1)))*((*(Ld.ptr<float>(Lstep.rows - 1) + j + 1)) - (*(Ld.ptr<float>(Lstep.rows - 1) + j))); |
||||
float xneg = ((*(c.ptr<float>(Lstep.rows - 1) + j - 1)) + (*(c.ptr<float>(Lstep.rows - 1) + j)))*((*(Ld.ptr<float>(Lstep.rows - 1) + j)) - (*(Ld.ptr<float>(Lstep.rows - 1) + j - 1))); |
||||
float ypos = ((*(c.ptr<float>(Lstep.rows - 1) + j)) + (*(c.ptr<float>(Lstep.rows - 1) + j)))*((*(Ld.ptr<float>(Lstep.rows - 1) + j)) - (*(Ld.ptr<float>(Lstep.rows - 1) + j))); |
||||
float yneg = ((*(c.ptr<float>(Lstep.rows - 2) + j)) + (*(c.ptr<float>(Lstep.rows - 1) + j)))*((*(Ld.ptr<float>(Lstep.rows - 1) + j)) - (*(Ld.ptr<float>(Lstep.rows - 2) + j))); |
||||
*(Lstep.ptr<float>(Lstep.rows - 1) + j) = 0.5f*stepsize*(xpos - xneg + ypos - yneg); |
||||
} |
||||
|
||||
for (int i = 1; i < Lstep.rows - 1; i++) { |
||||
float xpos = ((*(c.ptr<float>(i))) + (*(c.ptr<float>(i)+1)))*((*(Ld.ptr<float>(i)+1)) - (*(Ld.ptr<float>(i)))); |
||||
float xneg = ((*(c.ptr<float>(i))) + (*(c.ptr<float>(i))))*((*(Ld.ptr<float>(i))) - (*(Ld.ptr<float>(i)))); |
||||
float ypos = ((*(c.ptr<float>(i))) + (*(c.ptr<float>(i + 1))))*((*(Ld.ptr<float>(i + 1))) - (*(Ld.ptr<float>(i)))); |
||||
float yneg = ((*(c.ptr<float>(i - 1))) + (*(c.ptr<float>(i))))*((*(Ld.ptr<float>(i))) - (*(Ld.ptr<float>(i - 1)))); |
||||
*(Lstep.ptr<float>(i)) = 0.5f*stepsize*(xpos - xneg + ypos - yneg); |
||||
} |
||||
|
||||
for (int i = 1; i < Lstep.rows - 1; i++) { |
||||
float xneg = ((*(c.ptr<float>(i)+Lstep.cols - 2)) + (*(c.ptr<float>(i)+Lstep.cols - 1)))*((*(Ld.ptr<float>(i)+Lstep.cols - 1)) - (*(Ld.ptr<float>(i)+Lstep.cols - 2))); |
||||
float ypos = ((*(c.ptr<float>(i)+Lstep.cols - 1)) + (*(c.ptr<float>(i + 1) + Lstep.cols - 1)))*((*(Ld.ptr<float>(i + 1) + Lstep.cols - 1)) - (*(Ld.ptr<float>(i)+Lstep.cols - 1))); |
||||
float yneg = ((*(c.ptr<float>(i - 1) + Lstep.cols - 1)) + (*(c.ptr<float>(i)+Lstep.cols - 1)))*((*(Ld.ptr<float>(i)+Lstep.cols - 1)) - (*(Ld.ptr<float>(i - 1) + Lstep.cols - 1))); |
||||
*(Lstep.ptr<float>(i)+Lstep.cols - 1) = 0.5f*stepsize*(-xneg + ypos - yneg); |
||||
} |
||||
|
||||
Ld = Ld + Lstep; |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function downsamples the input image using OpenCV resize |
||||
* @param img Input image to be downsampled |
||||
* @param dst Output image with half of the resolution of the input image |
||||
*/ |
||||
void halfsample_image(const cv::Mat& src, cv::Mat& dst) { |
||||
|
||||
// Make sure the destination image is of the right size
|
||||
CV_Assert(src.cols / 2 == dst.cols); |
||||
CV_Assert(src.rows / 2 == dst.rows); |
||||
resize(src, dst, dst.size(), 0, 0, cv::INTER_AREA); |
||||
} |
||||
|
||||
/* ************************************************************************* */ |
||||
/**
|
||||
* @brief This function checks if a given pixel is a maximum in a local neighbourhood |
||||
* @param img Input image where we will perform the maximum search |
||||
* @param dsize Half size of the neighbourhood |
||||
* @param value Response value at (x,y) position |
||||
* @param row Image row coordinate |
||||
* @param col Image column coordinate |
||||
* @param same_img Flag to indicate if the image value at (x,y) is in the input image |
||||
* @return 1->is maximum, 0->otherwise |
||||
*/ |
||||
bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img) { |
||||
|
||||
bool response = true; |
||||
|
||||
for (int i = row - dsize; i <= row + dsize; i++) { |
||||
for (int j = col - dsize; j <= col + dsize; j++) { |
||||
if (i >= 0 && i < img.rows && j >= 0 && j < img.cols) { |
||||
if (same_img == true) { |
||||
if (i != row || j != col) { |
||||
if ((*(img.ptr<float>(i)+j)) > value) { |
||||
response = false; |
||||
return response; |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
if ((*(img.ptr<float>(i)+j)) > value) { |
||||
response = false; |
||||
return response; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return response; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,53 @@ |
||||
/**
|
||||
* @file nldiffusion_functions.h |
||||
* @brief Functions for non-linear diffusion applications: |
||||
* 2D Gaussian Derivatives |
||||
* Perona and Malik conductivity equations |
||||
* Perona and Malik evolution |
||||
* @date Dec 27, 2011 |
||||
* @author Pablo F. Alcantarilla |
||||
*/ |
||||
|
||||
#ifndef KAZE_NLDIFFUSION_FUNCTIONS_H |
||||
#define KAZE_NLDIFFUSION_FUNCTIONS_H |
||||
|
||||
/* ************************************************************************* */ |
||||
// Includes
|
||||
#include "precomp.hpp" |
||||
|
||||
/* ************************************************************************* */ |
||||
// Declaration of functions
|
||||
|
||||
namespace cv { |
||||
namespace details { |
||||
namespace kaze { |
||||
|
||||
// Gaussian 2D convolution
|
||||
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma); |
||||
|
||||
// Diffusivity functions
|
||||
void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k); |
||||
void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k); |
||||
void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k); |
||||
void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k); |
||||
|
||||
float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y); |
||||
|
||||
// Image derivatives
|
||||
void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder, int scale); |
||||
void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, int dx, int dy, int scale); |
||||
void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder); |
||||
|
||||
// Nonlinear diffusion filtering scalar step
|
||||
void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize); |
||||
|
||||
// For non-maxima suppresion
|
||||
bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img); |
||||
|
||||
// Image downsampling
|
||||
void halfsample_image(const cv::Mat& src, cv::Mat& dst); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endif |
Loading…
Reference in new issue