Path: blob/master/modules/photo/src/fast_nlmeans_multi_denoising_invoker.hpp
16347 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective icvers.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/4041#ifndef __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__42#define __OPENCV_FAST_NLMEANS_MULTI_DENOISING_INVOKER_HPP__4344#include "precomp.hpp"45#include <limits>4647#include "fast_nlmeans_denoising_invoker_commons.hpp"48#include "arrays.hpp"4950using namespace cv;5152template <typename T, typename IT, typename UIT, typename D, typename WT>53struct FastNlMeansMultiDenoisingInvoker :54ParallelLoopBody55{56public:57FastNlMeansMultiDenoisingInvoker(const std::vector<Mat>& srcImgs, int imgToDenoiseIndex,58int temporalWindowSize, Mat& dst, int template_window_size,59int search_window_size, const float *h);6061void operator() (const Range& range) const CV_OVERRIDE;6263private:64void operator= (const FastNlMeansMultiDenoisingInvoker&);6566int rows_;67int cols_;6869Mat& dst_;7071std::vector<Mat> extended_srcs_;72Mat main_extended_src_;73int border_size_;7475int template_window_size_;76int search_window_size_;77int temporal_window_size_;7879int template_window_half_size_;80int search_window_half_size_;81int temporal_window_half_size_;8283typename pixelInfo<WT>::sampleType fixed_point_mult_;84int almost_template_window_size_sq_bin_shift;85std::vector<WT> almost_dist2weight;8687void calcDistSumsForFirstElementInRow(int i, Array3d<int>& dist_sums,88Array4d<int>& col_dist_sums,89Array4d<int>& up_col_dist_sums) const;9091void calcDistSumsForElementInFirstRow(int i, int j, int first_col_num,92Array3d<int>& dist_sums, Array4d<int>& col_dist_sums,93Array4d<int>& up_col_dist_sums) const;94};9596template <typename T, typename IT, typename UIT, typename D, typename WT>97FastNlMeansMultiDenoisingInvoker<T, IT, UIT, D, WT>::FastNlMeansMultiDenoisingInvoker(98const std::vector<Mat>& srcImgs,99int imgToDenoiseIndex,100int temporalWindowSize,101cv::Mat& dst,102int template_window_size,103int search_window_size,104const float *h) :105dst_(dst), extended_srcs_(srcImgs.size())106{107CV_Assert(srcImgs.size() > 0);108CV_Assert(srcImgs[0].channels() == pixelInfo<T>::channels);109110rows_ = srcImgs[0].rows;111cols_ = srcImgs[0].cols;112113template_window_half_size_ = template_window_size / 2;114search_window_half_size_ = search_window_size / 2;115temporal_window_half_size_ = temporalWindowSize / 2;116117template_window_size_ = template_window_half_size_ * 2 + 1;118search_window_size_ = search_window_half_size_ * 2 + 1;119temporal_window_size_ = temporal_window_half_size_ * 2 + 1;120121border_size_ = search_window_half_size_ + template_window_half_size_;122for (int i = 0; i < temporal_window_size_; i++)123copyMakeBorder(srcImgs[imgToDenoiseIndex - temporal_window_half_size_ + i], extended_srcs_[i],124border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT);125126main_extended_src_ = extended_srcs_[temporal_window_half_size_];127const IT max_estimate_sum_value =128(IT)temporal_window_size_ * (IT)search_window_size_ * (IT)search_window_size_ * (IT)pixelInfo<T>::sampleMax();129fixed_point_mult_ = (int)std::min<IT>(std::numeric_limits<IT>::max() / max_estimate_sum_value,130pixelInfo<WT>::sampleMax());131132// precalc weight for every possible l2 dist between blocks133// additional optimization of precalced weights to replace division(averaging) by binary shift134int template_window_size_sq = template_window_size_ * template_window_size_;135almost_template_window_size_sq_bin_shift = 0;136while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq)137almost_template_window_size_sq_bin_shift++;138139int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift;140double almost_dist2actual_dist_multiplier = (double) almost_template_window_size_sq / template_window_size_sq;141142int max_dist = D::template maxDist<T>();143int almost_max_dist = (int)(max_dist / almost_dist2actual_dist_multiplier + 1);144almost_dist2weight.resize(almost_max_dist);145146for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++)147{148double dist = almost_dist * almost_dist2actual_dist_multiplier;149almost_dist2weight[almost_dist] =150D::template calcWeight<T, WT>(dist, h, fixed_point_mult_);151}152153// additional optimization init end154if (dst_.empty())155dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type());156}157158template <typename T, typename IT, typename UIT, typename D, typename WT>159void FastNlMeansMultiDenoisingInvoker<T, IT, UIT, D, WT>::operator() (const Range& range) const160{161int row_from = range.start;162int row_to = range.end - 1;163164Array3d<int> dist_sums(temporal_window_size_, search_window_size_, search_window_size_);165166// for lazy calc optimization167Array4d<int> col_dist_sums(template_window_size_, temporal_window_size_, search_window_size_, search_window_size_);168169int first_col_num = -1;170Array4d<int> up_col_dist_sums(cols_, temporal_window_size_, search_window_size_, search_window_size_);171172for (int i = row_from; i <= row_to; i++)173{174for (int j = 0; j < cols_; j++)175{176int search_window_y = i - search_window_half_size_;177int search_window_x = j - search_window_half_size_;178179// calc dist_sums180if (j == 0)181{182calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums);183first_col_num = 0;184}185else186{187// calc cur dist_sums using previous dist_sums188if (i == row_from)189{190calcDistSumsForElementInFirstRow(i, j, first_col_num,191dist_sums, col_dist_sums, up_col_dist_sums);192193}194else195{196int ay = border_size_ + i;197int ax = border_size_ + j + template_window_half_size_;198199int start_by =200border_size_ + i - search_window_half_size_;201202int start_bx =203border_size_ + j - search_window_half_size_ + template_window_half_size_;204205T a_up = main_extended_src_.at<T>(ay - template_window_half_size_ - 1, ax);206T a_down = main_extended_src_.at<T>(ay + template_window_half_size_, ax);207208// copy class member to local variable for optimization209int search_window_size = search_window_size_;210211for (int d = 0; d < temporal_window_size_; d++)212{213Mat cur_extended_src = extended_srcs_[d];214Array2d<int> cur_dist_sums = dist_sums[d];215Array2d<int> cur_col_dist_sums = col_dist_sums[first_col_num][d];216Array2d<int> cur_up_col_dist_sums = up_col_dist_sums[j][d];217for (int y = 0; y < search_window_size; y++)218{219int* dist_sums_row = cur_dist_sums.row_ptr(y);220221int* col_dist_sums_row = cur_col_dist_sums.row_ptr(y);222int* up_col_dist_sums_row = cur_up_col_dist_sums.row_ptr(y);223224const T* b_up_ptr = cur_extended_src.ptr<T>(start_by - template_window_half_size_ - 1 + y);225const T* b_down_ptr = cur_extended_src.ptr<T>(start_by + template_window_half_size_ + y);226227for (int x = 0; x < search_window_size; x++)228{229dist_sums_row[x] -= col_dist_sums_row[x];230231col_dist_sums_row[x] = up_col_dist_sums_row[x] +232D::template calcUpDownDist<T>(a_up, a_down, b_up_ptr[start_bx + x], b_down_ptr[start_bx + x]);233234dist_sums_row[x] += col_dist_sums_row[x];235up_col_dist_sums_row[x] = col_dist_sums_row[x];236}237}238}239}240241first_col_num = (first_col_num + 1) % template_window_size_;242}243244// calc weights245IT estimation[pixelInfo<T>::channels], weights_sum[pixelInfo<WT>::channels];246for (size_t channel_num = 0; channel_num < pixelInfo<T>::channels; channel_num++)247estimation[channel_num] = 0;248for (size_t channel_num = 0; channel_num < pixelInfo<WT>::channels; channel_num++)249weights_sum[channel_num] = 0;250251for (int d = 0; d < temporal_window_size_; d++)252{253const Mat& esrc_d = extended_srcs_[d];254for (int y = 0; y < search_window_size_; y++)255{256const T* cur_row_ptr = esrc_d.ptr<T>(border_size_ + search_window_y + y);257258int* dist_sums_row = dist_sums.row_ptr(d, y);259260for (int x = 0; x < search_window_size_; x++)261{262int almostAvgDist = dist_sums_row[x] >> almost_template_window_size_sq_bin_shift;263264WT weight = almost_dist2weight[almostAvgDist];265T p = cur_row_ptr[border_size_ + search_window_x + x];266incWithWeight<T, IT, WT>(estimation, weights_sum, weight, p);267}268}269}270271divByWeightsSum<IT, UIT, pixelInfo<T>::channels, pixelInfo<WT>::channels>(estimation,272weights_sum);273dst_.at<T>(i,j) = saturateCastFromArray<T, IT>(estimation);274}275}276}277278template <typename T, typename IT, typename UIT, typename D, typename WT>279inline void FastNlMeansMultiDenoisingInvoker<T, IT, UIT, D, WT>::calcDistSumsForFirstElementInRow(280int i, Array3d<int>& dist_sums, Array4d<int>& col_dist_sums, Array4d<int>& up_col_dist_sums) const281{282int j = 0;283284for (int d = 0; d < temporal_window_size_; d++)285{286Mat cur_extended_src = extended_srcs_[d];287for (int y = 0; y < search_window_size_; y++)288for (int x = 0; x < search_window_size_; x++)289{290dist_sums[d][y][x] = 0;291for (int tx = 0; tx < template_window_size_; tx++)292col_dist_sums[tx][d][y][x] = 0;293294int start_y = i + y - search_window_half_size_;295int start_x = j + x - search_window_half_size_;296297int* dist_sums_ptr = &dist_sums[d][y][x];298int* col_dist_sums_ptr = &col_dist_sums[0][d][y][x];299int col_dist_sums_step = col_dist_sums.step_size(0);300for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++)301{302for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)303{304int dist = D::template calcDist<T>(305main_extended_src_.at<T>(border_size_ + i + ty, border_size_ + j + tx),306cur_extended_src.at<T>(border_size_ + start_y + ty, border_size_ + start_x + tx));307308*dist_sums_ptr += dist;309*col_dist_sums_ptr += dist;310}311col_dist_sums_ptr += col_dist_sums_step;312}313314up_col_dist_sums[j][d][y][x] = col_dist_sums[template_window_size_ - 1][d][y][x];315}316}317}318319template <typename T, typename IT, typename UIT, typename D, typename WT>320inline void FastNlMeansMultiDenoisingInvoker<T, IT, UIT, D, WT>::calcDistSumsForElementInFirstRow(321int i, int j, int first_col_num, Array3d<int>& dist_sums,322Array4d<int>& col_dist_sums, Array4d<int>& up_col_dist_sums) const323{324int ay = border_size_ + i;325int ax = border_size_ + j + template_window_half_size_;326327int start_by = border_size_ + i - search_window_half_size_;328int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_;329330int new_last_col_num = first_col_num;331332for (int d = 0; d < temporal_window_size_; d++)333{334Mat cur_extended_src = extended_srcs_[d];335for (int y = 0; y < search_window_size_; y++)336for (int x = 0; x < search_window_size_; x++)337{338dist_sums[d][y][x] -= col_dist_sums[first_col_num][d][y][x];339340col_dist_sums[new_last_col_num][d][y][x] = 0;341int by = start_by + y;342int bx = start_bx + x;343344int* col_dist_sums_ptr = &col_dist_sums[new_last_col_num][d][y][x];345for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)346{347*col_dist_sums_ptr += D::template calcDist<T>(348main_extended_src_.at<T>(ay + ty, ax),349cur_extended_src.at<T>(by + ty, bx));350}351352dist_sums[d][y][x] += col_dist_sums[new_last_col_num][d][y][x];353354up_col_dist_sums[j][d][y][x] = col_dist_sums[new_last_col_num][d][y][x];355}356}357}358359#endif360361362