Merge KAZE and AKAZE features with most recent version

This commit is contained in:
Ievgen Khvedchenia 2014-04-23 23:02:02 +01:00
parent d27ed856f2
commit 6d500cc6f7
7 changed files with 535 additions and 698 deletions

File diff suppressed because it is too large Load Diff

View File

@ -6,148 +6,84 @@
* @author Pablo F. Alcantarilla, Jesus Nuevo
*/
#ifndef _AKAZE_H_
#define _AKAZE_H_
//*************************************************************************************
//*************************************************************************************
#pragma once
/* ************************************************************************* */
// Includes
#include "config.h"
#include "fed.h"
#include "nldiffusion_functions.h"
//*************************************************************************************
//*************************************************************************************
#include "precomp.hpp"
#include "AKAZEConfig.h"
/* ************************************************************************* */
// AKAZE Class Declaration
class AKAZEFeatures {
private:
// Parameters of the AKAZE class
int omax_; // Maximum octave level
int noctaves_; // Number of octaves
int nsublevels_; // Number of sublevels per octave level
int img_width_; // Width of the original image
int img_height_; // Height of the original image
float soffset_; // Base scale offset
float factor_size_; // Factor for the multiscale derivatives
float sderivatives_; // Standard deviation of the Gaussian for the nonlinear diff. derivatives
float kcontrast_; // The contrast parameter for the scalar nonlinear diffusion
float dthreshold_; // Feature detector threshold response
int diffusivity_; // Diffusivity type, 0->PM G1, 1->PM G2, 2-> Weickert, 3->Charbonnier
int descriptor_; // Descriptor mode:
// 0-> SURF_UPRIGHT, 1->SURF
// 2-> M-SURF_UPRIGHT, 3->M-SURF
// 4-> M-LDB_UPRIGHT, 5->M-LDB
int descriptor_size_; // Size of the descriptor in bits. Use 0 for the full descriptor
int descriptor_pattern_size_; // Size of the pattern. Actual size sampled is 2*pattern_size
int descriptor_channels_; // Number of channels to consider in the M-LDB descriptor
bool save_scale_space_; // For saving scale space images
bool verbosity_; // Verbosity level
std::vector<tevolution> evolution_; // Vector of nonlinear diffusion evolution
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
/// 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 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_;
/// 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_;
// Computation times variables in ms
double tkcontrast_; // Kcontrast factor computation
double tscale_; // Nonlinear Scale space generation
double tderivatives_; // Multiscale derivatives
double tdetector_; // Feature detector
double textrema_; // Scale Space extrema
double tsubpixel_; // Subpixel refinement
double tdescriptor_; // Feature descriptors
/// Computation times variables in ms
AKAZETiming timing_;
public:
// Constructor
AKAZEFeatures(const AKAZEOptions &options);
/// Constructor with input arguments
AKAZEFeatures(const AKAZEOptions& options);
// Destructor
~AKAZEFeatures(void);
/// Destructor
~AKAZEFeatures();
// Setters
void Set_Octave_Max(const int& omax) {
omax_ = omax;
}
void Set_NSublevels(const int& nsublevels) {
nsublevels_ = nsublevels;
}
void Set_Save_Scale_Space_Flag(const bool& save_scale_space) {
save_scale_space_ = save_scale_space;
}
void Set_Image_Width(const int& img_width) {
img_width_ = img_width;
}
void Set_Image_Height(const int& img_height) {
img_height_ = img_height;
}
/// 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);
void Feature_Suppression_Distance(std::vector<cv::KeyPoint>& kpts, float mdist) const;
// Getters
int Get_Image_Width(void) {
return img_width_;
}
int Get_Image_Height(void) {
return img_height_;
}
double Get_Time_KContrast(void) {
return tkcontrast_;
}
double Get_Time_Scale_Space(void) {
return tscale_;
}
double Get_Time_Derivatives(void) {
return tderivatives_;
}
double Get_Time_Detector(void) {
return tdetector_;
}
double Get_Time_Descriptor(void) {
return tdescriptor_;
}
// Feature description methods
void Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc);
void Compute_Main_Orientation(cv::KeyPoint& kpt) const;
// Scale Space methods
void Allocate_Memory_Evolution(void);
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);
void Feature_Suppression_Distance(std::vector<cv::KeyPoint>& kpts, float mdist);
// SURF Pattern Descriptor
void Get_SURF_Descriptor_Upright_64(const cv::KeyPoint& kpt, float* desc) const;
void Get_SURF_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
// Feature description methods
void Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc);
void Compute_Main_Orientation_SURF(cv::KeyPoint& kpt);
// M-SURF Pattern Descriptor
void Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
void Get_MSURF_Descriptor_64(const cv::KeyPoint& kpt, float* desc) const;
// SURF Pattern Descriptor
void Get_SURF_Descriptor_Upright_64(const cv::KeyPoint& kpt, float *desc);
void Get_SURF_Descriptor_64(const cv::KeyPoint& kpt, float *desc);
// M-LDB Pattern Descriptor
void Get_Upright_MLDB_Full_Descriptor(const cv::KeyPoint& kpt, unsigned char* desc) const;
void Get_MLDB_Full_Descriptor(const cv::KeyPoint& kpt, unsigned char* desc) const;
void Get_Upright_MLDB_Descriptor_Subset(const cv::KeyPoint& kpt, unsigned char* desc);
void Get_MLDB_Descriptor_Subset(const cv::KeyPoint& kpt, unsigned char* desc);
// M-SURF Pattern Descriptor
void Get_MSURF_Upright_Descriptor_64(const cv::KeyPoint& kpt, float *desc);
void Get_MSURF_Descriptor_64(const cv::KeyPoint& kpt, float *desc);
// Methods for saving some results and showing computation times
void Save_Scale_Space();
void Save_Detector_Responses();
void Show_Computation_Times() const;
// M-LDB Pattern Descriptor
void Get_Upright_MLDB_Full_Descriptor(const cv::KeyPoint& kpt, unsigned char *desc);
void Get_MLDB_Full_Descriptor(const cv::KeyPoint& kpt, unsigned char *desc);
void Get_Upright_MLDB_Descriptor_Subset(const cv::KeyPoint& kpt, unsigned char *desc);
void Get_MLDB_Descriptor_Subset(const cv::KeyPoint& kpt, unsigned char *desc);
/// Return the computation times
AKAZETiming Get_Computation_Times() const {
return timing_;
}
};
//*************************************************************************************
//*************************************************************************************
/* ************************************************************************* */
// Inline functions
/**
* @brief This function sets default parameters for the A-KAZE detector.
@ -157,13 +93,8 @@ void setDefaultAKAZEOptions(AKAZEOptions& options);
// Inline functions
void generateDescriptorSubsample(cv::Mat& sampleList, cv::Mat& comparisons,
int nbits, int pattern_size, int nchannels);
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, const int width, const int height);
void check_descriptor_limits(int& x, int& y, int width, int height);
int fRound(float flt);
//*************************************************************************************
//*************************************************************************************
#endif

View File

@ -9,13 +9,7 @@
/* ************************************************************************* */
// OpenCV
#include <opencv2/opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
// OpenMP
#ifdef _OPENMP
# include <omp.h>
#endif
#include "precomp.hpp"
// System Includes
#include <string>

