diff --git a/modules/photo/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp
index 2d1087e89..c25a35e6d 100644
--- a/modules/photo/include/opencv2/photo.hpp
+++ b/modules/photo/include/opencv2/photo.hpp
@@ -138,6 +138,31 @@ parameter.
CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3,
int templateWindowSize = 7, int searchWindowSize = 21);
+/** @brief Perform image denoising using Non-local Means Denoising
+algorithm
+with several computational optimizations. Noise expected to be a
+gaussian white noise. Uses squared sum of absolute value distances
+instead of sum of squared distances for weight calculation
+
+@param src Input 8-bit or 16-bit 1-channel, 2-channel or 3-channel image.
+@param dst Output image with the same size and type as src .
+@param templateWindowSize Size in pixels of the template patch that is used to compute weights.
+Should be odd. Recommended value 7 pixels
+@param searchWindowSize Size in pixels of the window that is used to compute weighted average for
+given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater
+denoising time. Recommended value 21 pixels
+@param h Parameter regulating filter strength. Big h value perfectly removes noise but also
+removes image details, smaller h value preserves details but also preserves some noise
+
+This function expected to be applied to grayscale images. For colored images look at
+fastNlMeansDenoisingColored. Advanced usage of this functions can be manual denoising of colored
+image in different colorspaces. Such approach is used in fastNlMeansDenoisingColored by converting
+image to CIELAB colorspace and then separately denoise L and AB components with different h
+parameter.
+ */
+CV_EXPORTS_W void fastNlMeansDenoisingAbs( InputArray src, OutputArray dst, float h = 3,
+ int templateWindowSize = 7, int searchWindowSize = 21);
+
/** @brief Modification of fastNlMeansDenoising function for colored images
@param src Input 8-bit 3-channel image.
@@ -186,6 +211,37 @@ CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputA
int imgToDenoiseIndex, int temporalWindowSize,
float h = 3, int templateWindowSize = 7, int searchWindowSize = 21);
+/** @brief Modification of fastNlMeansDenoising function for images
+sequence where consequtive images have been captured in small period
+of time. For example video. This version of the function is for
+grayscale images or for manual manipulation with colorspaces. For more
+details see
+. Uses
+squared sum of absolute value distances instead of sum of squared
+distances for weight calculation
+
+@param srcImgs Input 8-bit or 16-bit 1-channel, 2-channel or 3-channel
+images sequence. All images should
+have the same type and size.
+@param imgToDenoiseIndex Target image to denoise index in srcImgs sequence
+@param temporalWindowSize Number of surrounding images to use for target image denoising. Should
+be odd. Images from imgToDenoiseIndex - temporalWindowSize / 2 to
+imgToDenoiseIndex - temporalWindowSize / 2 from srcImgs will be used to denoise
+srcImgs[imgToDenoiseIndex] image.
+@param dst Output image with the same size and type as srcImgs images.
+@param templateWindowSize Size in pixels of the template patch that is used to compute weights.
+Should be odd. Recommended value 7 pixels
+@param searchWindowSize Size in pixels of the window that is used to compute weighted average for
+given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater
+denoising time. Recommended value 21 pixels
+@param h Parameter regulating filter strength for luminance component. Bigger h value perfectly
+removes noise but also removes image details, smaller h value preserves details but also preserves
+some noise
+ */
+CV_EXPORTS_W void fastNlMeansDenoisingMultiAbs( InputArrayOfArrays srcImgs, OutputArray dst,
+ int imgToDenoiseIndex, int temporalWindowSize,
+ float h = 3, int templateWindowSize = 7, int searchWindowSize = 21);
+
/** @brief Modification of fastNlMeansDenoisingMulti function for colored images sequences
@param srcImgs Input 8-bit 3-channel images sequence. All images should have the same type and
diff --git a/modules/photo/src/denoising.cpp b/modules/photo/src/denoising.cpp
index 8f9d1f84a..52065b5f6 100644
--- a/modules/photo/src/denoising.cpp
+++ b/modules/photo/src/denoising.cpp
@@ -65,32 +65,62 @@ void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h,
switch (src.type()) {
case CV_8U:
parallel_for_(cv::Range(0, src.rows),
- FastNlMeansDenoisingInvoker(
+ FastNlMeansDenoisingInvoker(
src, dst, templateWindowSize, searchWindowSize, h));
break;
case CV_8UC2:
parallel_for_(cv::Range(0, src.rows),
- FastNlMeansDenoisingInvoker(
+ FastNlMeansDenoisingInvoker(
src, dst, templateWindowSize, searchWindowSize, h));
break;
case CV_8UC3:
parallel_for_(cv::Range(0, src.rows),
- FastNlMeansDenoisingInvoker(
+ FastNlMeansDenoisingInvoker(
+ src, dst, templateWindowSize, searchWindowSize, h));
+ break;
+ default:
+ CV_Error(Error::StsBadArg,
+ "Unsupported image format! Only CV_8U, CV_8UC2, and CV_8UC3 are supported");
+ }
+}
+
+void cv::fastNlMeansDenoisingAbs( InputArray _src, OutputArray _dst, float h,
+ int templateWindowSize, int searchWindowSize)
+{
+ Size src_size = _src.size();
+ Mat src = _src.getMat();
+ _dst.create(src_size, src.type());
+ Mat dst = _dst.getMat();
+
+ switch (src.type()) {
+ case CV_8U:
+ parallel_for_(cv::Range(0, src.rows),
+ FastNlMeansDenoisingInvoker(
+ src, dst, templateWindowSize, searchWindowSize, h));
+ break;
+ case CV_8UC2:
+ parallel_for_(cv::Range(0, src.rows),
+ FastNlMeansDenoisingInvoker(
+ src, dst, templateWindowSize, searchWindowSize, h));
+ break;
+ case CV_8UC3:
+ parallel_for_(cv::Range(0, src.rows),
+ FastNlMeansDenoisingInvoker(
src, dst, templateWindowSize, searchWindowSize, h));
break;
case CV_16U:
parallel_for_(cv::Range(0, src.rows),
- FastNlMeansDenoisingInvoker(
+ FastNlMeansDenoisingInvoker(
src, dst, templateWindowSize, searchWindowSize, h));
break;
case CV_16UC2:
parallel_for_(cv::Range(0, src.rows),
- FastNlMeansDenoisingInvoker, int64, uint64>(
+ FastNlMeansDenoisingInvoker, int64, uint64, DistAbs>(
src, dst, templateWindowSize, searchWindowSize, h));
break;
case CV_16UC3:
parallel_for_(cv::Range(0, src.rows),
- FastNlMeansDenoisingInvoker, int64, uint64>(
+ FastNlMeansDenoisingInvoker, int64, uint64, DistAbs>(
src, dst, templateWindowSize, searchWindowSize, h));
break;
default:
@@ -105,9 +135,9 @@ void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
{
int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
Size src_size = _src.size();
- if (type != CV_8UC3 && type != CV_16UC3 && type != CV_8UC4 && type != CV_16UC4)
+ if (type != CV_8UC3 && type != CV_8UC4)
{
- CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3, CV_16UC3, CV_8UC4, or CV_16UC4");
+ CV_Error(Error::StsBadArg, "Type of input image should be CV_8UC3 or CV_8UC4!");
return;
}
@@ -190,37 +220,77 @@ void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _ds
{
case CV_8U:
parallel_for_(cv::Range(0, srcImgs[0].rows),
- FastNlMeansMultiDenoisingInvoker(
+ FastNlMeansMultiDenoisingInvoker(
srcImgs, imgToDenoiseIndex, temporalWindowSize,
dst, templateWindowSize, searchWindowSize, h));
break;
case CV_8UC2:
parallel_for_(cv::Range(0, srcImgs[0].rows),
- FastNlMeansMultiDenoisingInvoker(
+ FastNlMeansMultiDenoisingInvoker(
srcImgs, imgToDenoiseIndex, temporalWindowSize,
dst, templateWindowSize, searchWindowSize, h));
break;
case CV_8UC3:
parallel_for_(cv::Range(0, srcImgs[0].rows),
- FastNlMeansMultiDenoisingInvoker(
+ FastNlMeansMultiDenoisingInvoker(
+ srcImgs, imgToDenoiseIndex, temporalWindowSize,
+ dst, templateWindowSize, searchWindowSize, h));
+ break;
+ default:
+ CV_Error(Error::StsBadArg,
+ "Unsupported image format! Only CV_8U, CV_8UC2, and CV_8UC3 are supported");
+ }
+}
+
+void cv::fastNlMeansDenoisingMultiAbs( InputArrayOfArrays _srcImgs, OutputArray _dst,
+ int imgToDenoiseIndex, int temporalWindowSize,
+ float h, int templateWindowSize, int searchWindowSize)
+{
+ std::vector srcImgs;
+ _srcImgs.getMatVector(srcImgs);
+
+ fastNlMeansDenoisingMultiCheckPreconditions(
+ srcImgs, imgToDenoiseIndex,
+ temporalWindowSize, templateWindowSize, searchWindowSize);
+
+ _dst.create(srcImgs[0].size(), srcImgs[0].type());
+ Mat dst = _dst.getMat();
+
+ switch (srcImgs[0].type())
+ {
+ case CV_8U:
+ parallel_for_(cv::Range(0, srcImgs[0].rows),
+ FastNlMeansMultiDenoisingInvoker(
+ srcImgs, imgToDenoiseIndex, temporalWindowSize,
+ dst, templateWindowSize, searchWindowSize, h));
+ break;
+ case CV_8UC2:
+ parallel_for_(cv::Range(0, srcImgs[0].rows),
+ FastNlMeansMultiDenoisingInvoker(
+ srcImgs, imgToDenoiseIndex, temporalWindowSize,
+ dst, templateWindowSize, searchWindowSize, h));
+ break;
+ case CV_8UC3:
+ parallel_for_(cv::Range(0, srcImgs[0].rows),
+ FastNlMeansMultiDenoisingInvoker(
srcImgs, imgToDenoiseIndex, temporalWindowSize,
dst, templateWindowSize, searchWindowSize, h));
break;
case CV_16U:
parallel_for_(cv::Range(0, srcImgs[0].rows),
- FastNlMeansMultiDenoisingInvoker(
+ FastNlMeansMultiDenoisingInvoker(
srcImgs, imgToDenoiseIndex, temporalWindowSize,
dst, templateWindowSize, searchWindowSize, h));
break;
case CV_16UC2:
parallel_for_(cv::Range(0, srcImgs[0].rows),
- FastNlMeansMultiDenoisingInvoker, int64, uint64>(
+ FastNlMeansMultiDenoisingInvoker, int64, uint64, DistAbs>(
srcImgs, imgToDenoiseIndex, temporalWindowSize,
dst, templateWindowSize, searchWindowSize, h));
break;
case CV_16UC3:
parallel_for_(cv::Range(0, srcImgs[0].rows),
- FastNlMeansMultiDenoisingInvoker, int64, uint64>(
+ FastNlMeansMultiDenoisingInvoker, int64, uint64, DistAbs>(
srcImgs, imgToDenoiseIndex, temporalWindowSize,
dst, templateWindowSize, searchWindowSize, h));
break;
@@ -248,9 +318,9 @@ void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputAr
int type = srcImgs[0].type(), depth = CV_MAT_DEPTH(type);
int src_imgs_size = static_cast(srcImgs.size());
- if (type != CV_8UC3 && type != CV_16UC3)
+ if (type != CV_8UC3)
{
- CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3 or CV_16UC3!");
+ CV_Error(Error::StsBadArg, "Type of input images should be CV_8UC3!");
return;
}
diff --git a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp
index a641c990e..468fa82f7 100644
--- a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp
+++ b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp
@@ -50,7 +50,7 @@
using namespace cv;
-template
+template
struct FastNlMeansDenoisingInvoker :
public ParallelLoopBody
{
@@ -99,8 +99,8 @@ inline int getNearestPowerOf2(int value)
return p;
}
-template
-FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker(
+template
+FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker(
const Mat& src, Mat& dst,
int template_window_size,
int search_window_size,
@@ -128,7 +128,7 @@ FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker(
almost_template_window_size_sq_bin_shift_ = getNearestPowerOf2(template_window_size_sq);
double almost_dist2actual_dist_multiplier = ((double)(1 << almost_template_window_size_sq_bin_shift_)) / template_window_size_sq;
- IT max_dist = (IT)pixelInfo::sampleMax() * (IT)pixelInfo::channels;
+ IT max_dist = D::template maxDist();
size_t almost_max_dist = (size_t)(max_dist / almost_dist2actual_dist_multiplier + 1);
almost_dist2weight_.resize(almost_max_dist);
@@ -136,7 +136,7 @@ FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker(
for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++)
{
double dist = almost_dist * almost_dist2actual_dist_multiplier;
- IT weight = (IT)round(fixed_point_mult_ * std::exp(-dist*dist / (h * h * pixelInfo::channels)));
+ IT weight = (IT)round(fixed_point_mult_ * D::template calcWeight(dist, h));
if (weight < WEIGHT_THRESHOLD * fixed_point_mult_)
weight = 0;
@@ -149,8 +149,8 @@ FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker(
dst_ = Mat::zeros(src_.size(), src_.type());
}
-template
-void FastNlMeansDenoisingInvoker::operator() (const Range& range) const
+template
+void FastNlMeansDenoisingInvoker::operator() (const Range& range) const
{
int row_from = range.start;
int row_to = range.end - 1;
@@ -215,7 +215,7 @@ void FastNlMeansDenoisingInvoker::operator() (const Range& range) co
dist_sums_row[x] -= col_dist_sums_row[x];
int bx = start_bx + x;
- col_dist_sums_row[x] = up_col_dist_sums_row[x] + calcUpDownDist(a_up, a_down, b_up_ptr[bx], b_down_ptr[bx]);
+ col_dist_sums_row[x] = up_col_dist_sums_row[x] + D::template calcUpDownDist(a_up, a_down, b_up_ptr[bx], b_down_ptr[bx]);
dist_sums_row[x] += col_dist_sums_row[x];
up_col_dist_sums_row[x] = col_dist_sums_row[x];
@@ -254,8 +254,8 @@ void FastNlMeansDenoisingInvoker::operator() (const Range& range) co
}
}
-template
-inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElementInRow(
+template
+inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElementInRow(
int i,
Array2d& dist_sums,
Array3d& col_dist_sums,
@@ -276,7 +276,7 @@ inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElement
for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)
for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++)
{
- int dist = calcDist(extended_src_,
+ int dist = D::template calcDist(extended_src_,
border_size_ + i + ty, border_size_ + j + tx,
border_size_ + start_y + ty, border_size_ + start_x + tx);
@@ -288,8 +288,8 @@ inline void FastNlMeansDenoisingInvoker::calcDistSumsForFirstElement
}
}
-template
-inline void FastNlMeansDenoisingInvoker::calcDistSumsForElementInFirstRow(
+template
+inline void FastNlMeansDenoisingInvoker::calcDistSumsForElementInFirstRow(
int i, int j, int first_col_num,
Array2d& dist_sums,
Array3d& col_dist_sums,
@@ -312,7 +312,7 @@ inline void FastNlMeansDenoisingInvoker::calcDistSumsForElementInFir
int by = start_by + y;
int bx = start_bx + x;
for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)
- col_dist_sums[new_last_col_num][y][x] += calcDist(extended_src_, ay + ty, ax, by + ty, bx);
+ col_dist_sums[new_last_col_num][y][x] += D::template calcDist(extended_src_, ay + ty, ax, by + ty, bx);
dist_sums[y][x] += col_dist_sums[new_last_col_num][y][x];
up_col_dist_sums[j][y][x] = col_dist_sums[new_last_col_num][y][x];
diff --git a/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp b/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp
index 4ca63d652..d55d93ce7 100644
--- a/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp
+++ b/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp
@@ -81,47 +81,150 @@ template struct pixelInfo: public pixelInfo_
}
};
-template struct calcDist_
+class DistAbs
{
- static inline IT f(const T a, const T b)
+ template struct calcDist_
{
- return std::abs((IT)(a-b));
+ static inline IT f(const T a, const T b)
+ {
+ return std::abs((IT)(a-b));
+ }
+ };
+
+ template struct calcDist_, IT>
+ {
+ static inline IT f(const Vec a, const Vec b)
+ {
+ return std::abs((IT)(a[0]-b[0])) + std::abs((IT)(a[1]-b[1]));
+ }
+ };
+
+ template struct calcDist_, IT>
+ {
+ static inline IT f(const Vec a, const Vec b)
+ {
+ return
+ std::abs((IT)(a[0]-b[0])) +
+ std::abs((IT)(a[1]-b[1])) +
+ std::abs((IT)(a[2]-b[2]));
+ }
+ };
+
+public:
+ template static inline IT calcDist(const T a, const T b)
+ {
+ return calcDist_::f(a, b);
+ }
+
+ template
+ static inline IT calcDist(const Mat& m, int i1, int j1, int i2, int j2)
+ {
+ const T a = m.at(i1, j1);
+ const T b = m.at(i2, j2);
+ return calcDist(a,b);
+ }
+
+ template
+ static inline IT calcUpDownDist(T a_up, T a_down, T b_up, T b_down)
+ {
+ return calcDist(a_down, b_down) - calcDist(a_up, b_up);
+ };
+
+ template
+ static double calcWeight(double dist, double h)
+ {
+ return std::exp(-dist*dist / (h * h * pixelInfo::channels));
+ }
+
+ template
+ static double maxDist()
+ {
+ return (IT)pixelInfo::sampleMax() * (IT)pixelInfo::channels;
}
};
-template struct calcDist_, IT>
+class DistSquared
{
- static inline IT f(const Vec a, const Vec b)
+ template struct calcDist_
{
- return std::abs((IT)(a[0]-b[0])) + std::abs((IT)(a[1]-b[1]));
- }
-};
+ static inline IT f(const T a, const T b)
+ {
+ return (IT)(a-b) * (IT)(a-b);
+ }
+ };
-template struct calcDist_, IT>
-{
- static inline IT f(const Vec a, const Vec b)
+ template struct calcDist_, IT>
{
- return std::abs((IT)(a[0]-b[0])) + std::abs((IT)(a[1]-b[1])) + std::abs((IT)(a[2]-b[2]));
+ static inline IT f(const Vec a, const Vec b)
+ {
+ return (IT)(a[0]-b[0])*(IT)(a[0]-b[0]) + (IT)(a[1]-b[1])*(IT)(a[1]-b[1]);
+ }
+ };
+
+ template struct calcDist_, IT>
+ {
+ static inline IT f(const Vec a, const Vec b)
+ {
+ return
+ (IT)(a[0]-b[0])*(IT)(a[0]-b[0]) +
+ (IT)(a[1]-b[1])*(IT)(a[1]-b[1]) +
+ (IT)(a[2]-b[2])*(IT)(a[2]-b[2]);
+ }
+ };
+
+ template struct calcUpDownDist_
+ {
+ static inline IT f(T a_up, T a_down, T b_up, T b_down)
+ {
+ IT A = a_down - b_down;
+ IT B = a_up - b_up;
+ return (A-B)*(A+B);
+ }
+ };
+
+ template struct calcUpDownDist_, IT>
+ {
+ private:
+ typedef Vec T;
+ public:
+ static inline IT f(T a_up, T a_down, T b_up, T b_down)
+ {
+ return calcDist(a_down, b_down) - calcDist(a_up, b_up);
+ }
+ };
+
+public:
+ template static inline IT calcDist(const T a, const T b)
+ {
+ return calcDist_::f(a, b);
}
-};
-template static inline IT calcDist(const T a, const T b)
-{
- return calcDist_::f(a, b);
-}
+ template
+ static inline IT calcDist(const Mat& m, int i1, int j1, int i2, int j2)
+ {
+ const T a = m.at(i1, j1);
+ const T b = m.at(i2, j2);
+ return calcDist(a,b);
+ }
-template
-static inline IT calcDist(const Mat& m, int i1, int j1, int i2, int j2)
-{
- const T a = m.at(i1, j1);
- const T b = m.at(i2, j2);
- return calcDist(a,b);
-}
+ template
+ static inline IT calcUpDownDist(T a_up, T a_down, T b_up, T b_down)
+ {
+ return calcUpDownDist_::f(a_up, a_down, b_up, b_down);
+ };
-template
-static inline IT calcUpDownDist(T a_up, T a_down, T b_up, T b_down)
-{
- return calcDist(a_down, b_down) - calcDist(a_up, b_up);
+ template
+ static double calcWeight(double dist, double h)
+ {
+ return std::exp(-dist / (h * h * pixelInfo::channels));
+ }
+
+ template
+ static double maxDist()
+ {
+ return (IT)pixelInfo::sampleMax() * (IT)pixelInfo::sampleMax() *
+ (IT)pixelInfo::channels;
+ }
};
template struct incWithWeight_
diff --git a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp
index 808b01f50..0a2bdd739 100644
--- a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp
+++ b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp
@@ -50,7 +50,7 @@
using namespace cv;
-template
+template
struct FastNlMeansMultiDenoisingInvoker :
ParallelLoopBody
{
@@ -94,8 +94,8 @@ private:
Array4d& up_col_dist_sums) const;
};
-template
-FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker(
+template
+FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker(
const std::vector& srcImgs,
int imgToDenoiseIndex,
int temporalWindowSize,
@@ -139,7 +139,7 @@ FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker(
int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift;
double almost_dist2actual_dist_multiplier = (double) almost_template_window_size_sq / template_window_size_sq;
- IT max_dist = (IT)pixelInfo::sampleMax() * (IT)pixelInfo::channels;
+ IT max_dist = D::template maxDist();
int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1);
almost_dist2weight.resize(almost_max_dist);
@@ -147,7 +147,7 @@ FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker(
for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++)
{
double dist = almost_dist * almost_dist2actual_dist_multiplier;
- IT weight = (IT)round(fixed_point_mult_ * std::exp(-dist*dist / (h * h * pixelInfo::channels)));
+ IT weight = (IT)round(fixed_point_mult_ * D::template calcWeight(dist, h));
if (weight < WEIGHT_THRESHOLD * fixed_point_mult_)
weight = 0;
@@ -160,8 +160,8 @@ FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker(
dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type());
}
-template
-void FastNlMeansMultiDenoisingInvoker::operator() (const Range& range) const
+template
+void FastNlMeansMultiDenoisingInvoker::operator() (const Range& range) const
{
int row_from = range.start;
int row_to = range.end - 1;
@@ -234,7 +234,7 @@ void FastNlMeansMultiDenoisingInvoker::operator() (const Range& rang
dist_sums_row[x] -= col_dist_sums_row[x];
col_dist_sums_row[x] = up_col_dist_sums_row[x] +
- calcUpDownDist(a_up, a_down, b_up_ptr[start_bx + x], b_down_ptr[start_bx + x]);
+ D::template calcUpDownDist(a_up, a_down, b_up_ptr[start_bx + x], b_down_ptr[start_bx + x]);
dist_sums_row[x] += col_dist_sums_row[x];
up_col_dist_sums_row[x] = col_dist_sums_row[x];
@@ -284,8 +284,8 @@ void FastNlMeansMultiDenoisingInvoker::operator() (const Range& rang
}
}
-template
-inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstElementInRow(
+template
+inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstElementInRow(
int i, Array3d& dist_sums, Array4d& col_dist_sums, Array4d& up_col_dist_sums) const
{
int j = 0;
@@ -310,7 +310,7 @@ inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstEl
{
for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)
{
- IT dist = calcDist(
+ IT dist = D::template calcDist(
main_extended_src_.at(border_size_ + i + ty, border_size_ + j + tx),
cur_extended_src.at(border_size_ + start_y + ty, border_size_ + start_x + tx));
@@ -325,8 +325,8 @@ inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForFirstEl
}
}
-template
-inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForElementInFirstRow(
+template
+inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForElementInFirstRow(
int i, int j, int first_col_num, Array3d& dist_sums,
Array4d& col_dist_sums, Array4d& up_col_dist_sums) const
{
@@ -353,7 +353,7 @@ inline void FastNlMeansMultiDenoisingInvoker::calcDistSumsForElement
IT* col_dist_sums_ptr = &col_dist_sums[new_last_col_num][d][y][x];
for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)
{
- *col_dist_sums_ptr += calcDist(
+ *col_dist_sums_ptr += D::template calcDist(
main_extended_src_.at(ay + ty, ax),
cur_extended_src.at(by + ty, bx));
}