some refactoring

This commit is contained in:
Ilya Lavrenov 2014-02-11 19:08:13 +04:00
parent edbff68843
commit e16d89e8d6
3 changed files with 210 additions and 209 deletions

@ -51,61 +51,61 @@
using namespace cv; using namespace cv;
template <typename T> template <typename T>
struct FastNlMeansDenoisingInvoker : ParallelLoopBody { struct FastNlMeansDenoisingInvoker :
public: public ParallelLoopBody
FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst, {
int template_window_size, int search_window_size, const float h); public:
FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst,
int template_window_size, int search_window_size, const float h);
void operator() (const Range& range) const; void operator() (const Range& range) const;
private: private:
void operator= (const FastNlMeansDenoisingInvoker&); void operator= (const FastNlMeansDenoisingInvoker&);
const Mat& src_; const Mat& src_;
Mat& dst_; Mat& dst_;
Mat extended_src_; Mat extended_src_;
int border_size_; int border_size_;
int template_window_size_; int template_window_size_;
int search_window_size_; int search_window_size_;
int template_window_half_size_; int template_window_half_size_;
int search_window_half_size_; int search_window_half_size_;
int fixed_point_mult_; int fixed_point_mult_;
int almost_template_window_size_sq_bin_shift_; int almost_template_window_size_sq_bin_shift_;
std::vector<int> almost_dist2weight_; std::vector<int> almost_dist2weight_;
void calcDistSumsForFirstElementInRow( void calcDistSumsForFirstElementInRow(
int i, int i, Array2d<int>& dist_sums,
Array2d<int>& dist_sums, Array3d<int>& col_dist_sums,
Array3d<int>& col_dist_sums, Array3d<int>& up_col_dist_sums) const;
Array3d<int>& up_col_dist_sums) const;
void calcDistSumsForElementInFirstRow( void calcDistSumsForElementInFirstRow(
int i, int i, int j, int first_col_num,
int j, Array2d<int>& dist_sums,
int first_col_num, Array3d<int>& col_dist_sums,
Array2d<int>& dist_sums, Array3d<int>& up_col_dist_sums) const;
Array3d<int>& col_dist_sums,
Array3d<int>& up_col_dist_sums) const;
}; };
inline int getNearestPowerOf2(int value) inline int getNearestPowerOf2(int value)
{ {
int p = 0; int p = 0;
while( 1 << p < value) ++p; while( 1 << p < value)
++p;
return p; return p;
} }
template <class T> template <class T>
FastNlMeansDenoisingInvoker<T>::FastNlMeansDenoisingInvoker( FastNlMeansDenoisingInvoker<T>::FastNlMeansDenoisingInvoker(
const cv::Mat& src, const cv::Mat& src, cv::Mat& dst,
cv::Mat& dst,
int template_window_size, int template_window_size,
int search_window_size, int search_window_size,
const float h) : src_(src), dst_(dst) const float h) :
src_(src), dst_(dst)
{ {
CV_Assert(src.channels() == sizeof(T)); //T is Vec1b or Vec2b or Vec3b CV_Assert(src.channels() == sizeof(T)); //T is Vec1b or Vec2b or Vec3b
@ -134,7 +134,8 @@ FastNlMeansDenoisingInvoker<T>::FastNlMeansDenoisingInvoker(
almost_dist2weight_.resize(almost_max_dist); almost_dist2weight_.resize(almost_max_dist);
const double WEIGHT_THRESHOLD = 0.001; const double WEIGHT_THRESHOLD = 0.001;
for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++)
{
double dist = almost_dist * almost_dist2actual_dist_multiplier; double dist = almost_dist * almost_dist2actual_dist_multiplier;
int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T))));
@ -144,15 +145,15 @@ FastNlMeansDenoisingInvoker<T>::FastNlMeansDenoisingInvoker(
almost_dist2weight_[almost_dist] = weight; almost_dist2weight_[almost_dist] = weight;
} }
CV_Assert(almost_dist2weight_[0] == fixed_point_mult_); CV_Assert(almost_dist2weight_[0] == fixed_point_mult_);
// additional optimization init end
if (dst_.empty()) { // additional optimization init end
if (dst_.empty())
dst_ = Mat::zeros(src_.size(), src_.type()); dst_ = Mat::zeros(src_.size(), src_.type());
}
} }
template <class T> template <class T>
void FastNlMeansDenoisingInvoker<T>::operator() (const Range& range) const { void FastNlMeansDenoisingInvoker<T>::operator() (const Range& range) const
{
int row_from = range.start; int row_from = range.start;
int row_to = range.end - 1; int row_to = range.end - 1;
@ -164,30 +165,36 @@ void FastNlMeansDenoisingInvoker<T>::operator() (const Range& range) const {
int first_col_num = -1; int first_col_num = -1;
Array3d<int> up_col_dist_sums(src_.cols, search_window_size_, search_window_size_); Array3d<int> up_col_dist_sums(src_.cols, search_window_size_, search_window_size_);
for (int i = row_from; i <= row_to; i++) { for (int i = row_from; i <= row_to; i++)
for (int j = 0; j < src_.cols; j++) { {
for (int j = 0; j < src_.cols; j++)
{
int search_window_y = i - search_window_half_size_; int search_window_y = i - search_window_half_size_;
int search_window_x = j - search_window_half_size_; int search_window_x = j - search_window_half_size_;
// calc dist_sums // calc dist_sums
if (j == 0) { if (j == 0)
{
calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums);
first_col_num = 0; first_col_num = 0;
} else { // calc cur dist_sums using previous dist_sums }
if (i == row_from) { else
{
// calc cur dist_sums using previous dist_sums
if (i == row_from)
{
calcDistSumsForElementInFirstRow(i, j, first_col_num, calcDistSumsForElementInFirstRow(i, j, first_col_num,
dist_sums, col_dist_sums, up_col_dist_sums); dist_sums, col_dist_sums, up_col_dist_sums);
} else { }
else
{
int ay = border_size_ + i; int ay = border_size_ + i;
int ax = border_size_ + j + template_window_half_size_; int ax = border_size_ + j + template_window_half_size_;
int start_by = int start_by = border_size_ + i - search_window_half_size_;
border_size_ + i - search_window_half_size_; int start_bx = border_size_ + j - search_window_half_size_ + template_window_half_size_;
int start_bx =
border_size_ + j - search_window_half_size_ + template_window_half_size_;
T a_up = extended_src_.at<T>(ay - template_window_half_size_ - 1, ax); T a_up = extended_src_.at<T>(ay - template_window_half_size_ - 1, ax);
T a_down = extended_src_.at<T>(ay + template_window_half_size_, ax); T a_down = extended_src_.at<T>(ay + template_window_half_size_, ax);
@ -195,20 +202,18 @@ void FastNlMeansDenoisingInvoker<T>::operator() (const Range& range) const {
// copy class member to local variable for optimization // copy class member to local variable for optimization
int search_window_size = search_window_size_; int search_window_size = search_window_size_;
for (int y = 0; y < search_window_size; y++) { for (int y = 0; y < search_window_size; y++)
{
int* dist_sums_row = dist_sums.row_ptr(y); int* dist_sums_row = dist_sums.row_ptr(y);
int* col_dist_sums_row = col_dist_sums.row_ptr(first_col_num,y); int* col_dist_sums_row = col_dist_sums.row_ptr(first_col_num,y);
int* up_col_dist_sums_row = up_col_dist_sums.row_ptr(j, y); int* up_col_dist_sums_row = up_col_dist_sums.row_ptr(j, y);
const T* b_up_ptr = const T* b_up_ptr = extended_src_.ptr<T>(start_by - template_window_half_size_ - 1 + y);
extended_src_.ptr<T>(start_by - template_window_half_size_ - 1 + y); const T* b_down_ptr = extended_src_.ptr<T>(start_by + template_window_half_size_ + y);
const T* b_down_ptr = for (int x = 0; x < search_window_size; x++)
extended_src_.ptr<T>(start_by + template_window_half_size_ + y); {
for (int x = 0; x < search_window_size; x++) {
dist_sums_row[x] -= col_dist_sums_row[x]; dist_sums_row[x] -= col_dist_sums_row[x];
col_dist_sums_row[x] = col_dist_sums_row[x] =
@ -233,14 +238,15 @@ void FastNlMeansDenoisingInvoker<T>::operator() (const Range& range) const {
int weights_sum = 0; int weights_sum = 0;
int estimation[3]; int estimation[3];
for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++)
estimation[channel_num] = 0; estimation[channel_num] = 0;
}
for (int y = 0; y < search_window_size_; y++) { for (int y = 0; y < search_window_size_; y++)
{
const T* cur_row_ptr = extended_src_.ptr<T>(border_size_ + search_window_y + y); const T* cur_row_ptr = extended_src_.ptr<T>(border_size_ + search_window_y + y);
int* dist_sums_row = dist_sums.row_ptr(y); int* dist_sums_row = dist_sums.row_ptr(y);
for (int x = 0; x < search_window_size_; x++) { for (int x = 0; x < search_window_size_; x++)
{
int almostAvgDist = int almostAvgDist =
dist_sums_row[x] >> almost_template_window_size_sq_bin_shift_; dist_sums_row[x] >> almost_template_window_size_sq_bin_shift_;
@ -269,18 +275,19 @@ inline void FastNlMeansDenoisingInvoker<T>::calcDistSumsForFirstElementInRow(
{ {
int j = 0; int j = 0;
for (int y = 0; y < search_window_size_; y++) { for (int y = 0; y < search_window_size_; y++)
for (int x = 0; x < search_window_size_; x++) { for (int x = 0; x < search_window_size_; x++)
{
dist_sums[y][x] = 0; dist_sums[y][x] = 0;
for (int tx = 0; tx < template_window_size_; tx++) { for (int tx = 0; tx < template_window_size_; tx++)
col_dist_sums[tx][y][x] = 0; col_dist_sums[tx][y][x] = 0;
}
int start_y = i + y - search_window_half_size_; int start_y = i + y - search_window_half_size_;
int start_x = j + x - search_window_half_size_; int start_x = j + x - search_window_half_size_;
for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { 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++) { for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++)
{
int dist = calcDist<T>(extended_src_, int dist = calcDist<T>(extended_src_,
border_size_ + i + ty, border_size_ + j + tx, border_size_ + i + ty, border_size_ + j + tx,
border_size_ + start_y + ty, border_size_ + start_x + tx); border_size_ + start_y + ty, border_size_ + start_x + tx);
@ -288,11 +295,9 @@ inline void FastNlMeansDenoisingInvoker<T>::calcDistSumsForFirstElementInRow(
dist_sums[y][x] += dist; dist_sums[y][x] += dist;
col_dist_sums[tx + template_window_half_size_][y][x] += dist; col_dist_sums[tx + template_window_half_size_][y][x] += dist;
} }
}
up_col_dist_sums[j][y][x] = col_dist_sums[template_window_size_ - 1][y][x]; up_col_dist_sums[j][y][x] = col_dist_sums[template_window_size_ - 1][y][x];
} }
}
} }
template <class T> template <class T>
@ -312,23 +317,21 @@ inline void FastNlMeansDenoisingInvoker<T>::calcDistSumsForElementInFirstRow(
int new_last_col_num = first_col_num; int new_last_col_num = first_col_num;
for (int y = 0; y < search_window_size_; y++) { for (int y = 0; y < search_window_size_; y++)
for (int x = 0; x < search_window_size_; x++) { for (int x = 0; x < search_window_size_; x++)
{
dist_sums[y][x] -= col_dist_sums[first_col_num][y][x]; dist_sums[y][x] -= col_dist_sums[first_col_num][y][x];
col_dist_sums[new_last_col_num][y][x] = 0; col_dist_sums[new_last_col_num][y][x] = 0;
int by = start_by + y; int by = start_by + y;
int bx = start_bx + x; int bx = start_bx + x;
for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)
col_dist_sums[new_last_col_num][y][x] += col_dist_sums[new_last_col_num][y][x] +=
calcDist<T>(extended_src_, ay + ty, ax, by + ty, bx); calcDist<T>(extended_src_, ay + ty, ax, by + ty, bx);
}
dist_sums[y][x] += col_dist_sums[new_last_col_num][y][x]; 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]; up_col_dist_sums[j][y][x] = col_dist_sums[new_last_col_num][y][x];
} }
}
} }
#endif #endif

@ -46,29 +46,35 @@ using namespace cv;
template <typename T> static inline int calcDist(const T a, const T b); template <typename T> static inline int calcDist(const T a, const T b);
template <> inline int calcDist(const uchar a, const uchar b) { template <> inline int calcDist(const uchar a, const uchar b)
{
return (a-b) * (a-b); return (a-b) * (a-b);
} }
template <> inline int calcDist(const Vec2b a, const Vec2b b) { template <> inline int calcDist(const Vec2b a, const Vec2b b)
{
return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]); return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]);
} }
template <> inline int calcDist(const Vec3b a, const Vec3b b) { template <> inline int calcDist(const Vec3b a, const Vec3b b)
{
return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]); return (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]);
} }
template <typename T> static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2) { template <typename T> static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2)
{
const T a = m.at<T>(i1, j1); const T a = m.at<T>(i1, j1);
const T b = m.at<T>(i2, j2); const T b = m.at<T>(i2, j2);
return calcDist<T>(a,b); return calcDist<T>(a,b);
} }
template <typename T> static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down) { template <typename T> static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down)
{
return calcDist(a_down,b_down) - calcDist(a_up, b_up); return calcDist(a_down,b_down) - calcDist(a_up, b_up);
} }
template <> inline int calcUpDownDist(uchar a_up, uchar a_down, uchar b_up, uchar b_down) { template <> inline int calcUpDownDist(uchar a_up, uchar a_down, uchar b_up, uchar b_down)
{
int A = a_down - b_down; int A = a_down - b_down;
int B = a_up - b_up; int B = a_up - b_up;
return (A-B)*(A+B); return (A-B)*(A+B);
@ -76,16 +82,20 @@ template <> inline int calcUpDownDist(uchar a_up, uchar a_down, uchar b_up, uch
template <typename T> static inline void incWithWeight(int* estimation, int weight, T p); template <typename T> static inline void incWithWeight(int* estimation, int weight, T p);
template <> inline void incWithWeight(int* estimation, int weight, uchar p) { template <> inline void incWithWeight(int* estimation, int weight, uchar p)
{
estimation[0] += weight * p; estimation[0] += weight * p;
} }
template <> inline void incWithWeight(int* estimation, int weight, Vec2b p) { template <> inline void incWithWeight(int* estimation, int weight, Vec2b p)
{
estimation[0] += weight * p[0]; estimation[0] += weight * p[0];
estimation[1] += weight * p[1]; estimation[1] += weight * p[1];
} }
template <> inline void incWithWeight(int* estimation, int weight, Vec3b p) { template <> inline void incWithWeight(int* estimation, int weight, Vec3b p)
{
estimation[0] += weight * p[0]; estimation[0] += weight * p[0];
estimation[1] += weight * p[1]; estimation[1] += weight * p[1];
estimation[2] += weight * p[2]; estimation[2] += weight * p[2];
@ -93,18 +103,21 @@ template <> inline void incWithWeight(int* estimation, int weight, Vec3b p) {
template <typename T> static inline T saturateCastFromArray(int* estimation); template <typename T> static inline T saturateCastFromArray(int* estimation);
template <> inline uchar saturateCastFromArray(int* estimation) { template <> inline uchar saturateCastFromArray(int* estimation)
{
return saturate_cast<uchar>(estimation[0]); return saturate_cast<uchar>(estimation[0]);
} }
template <> inline Vec2b saturateCastFromArray(int* estimation) { template <> inline Vec2b saturateCastFromArray(int* estimation)
{
Vec2b res; Vec2b res;
res[0] = saturate_cast<uchar>(estimation[0]); res[0] = saturate_cast<uchar>(estimation[0]);
res[1] = saturate_cast<uchar>(estimation[1]); res[1] = saturate_cast<uchar>(estimation[1]);
return res; return res;
} }
template <> inline Vec3b saturateCastFromArray(int* estimation) { template <> inline Vec3b saturateCastFromArray(int* estimation)
{
Vec3b res; Vec3b res;
res[0] = saturate_cast<uchar>(estimation[0]); res[0] = saturate_cast<uchar>(estimation[0]);
res[1] = saturate_cast<uchar>(estimation[1]); res[1] = saturate_cast<uchar>(estimation[1]);

@ -51,51 +51,47 @@
using namespace cv; using namespace cv;
template <typename T> template <typename T>
struct FastNlMeansMultiDenoisingInvoker : ParallelLoopBody { struct FastNlMeansMultiDenoisingInvoker :
public: ParallelLoopBody
FastNlMeansMultiDenoisingInvoker( {
const std::vector<Mat>& srcImgs, int imgToDenoiseIndex, int temporalWindowSize, public:
Mat& dst, int template_window_size, int search_window_size, const float h); FastNlMeansMultiDenoisingInvoker(const std::vector<Mat>& srcImgs, int imgToDenoiseIndex,
int temporalWindowSize, Mat& dst, int template_window_size,
int search_window_size, const float h);
void operator() (const Range& range) const; void operator() (const Range& range) const;
private: private:
void operator= (const FastNlMeansMultiDenoisingInvoker&); void operator= (const FastNlMeansMultiDenoisingInvoker&);
int rows_; int rows_;
int cols_; int cols_;
Mat& dst_; Mat& dst_;
std::vector<Mat> extended_srcs_; std::vector<Mat> extended_srcs_;
Mat main_extended_src_; Mat main_extended_src_;
int border_size_; int border_size_;
int template_window_size_; int template_window_size_;
int search_window_size_; int search_window_size_;
int temporal_window_size_; int temporal_window_size_;
int template_window_half_size_; int template_window_half_size_;
int search_window_half_size_; int search_window_half_size_;
int temporal_window_half_size_; int temporal_window_half_size_;
int fixed_point_mult_; int fixed_point_mult_;
int almost_template_window_size_sq_bin_shift; int almost_template_window_size_sq_bin_shift;
std::vector<int> almost_dist2weight; std::vector<int> almost_dist2weight;
void calcDistSumsForFirstElementInRow( void calcDistSumsForFirstElementInRow(int i, Array3d<int>& dist_sums,
int i, Array4d<int>& col_dist_sums,
Array3d<int>& dist_sums, Array4d<int>& up_col_dist_sums) const;
Array4d<int>& col_dist_sums,
Array4d<int>& up_col_dist_sums) const;
void calcDistSumsForElementInFirstRow( void calcDistSumsForElementInFirstRow(int i, int j, int first_col_num,
int i, Array3d<int>& dist_sums, Array4d<int>& col_dist_sums,
int j, Array4d<int>& up_col_dist_sums) const;
int first_col_num,
Array3d<int>& dist_sums,
Array4d<int>& col_dist_sums,
Array4d<int>& up_col_dist_sums) const;
}; };
template <class T> template <class T>
@ -106,7 +102,8 @@ FastNlMeansMultiDenoisingInvoker<T>::FastNlMeansMultiDenoisingInvoker(
cv::Mat& dst, cv::Mat& dst,
int template_window_size, int template_window_size,
int search_window_size, int search_window_size,
const float h) : dst_(dst), extended_srcs_(srcImgs.size()) const float h) :
dst_(dst), extended_srcs_(srcImgs.size())
{ {
CV_Assert(srcImgs.size() > 0); CV_Assert(srcImgs.size() > 0);
CV_Assert(srcImgs[0].channels() == sizeof(T)); CV_Assert(srcImgs[0].channels() == sizeof(T));
@ -123,85 +120,84 @@ FastNlMeansMultiDenoisingInvoker<T>::FastNlMeansMultiDenoisingInvoker(
temporal_window_size_ = temporal_window_half_size_ * 2 + 1; temporal_window_size_ = temporal_window_half_size_ * 2 + 1;
border_size_ = search_window_half_size_ + template_window_half_size_; border_size_ = search_window_half_size_ + template_window_half_size_;
for (int i = 0; i < temporal_window_size_; i++) { for (int i = 0; i < temporal_window_size_; i++)
copyMakeBorder( copyMakeBorder(srcImgs[imgToDenoiseIndex - temporal_window_half_size_ + i], extended_srcs_[i],
srcImgs[imgToDenoiseIndex - temporal_window_half_size_ + i], extended_srcs_[i],
border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT); border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT);
}
main_extended_src_ = extended_srcs_[temporal_window_half_size_]; main_extended_src_ = extended_srcs_[temporal_window_half_size_];
const int max_estimate_sum_value = temporal_window_size_ * search_window_size_ * search_window_size_ * 255;
const int max_estimate_sum_value =
temporal_window_size_ * search_window_size_ * search_window_size_ * 255;
fixed_point_mult_ = std::numeric_limits<int>::max() / max_estimate_sum_value; fixed_point_mult_ = std::numeric_limits<int>::max() / max_estimate_sum_value;
// precalc weight for every possible l2 dist between blocks // precalc weight for every possible l2 dist between blocks
// additional optimization of precalced weights to replace division(averaging) by binary shift // additional optimization of precalced weights to replace division(averaging) by binary shift
int template_window_size_sq = template_window_size_ * template_window_size_; int template_window_size_sq = template_window_size_ * template_window_size_;
almost_template_window_size_sq_bin_shift = 0; almost_template_window_size_sq_bin_shift = 0;
while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) { 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++;
}
int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift; int almost_template_window_size_sq = 1 << almost_template_window_size_sq_bin_shift;
double almost_dist2actual_dist_multiplier = double almost_dist2actual_dist_multiplier = (double) almost_template_window_size_sq / template_window_size_sq;
((double) almost_template_window_size_sq) / template_window_size_sq;
int max_dist = 255 * 255 * sizeof(T); int max_dist = 255 * 255 * sizeof(T);
int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1); int almost_max_dist = (int) (max_dist / almost_dist2actual_dist_multiplier + 1);
almost_dist2weight.resize(almost_max_dist); almost_dist2weight.resize(almost_max_dist);
const double WEIGHT_THRESHOLD = 0.001; const double WEIGHT_THRESHOLD = 0.001;
for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++) { for (int almost_dist = 0; almost_dist < almost_max_dist; almost_dist++)
{
double dist = almost_dist * almost_dist2actual_dist_multiplier; double dist = almost_dist * almost_dist2actual_dist_multiplier;
int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T)))); int weight = cvRound(fixed_point_mult_ * std::exp(-dist / (h * h * sizeof(T))));
if (weight < WEIGHT_THRESHOLD * fixed_point_mult_) { if (weight < WEIGHT_THRESHOLD * fixed_point_mult_)
weight = 0; weight = 0;
}
almost_dist2weight[almost_dist] = weight; almost_dist2weight[almost_dist] = weight;
} }
CV_Assert(almost_dist2weight[0] == fixed_point_mult_); CV_Assert(almost_dist2weight[0] == fixed_point_mult_);
// additional optimization init end
if (dst_.empty()) { // additional optimization init end
if (dst_.empty())
dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type()); dst_ = Mat::zeros(srcImgs[0].size(), srcImgs[0].type());
}
} }
template <class T> template <class T>
void FastNlMeansMultiDenoisingInvoker<T>::operator() (const Range& range) const { void FastNlMeansMultiDenoisingInvoker<T>::operator() (const Range& range) const
{
int row_from = range.start; int row_from = range.start;
int row_to = range.end - 1; int row_to = range.end - 1;
Array3d<int> dist_sums(temporal_window_size_, search_window_size_, search_window_size_); Array3d<int> dist_sums(temporal_window_size_, search_window_size_, search_window_size_);
// for lazy calc optimization // for lazy calc optimization
Array4d<int> col_dist_sums( Array4d<int> col_dist_sums(template_window_size_, temporal_window_size_, search_window_size_, search_window_size_);
template_window_size_, temporal_window_size_, search_window_size_, search_window_size_);
int first_col_num = -1; int first_col_num = -1;
Array4d<int> up_col_dist_sums(cols_, temporal_window_size_, search_window_size_, search_window_size_);
Array4d<int> up_col_dist_sums( for (int i = row_from; i <= row_to; i++)
cols_, temporal_window_size_, search_window_size_, search_window_size_); {
for (int j = 0; j < cols_; j++)
for (int i = row_from; i <= row_to; i++) { {
for (int j = 0; j < cols_; j++) {
int search_window_y = i - search_window_half_size_; int search_window_y = i - search_window_half_size_;
int search_window_x = j - search_window_half_size_; int search_window_x = j - search_window_half_size_;
// calc dist_sums // calc dist_sums
if (j == 0) { if (j == 0)
{
calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums); calcDistSumsForFirstElementInRow(i, dist_sums, col_dist_sums, up_col_dist_sums);
first_col_num = 0; first_col_num = 0;
}
} else { // calc cur dist_sums using previous dist_sums else
if (i == row_from) { {
// calc cur dist_sums using previous dist_sums
if (i == row_from)
{
calcDistSumsForElementInFirstRow(i, j, first_col_num, calcDistSumsForElementInFirstRow(i, j, first_col_num,
dist_sums, col_dist_sums, up_col_dist_sums); dist_sums, col_dist_sums, up_col_dist_sums);
} else { }
else
{
int ay = border_size_ + i; int ay = border_size_ + i;
int ax = border_size_ + j + template_window_half_size_; int ax = border_size_ + j + template_window_half_size_;
@ -217,36 +213,31 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const Range& range) const
// copy class member to local variable for optimization // copy class member to local variable for optimization
int search_window_size = search_window_size_; int search_window_size = search_window_size_;
for (int d = 0; d < temporal_window_size_; d++) { for (int d = 0; d < temporal_window_size_; d++)
{
Mat cur_extended_src = extended_srcs_[d]; Mat cur_extended_src = extended_srcs_[d];
Array2d<int> cur_dist_sums = dist_sums[d]; Array2d<int> cur_dist_sums = dist_sums[d];
Array2d<int> cur_col_dist_sums = col_dist_sums[first_col_num][d]; Array2d<int> cur_col_dist_sums = col_dist_sums[first_col_num][d];
Array2d<int> cur_up_col_dist_sums = up_col_dist_sums[j][d]; Array2d<int> cur_up_col_dist_sums = up_col_dist_sums[j][d];
for (int y = 0; y < search_window_size; y++) { for (int y = 0; y < search_window_size; y++)
{
int* dist_sums_row = cur_dist_sums.row_ptr(y); int* dist_sums_row = cur_dist_sums.row_ptr(y);
int* col_dist_sums_row = cur_col_dist_sums.row_ptr(y); int* col_dist_sums_row = cur_col_dist_sums.row_ptr(y);
int* up_col_dist_sums_row = cur_up_col_dist_sums.row_ptr(y); int* up_col_dist_sums_row = cur_up_col_dist_sums.row_ptr(y);
const T* b_up_ptr = const T* b_up_ptr = cur_extended_src.ptr<T>(start_by - template_window_half_size_ - 1 + y);
cur_extended_src.ptr<T>(start_by - template_window_half_size_ - 1 + y); const T* b_down_ptr = cur_extended_src.ptr<T>(start_by + template_window_half_size_ + y);
const T* b_down_ptr =
cur_extended_src.ptr<T>(start_by + template_window_half_size_ + y);
for (int x = 0; x < search_window_size; x++) { for (int x = 0; x < search_window_size; x++)
{
dist_sums_row[x] -= col_dist_sums_row[x]; dist_sums_row[x] -= col_dist_sums_row[x];
col_dist_sums_row[x] = up_col_dist_sums_row[x] + col_dist_sums_row[x] = up_col_dist_sums_row[x] +
calcUpDownDist( calcUpDownDist(a_up, a_down, b_up_ptr[start_bx + x], b_down_ptr[start_bx + x]);
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]; dist_sums_row[x] += col_dist_sums_row[x];
up_col_dist_sums_row[x] = col_dist_sums_row[x]; up_col_dist_sums_row[x] = col_dist_sums_row[x];
} }
} }
} }
@ -259,19 +250,21 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const Range& range) const
int weights_sum = 0; int weights_sum = 0;
int estimation[3]; int estimation[3];
for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++) { for (size_t channel_num = 0; channel_num < sizeof(T); channel_num++)
estimation[channel_num] = 0; estimation[channel_num] = 0;
}
for (int d = 0; d < temporal_window_size_; d++) { for (int d = 0; d < temporal_window_size_; d++)
{
const Mat& esrc_d = extended_srcs_[d]; const Mat& esrc_d = extended_srcs_[d];
for (int y = 0; y < search_window_size_; y++) { for (int y = 0; y < search_window_size_; y++)
{
const T* cur_row_ptr = esrc_d.ptr<T>(border_size_ + search_window_y + y); const T* cur_row_ptr = esrc_d.ptr<T>(border_size_ + search_window_y + y);
int* dist_sums_row = dist_sums.row_ptr(d, y); int* dist_sums_row = dist_sums.row_ptr(d, y);
for (int x = 0; x < search_window_size_; x++) { for (int x = 0; x < search_window_size_; x++)
int almostAvgDist = {
dist_sums_row[x] >> almost_template_window_size_sq_bin_shift; int almostAvgDist = dist_sums_row[x] >> almost_template_window_size_sq_bin_shift;
int weight = almost_dist2weight[almostAvgDist]; int weight = almost_dist2weight[almostAvgDist];
weights_sum += weight; weights_sum += weight;
@ -293,21 +286,19 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const Range& range) const
template <class T> template <class T>
inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForFirstElementInRow( inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForFirstElementInRow(
int i, int i, Array3d<int>& dist_sums, Array4d<int>& col_dist_sums, Array4d<int>& up_col_dist_sums) const
Array3d<int>& dist_sums,
Array4d<int>& col_dist_sums,
Array4d<int>& up_col_dist_sums) const
{ {
int j = 0; int j = 0;
for (int d = 0; d < temporal_window_size_; d++) { for (int d = 0; d < temporal_window_size_; d++)
{
Mat cur_extended_src = extended_srcs_[d]; Mat cur_extended_src = extended_srcs_[d];
for (int y = 0; y < search_window_size_; y++) { for (int y = 0; y < search_window_size_; y++)
for (int x = 0; x < search_window_size_; x++) { for (int x = 0; x < search_window_size_; x++)
{
dist_sums[d][y][x] = 0; dist_sums[d][y][x] = 0;
for (int tx = 0; tx < template_window_size_; tx++) { for (int tx = 0; tx < template_window_size_; tx++)
col_dist_sums[tx][d][y][x] = 0; col_dist_sums[tx][d][y][x] = 0;
}
int start_y = i + y - search_window_half_size_; int start_y = i + y - search_window_half_size_;
int start_x = j + x - search_window_half_size_; int start_x = j + x - search_window_half_size_;
@ -315,14 +306,13 @@ inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForFirstElementInRo
int* dist_sums_ptr = &dist_sums[d][y][x]; int* dist_sums_ptr = &dist_sums[d][y][x];
int* col_dist_sums_ptr = &col_dist_sums[0][d][y][x]; int* col_dist_sums_ptr = &col_dist_sums[0][d][y][x];
int col_dist_sums_step = col_dist_sums.step_size(0); int col_dist_sums_step = col_dist_sums.step_size(0);
for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++) { for (int tx = -template_window_half_size_; tx <= template_window_half_size_; tx++)
for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++) { {
for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)
{
int dist = calcDist<T>( int dist = calcDist<T>(
main_extended_src_.at<T>( main_extended_src_.at<T>(border_size_ + i + ty, border_size_ + j + tx),
border_size_ + i + ty, border_size_ + j + tx), cur_extended_src.at<T>(border_size_ + start_y + ty, border_size_ + start_x + tx));
cur_extended_src.at<T>(
border_size_ + start_y + ty, border_size_ + start_x + tx)
);
*dist_sums_ptr += dist; *dist_sums_ptr += dist;
*col_dist_sums_ptr += dist; *col_dist_sums_ptr += dist;
@ -332,18 +322,13 @@ inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForFirstElementInRo
up_col_dist_sums[j][d][y][x] = col_dist_sums[template_window_size_ - 1][d][y][x]; up_col_dist_sums[j][d][y][x] = col_dist_sums[template_window_size_ - 1][d][y][x];
} }
}
} }
} }
template <class T> template <class T>
inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForElementInFirstRow( inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForElementInFirstRow(
int i, int i, int j, int first_col_num, Array3d<int>& dist_sums,
int j, Array4d<int>& col_dist_sums, Array4d<int>& up_col_dist_sums) const
int first_col_num,
Array3d<int>& dist_sums,
Array4d<int>& col_dist_sums,
Array4d<int>& up_col_dist_sums) const
{ {
int ay = border_size_ + i; int ay = border_size_ + i;
int ax = border_size_ + j + template_window_half_size_; int ax = border_size_ + j + template_window_half_size_;
@ -353,10 +338,12 @@ inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForElementInFirstRo
int new_last_col_num = first_col_num; int new_last_col_num = first_col_num;
for (int d = 0; d < temporal_window_size_; d++) { for (int d = 0; d < temporal_window_size_; d++)
{
Mat cur_extended_src = extended_srcs_[d]; Mat cur_extended_src = extended_srcs_[d];
for (int y = 0; y < search_window_size_; y++) { for (int y = 0; y < search_window_size_; y++)
for (int x = 0; x < search_window_size_; x++) { for (int x = 0; x < search_window_size_; x++)
{
dist_sums[d][y][x] -= col_dist_sums[first_col_num][d][y][x]; dist_sums[d][y][x] -= col_dist_sums[first_col_num][d][y][x];
col_dist_sums[new_last_col_num][d][y][x] = 0; col_dist_sums[new_last_col_num][d][y][x] = 0;
@ -364,19 +351,17 @@ inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForElementInFirstRo
int bx = start_bx + x; int bx = start_bx + x;
int* col_dist_sums_ptr = &col_dist_sums[new_last_col_num][d][y][x]; int* 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++) { for (int ty = -template_window_half_size_; ty <= template_window_half_size_; ty++)
*col_dist_sums_ptr += {
calcDist<T>( *col_dist_sums_ptr += calcDist<T>(
main_extended_src_.at<T>(ay + ty, ax), main_extended_src_.at<T>(ay + ty, ax),
cur_extended_src.at<T>(by + ty, bx) cur_extended_src.at<T>(by + ty, bx));
);
} }
dist_sums[d][y][x] += col_dist_sums[new_last_col_num][d][y][x]; dist_sums[d][y][x] += col_dist_sums[new_last_col_num][d][y][x];
up_col_dist_sums[j][d][y][x] = col_dist_sums[new_last_col_num][d][y][x]; up_col_dist_sums[j][d][y][x] = col_dist_sums[new_last_col_num][d][y][x];
} }
}
} }
} }