mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 14:36:36 +08:00
Minor refactoring of NL-means denoising
This commit is contained in:
parent
3c4917555d
commit
7e35838849
@ -47,20 +47,20 @@ template <class T> struct Array2d {
|
|||||||
int n1,n2;
|
int n1,n2;
|
||||||
bool needToDeallocArray;
|
bool needToDeallocArray;
|
||||||
|
|
||||||
Array2d(const Array2d& array2d):
|
Array2d(const Array2d& array2d):
|
||||||
a(array2d.a), n1(array2d.n1), n2(array2d.n2), needToDeallocArray(false)
|
a(array2d.a), n1(array2d.n1), n2(array2d.n2), needToDeallocArray(false)
|
||||||
{
|
{
|
||||||
if (array2d.needToDeallocArray) {
|
if (array2d.needToDeallocArray) {
|
||||||
// copy constructor for self allocating arrays not supported
|
// copy constructor for self allocating arrays not supported
|
||||||
throw new exception();
|
throw new exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Array2d(T* _a, int _n1, int _n2):
|
Array2d(T* _a, int _n1, int _n2):
|
||||||
a(_a), n1(_n1), n2(_n2), needToDeallocArray(false) {}
|
a(_a), n1(_n1), n2(_n2), needToDeallocArray(false) {}
|
||||||
|
|
||||||
Array2d(int _n1, int _n2):
|
Array2d(int _n1, int _n2):
|
||||||
n1(_n1), n2(_n2), needToDeallocArray(true)
|
n1(_n1), n2(_n2), needToDeallocArray(true)
|
||||||
{
|
{
|
||||||
a = new T[n1*n2];
|
a = new T[n1*n2];
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ template <class T> struct Array2d {
|
|||||||
T* operator [] (int i) {
|
T* operator [] (int i) {
|
||||||
return a + i*n2;
|
return a + i*n2;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline T* row_ptr(int i) {
|
inline T* row_ptr(int i) {
|
||||||
return (*this)[i];
|
return (*this)[i];
|
||||||
}
|
}
|
||||||
@ -84,12 +84,12 @@ template <class T> struct Array3d {
|
|||||||
T* a;
|
T* a;
|
||||||
int n1,n2,n3;
|
int n1,n2,n3;
|
||||||
bool needToDeallocArray;
|
bool needToDeallocArray;
|
||||||
|
|
||||||
Array3d(T* _a, int _n1, int _n2, int _n3):
|
Array3d(T* _a, int _n1, int _n2, int _n3):
|
||||||
a(_a), n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(false) {}
|
a(_a), n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(false) {}
|
||||||
|
|
||||||
Array3d(int _n1, int _n2, int _n3):
|
Array3d(int _n1, int _n2, int _n3):
|
||||||
n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(true)
|
n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(true)
|
||||||
{
|
{
|
||||||
a = new T[n1*n2*n3];
|
a = new T[n1*n2*n3];
|
||||||
}
|
}
|
||||||
@ -115,25 +115,25 @@ template <class T> struct Array4d {
|
|||||||
int n1,n2,n3,n4;
|
int n1,n2,n3,n4;
|
||||||
bool needToDeallocArray;
|
bool needToDeallocArray;
|
||||||
int steps[4];
|
int steps[4];
|
||||||
|
|
||||||
void init_steps() {
|
void init_steps() {
|
||||||
steps[0] = n2*n3*n4;
|
steps[0] = n2*n3*n4;
|
||||||
steps[1] = n3*n4;
|
steps[1] = n3*n4;
|
||||||
steps[2] = n4;
|
steps[2] = n4;
|
||||||
steps[3] = 1;
|
steps[3] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array4d(T* _a, int _n1, int _n2, int _n3, int _n4):
|
Array4d(T* _a, int _n1, int _n2, int _n3, int _n4):
|
||||||
a(_a), n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(false)
|
a(_a), n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(false)
|
||||||
{
|
{
|
||||||
init_steps();
|
init_steps();
|
||||||
}
|
}
|
||||||
|
|
||||||
Array4d(int _n1, int _n2, int _n3, int _n4):
|
Array4d(int _n1, int _n2, int _n3, int _n4):
|
||||||
n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(true)
|
n1(_n1), n2(_n2), n3(_n3), n4(_n4), needToDeallocArray(true)
|
||||||
{
|
{
|
||||||
a = new T[n1*n2*n3*n4];
|
a = new T[n1*n2*n3*n4];
|
||||||
init_steps();
|
init_steps();
|
||||||
}
|
}
|
||||||
|
|
||||||
~Array4d() {
|
~Array4d() {
|
||||||
|
@ -51,37 +51,37 @@ void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst,
|
|||||||
Mat src = _src.getMat();
|
Mat src = _src.getMat();
|
||||||
_dst.create(src.size(), src.type());
|
_dst.create(src.size(), src.type());
|
||||||
Mat dst = _dst.getMat();
|
Mat dst = _dst.getMat();
|
||||||
|
|
||||||
switch (src.type()) {
|
switch (src.type()) {
|
||||||
case CV_8U:
|
case CV_8U:
|
||||||
parallel_for(cv::BlockedRange(0, src.rows),
|
parallel_for(cv::BlockedRange(0, src.rows),
|
||||||
FastNlMeansDenoisingInvoker<uchar>(
|
FastNlMeansDenoisingInvoker<uchar>(
|
||||||
src, dst, templateWindowSize, searchWindowSize, h));
|
src, dst, templateWindowSize, searchWindowSize, h));
|
||||||
break;
|
break;
|
||||||
case CV_8UC2:
|
case CV_8UC2:
|
||||||
parallel_for(cv::BlockedRange(0, src.rows),
|
parallel_for(cv::BlockedRange(0, src.rows),
|
||||||
FastNlMeansDenoisingInvoker<cv::Vec2b>(
|
FastNlMeansDenoisingInvoker<cv::Vec2b>(
|
||||||
src, dst, templateWindowSize, searchWindowSize, h));
|
src, dst, templateWindowSize, searchWindowSize, h));
|
||||||
break;
|
break;
|
||||||
case CV_8UC3:
|
case CV_8UC3:
|
||||||
parallel_for(cv::BlockedRange(0, src.rows),
|
parallel_for(cv::BlockedRange(0, src.rows),
|
||||||
FastNlMeansDenoisingInvoker<cv::Vec3b>(
|
FastNlMeansDenoisingInvoker<cv::Vec3b>(
|
||||||
src, dst, templateWindowSize, searchWindowSize, h));
|
src, dst, templateWindowSize, searchWindowSize, h));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
CV_Error(CV_StsBadArg,
|
CV_Error(CV_StsBadArg,
|
||||||
"Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported");
|
"Unsupported image format! Only CV_8UC1, CV_8UC2 and CV_8UC3 are supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
|
void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
|
||||||
int templateWindowSize, int searchWindowSize,
|
int templateWindowSize, int searchWindowSize,
|
||||||
int h, int hForColorComponents)
|
int h, int hForColorComponents)
|
||||||
{
|
{
|
||||||
Mat src = _src.getMat();
|
Mat src = _src.getMat();
|
||||||
_dst.create(src.size(), src.type());
|
_dst.create(src.size(), src.type());
|
||||||
Mat dst = _dst.getMat();
|
Mat dst = _dst.getMat();
|
||||||
|
|
||||||
if (src.type() != CV_8UC3) {
|
if (src.type() != CV_8UC3) {
|
||||||
CV_Error(CV_StsBadArg, "Type of input image should be CV_8UC3!");
|
CV_Error(CV_StsBadArg, "Type of input image should be CV_8UC3!");
|
||||||
return;
|
return;
|
||||||
@ -89,13 +89,13 @@ void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
|
|||||||
|
|
||||||
Mat src_lab;
|
Mat src_lab;
|
||||||
cvtColor(src, src_lab, CV_LBGR2Lab);
|
cvtColor(src, src_lab, CV_LBGR2Lab);
|
||||||
|
|
||||||
Mat l(src.size(), CV_8U);
|
Mat l(src.size(), CV_8U);
|
||||||
Mat ab(src.size(), CV_8UC2);
|
Mat ab(src.size(), CV_8UC2);
|
||||||
Mat l_ab[] = { l, ab };
|
Mat l_ab[] = { l, ab };
|
||||||
int from_to[] = { 0,0, 1,1, 2,2 };
|
int from_to[] = { 0,0, 1,1, 2,2 };
|
||||||
mixChannels(&src_lab, 1, l_ab, 2, from_to, 3);
|
mixChannels(&src_lab, 1, l_ab, 2, from_to, 3);
|
||||||
|
|
||||||
fastNlMeansDenoising(l, l, templateWindowSize, searchWindowSize, h);
|
fastNlMeansDenoising(l, l, templateWindowSize, searchWindowSize, h);
|
||||||
fastNlMeansDenoising(ab, ab, templateWindowSize, searchWindowSize, hForColorComponents);
|
fastNlMeansDenoising(ab, ab, templateWindowSize, searchWindowSize, hForColorComponents);
|
||||||
|
|
||||||
@ -106,10 +106,10 @@ void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
|
|||||||
cvtColor(dst_lab, dst, CV_Lab2LBGR);
|
cvtColor(dst_lab, dst, CV_Lab2LBGR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fastNlMeansDenoisingMultiCheckPreconditions(
|
static void fastNlMeansDenoisingMultiCheckPreconditions(
|
||||||
const std::vector<Mat>& srcImgs,
|
const std::vector<Mat>& srcImgs,
|
||||||
int imgToDenoiseIndex, int temporalWindowSize,
|
int imgToDenoiseIndex, int temporalWindowSize,
|
||||||
int templateWindowSize, int searchWindowSize)
|
int templateWindowSize, int searchWindowSize)
|
||||||
{
|
{
|
||||||
int src_imgs_size = (int)srcImgs.size();
|
int src_imgs_size = (int)srcImgs.size();
|
||||||
if (src_imgs_size == 0) {
|
if (src_imgs_size == 0) {
|
||||||
@ -123,10 +123,10 @@ static void fastNlMeansDenoisingMultiCheckPreconditions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int temporalWindowHalfSize = temporalWindowSize / 2;
|
int temporalWindowHalfSize = temporalWindowSize / 2;
|
||||||
if (imgToDenoiseIndex - temporalWindowHalfSize < 0 ||
|
if (imgToDenoiseIndex - temporalWindowHalfSize < 0 ||
|
||||||
imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size)
|
imgToDenoiseIndex + temporalWindowHalfSize >= src_imgs_size)
|
||||||
{
|
{
|
||||||
CV_Error(CV_StsBadArg,
|
CV_Error(CV_StsBadArg,
|
||||||
"imgToDenoiseIndex and temporalWindowSize "
|
"imgToDenoiseIndex and temporalWindowSize "
|
||||||
"should be choosen corresponding srcImgs size!");
|
"should be choosen corresponding srcImgs size!");
|
||||||
}
|
}
|
||||||
@ -138,16 +138,16 @@ static void fastNlMeansDenoisingMultiCheckPreconditions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs,
|
void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs,
|
||||||
int imgToDenoiseIndex, int temporalWindowSize,
|
int imgToDenoiseIndex, int temporalWindowSize,
|
||||||
OutputArray _dst,
|
OutputArray _dst,
|
||||||
int templateWindowSize, int searchWindowSize, int h)
|
int templateWindowSize, int searchWindowSize, int h)
|
||||||
{
|
{
|
||||||
vector<Mat> srcImgs;
|
vector<Mat> srcImgs;
|
||||||
_srcImgs.getMatVector(srcImgs);
|
_srcImgs.getMatVector(srcImgs);
|
||||||
|
|
||||||
fastNlMeansDenoisingMultiCheckPreconditions(
|
fastNlMeansDenoisingMultiCheckPreconditions(
|
||||||
srcImgs, imgToDenoiseIndex,
|
srcImgs, imgToDenoiseIndex,
|
||||||
temporalWindowSize, templateWindowSize, searchWindowSize
|
temporalWindowSize, templateWindowSize, searchWindowSize
|
||||||
);
|
);
|
||||||
_dst.create(srcImgs[0].size(), srcImgs[0].type());
|
_dst.create(srcImgs[0].size(), srcImgs[0].type());
|
||||||
@ -155,43 +155,43 @@ void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs,
|
|||||||
|
|
||||||
switch (srcImgs[0].type()) {
|
switch (srcImgs[0].type()) {
|
||||||
case CV_8U:
|
case CV_8U:
|
||||||
parallel_for(cv::BlockedRange(0, srcImgs[0].rows),
|
parallel_for(cv::BlockedRange(0, srcImgs[0].rows),
|
||||||
FastNlMeansMultiDenoisingInvoker<uchar>(
|
FastNlMeansMultiDenoisingInvoker<uchar>(
|
||||||
srcImgs, imgToDenoiseIndex, temporalWindowSize,
|
srcImgs, imgToDenoiseIndex, temporalWindowSize,
|
||||||
dst, templateWindowSize, searchWindowSize, h));
|
dst, templateWindowSize, searchWindowSize, h));
|
||||||
break;
|
break;
|
||||||
case CV_8UC2:
|
case CV_8UC2:
|
||||||
parallel_for(cv::BlockedRange(0, srcImgs[0].rows),
|
parallel_for(cv::BlockedRange(0, srcImgs[0].rows),
|
||||||
FastNlMeansMultiDenoisingInvoker<cv::Vec2b>(
|
FastNlMeansMultiDenoisingInvoker<cv::Vec2b>(
|
||||||
srcImgs, imgToDenoiseIndex, temporalWindowSize,
|
srcImgs, imgToDenoiseIndex, temporalWindowSize,
|
||||||
dst, templateWindowSize, searchWindowSize, h));
|
dst, templateWindowSize, searchWindowSize, h));
|
||||||
break;
|
break;
|
||||||
case CV_8UC3:
|
case CV_8UC3:
|
||||||
parallel_for(cv::BlockedRange(0, srcImgs[0].rows),
|
parallel_for(cv::BlockedRange(0, srcImgs[0].rows),
|
||||||
FastNlMeansMultiDenoisingInvoker<cv::Vec3b>(
|
FastNlMeansMultiDenoisingInvoker<cv::Vec3b>(
|
||||||
srcImgs, imgToDenoiseIndex, temporalWindowSize,
|
srcImgs, imgToDenoiseIndex, temporalWindowSize,
|
||||||
dst, templateWindowSize, searchWindowSize, h));
|
dst, templateWindowSize, searchWindowSize, h));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
CV_Error(CV_StsBadArg,
|
CV_Error(CV_StsBadArg,
|
||||||
"Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported");
|
"Unsupported matrix format! Only uchar, Vec2b, Vec3b are supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs,
|
void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs,
|
||||||
int imgToDenoiseIndex, int temporalWindowSize,
|
int imgToDenoiseIndex, int temporalWindowSize,
|
||||||
OutputArray _dst,
|
OutputArray _dst,
|
||||||
int templateWindowSize, int searchWindowSize,
|
int templateWindowSize, int searchWindowSize,
|
||||||
int h, int hForColorComponents)
|
int h, int hForColorComponents)
|
||||||
{
|
{
|
||||||
vector<Mat> srcImgs;
|
vector<Mat> srcImgs;
|
||||||
_srcImgs.getMatVector(srcImgs);
|
_srcImgs.getMatVector(srcImgs);
|
||||||
|
|
||||||
fastNlMeansDenoisingMultiCheckPreconditions(
|
fastNlMeansDenoisingMultiCheckPreconditions(
|
||||||
srcImgs, imgToDenoiseIndex,
|
srcImgs, imgToDenoiseIndex,
|
||||||
temporalWindowSize, templateWindowSize, searchWindowSize
|
temporalWindowSize, templateWindowSize, searchWindowSize
|
||||||
);
|
);
|
||||||
|
|
||||||
_dst.create(srcImgs[0].size(), srcImgs[0].type());
|
_dst.create(srcImgs[0].size(), srcImgs[0].type());
|
||||||
Mat dst = _dst.getMat();
|
Mat dst = _dst.getMat();
|
||||||
|
|
||||||
@ -207,26 +207,26 @@ void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs,
|
|||||||
// TODO convert only required images
|
// TODO convert only required images
|
||||||
vector<Mat> src_lab(src_imgs_size);
|
vector<Mat> src_lab(src_imgs_size);
|
||||||
vector<Mat> l(src_imgs_size);
|
vector<Mat> l(src_imgs_size);
|
||||||
vector<Mat> ab(src_imgs_size);
|
vector<Mat> ab(src_imgs_size);
|
||||||
for (int i = 0; i < src_imgs_size; i++) {
|
for (int i = 0; i < src_imgs_size; i++) {
|
||||||
src_lab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC3);
|
src_lab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC3);
|
||||||
l[i] = Mat::zeros(srcImgs[0].size(), CV_8UC1);
|
l[i] = Mat::zeros(srcImgs[0].size(), CV_8UC1);
|
||||||
ab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC2);
|
ab[i] = Mat::zeros(srcImgs[0].size(), CV_8UC2);
|
||||||
cvtColor(srcImgs[i], src_lab[i], CV_LBGR2Lab);
|
cvtColor(srcImgs[i], src_lab[i], CV_LBGR2Lab);
|
||||||
|
|
||||||
Mat l_ab[] = { l[i], ab[i] };
|
Mat l_ab[] = { l[i], ab[i] };
|
||||||
mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3);
|
mixChannels(&src_lab[i], 1, l_ab, 2, from_to, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mat dst_l;
|
Mat dst_l;
|
||||||
Mat dst_ab;
|
Mat dst_ab;
|
||||||
|
|
||||||
fastNlMeansDenoisingMulti(
|
fastNlMeansDenoisingMulti(
|
||||||
l, imgToDenoiseIndex, temporalWindowSize,
|
l, imgToDenoiseIndex, temporalWindowSize,
|
||||||
dst_l, templateWindowSize, searchWindowSize, h);
|
dst_l, templateWindowSize, searchWindowSize, h);
|
||||||
|
|
||||||
fastNlMeansDenoisingMulti(
|
fastNlMeansDenoisingMulti(
|
||||||
ab, imgToDenoiseIndex, temporalWindowSize,
|
ab, imgToDenoiseIndex, temporalWindowSize,
|
||||||
dst_ab, templateWindowSize, searchWindowSize, hForColorComponents);
|
dst_ab, templateWindowSize, searchWindowSize, hForColorComponents);
|
||||||
|
|
||||||
Mat l_ab_denoised[] = { dst_l, dst_ab };
|
Mat l_ab_denoised[] = { dst_l, dst_ab };
|
||||||
|
@ -56,17 +56,15 @@ using namespace cv;
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct FastNlMeansDenoisingInvoker {
|
struct FastNlMeansDenoisingInvoker {
|
||||||
public:
|
public:
|
||||||
FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst,
|
FastNlMeansDenoisingInvoker(const Mat& src, Mat& dst,
|
||||||
int template_window_size, int search_window_size, const double h);
|
int template_window_size, int search_window_size, const double h);
|
||||||
|
|
||||||
void operator() (const BlockedRange& range) const;
|
void operator() (const BlockedRange& range) const;
|
||||||
|
|
||||||
void operator= (const FastNlMeansDenoisingInvoker&) {
|
|
||||||
CV_Error(CV_StsNotImplemented, "Assigment operator is not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void operator= (const FastNlMeansDenoisingInvoker&);
|
||||||
|
|
||||||
const Mat& src_;
|
const Mat& src_;
|
||||||
Mat& dst_;
|
Mat& dst_;
|
||||||
|
|
||||||
@ -80,41 +78,48 @@ struct FastNlMeansDenoisingInvoker {
|
|||||||
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_;
|
||||||
vector<int> almost_dist2weight;
|
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 j,
|
||||||
int first_col_num,
|
int first_col_num,
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline int getNearestPowerOf2(int value)
|
||||||
|
{
|
||||||
|
int p = 0;
|
||||||
|
while( 1 << p < value) ++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 double h) : src_(src), dst_(dst)
|
const double h) : src_(src), dst_(dst)
|
||||||
{
|
{
|
||||||
CV_Assert(src.channels() <= 3);
|
CV_Assert(src.channels() == sizeof(T)); //T is Vec1b or Vec2b or Vec3b
|
||||||
|
|
||||||
template_window_half_size_ = template_window_size / 2;
|
template_window_half_size_ = template_window_size / 2;
|
||||||
search_window_half_size_ = search_window_size / 2;
|
search_window_half_size_ = search_window_size / 2;
|
||||||
template_window_size_ = template_window_half_size_ * 2 + 1;
|
template_window_size_ = template_window_half_size_ * 2 + 1;
|
||||||
search_window_size_ = search_window_half_size_ * 2 + 1;
|
search_window_size_ = search_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_;
|
||||||
copyMakeBorder(src_, extended_src_,
|
copyMakeBorder(src_, extended_src_,
|
||||||
border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT);
|
border_size_, border_size_, border_size_, border_size_, cv::BORDER_DEFAULT);
|
||||||
|
|
||||||
const int max_estimate_sum_value = search_window_size_ * search_window_size_ * 255;
|
const int max_estimate_sum_value = search_window_size_ * search_window_size_ * 255;
|
||||||
@ -122,19 +127,15 @@ FastNlMeansDenoisingInvoker<T>::FastNlMeansDenoisingInvoker(
|
|||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
|
CV_Assert(template_window_size_ <= 46340 ); // sqrt(INT_MAX)
|
||||||
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_ = getNearestPowerOf2(template_window_size_sq);
|
||||||
while (1 << almost_template_window_size_sq_bin_shift < template_window_size_sq) {
|
double almost_dist2actual_dist_multiplier = ((double)(1 << almost_template_window_size_sq_bin_shift_)) / template_window_size_sq;
|
||||||
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_template_window_size_sq) / template_window_size_sq;
|
|
||||||
|
|
||||||
int max_dist = 256 * 256 * src_.channels();
|
int max_dist = 256 * 256 * src_.channels();
|
||||||
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++) {
|
||||||
@ -145,7 +146,7 @@ FastNlMeansDenoisingInvoker<T>::FastNlMeansDenoisingInvoker(
|
|||||||
weight = 0;
|
weight = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
almost_dist2weight[almost_dist] = weight;
|
almost_dist2weight_[almost_dist] = weight;
|
||||||
}
|
}
|
||||||
// additional optimization init end
|
// additional optimization init end
|
||||||
|
|
||||||
@ -160,10 +161,10 @@ void FastNlMeansDenoisingInvoker<T>::operator() (const BlockedRange& range) cons
|
|||||||
int row_to = range.end() - 1;
|
int row_to = range.end() - 1;
|
||||||
|
|
||||||
Array2d<int> dist_sums(search_window_size_, search_window_size_);
|
Array2d<int> dist_sums(search_window_size_, search_window_size_);
|
||||||
|
|
||||||
// for lazy calc optimization
|
// for lazy calc optimization
|
||||||
Array3d<int> col_dist_sums(template_window_size_, search_window_size_, search_window_size_);
|
Array3d<int> col_dist_sums(template_window_size_, search_window_size_, search_window_size_);
|
||||||
|
|
||||||
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_);
|
||||||
|
|
||||||
@ -179,17 +180,17 @@ void FastNlMeansDenoisingInvoker<T>::operator() (const BlockedRange& range) cons
|
|||||||
|
|
||||||
} else { // calc cur dist_sums using previous dist_sums
|
} else { // calc cur dist_sums using previous dist_sums
|
||||||
if (i == row_from) {
|
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 =
|
int start_bx =
|
||||||
border_size_ + j - search_window_half_size_ + template_window_half_size_;
|
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);
|
||||||
@ -200,64 +201,64 @@ void FastNlMeansDenoisingInvoker<T>::operator() (const BlockedRange& range) cons
|
|||||||
|
|
||||||
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 =
|
const T* b_down_ptr =
|
||||||
extended_src_.ptr<T>(start_by + template_window_half_size_ + y);
|
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] =
|
col_dist_sums_row[x] =
|
||||||
up_col_dist_sums_row[x] +
|
up_col_dist_sums_row[x] +
|
||||||
calcUpDownDist(
|
calcUpDownDist(
|
||||||
a_up, a_down,
|
a_up, a_down,
|
||||||
b_up_ptr[start_bx + x], b_down_ptr[start_bx + x]
|
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];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
first_col_num = (first_col_num + 1) % template_window_size_;
|
first_col_num = (first_col_num + 1) % template_window_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calc weights
|
// calc weights
|
||||||
int weights_sum = 0;
|
int weights_sum = 0;
|
||||||
|
|
||||||
int estimation[3];
|
int estimation[3];
|
||||||
for (int channel_num = 0; channel_num < src_.channels(); channel_num++) {
|
for (int channel_num = 0; channel_num < src_.channels(); 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_;
|
||||||
|
|
||||||
int weight = almost_dist2weight[almostAvgDist];
|
int weight = almost_dist2weight_[almostAvgDist];
|
||||||
weights_sum += weight;
|
weights_sum += weight;
|
||||||
|
|
||||||
T p = cur_row_ptr[border_size_ + search_window_x + x];
|
T p = cur_row_ptr[border_size_ + search_window_x + x];
|
||||||
incWithWeight(estimation, weight, p);
|
incWithWeight(estimation, weight, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weights_sum > 0) {
|
if (weights_sum > 0) {
|
||||||
for (int channel_num = 0; channel_num < src_.channels(); channel_num++) {
|
for (int channel_num = 0; channel_num < src_.channels(); channel_num++) {
|
||||||
estimation[channel_num] =
|
estimation[channel_num] =
|
||||||
cvRound(((double)estimation[channel_num]) / weights_sum);
|
cvRound(((double)estimation[channel_num]) / weights_sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,9 +273,9 @@ void FastNlMeansDenoisingInvoker<T>::operator() (const BlockedRange& range) cons
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void FastNlMeansDenoisingInvoker<T>::calcDistSumsForFirstElementInRow(
|
inline void FastNlMeansDenoisingInvoker<T>::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
|
||||||
{
|
{
|
||||||
int j = 0;
|
int j = 0;
|
||||||
@ -291,7 +292,7 @@ inline void FastNlMeansDenoisingInvoker<T>::calcDistSumsForFirstElementInRow(
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@ -310,29 +311,29 @@ inline void FastNlMeansDenoisingInvoker<T>::calcDistSumsForElementInFirstRow(
|
|||||||
int i,
|
int i,
|
||||||
int j,
|
int j,
|
||||||
int first_col_num,
|
int first_col_num,
|
||||||
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
|
||||||
{
|
{
|
||||||
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 = border_size_ + i - search_window_half_size_;
|
int start_by = 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_;
|
||||||
|
|
||||||
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];
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ template <> inline int calcDist(const Vec3b a, const Vec3b b) {
|
|||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ template <> inline Vec2b saturateCastFromArray(int* estimation) {
|
|||||||
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]);
|
||||||
|
@ -56,16 +56,16 @@ using namespace cv;
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct FastNlMeansMultiDenoisingInvoker {
|
struct FastNlMeansMultiDenoisingInvoker {
|
||||||
public:
|
public:
|
||||||
FastNlMeansMultiDenoisingInvoker(
|
FastNlMeansMultiDenoisingInvoker(
|
||||||
const std::vector<Mat>& srcImgs, int imgToDenoiseIndex, int temporalWindowSize,
|
const std::vector<Mat>& srcImgs, int imgToDenoiseIndex, int temporalWindowSize,
|
||||||
Mat& dst, int template_window_size, int search_window_size, const double h);
|
Mat& dst, int template_window_size, int search_window_size, const double h);
|
||||||
|
|
||||||
void operator() (const BlockedRange& range) const;
|
void operator() (const BlockedRange& range) const;
|
||||||
|
|
||||||
void operator= (const FastNlMeansMultiDenoisingInvoker&) {
|
void operator= (const FastNlMeansMultiDenoisingInvoker&) {
|
||||||
CV_Error(CV_StsNotImplemented, "Assigment operator is not implemented");
|
CV_Error(CV_StsNotImplemented, "Assigment operator is not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int rows_;
|
int rows_;
|
||||||
@ -91,28 +91,28 @@ struct FastNlMeansMultiDenoisingInvoker {
|
|||||||
vector<int> almost_dist2weight;
|
vector<int> almost_dist2weight;
|
||||||
|
|
||||||
void calcDistSumsForFirstElementInRow(
|
void calcDistSumsForFirstElementInRow(
|
||||||
int i,
|
int i,
|
||||||
Array3d<int>& dist_sums,
|
Array3d<int>& dist_sums,
|
||||||
Array4d<int>& col_dist_sums,
|
Array4d<int>& col_dist_sums,
|
||||||
Array4d<int>& up_col_dist_sums) const;
|
Array4d<int>& up_col_dist_sums) const;
|
||||||
|
|
||||||
void calcDistSumsForElementInFirstRow(
|
void calcDistSumsForElementInFirstRow(
|
||||||
int i,
|
int i,
|
||||||
int j,
|
int j,
|
||||||
int first_col_num,
|
int first_col_num,
|
||||||
Array3d<int>& dist_sums,
|
Array3d<int>& dist_sums,
|
||||||
Array4d<int>& col_dist_sums,
|
Array4d<int>& col_dist_sums,
|
||||||
Array4d<int>& up_col_dist_sums) const;
|
Array4d<int>& up_col_dist_sums) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
FastNlMeansMultiDenoisingInvoker<T>::FastNlMeansMultiDenoisingInvoker(
|
FastNlMeansMultiDenoisingInvoker<T>::FastNlMeansMultiDenoisingInvoker(
|
||||||
const vector<Mat>& srcImgs,
|
const vector<Mat>& srcImgs,
|
||||||
int imgToDenoiseIndex,
|
int imgToDenoiseIndex,
|
||||||
int temporalWindowSize,
|
int temporalWindowSize,
|
||||||
cv::Mat& dst,
|
cv::Mat& dst,
|
||||||
int template_window_size,
|
int template_window_size,
|
||||||
int search_window_size,
|
int search_window_size,
|
||||||
const double h) : dst_(dst), extended_srcs_(srcImgs.size())
|
const double h) : dst_(dst), extended_srcs_(srcImgs.size())
|
||||||
{
|
{
|
||||||
CV_Assert(srcImgs.size() > 0);
|
CV_Assert(srcImgs.size() > 0);
|
||||||
@ -131,14 +131,14 @@ 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 =
|
const int max_estimate_sum_value =
|
||||||
temporal_window_size_ * search_window_size_ * search_window_size_ * 255;
|
temporal_window_size_ * search_window_size_ * search_window_size_ * 255;
|
||||||
|
|
||||||
fixed_point_mult_ = numeric_limits<int>::max() / max_estimate_sum_value;
|
fixed_point_mult_ = numeric_limits<int>::max() / max_estimate_sum_value;
|
||||||
@ -150,9 +150,9 @@ FastNlMeansMultiDenoisingInvoker<T>::FastNlMeansMultiDenoisingInvoker(
|
|||||||
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 = 256 * 256 * channels_count_;
|
int max_dist = 256 * 256 * channels_count_;
|
||||||
@ -183,16 +183,16 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const BlockedRange& range)
|
|||||||
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(
|
Array4d<int> up_col_dist_sums(
|
||||||
cols_, temporal_window_size_, search_window_size_, search_window_size_);
|
cols_, temporal_window_size_, 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 < cols_; j++) {
|
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_;
|
||||||
@ -205,17 +205,17 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const BlockedRange& range)
|
|||||||
|
|
||||||
} else { // calc cur dist_sums using previous dist_sums
|
} else { // calc cur dist_sums using previous dist_sums
|
||||||
if (i == row_from) {
|
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 =
|
int start_bx =
|
||||||
border_size_ + j - search_window_half_size_ + template_window_half_size_;
|
border_size_ + j - search_window_half_size_ + template_window_half_size_;
|
||||||
|
|
||||||
T a_up = main_extended_src_.at<T>(ay - template_window_half_size_ - 1, ax);
|
T a_up = main_extended_src_.at<T>(ay - template_window_half_size_ - 1, ax);
|
||||||
@ -231,41 +231,41 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const BlockedRange& range)
|
|||||||
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 =
|
const T* b_down_ptr =
|
||||||
cur_extended_src.ptr<T>(start_by + template_window_half_size_ + y);
|
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,
|
a_up, a_down,
|
||||||
b_up_ptr[start_bx + x], b_down_ptr[start_bx + x]
|
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];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
first_col_num = (first_col_num + 1) % template_window_size_;
|
first_col_num = (first_col_num + 1) % template_window_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calc weights
|
// calc weights
|
||||||
int weights_sum = 0;
|
int weights_sum = 0;
|
||||||
|
|
||||||
int estimation[3];
|
int estimation[3];
|
||||||
for (int channel_num = 0; channel_num < channels_count_; channel_num++) {
|
for (int channel_num = 0; channel_num < channels_count_; channel_num++) {
|
||||||
estimation[channel_num] = 0;
|
estimation[channel_num] = 0;
|
||||||
}
|
}
|
||||||
@ -277,12 +277,12 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const BlockedRange& range)
|
|||||||
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 =
|
int almostAvgDist =
|
||||||
dist_sums_row[x] >> almost_template_window_size_sq_bin_shift;
|
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;
|
||||||
|
|
||||||
T p = cur_row_ptr[border_size_ + search_window_x + x];
|
T p = cur_row_ptr[border_size_ + search_window_x + x];
|
||||||
incWithWeight(estimation, weight, p);
|
incWithWeight(estimation, weight, p);
|
||||||
}
|
}
|
||||||
@ -291,7 +291,7 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const BlockedRange& range)
|
|||||||
|
|
||||||
if (weights_sum > 0) {
|
if (weights_sum > 0) {
|
||||||
for (int channel_num = 0; channel_num < channels_count_; channel_num++) {
|
for (int channel_num = 0; channel_num < channels_count_; channel_num++) {
|
||||||
estimation[channel_num] =
|
estimation[channel_num] =
|
||||||
cvRound(((double)estimation[channel_num]) / weights_sum);
|
cvRound(((double)estimation[channel_num]) / weights_sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,9 +307,9 @@ void FastNlMeansMultiDenoisingInvoker<T>::operator() (const BlockedRange& range)
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForFirstElementInRow(
|
inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForFirstElementInRow(
|
||||||
int i,
|
int i,
|
||||||
Array3d<int>& dist_sums,
|
Array3d<int>& dist_sums,
|
||||||
Array4d<int>& col_dist_sums,
|
Array4d<int>& col_dist_sums,
|
||||||
Array4d<int>& up_col_dist_sums) const
|
Array4d<int>& up_col_dist_sums) const
|
||||||
{
|
{
|
||||||
int j = 0;
|
int j = 0;
|
||||||
@ -328,7 +328,7 @@ 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>(
|
||||||
@ -355,16 +355,16 @@ inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForElementInFirstRo
|
|||||||
int i,
|
int i,
|
||||||
int j,
|
int j,
|
||||||
int first_col_num,
|
int first_col_num,
|
||||||
Array3d<int>& dist_sums,
|
Array3d<int>& dist_sums,
|
||||||
Array4d<int>& col_dist_sums,
|
Array4d<int>& col_dist_sums,
|
||||||
Array4d<int>& up_col_dist_sums) const
|
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_;
|
||||||
|
|
||||||
int start_by = border_size_ + i - search_window_half_size_;
|
int start_by = 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_;
|
||||||
|
|
||||||
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++) {
|
||||||
@ -372,19 +372,19 @@ inline void FastNlMeansMultiDenoisingInvoker<T>::calcDistSumsForElementInFirstRo
|
|||||||
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;
|
||||||
int by = start_by + y;
|
int by = start_by + y;
|
||||||
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 +=
|
*col_dist_sums_ptr +=
|
||||||
calcDist<T>(
|
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];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user