View File

@ -24,9 +24,7 @@
using namespace std;
using namespace cv;
//*************************************************************************************
//*************************************************************************************
/* ************************************************************************* */
/**
* @brief This function smoothes an image with a Gaussian kernel
* @param src Input image
@ -36,32 +34,30 @@ using namespace cv;
* @param sigma Kernel standard deviation
*/
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, const size_t& ksize_x,
const size_t& ksize_y, const float& sigma) {
const size_t& ksize_y, const float& sigma) {
size_t ksize_x_ = 0, ksize_y_ = 0;
size_t 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_ = ceil(2.0*(1.0 + (sigma-0.8)/(0.3)));
ksize_y_ = ksize_x_;
}
// 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_ = ceil(2.0*(1.0 + (sigma - 0.8) / (0.3)));
ksize_y_ = ksize_x_;
}
// The kernel size must be and odd number
if ((ksize_x_ % 2) == 0) {
ksize_x_ += 1;
}
// The kernel size must be and odd number
if ((ksize_x_ % 2) == 0) {
ksize_x_ += 1;
}
if ((ksize_y_ % 2) == 0) {
ksize_y_ += 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);
// 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
@ -74,13 +70,11 @@ void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, const size_t& ksi
* Journal of Visual Communication and Image Representation 2002
*/
void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst,
const size_t& xorder, const size_t& yorder) {
Scharr(src,dst,CV_32F,xorder,yorder,1.0,0,BORDER_DEFAULT);
const size_t& xorder, const size_t& 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)
@ -90,12 +84,10 @@ void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst,
* @param k Contrast factor parameter
*/
void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k) {
exp(-(Lx.mul(Lx)+Ly.mul(Ly))/(k*k),dst);
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)
@ -105,12 +97,10 @@ void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k) {
* @param k Contrast factor parameter
*/
void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k) {
dst = 1.0/(1.0+(Lx.mul(Lx)+Ly.mul(Ly))/(k*k));
dst = 1.0 / (1.0 + (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)
@ -122,15 +112,13 @@ void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k) {
* Proceedings of Algorithmy 2000
*/
void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k) {
Mat modg;
pow((Lx.mul(Lx) + Ly.mul(Ly))/(k*k),4,modg);
cv::exp(-3.315/modg, dst);
dst = 1.0 - dst;
Mat modg;
pow((Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), 4, modg);
cv::exp(-3.315 / modg, dst);
dst = 1.0 - dst;
}
//*************************************************************************************
//*************************************************************************************
/* ************************************************************************* */
/**
* @brief This function computes Charbonnier conductivity coefficient gc
* gc = 1 / sqrt(1 + dL^2 / k^2)
@ -143,14 +131,12 @@ void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, co
* Proceedings of Algorithmy 2000
*/
void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k) {
Mat den;
cv::sqrt(1.0+(Lx.mul(Lx)+Ly.mul(Ly))/(k*k),den);
dst = 1.0/ den;
Mat den;
cv::sqrt(1.0 + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), den);
dst = 1.0 / 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
@ -163,90 +149,87 @@ void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst,
* @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, const float& perc, const float& gscale,
const size_t& nbins, const size_t& ksize_x, const size_t& ksize_y) {
float compute_k_percentile(const cv::Mat& img, float perc, float gscale,
size_t nbins, size_t ksize_x, size_t ksize_y) {
size_t 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;
size_t 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
float *hist = new float[nbins];
// Create the array for the histogram
float *hist = new float[nbins];
// 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);
// Create the matrices
cv::Mat gaussian = cv::Mat::zeros(img.rows, img.cols, CV_32F);
cv::Mat Lx = cv::Mat::zeros(img.rows, img.cols, CV_32F);
cv::Mat Ly = cv::Mat::zeros(img.rows, img.cols, CV_32F);
// Set the histogram to zero, just in case
for (size_t i = 0; i < nbins; i++) {
hist[i] = 0.0;
}
// Set the histogram to zero
for (size_t i = 0; i < nbins; i++)
hist[i] = 0.0;
// Perform the Gaussian convolution
gaussian_2D_convolution(img,gaussian,ksize_x,ksize_y,gscale);
// Perform the Gaussian convolution
gaussian_2D_convolution(img, gaussian, ksize_x, ksize_y, gscale);
// Compute the Gaussian derivatives Lx and Ly
image_derivatives_scharr(gaussian,Lx,1,0);
image_derivatives_scharr(gaussian,Ly,0,1);
// Compute the Gaussian derivatives Lx and Ly
image_derivatives_scharr(gaussian, Lx, 1, 0);
image_derivatives_scharr(gaussian, Ly, 0, 1);
// 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);
// 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 = floor(nbins*(modg/hmax));
if (nbin == nbins) {
nbin--;
// Get the maximum
if (modg > hmax) {
hmax = modg;
}
}
hist[nbin]++;
npoints++;
}
}
}
// Now find the perc of the histogram percentile
nthreshold = (size_t)(npoints*perc);
// 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);
for (k = 0; nelements < nthreshold && k < nbins; k++) {
nelements = nelements + hist[k];
}
// Find the correspondent bin
if (modg != 0.0) {
nbin = floor(nbins*(modg / hmax));
if (nelements < nthreshold) {
kperc = 0.03;
}
else {
kperc = hmax*((float)(k)/(float)nbins);
}
if (nbin == nbins) {
nbin--;
}
delete [] hist;
return kperc;
hist[nbin]++;
npoints++;
}
}
}
// Now find the perc of the histogram percentile
nthreshold = (size_t)(npoints*perc);
for (k = 0; nelements < nthreshold && k < nbins; k++) {
nelements = nelements + hist[k];
}
if (nelements < nthreshold) {
kperc = 0.03;
}
else {
kperc = hmax*((float)(k) / (float)nbins);
}
delete[] hist;
return kperc;
}
//*************************************************************************************
//*************************************************************************************
/* ************************************************************************* */
/**
* @brief This function computes Scharr image derivatives
* @param src Input image
@ -256,16 +239,14 @@ float compute_k_percentile(const cv::Mat& img, const float& perc, const float& g
* @param scale Scale factor for the derivative size
*/
void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, const size_t& xorder,
const size_t& yorder, const size_t& scale) {
const size_t& yorder, const size_t& scale) {
Mat kx, ky;
compute_derivative_kernels(kx, ky, xorder,yorder,scale);
sepFilter2D(src,dst,CV_32F,kx,ky);
Mat kx, ky;
compute_derivative_kernels(kx, ky, xorder, yorder, scale);
sepFilter2D(src, dst, CV_32F, kx, ky);
}
//*************************************************************************************
//*************************************************************************************
/* ************************************************************************* */
/**
* @brief This function performs a scalar non-linear diffusion step
* @param Ld2 Output image in the evolution
@ -281,64 +262,50 @@ void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, const float&
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for (int i = 1; i < Lstep.rows-1; 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.5*stepsize*(xpos-xneg + ypos-yneg);
for (int i = 1; i < Lstep.rows - 1; 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.5*stepsize*(xpos - xneg + ypos - yneg);
}
}
}
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)));
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.5*stepsize*(xpos - xneg + ypos);
}
float ypos = ((*(c.ptr<float>(0)+j))+(*(c.ptr<float>(1)+j)))*((*(Ld.ptr<float>(1)+j))-(*(Ld.ptr<float>(0)+j)));
float yneg = ((*(c.ptr<float>(0)+j))+(*(c.ptr<float>(0)+j)))*((*(Ld.ptr<float>(0)+j))-(*(Ld.ptr<float>(0)+j)));
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.5*stepsize*(xpos - xneg + ypos - yneg);
}
*(Lstep.ptr<float>(0)+j) = 0.5*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.5*stepsize*(xpos - xneg + ypos - yneg);
}
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)));
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.5*stepsize*(-xneg + ypos - yneg);
}
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.5*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.5*stepsize*(xpos-xneg + ypos-yneg);
}
for (int i = 1; i < Lstep.rows-1; i++) {
float xpos = ((*(c.ptr<float>(i)+Lstep.cols-1))+(*(c.ptr<float>(i)+Lstep.cols-1)))*((*(Ld.ptr<float>(i)+Lstep.cols-1))-(*(Ld.ptr<float>(i)+Lstep.cols-1)));
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.5*stepsize*(xpos-xneg + ypos-yneg);
}
Ld = Ld + Lstep;
Ld = Ld + Lstep;
}
//*************************************************************************************
//*************************************************************************************
/* ************************************************************************* */
/**
* @brief This function downsamples the input image with the kernel [1/4,1/2,1/4]
* @param img Input image to be downsampled
@ -346,22 +313,20 @@ void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, const float&
*/
void downsample_image(const cv::Mat& src, cv::Mat& dst) {
int i1 = 0, j1 = 0, i2 = 0, j2 = 0;
int i1 = 0, j1 = 0, i2 = 0, j2 = 0;
for (i1 = 1; i1 < src.rows; i1+=2) {
j2 = 0;
for (j1 = 1; j1 < src.cols; j1+=2) {
*(dst.ptr<float>(i2)+j2) = 0.5*(*(src.ptr<float>(i1)+j1))+0.25*(*(src.ptr<float>(i1)+j1-1) + *(src.ptr<float>(i1)+j1+1));
j2++;
for (i1 = 1; i1 < src.rows; i1 += 2) {
j2 = 0;
for (j1 = 1; j1 < src.cols; j1 += 2) {
*(dst.ptr<float>(i2)+j2) = 0.5*(*(src.ptr<float>(i1)+j1)) + 0.25*(*(src.ptr<float>(i1)+j1 - 1) + *(src.ptr<float>(i1)+j1 + 1));
j2++;
}
i2++;
}
i2++;
}
}
//*************************************************************************************
//*************************************************************************************
/* ************************************************************************* */
/**
* @brief This function downsamples the input image using OpenCV resize
* @param img Input image to be downsampled
@ -369,15 +334,13 @@ void downsample_image(const cv::Mat& src, cv::Mat& dst) {
*/
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);
// 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 Compute Scharr derivative kernels for sizes different than 3
* @param kx_ The derivative kernel in x-direction
@ -387,45 +350,45 @@ void halfsample_image(const cv::Mat& src, cv::Mat& dst) {
* @param scale The kernel size
*/
void compute_derivative_kernels(cv::OutputArray kx_, cv::OutputArray ky_,
const size_t& dx, const size_t& dy, const size_t& scale) {
const size_t& dx, const size_t& dy, const size_t& scale) {
const int ksize = 3 + 2*(scale-1);
const int ksize = 3 + 2 * (scale - 1);
// The usual 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.0/3.0;
float norm = 1.0/(2.0*scale*(w+2.0));
for (int k = 0; k < 2; k++) {
Mat* kernel = k == 0 ? &kx : &ky;
int order = k == 0 ? dx : dy;
float kerI[1000];
for (int t = 0; t<ksize; t++) {
kerI[t] = 0;
// The usual Scharr kernel
if (scale == 1) {
getDerivKernels(kx_, ky_, dx, dy, 0, true, CV_32F);
return;
}
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;
}
kx_.create(ksize, 1, CV_32F, -1, true);
ky_.create(ksize, 1, CV_32F, -1, true);
Mat kx = kx_.getMat();
Mat ky = ky_.getMat();
Mat temp(kernel->rows, kernel->cols, CV_32F, &kerI[0]);
temp.copyTo(*kernel);
}
float w = 10.0 / 3.0;
float norm = 1.0 / (2.0*scale*(w + 2.0));
for (int k = 0; k < 2; k++) {
Mat* kernel = k == 0 ? &kx : &ky;
int order = k == 0 ? dx : dy;
float kerI[1000];
for (int t = 0; t < ksize; t++) {
kerI[t] = 0;
}
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);
}
}

