Commit c1bf4532 authored by Ievgen Khvedchenia's avatar Ievgen Khvedchenia

Wrapped nldiffusion functions with details::kaze or details::amaze namespace to…

Wrapped nldiffusion functions with details::kaze or details::amaze namespace to avoid collision of function names
parent c68cbfce
...@@ -114,7 +114,7 @@ struct AKAZEOptions { ...@@ -114,7 +114,7 @@ struct AKAZEOptions {
float kcontrast; ///< The contrast factor parameter float kcontrast; ///< The contrast factor parameter
float kcontrast_percentile; ///< Percentile level for the contrast factor float kcontrast_percentile; ///< Percentile level for the contrast factor
size_t kcontrast_nbins; ///< Number of bins for the contrast factor histogram int kcontrast_nbins; ///< Number of bins for the contrast factor histogram
bool save_scale_space; ///< Set to true for saving the scale space images bool save_scale_space; ///< Set to true for saving the scale space images
bool save_keypoints; ///< Set to true for saving the detected keypoints and descriptors bool save_keypoints; ///< Set to true for saving the detected keypoints and descriptors
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
using namespace std; using namespace std;
using namespace cv; using namespace cv;
using namespace cv::details::akaze;
/* ************************************************************************* */ /* ************************************************************************* */
/** /**
...@@ -110,8 +111,7 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img) { ...@@ -110,8 +111,7 @@ int AKAZEFeatures::Create_Nonlinear_Scale_Space(const cv::Mat& img) {
evolution_[0].Lt.copyTo(evolution_[0].Lsmooth); evolution_[0].Lt.copyTo(evolution_[0].Lsmooth);
// First compute the kcontrast factor // First compute the kcontrast factor
options_.kcontrast = compute_k_percentile(img, options_.kcontrast_percentile, options_.kcontrast = compute_k_percentile(img, options_.kcontrast_percentile, 1.0f, options_.kcontrast_nbins, 0, 0);
1.0f, options_.kcontrast_nbins, 0, 0);
//t2 = cv::getTickCount(); //t2 = cv::getTickCount();
//timing_.kcontrast = 1000.0*(t2 - t1) / cv::getTickFrequency(); //timing_.kcontrast = 1000.0*(t2 - t1) / cv::getTickFrequency();
......
...@@ -19,368 +19,373 @@ ...@@ -19,368 +19,373 @@
* @author Pablo F. Alcantarilla, Jesus Nuevo * @author Pablo F. Alcantarilla, Jesus Nuevo
*/ */
#include "nldiffusion_functions.h" #include "akaze/nldiffusion_functions.h"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
/* ************************************************************************* */ namespace cv {
/** namespace details {
* @brief This function smoothes an image with a Gaussian kernel namespace akaze {
* @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) * @brief This function smoothes an image with a Gaussian kernel
* @param sigma Kernel standard deviation * @param src Input image
*/ * @param dst Output image
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, const size_t& ksize_x, * @param ksize_x Kernel size in X-direction (horizontal)
const size_t& ksize_y, const float& sigma) { * @param ksize_y Kernel size in Y-direction (vertical)
* @param sigma Kernel standard deviation
int ksize_x_ = 0, ksize_y_ = 0; */
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma) {
// Compute an appropriate kernel size according to the specified sigma
if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0) { int ksize_x_ = 0, ksize_y_ = 0;
ksize_x_ = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
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_ = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
// The kernel size must be and odd number ksize_y_ = ksize_x_;
if ((ksize_x_ % 2) == 0) { }
ksize_x_ += 1;
}
if ((ksize_y_ % 2) == 0) {
ksize_y_ += 1;
}
// Perform the Gaussian Smoothing with border replication // The kernel size must be and odd number
GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_REPLICATE); if ((ksize_x_ % 2) == 0) {
} ksize_x_ += 1;
}
/* ************************************************************************* */ if ((ksize_y_ % 2) == 0) {
/** ksize_y_ += 1;
* @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);
}
/* ************************************************************************* */ // Perform the Gaussian Smoothing with border replication
/** GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, BORDER_REPLICATE);
* @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, const float& k) {
exp(-(Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), dst);
}
/* ************************************************************************* */ /* ************************************************************************* */
/** /**
* @brief This function computes the Perona and Malik conductivity coefficient g2 * @brief This function computes image derivatives with Scharr kernel
* g2 = 1 / (1 + dL^2 / k^2) * @param src Input image
* @param Lx First order image derivative in X-direction (horizontal) * @param dst Output image
* @param Ly First order image derivative in Y-direction (vertical) * @param xorder Derivative order in X-direction (horizontal)
* @param dst Output image * @param yorder Derivative order in Y-direction (vertical)
* @param k Contrast factor parameter * @note Scharr operator approximates better rotation invariance than
*/ * other stencils such as Sobel. See Weickert and Scharr,
void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k) { * A Scheme for Coherence-Enhancing Diffusion Filtering with Optimized Rotation Invariance,
dst = 1.0 / (1.0 + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k)); * 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 Weickert conductivity coefficient gw * @brief This function computes the Perona and Malik conductivity coefficient g1
* @param Lx First order image derivative in X-direction (horizontal) * g1 = exp(-|dL|^2/k^2)
* @param Ly First order image derivative in Y-direction (vertical) * @param Lx First order image derivative in X-direction (horizontal)
* @param dst Output image * @param Ly First order image derivative in Y-direction (vertical)
* @param k Contrast factor parameter * @param dst Output image
* @note For more information check the following paper: J. Weickert * @param k Contrast factor parameter
* Applications of nonlinear diffusion in image processing and computer vision, */
* Proceedings of Algorithmy 2000 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);
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;
}
/* ************************************************************************* */
/**
* @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, const float& k) {
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 * @brief This function computes the Perona and Malik conductivity coefficient g2
* given an input image, the percentile (0-1), the gradient scale and the number of * g2 = 1 / (1 + dL^2 / k^2)
* bins in the histogram * @param Lx First order image derivative in X-direction (horizontal)
* @param img Input image * @param Ly First order image derivative in Y-direction (vertical)
* @param perc Percentile of the image gradient histogram (0-1) * @param dst Output image
* @param gscale Scale for computing the image gradient histogram * @param k Contrast factor parameter
* @param nbins Number of histogram bins */
* @param ksize_x Kernel size in X-direction (horizontal) for the Gaussian smoothing kernel void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k) {
* @param ksize_y Kernel size in Y-direction (vertical) for the Gaussian smoothing kernel dst = 1.0 / (1.0 + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k));
* @return k contrast factor
*/
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;
// Create the array for the histogram
std::vector<size_t> hist(nbins, 0);
// 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);
// 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);
// 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++) { * @brief This function computes Weickert conductivity coefficient gw
lx = *(Lx.ptr<float>(i)+j); * @param Lx First order image derivative in X-direction (horizontal)
ly = *(Ly.ptr<float>(i)+j); * @param Ly First order image derivative in Y-direction (vertical)
modg = sqrt(lx*lx + ly*ly); * @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, 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;
}
// Find the correspondent bin /* ************************************************************************* */
if (modg != 0.0) { /**
nbin = (size_t)floor(nbins*(modg / hmax)); * @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, const float& k) {
Mat den;
cv::sqrt(1.0 + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k), den);
dst = 1.0 / den;
}
if (nbin == nbins) { /* ************************************************************************* */
nbin--; /**
* @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
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);
// 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);
// 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;
}
}
} }
hist[nbin]++; // Skip the borders for computing the histogram
npoints++; 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 // Now find the perc of the histogram percentile
nthreshold = (size_t)(npoints*perc); nthreshold = (int)(npoints*perc);
for (k = 0; nelements < nthreshold && k < nbins; k++) { for (k = 0; nelements < nthreshold && k < nbins; k++) {
nelements = nelements + hist[k]; nelements = nelements + hist[k];
} }
if (nelements < nthreshold) {
kperc = 0.03f;
}
else {
kperc = hmax*((float)(k) / (float)nbins);
}
return kperc; 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 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 This function performs a scalar non-linear diffusion step * @brief This function performs a scalar non-linear diffusion step
* @param Ld2 Output image in the evolution * @param Ld2 Output image in the evolution
* @param c Conductivity image * @param c Conductivity image
* @param Lstep Previous image in the evolution * @param Lstep Previous image in the evolution
* @param stepsize The step size in time units * @param stepsize The step size in time units
* @note Forward Euler Scheme 3x3 stencil * @note Forward Euler Scheme 3x3 stencil
* The function c is a scalar value that depends on the gradient norm * 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 * 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, const float& stepsize) { void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, const float& stepsize) {
#ifdef _OPENMP #ifdef _OPENMP
#pragma omp parallel for schedule(dynamic) #pragma omp parallel for schedule(dynamic)
#endif #endif
for (int i = 1; i < Lstep.rows - 1; i++) { for (int i = 1; i < Lstep.rows - 1; i++) {
for (int j = 1; j < Lstep.cols - 1; j++) { 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 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 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 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))); 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); *(Lstep.ptr<float>(i)+j) = 0.5f*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)));
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 with the kernel [1/4,1/2,1/4]
* @param img Input image to be downsampled
* @param dst Output image with half of the resolution of the input image
*/
void downsample_image(const cv::Mat& src, cv::Mat& dst) {
int i1 = 0, j1 = 0, i2 = 0, j2 = 0;
for (i1 = 1; i1 < src.rows; i1 += 2) { for (int j = 1; j < Lstep.cols - 1; j++) {
j2 = 0; float xpos = ((*(c.ptr<float>(0) + j)) + (*(c.ptr<float>(0) + j + 1)))*((*(Ld.ptr<float>(0) + j + 1)) - (*(Ld.ptr<float>(0) + j)));
for (j1 = 1; j1 < src.cols; j1 += 2) { float xneg = ((*(c.ptr<float>(0) + j - 1)) + (*(c.ptr<float>(0) + j)))*((*(Ld.ptr<float>(0) + j)) - (*(Ld.ptr<float>(0) + j - 1)));
*(dst.ptr<float>(i2)+j2) = 0.5f*(*(src.ptr<float>(i1)+j1)) + 0.25f*(*(src.ptr<float>(i1)+j1 - 1) + *(src.ptr<float>(i1)+j1 + 1)); float ypos = ((*(c.ptr<float>(0) + j)) + (*(c.ptr<float>(1) + j)))*((*(Ld.ptr<float>(1) + j)) - (*(Ld.ptr<float>(0) + j)));
j2++; *(Lstep.ptr<float>(0) + j) = 0.5f*stepsize*(xpos - xneg + ypos);
} }
i2++; 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))));
* @brief This function downsamples the input image using OpenCV resize float xneg = ((*(c.ptr<float>(i))) + (*(c.ptr<float>(i))))*((*(Ld.ptr<float>(i))) - (*(Ld.ptr<float>(i))));
* @param img Input image to be downsampled float ypos = ((*(c.ptr<float>(i))) + (*(c.ptr<float>(i + 1))))*((*(Ld.ptr<float>(i + 1))) - (*(Ld.ptr<float>(i))));
* @param dst Output image with half of the resolution of the input image 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);
void halfsample_image(const cv::Mat& src, cv::Mat& dst) { }
// Make sure the destination image is of the right size for (int i = 1; i < Lstep.rows - 1; i++) {
CV_Assert(src.cols / 2 == dst.cols); 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)));
CV_Assert(src.rows / 2 == dst.rows); 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)));
resize(src, dst, dst.size(), 0, 0, cv::INTER_AREA); 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 Compute Scharr derivative kernels for sizes different than 3
* @param kx_ The derivative kernel in x-direction
* @param ky_ The derivative kernel in y-direction
* @param dx The derivative order in x-direction
* @param dy The derivative order in y-direction
* @param scale The kernel size
*/
void compute_derivative_kernels(cv::OutputArray kx_, cv::OutputArray ky_, int dx, int dy, int scale) {
const int ksize = 3 + 2 * (scale - 1); /* ************************************************************************* */
/**
* @brief This function downsamples the input image with the kernel [1/4,1/2,1/4]
* @param img Input image to be downsampled
* @param dst Output image with half of the resolution of the input image
*/
void downsample_image(const cv::Mat& src, cv::Mat& dst) {
// The usual Scharr kernel int i1 = 0, j1 = 0, i2 = 0, j2 = 0;
if (scale == 1) {
getDerivKernels(kx_, ky_, dx, dy, 0, true, CV_32F);
return;
}
kx_.create(ksize, 1, CV_32F, -1, true); for (i1 = 1; i1 < src.rows; i1 += 2) {
ky_.create(ksize, 1, CV_32F, -1, true); j2 = 0;
Mat kx = kx_.getMat(); for (j1 = 1; j1 < src.cols; j1 += 2) {
Mat ky = ky_.getMat(); *(dst.ptr<float>(i2)+j2) = 0.5f*(*(src.ptr<float>(i1)+j1)) + 0.25f*(*(src.ptr<float>(i1)+j1 - 1) + *(src.ptr<float>(i1)+j1 + 1));
j2++;
}
float w = 10.0f / 3.0f; i2++;
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; * @brief This function downsamples the input image using OpenCV resize
float kerI[1000]; * @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);
}
for (int t = 0; t < ksize; t++) { /* ************************************************************************* */
kerI[t] = 0; /**
} * @brief Compute Scharr derivative kernels for sizes different than 3
* @param kx_ The derivative kernel in x-direction
* @param ky_ The derivative kernel in y-direction
* @param dx The derivative order in x-direction
* @param dy The derivative order in y-direction
* @param scale The kernel size
*/
void compute_derivative_kernels(cv::OutputArray kx_, cv::OutputArray ky_, int dx, int dy, int scale) {
const int ksize = 3 + 2 * (scale - 1);
// The usual Scharr kernel
if (scale == 1) {
getDerivKernels(kx_, ky_, dx, dy, 0, true, CV_32F);
return;
}
if (order == 0) { kx_.create(ksize, 1, CV_32F, -1, true);
kerI[0] = norm; ky_.create(ksize, 1, CV_32F, -1, true);
kerI[ksize / 2] = w*norm; Mat kx = kx_.getMat();
kerI[ksize - 1] = norm; Mat ky = ky_.getMat();
}
else if (order == 1) { float w = 10.0f / 3.0f;
kerI[0] = -1; float norm = 1.0f / (2.0f*scale*(w + 2.0f));
kerI[ksize / 2] = 0;
kerI[ksize - 1] = 1; 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);
}
}
} }
Mat temp(kernel->rows, kernel->cols, CV_32F, &kerI[0]);
temp.copyTo(*kernel);
} }
} }
\ No newline at end of file
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* @author Pablo F. Alcantarilla, Jesus Nuevo * @author Pablo F. Alcantarilla, Jesus Nuevo
*/ */
#pragma once #ifndef AKAZE_NLDIFFUSION_FUNCTIONS_H
#define AKAZE_NLDIFFUSION_FUNCTIONS_H
/* ************************************************************************* */ /* ************************************************************************* */
// Includes // Includes
...@@ -13,20 +14,27 @@ ...@@ -13,20 +14,27 @@
/* ************************************************************************* */ /* ************************************************************************* */
// Declaration of functions // 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); namespace cv {
void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, namespace details {
const size_t& xorder, const size_t& yorder); namespace akaze {
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 gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma);
void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k); void image_derivatives_scharr(const cv::Mat& src, cv::Mat& dst, int xorder, int yorder);
void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k); void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k);
float compute_k_percentile(const cv::Mat& img, float perc, float gscale, void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k);
size_t nbins, size_t ksize_x, size_t ksize_y); void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k);
void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int, int scale); void charbonnier_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, const float& k);
void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, const float& stepsize); float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y);
void downsample_image(const cv::Mat& src, cv::Mat& dst); void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, int xorder, int, int scale);
void halfsample_image(const cv::Mat& src, cv::Mat& dst); void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, const float& stepsize);
void compute_derivative_kernels(cv::OutputArray kx_, cv::OutputArray ky_, int dx, int dy, int scale); void downsample_image(const cv::Mat& src, cv::Mat& dst);
bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, void halfsample_image(const cv::Mat& src, cv::Mat& dst);
int row, int col, bool same_img); void compute_derivative_kernels(cv::OutputArray kx_, cv::OutputArray ky_, int dx, int dy, int scale);
bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img);
}
}
}
#endif
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
// Namespaces // Namespaces
using namespace std; using namespace std;
using namespace cv; using namespace cv;
using namespace cv::details::kaze;
//******************************************************************************* //*******************************************************************************
//******************************************************************************* //*******************************************************************************
......
...@@ -28,349 +28,355 @@ ...@@ -28,349 +28,355 @@
// Namespaces // Namespaces
using namespace std; using namespace std;
using namespace cv; using namespace cv;
using namespace cv::details::kaze;
//************************************************************************************* //*************************************************************************************
//************************************************************************************* //*************************************************************************************
/** namespace cv {
* @brief This function smoothes an image with a Gaussian kernel namespace details {
* @param src Input image namespace kaze {
* @param dst Output image /**
* @param ksize_x Kernel size in X-direction (horizontal) * @brief This function smoothes an image with a Gaussian kernel
* @param ksize_y Kernel size in Y-direction (vertical) * @param src Input image
* @param sigma Kernel standard deviation * @param dst Output image
*/ * @param ksize_x Kernel size in X-direction (horizontal)
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, * @param ksize_y Kernel size in Y-direction (vertical)
int ksize_x, int ksize_y, float sigma) { * @param sigma Kernel standard deviation
*/
int ksize_x_ = 0, ksize_y_ = 0; void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst,
int ksize_x, int ksize_y, float sigma) {
// Compute an appropriate kernel size according to the specified sigma
if (sigma > ksize_x || sigma > ksize_y || ksize_x == 0 || ksize_y == 0) { int ksize_x_ = 0, ksize_y_ = 0;
ksize_x_ = (int)ceil(2.0f*(1.0f + (sigma-0.8f)/(0.3f)));
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_ = (int)ceil(2.0f*(1.0f + (sigma - 0.8f) / (0.3f)));
// The kernel size must be and odd number ksize_y_ = ksize_x_;
if ((ksize_x_ % 2) == 0) { }
ksize_x_ += 1;
} // The kernel size must be and odd number
if ((ksize_x_ % 2) == 0) {
if ((ksize_y_ % 2) == 0) { ksize_x_ += 1;
ksize_y_ += 1; }
}
if ((ksize_y_ % 2) == 0) {
// Perform the Gaussian Smoothing with border replication ksize_y_ += 1;
GaussianBlur(src,dst,Size(ksize_x_,ksize_y_),sigma,sigma,cv::BORDER_REPLICATE); }
}
// Perform the Gaussian Smoothing with border replication
//************************************************************************************* GaussianBlur(src, dst, Size(ksize_x_, ksize_y_), sigma, sigma, cv::BORDER_REPLICATE);
//************************************************************************************* }
/**
* @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./(1. + (Lx.mul(Lx) + Ly.mul(Ly))/(k*k));
}
//*************************************************************************************
//*************************************************************************************
/**
* @brief This function computes Weickert conductivity coefficient g3
* @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.315/modg, dst);
dst = 1.0f - dst;
}
//*************************************************************************************
//*************************************************************************************
/**
* @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 = (size_t)(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 or 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(); /**
* @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);
}
float w = 10.0f/3.0f; //*************************************************************************************
float norm = 1.0f/(2.0f*scale*(w+2.0f)); //*************************************************************************************
/**
* @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. / (1. + (Lx.mul(Lx) + Ly.mul(Ly)) / (k*k));
}
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); /**
* @brief This function computes Weickert conductivity coefficient g3
* @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.315 / modg, dst);
dst = 1.0f - dst;
}
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; * @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 = (size_t)(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;
}
Mat temp(kernel->rows,kernel->cols,CV_32F,&kerI[0]); //*************************************************************************************
temp.copyTo(*kernel); //*************************************************************************************
}
} /**
* @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 or 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);
}
}
/** //*************************************************************************************
* @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 * @brief This function performs a scalar non-linear diffusion step
* @param stepsize The step size in time units * @param Ld2 Output image in the evolution
* @note Forward Euler Scheme 3x3 stencil * @param c Conductivity image
* The function c is a scalar value that depends on the gradient norm * @param Lstep Previous image in the evolution
* dL_by_ds = d(c dL_by_dx)_by_dx + d(c dL_by_dy)_by_dy * @param stepsize The step size in time units
*/ * @note Forward Euler Scheme 3x3 stencil
void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize) { * 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) {
#ifdef _OPENMP #ifdef _OPENMP
#pragma omp parallel for schedule(dynamic) #pragma omp parallel for schedule(dynamic)
#endif #endif
for (int i = 1; i < Lstep.rows-1; i++) { for (int i = 1; i < Lstep.rows - 1; i++) {
for (int j = 1; j < Lstep.cols-1; j++) { 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 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 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 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))); 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); *(Lstep.ptr<float>(i)+j) = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
} }
} }
for (int j = 1; j < Lstep.cols-1; j++) { 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 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 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))); 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))); float yneg = ((*(c.ptr<float>(0) + j)) + (*(c.ptr<float>(0) + j)))*((*(Ld.ptr<float>(0) + j)) - (*(Ld.ptr<float>(0) + j)));
*(Lstep.ptr<float>(0)+j) = 0.5f*stepsize*(xpos-xneg + ypos-yneg); *(Lstep.ptr<float>(0) + j) = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
} }
for (int j = 1; j < Lstep.cols-1; 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 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 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 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))); 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); *(Lstep.ptr<float>(Lstep.rows - 1) + j) = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
} }
for (int i = 1; i < Lstep.rows-1; i++) { 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 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 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 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)))); 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); *(Lstep.ptr<float>(i)) = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
} }
for (int i = 1; i < Lstep.rows-1; i++) { 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 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 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 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))); 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*(xpos-xneg + ypos-yneg); *(Lstep.ptr<float>(i)+Lstep.cols - 1) = 0.5f*stepsize*(xpos - xneg + ypos - yneg);
} }
Ld = Ld + Lstep; Ld = Ld + Lstep;
} }
//*************************************************************************************
//*************************************************************************************
/** //*************************************************************************************
* @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 * @brief This function checks if a given pixel is a maximum in a local neighbourhood
* @param row Image row coordinate * @param img Input image where we will perform the maximum search
* @param col Image column coordinate * @param dsize Half size of the neighbourhood
* @param same_img Flag to indicate if the image value at (x,y) is in the input image * @param value Response value at (x,y) position
* @return 1->is maximum, 0->otherwise * @param row Image row coordinate
*/ * @param col Image column coordinate
bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, * @param same_img Flag to indicate if the image value at (x,y) is in the input image
int row, int col, bool same_img) { * @return 1->is maximum, 0->otherwise
*/
bool response = true; bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value,
int row, int col, bool same_img) {
for (int i = row-dsize; i <= row+dsize; i++) {
for (int j = col-dsize; j <= col+dsize; j++) { bool response = true;
if (i >= 0 && i < img.rows && j >= 0 && j < img.cols) {
if (same_img == true) { for (int i = row - dsize; i <= row + dsize; i++) {
if (i != row || j != col) { for (int j = col - dsize; j <= col + dsize; j++) {
if ((*(img.ptr<float>(i)+j)) > value) { if (i >= 0 && i < img.rows && j >= 0 && j < img.cols) {
response = false; if (same_img == true) {
return response; 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;
} }
}
} }
else {
if ((*(img.ptr<float>(i)+j)) > value) {
response = false;
return response;
}
}
}
} }
} }
\ No newline at end of file
return response;
}
/** /**
* @file nldiffusion_functions.h * @file nldiffusion_functions.h
* @brief Functions for non-linear diffusion applications: * @brief Functions for non-linear diffusion applications:
...@@ -9,43 +8,40 @@ ...@@ -9,43 +8,40 @@
* @author Pablo F. Alcantarilla * @author Pablo F. Alcantarilla
*/ */
#ifndef NLDIFFUSION_FUNCTIONS_H_ #ifndef KAZE_NLDIFFUSION_FUNCTIONS_H
#define NLDIFFUSION_FUNCTIONS_H_ #define KAZE_NLDIFFUSION_FUNCTIONS_H
//******************************************************************************
//******************************************************************************
// Includes // Includes
#include "config.h" #include "precomp.hpp"
//************************************************************************************* //*************************************************************************************
//************************************************************************************* //*************************************************************************************
// Gaussian 2D convolution namespace cv {
void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, namespace details {
int ksize_x, int ksize_y, float sigma); namespace kaze {
// Diffusivity functions // Gaussian 2D convolution
void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k); void gaussian_2D_convolution(const cv::Mat& src, cv::Mat& dst, int ksize_x, int ksize_y, float sigma);
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);
float compute_k_percentile(const cv::Mat& img, float perc, float gscale,
int nbins, int ksize_x, int ksize_y);
// Image derivatives // Diffusivity functions
void compute_scharr_derivatives(const cv::Mat& src, cv::Mat& dst, void pm_g1(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
int xorder, int yorder, int scale); void pm_g2(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
void compute_derivative_kernels(cv::OutputArray _kx, cv::OutputArray _ky, void weickert_diffusivity(const cv::Mat& Lx, const cv::Mat& Ly, cv::Mat& dst, float k);
int dx, int dy, int scale); float compute_k_percentile(const cv::Mat& img, float perc, float gscale, int nbins, int ksize_x, int ksize_y);
// Nonlinear diffusion filtering scalar step // Image derivatives
void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize); 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);
// For non-maxima suppresion // Nonlinear diffusion filtering scalar step
bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, void nld_step_scalar(cv::Mat& Ld, const cv::Mat& c, cv::Mat& Lstep, float stepsize);
int row, int col, bool same_img);
//************************************************************************************* // For non-maxima suppresion
//************************************************************************************* bool check_maximum_neighbourhood(const cv::Mat& img, int dsize, float value, int row, int col, bool same_img);
}
}
}
#endif // NLDIFFUSION_FUNCTIONS_H_ #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment