diff --git a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp index 2ad0189ef..202e36013 100644 --- a/modules/photo/src/fast_nlmeans_denoising_invoker.hpp +++ b/modules/photo/src/fast_nlmeans_denoising_invoker.hpp @@ -107,7 +107,7 @@ FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker( const float h) : src_(src), dst_(dst) { - CV_Assert(src.channels() == sizeof(T)); //T is Vec1b or Vec2b or Vec3b + CV_Assert(src.channels() == pixelInfo::channels); template_window_half_size_ = template_window_size / 2; search_window_half_size_ = search_window_size / 2; @@ -117,17 +117,21 @@ FastNlMeansDenoisingInvoker::FastNlMeansDenoisingInvoker( border_size_ = search_window_half_size_ + template_window_half_size_; copyMakeBorder(src_, extended_src_, border_size_, border_size_, border_size_, border_size_, BORDER_DEFAULT); - const IT max_estimate_sum_value = (IT)search_window_size_ * (IT)search_window_size_ * 255; + const IT max_estimate_sum_value = + (IT)search_window_size_ * (IT)search_window_size_ * (IT)pixelInfo::sampleMax(); fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; // precalc weight for every possible l2 dist between blocks // additional optimization of precalced weights to replace division(averaging) by binary shift + // squared distances are truncated to 16 bits to get a reasonable table size CV_Assert(template_window_size_ <= 46340); // sqrt(INT_MAX) int template_window_size_sq = template_window_size_ * template_window_size_; - almost_template_window_size_sq_bin_shift_ = getNearestPowerOf2(template_window_size_sq); + almost_template_window_size_sq_bin_shift_ = + getNearestPowerOf2(template_window_size_sq) + 2*pixelInfo::sampleBits() - 16; double almost_dist2actual_dist_multiplier = ((double)(1 << almost_template_window_size_sq_bin_shift_)) / template_window_size_sq; - IT max_dist = 255 * 255 * sizeof(T); + IT max_dist = + (IT)pixelInfo::sampleMax() * (IT)pixelInfo::sampleMax() * (IT)pixelInfo::channels; int almost_max_dist = (int)(max_dist / almost_dist2actual_dist_multiplier + 1); almost_dist2weight_.resize(almost_max_dist); diff --git a/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp b/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp index e4e0a3a59..0a8713b91 100644 --- a/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp +++ b/modules/photo/src/fast_nlmeans_denoising_invoker_commons.hpp @@ -44,30 +44,62 @@ using namespace cv; -template struct calcDist_ +template struct pixelInfo_ { - static inline IT f(const T a, const T b); + static const int channels = 1; + typedef T sampleType; }; -template struct calcDist_ +template struct pixelInfo_ > { - static inline IT f(uchar a, uchar b) + static const int channels = n; + typedef ET sampleType; +}; + +template struct pixelInfo: public pixelInfo_ +{ + using typename pixelInfo_::sampleType; + + static inline sampleType sampleMax() + { + return std::numeric_limits::max(); + } + + static inline sampleType sampleMin() + { + return std::numeric_limits::min(); + } + + static inline size_t sampleBytes() + { + return sizeof(sampleType); + } + + static inline size_t sampleBits() + { + return 8*sampleBytes(); + } +}; + +template struct calcDist_ +{ + static inline IT f(const T a, const T b) { return (IT)(a-b) * (IT)(a-b); } }; -template struct calcDist_ +template struct calcDist_, IT> { - static inline IT f(const Vec2b a, const Vec2b b) + 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_ +template struct calcDist_, IT> { - static inline IT f(const Vec3b a, const Vec3b b) + static inline IT f(const Vec a, const Vec b) { return (IT)(a[0]-b[0])*(IT)(a[0]-b[0]) + @@ -92,14 +124,6 @@ static inline IT calcDist(const Mat& m, int i1, int j1, int i2, int j2) template struct calcUpDownDist_ { 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); - } -}; - -template struct calcUpDownDist_ -{ - static inline IT f(uchar a_up, uchar a_down, uchar b_up, uchar b_down) { IT A = a_down - b_down; IT B = a_up - b_up; @@ -107,6 +131,17 @@ template struct calcUpDownDist_ } }; +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); + } +}; + template static inline IT calcUpDownDist(T a_up, T a_down, T b_up, T b_down) { @@ -115,29 +150,24 @@ static inline IT calcUpDownDist(T a_up, T a_down, T b_up, T b_down) template struct incWithWeight_ { - static inline void f(IT* estimation, IT weight, T p); -}; - -template struct incWithWeight_ -{ - static inline void f(IT* estimation, IT weight, uchar p) + static inline void f(IT* estimation, IT weight, T p) { estimation[0] += weight * p; } }; -template struct incWithWeight_ +template struct incWithWeight_, IT> { - static inline void f(IT* estimation, IT weight, Vec2b p) + static inline void f(IT* estimation, IT weight, Vec p) { estimation[0] += weight * p[0]; estimation[1] += weight * p[1]; } }; -template struct incWithWeight_ +template struct incWithWeight_, IT> { - static inline void f(IT* estimation, IT weight, Vec3b p) + static inline void f(IT* estimation, IT weight, Vec p) { estimation[0] += weight * p[0]; estimation[1] += weight * p[1]; @@ -153,36 +183,31 @@ static inline void incWithWeight(IT* estimation, IT weight, T p) template struct saturateCastFromArray_ { - static inline T f(IT* estimation); -}; - -template struct saturateCastFromArray_ -{ - static inline uchar f(IT* estimation) + static inline T f(IT* estimation) { - return saturate_cast(estimation[0]); + return saturate_cast(estimation[0]); } }; -template struct saturateCastFromArray_ +template struct saturateCastFromArray_, IT> { - static inline Vec2b f(IT* estimation) + static inline Vec f(IT* estimation) { - Vec2b res; - res[0] = saturate_cast(estimation[0]); - res[1] = saturate_cast(estimation[1]); + Vec res; + res[0] = saturate_cast(estimation[0]); + res[1] = saturate_cast(estimation[1]); return res; } }; -template struct saturateCastFromArray_ +template struct saturateCastFromArray_, IT> { - static inline Vec3b f(IT* estimation) + static inline Vec f(IT* estimation) { - Vec3b res; - res[0] = saturate_cast(estimation[0]); - res[1] = saturate_cast(estimation[1]); - res[2] = saturate_cast(estimation[2]); + Vec res; + res[0] = saturate_cast(estimation[0]); + res[1] = saturate_cast(estimation[1]); + res[2] = saturate_cast(estimation[2]); return res; } }; diff --git a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp index 392733c08..48276b426 100644 --- a/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp +++ b/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp @@ -106,7 +106,7 @@ FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker( dst_(dst), extended_srcs_(srcImgs.size()) { CV_Assert(srcImgs.size() > 0); - CV_Assert(srcImgs[0].channels() == sizeof(T)); + CV_Assert(srcImgs[0].channels() == pixelInfo::channels); rows_ = srcImgs[0].rows; cols_ = srcImgs[0].cols; @@ -126,20 +126,23 @@ FastNlMeansMultiDenoisingInvoker::FastNlMeansMultiDenoisingInvoker( main_extended_src_ = extended_srcs_[temporal_window_half_size_]; const IT max_estimate_sum_value = - (IT)temporal_window_size_ * (IT)search_window_size_ * (IT)search_window_size_ * 255; + (IT)temporal_window_size_ * (IT)search_window_size_ * (IT)search_window_size_ * (IT)pixelInfo::sampleMax(); fixed_point_mult_ = std::numeric_limits::max() / max_estimate_sum_value; // precalc weight for every possible l2 dist between blocks // additional optimization of precalced weights to replace division(averaging) by binary shift + // squared distances are truncated to 16 bits to get a reasonable table size int template_window_size_sq = template_window_size_ * template_window_size_; almost_template_window_size_sq_bin_shift = 0; while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) almost_template_window_size_sq_bin_shift++; + almost_template_window_size_sq_bin_shift += 2*pixelInfo::sampleBits() - 16; 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 = 255 * 255 * sizeof(T); + IT max_dist = + (IT)pixelInfo::sampleMax() * (IT)pixelInfo::sampleMax() * (IT)pixelInfo::channels; int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); almost_dist2weight.resize(almost_max_dist);