View File

@ -1,20 +1,17 @@
#ifndef _NLDIFFUSION_FUNCTIONS_H_
#define _NLDIFFUSION_FUNCTIONS_H_
/**
* @file nldiffusion_functions.h
* @brief Functions for nonlinear diffusion filtering applications
* @date Sep 15, 2013
* @author Pablo F. Alcantarilla, Jesus Nuevo
*/
//******************************************************************************
//******************************************************************************
#pragma once
/* ************************************************************************* */
// Includes
#include "precomp.hpp"
// OpenMP Includes
#ifdef _OPENMP
# include <omp.h>
#endif
//*************************************************************************************
//*************************************************************************************
/* ************************************************************************* */
// Declaration of functions
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, const size_t& ksize_x,
const size_t& ksize_y, const float& sigma);
@ -24,8 +21,8 @@ void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k);
void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k);
void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k);
void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k);
float compute_k_percentile(const cv::Mat& img, const float& perc, const float& gscale,
const size_t& nbins, const size_t& ksize_x, const size_t& ksize_y);
float compute_k_percentile(const cv::Mat& img, float perc, float gscale,
size_t nbins, size_t ksize_x, size_t ksize_y);
void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, const size_t& xorder,
const size_t& yorder, const size_t& scale);
void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, const float& stepsize);
@ -33,9 +30,5 @@ void downsample_image(const cv::Mat& src, cv::Mat& dst);
void halfsample_image(const cv::Mat& src, cv::Mat& dst);
void compute_derivative_kernels(cv::OutputArray kx_, cv::OutputArray ky_,
const size_t& dx, const size_t& dy, const size_t& scale);
//*************************************************************************************
//*************************************************************************************
#endif
bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value,
int row, int col, bool same_img);

View File

@ -262,11 +262,7 @@ void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky,
for (int k = 0; k < 2; k++) {
Mat* kernel = k == 0 ? &kx : &ky;
int order = k == 0 ? dx : dy;
std::vector<float> kerI(ksize);
for (int t=0; t<ksize; t++) {
kerI[t] = 0;
}
std::vector<float> kerI(ksize, 0.0f);
if (order == 0) {
kerI[0] = norm, kerI[ksize/2] = w*norm, kerI[ksize-1] = norm;

0
modules/features2d/src/kaze/nldiffusion_functions.h Executable file → Normal file
View File