cimg.cxx 3.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,287 @@
1
+ /*************************************************************************
2
+ * matlab.h
3
+ * ---------
4
+ *
5
+ * matlab.h is a "plugin" for the CImg library that allows to convert
6
+ * CImg<T> images from/to MATLAB arrays, so that CImg can be used to write
7
+ * MATLAB mex files. It also swaps the "x" and "y" coordinates when going
8
+ * from / to MATLAB array, i.e. the usual image-processing annoying MATLAB
9
+ * behaviour of considering images as matrices.
10
+ *
11
+ * Added to the CImg<T> class are:
12
+ *
13
+ * - a constructor : CImg(const mxArray *matlabArray, bool vdata = false)
14
+ * the vdata serves to decide whether a 3D matlab array should give
15
+ * rise to a 3D CImg object or a "2D vectorial" one.
16
+ *
17
+ * - a assignment operator : CImg & operator=(const mxArray *matlabArray)
18
+ * (I use myself extremely seldom and might remove it in the future).
19
+ *
20
+ * - a routine converting a CImg image to a matlab array:
21
+ * mxArray *toMatlab(mxClassID classID = mxDOUBLE_CLASS,
22
+ * bool squeeze = false) const
23
+ * the squeeze argument serves the opposite purpose than the vdata from
24
+ * the constructor.
25
+ *
26
+ * For a bit more documentation, the manual is this header, see the more
27
+ * detailed comments in the source code (i.e. RTFM)
28
+ *
29
+ *
30
+ * Its usage should be straightforward:
31
+ *
32
+ * - file matlab.h must be in a directory that the compiler can locate.
33
+ * - prior to include CImg.h, mex.h must be included first, else it will
34
+ * result in a compiler error.
35
+ * - after the inclusion of mex.h, one must define the macro cimg_plugin as
36
+ * "matlab.h" or <matlab.h> or <CImg/plugins/matlab.h> or
37
+ * a variation that matches your local installation of CImg package and
38
+ * plugins probably via the appropriate specification of the include path
39
+ * "-Ipath/to/cimg/and/plugins" at mex cmdline.
40
+ *
41
+ * You would probably have this kind of declaration:
42
+ *
43
+ * // The begining of my fantastic mex file code...
44
+ * #include <mex.h>
45
+ * ...
46
+ * #define cimg_plugin <matlab.h>
47
+ * #include <CImg.h>
48
+ * ...
49
+ * // and now I can implement my new killer MATLAB function!
50
+ * ....
51
+ *
52
+ *
53
+ * Copyright (c) 2004-2008 Francois Lauze
54
+ * Licence: the Gnu Lesser General Public License
55
+ * http://www.gnu.org/licenses/lgpl.html
56
+ *
57
+ * MATLAB is copyright of The MathWorks, Inc, http://www.mathworks.com
58
+ *
59
+ * Any comments, improvements and potential bug corrections are welcome, so
60
+ * write to me at francois@diku.dk, or use CImg forums, I promise I'll try
61
+ * to read them once in a while. BTW who modified the cpMatlabData with the
62
+ * cimg::type<t>::is_float() test (good idea!)
63
+ *
64
+ ***************************************************************************/
65
+
66
+ #ifndef cimg_plugin_matlab
67
+ #define cimg_plugin_matlab
68
+
69
+ #define CIMGMATLAB_VER 0102
70
+ #ifndef mex_h
71
+ #error the file mex.h must be included prior to inclusion of matlab.h
72
+ #endif
73
+ #ifndef cimg_version
74
+ #error matlab.h requires that CImg.h is included!
75
+ #endif
76
+
77
+ /**********************************************************
78
+ * introduction of mwSize and mwIndex types in relatively *
79
+ * recent versions of matlab, 7.3.0 from what I gathered. *
80
+ * here is hopefully a needed fix for older versions *
81
+ **********************************************************/
82
+ #if !defined(MX_API_VER) || MX_API_VER < 0x7030000
83
+ typedef int mwSize;
84
+ #endif
85
+
86
+ /*********************************************************
87
+ * begin of included methods *
88
+ * They are just added as member functions / constructor *
89
+ * for the CImg<T> class. *
90
+ *********************************************************/
91
+
92
+ private:
93
+
94
+ /**********************************************************************
95
+ * internally used to transfer MATLAB array values to CImg<> objects,
96
+ * check wether the array type is a "numerical" one (including logical)
97
+ */
98
+ static int isNumericalClassID(mxClassID id) {
99
+ // all these constants are defined in matrix.h included by mex.h
100
+ switch (id) {
101
+ case mxLOGICAL_CLASS:
102
+ case mxDOUBLE_CLASS:
103
+ case mxSINGLE_CLASS:
104
+ case mxINT8_CLASS:
105
+ case mxUINT8_CLASS:
106
+ case mxINT16_CLASS:
107
+ case mxUINT16_CLASS:
108
+ case mxINT32_CLASS:
109
+ case mxUINT32_CLASS:
110
+ case mxINT64_CLASS:
111
+ case mxUINT64_CLASS: return 1;
112
+ default: return 0;
113
+ }
114
+ }
115
+
116
+ /***************************************************
117
+ * driving routine that will copy the content of
118
+ * a MATLAB array to this->_data
119
+ * The type names used are defined in matlab c/c++
120
+ * header file tmwtypes.h
121
+ */
122
+ void makeImageFromMatlabData(const mxArray *matlabArray, mxClassID classID) {
123
+ if (classID==mxLOGICAL_CLASS) {
124
+ // logical type works a bit differently than the numerical types
125
+ mxLogical *mdata = mxGetLogicals(matlabArray);
126
+ cpMatlabData((const mxLogical *)mdata);
127
+ } else {
128
+ void *mdata = (void*)mxGetPr(matlabArray);
129
+ switch (classID) {
130
+ case mxDOUBLE_CLASS : cpMatlabData((const real64_T*)mdata); break;
131
+ case mxSINGLE_CLASS : cpMatlabData((const real32_T*)mdata); break;
132
+ case mxINT8_CLASS : cpMatlabData((const int8_T*)mdata); break;
133
+ case mxUINT8_CLASS : cpMatlabData((const uint8_T*)mdata); break;
134
+ case mxINT16_CLASS : cpMatlabData((const int16_T*)mdata); break;
135
+ case mxUINT16_CLASS : cpMatlabData((const uint16_T*)mdata); break;
136
+ case mxINT32_CLASS : cpMatlabData((const int32_T*)mdata); break;
137
+ case mxUINT32_CLASS : cpMatlabData((const uint32_T*)mdata); break;
138
+ case mxINT64_CLASS : cpMatlabData((const int64_T*)mdata); break;
139
+ case mxUINT64_CLASS : cpMatlabData((const uint64_T*)mdata); break;
140
+ }
141
+ }
142
+ }
143
+
144
+ /***********************************************************
145
+ * the actual memory copy and base type conversion is then
146
+ * performed by this routine that handles the annoying x-y
147
+ * problem of MATLAB when dealing with images: we switch
148
+ * line and column storage: the MATLAB A(x,y) becomes the
149
+ * CImg img(y,x)
150
+ */
151
+ template <typename t> void cpMatlabData(const t* mdata) {
152
+ if (cimg::type<t>::is_float()) {
153
+ cimg_forXYZC(*this,x,y,z,v) (*this)(x,y,z,v) = (T)(mdata[((v*_depth + z)*_width + x)*_height + y]);
154
+ } else {
155
+ cimg_forXYZC(*this,x,y,z,v) (*this)(x,y,z,v) = (T)(int)(mdata[((v*_depth + z)*_width + x)*_height + y]);
156
+ }
157
+ }
158
+
159
+ public:
160
+
161
+ /******************************************************************
162
+ * Consruct a CImg<T> object from a MATLAB mxArray.
163
+ * The MATLAB array must be AT MOST 4-dimensional. The boolean
164
+ * argument vdata is employed in the case the the input mxArray
165
+ * has dimension 3, say M x N x K. In that case, if vdata is true,
166
+ * the last dimension is assumed to be "vectorial" and the
167
+ * resulting CImg<T> object has dimension N x M x 1 x K. Otherwise,
168
+ * the resulting object has dimension N x M x K x 1.
169
+ * When MATLAB array has dimension 2 or 4, vdata has no effects.
170
+ * No shared memory mechanisms are used, it would be the easiest
171
+ * to crash Matlab (from my own experience...)
172
+ */
173
+ CImg(const mxArray *matlabArray, const bool vdata = false)
174
+ : _is_shared(false) {
175
+ mwSize nbdims = mxGetNumberOfDimensions(matlabArray);
176
+ mxClassID classID = mxGetClassID(matlabArray);
177
+ if (nbdims>4 || !isNumericalClassID(classID)) {
178
+ _data = 0; _width = _height = _depth = _spectrum = 0;
179
+ #if cimg_debug>1
180
+ cimg::warn("MATLAB array is more than 4D or/and not numerical, returning an empty image.");
181
+ #endif
182
+ } else {
183
+ const mwSize *dims = mxGetDimensions(matlabArray);
184
+ _depth = _spectrum = 1;
185
+ _width = (unsigned)dims[1];
186
+ _height = (unsigned)dims[0];
187
+ if (nbdims==4) { _depth = (unsigned)dims[2]; _spectrum = (unsigned)dims[3]; }
188
+ else if (nbdims==3) {
189
+ if (vdata) _spectrum = (unsigned)dims[2]; else _depth = (unsigned)dims[2];
190
+ }
191
+ _data = new T[size()];
192
+ makeImageFromMatlabData(matlabArray,classID);
193
+ }
194
+ }
195
+
196
+ /*******************************************************************
197
+ * operator=(). Copy mxMarray data mArray into the current image
198
+ * Works as the previous constructor, but without the vdata stuff.
199
+ * don't know if it is of any use...
200
+ */
201
+ CImg & operator=(const mxArray *matlabArray) {
202
+ int
203
+ nbdims = (int)mxGetNumberOfDimensions(matlabArray),
204
+ classID = mxGetClassID(matlabArray);
205
+ if (nbdims>4 || !isNumericalClassID(classID)) {
206
+ delete [] _data; _data = 0;
207
+ _width = _height = _depth = _spectrum = 0;
208
+ #if cimg_debug>1
209
+ cimg::warn("MATLAB array is more than 4D or/and not numerical, returning an empty image.");
210
+ #endif
211
+ } else {
212
+ const mwSize *dims = mxGetDimensions(matlabArray);
213
+ _depth = _spectrum = 1;
214
+ _width = (unsigned)dims[1];
215
+ _height = (unsigned)dims[0];
216
+ if (nbdims>2) _depth = (unsigned)dims[2];
217
+ else if (nbdims>3) _spectrum = (unsigned)dims[3];
218
+ delete [] _data;
219
+ _data = new T[size()];
220
+ makeImageFromMatlabData(matlabArray,classID);
221
+ }
222
+ }
223
+
224
+ private:
225
+
226
+ /*****************************************************************
227
+ * private routines used for transfering a CImg<T> to a mxArray
228
+ * here also, we have to exchange the x and y dims so we get the
229
+ * expected MATLAB array.
230
+ */
231
+ template <typename c> void populate_maltlab_array(c *const mdata) const {
232
+ cimg_forXYZC(*this,x,y,z,v) mdata[((v*_depth + z)*_width + x)*_height + y] = (c)(*this)(x,y,z,v);
233
+ }
234
+
235
+ /*************************************************
236
+ * the specialized version for "logical" entries
237
+ */
238
+ void populate_maltlab_array(mxLogical *const mdata) const {
239
+ cimg_forXYZC(*this,x,y,z,v) mdata[((v*_depth + z)*_width + x)*_height + y] = (mxLogical)((*this)(x,y,z,v)!=0);
240
+ }
241
+
242
+ public:
243
+
244
+ /******************************************
245
+ * export a CImg image to a MATLAB array.
246
+ **/
247
+ mxArray *toMatlab(mxClassID classID=mxDOUBLE_CLASS, const bool squeeze=false) const {
248
+ if (!isNumericalClassID(classID)) {
249
+ #if cimg_debug>1
250
+ cimg::warn("Invalid MATLAB Class Id Specified.");
251
+ #endif
252
+ return 0;
253
+ }
254
+ mwSize dims[4];
255
+ dims[0] = (mwSize)_height;
256
+ dims[1] = (mwSize)_width;
257
+ dims[2] = (mwSize)_depth;
258
+ dims[3] = (mwSize)_spectrum;
259
+
260
+ if (squeeze && _depth == 1) {
261
+ dims[2] = (mwSize)_spectrum;
262
+ dims[3] = (mwSize)1;
263
+ }
264
+ mxArray *matlabArray = mxCreateNumericArray((mwSize)4,dims,classID,mxREAL);
265
+ if (classID==mxLOGICAL_CLASS) {
266
+ mxLogical *mdata = mxGetLogicals(matlabArray);
267
+ populate_maltlab_array(mdata);
268
+ } else {
269
+ void *mdata = mxGetPr(matlabArray);
270
+ switch (classID) {
271
+ case mxDOUBLE_CLASS : populate_maltlab_array((real64_T*)mdata); break;
272
+ case mxSINGLE_CLASS : populate_maltlab_array((real32_T*)mdata); break;
273
+ case mxINT8_CLASS : populate_maltlab_array((int8_T*)mdata); break;
274
+ case mxUINT8_CLASS : populate_maltlab_array((uint8_T*)mdata); break;
275
+ case mxINT16_CLASS : populate_maltlab_array((int16_T*)mdata); break;
276
+ case mxUINT16_CLASS : populate_maltlab_array((uint16_T*)mdata); break;
277
+ case mxINT32_CLASS : populate_maltlab_array((int32_T*)mdata); break;
278
+ case mxUINT32_CLASS : populate_maltlab_array((uint32_T*)mdata); break;
279
+ case mxINT64_CLASS : populate_maltlab_array((int64_T*)mdata); break;
280
+ case mxUINT64_CLASS : populate_maltlab_array((uint64_T*)mdata); break;
281
+ }
282
+ }
283
+ return matlabArray;
284
+ }
285
+
286
+ // end of matlab.h
287
+ #endif /* cimg_plugin_matlab */
@@ -0,0 +1,242 @@
1
+ /*
2
+ #
3
+ # File : nlmeans.h
4
+ # ( C++ header file - CImg plug-in )
5
+ #
6
+ # Description : CImg plugin that implements the non-local mean filter.
7
+ # This file is a part of the CImg Library project.
8
+ # ( http://cimg.eu )
9
+ #
10
+ # [1] Buades, A.; Coll, B.; Morel, J.-M.: A non-local algorithm for image denoising
11
+ # IEEE Computer Society Conference on Computer Vision and Pattern Recognition, 2005. CVPR 2005.
12
+ # Volume 2, 20-25 June 2005 Page(s):60 - 65 vol. 2
13
+ #
14
+ # [2] Buades, A. Coll, B. and Morel, J.: A review of image denoising algorithms, with a new one.
15
+ # Multiscale Modeling and Simulation: A SIAM Interdisciplinary Journal 4 (2004) 490-530
16
+ #
17
+ # [3] Gasser, T. Sroka,L. Jennen Steinmetz,C. Residual variance and residual pattern nonlinear regression.
18
+ # Biometrika 73 (1986) 625-659
19
+ #
20
+ # Copyright : Jerome Boulanger
21
+ # ( http://www.irisa.fr/vista/Equipe/People/Jerome.Boulanger.html )
22
+ #
23
+ # License : CeCILL v2.0
24
+ # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
25
+ #
26
+ # This software is governed by the CeCILL license under French law and
27
+ # abiding by the rules of distribution of free software. You can use,
28
+ # modify and/ or redistribute the software under the terms of the CeCILL
29
+ # license as circulated by CEA, CNRS and INRIA at the following URL
30
+ # "http://www.cecill.info".
31
+ #
32
+ # As a counterpart to the access to the source code and rights to copy,
33
+ # modify and redistribute granted by the license, users are provided only
34
+ # with a limited warranty and the software's author, the holder of the
35
+ # economic rights, and the successive licensors have only limited
36
+ # liability.
37
+ #
38
+ # In this respect, the user's attention is drawn to the risks associated
39
+ # with loading, using, modifying and/or developing or reproducing the
40
+ # software by the user in light of its specific status of free software,
41
+ # that may mean that it is complicated to manipulate, and that also
42
+ # therefore means that it is reserved for developers and experienced
43
+ # professionals having in-depth computer knowledge. Users are therefore
44
+ # encouraged to load and test the software's suitability as regards their
45
+ # requirements in conditions enabling the security of their systems and/or
46
+ # data to be ensured and, more generally, to use and operate it in the
47
+ # same conditions as regards security.
48
+ #
49
+ # The fact that you are presently reading this means that you have had
50
+ # knowledge of the CeCILL license and that you accept its terms.
51
+ #
52
+ */
53
+
54
+ #ifndef cimg_plugin_nlmeans
55
+ #define cimg_plugin_nlmeans
56
+
57
+ //! NL-Means denoising algorithm.
58
+ /**
59
+ This is the in-place version of get_nlmean().
60
+ **/
61
+ CImg<T>& nlmeans(int patch_size=1, double lambda=-1, double alpha=3, double sigma=-1, int sampling=1){
62
+ if (!is_empty()){
63
+ if (sigma<0) sigma = std::sqrt(variance_noise()); // noise variance estimation
64
+ const double np = (2*patch_size + 1)*(2*patch_size + 1)*spectrum()/(double)sampling;
65
+ if (lambda<0) {// Bandwidth estimation
66
+ if (np<100)
67
+ lambda = ((((((1.1785e-12*np - 5.1827e-10)*np + 9.5946e-08)*np -
68
+ 9.7798e-06)*np + 6.0756e-04)*np - 0.0248)*np + 1.9203)*np + 7.9599;
69
+ else
70
+ lambda = (-7.2611e-04*np + 1.3213)*np + 15.2726;
71
+ }
72
+ #if cimg_debug>=1
73
+ std::fprintf(stderr,"Size of the patch : %dx%d \n",
74
+ 2*patch_size + 1,2*patch_size + 1);
75
+ std::fprintf(stderr,"Size of window where similar patch are looked for : %dx%d \n",
76
+ (int)(alpha*(2*patch_size + 1)),(int)(alpha*(2*patch_size + 1)));
77
+ std::fprintf(stderr,"Bandwidth of the kernel : %fx%f^2 \n",
78
+ lambda,sigma);
79
+ std::fprintf(stderr,"Noise standard deviation estimated to : %f \n",
80
+ sigma);
81
+ #endif
82
+
83
+ CImg<T> dest(width(),height(),depth(),spectrum(),0);
84
+ double *uhat = new double[spectrum()];
85
+ const double h2 = -.5/(lambda*sigma*sigma); // [Kervrann] notations
86
+ if (depth()!=1){ // 3D case
87
+ const CImg<> P = (*this).get_blur(1); // inspired from Mahmoudi&Sapiro SPletter dec 05
88
+ const int n_simu = 64;
89
+ CImg<> tmp(n_simu,n_simu,n_simu);
90
+ const double sig = std::sqrt(tmp.fill(0.f).noise(sigma).blur(1).pow(2.).sum()/(n_simu*n_simu*n_simu));
91
+ const int
92
+ patch_size_z = 0,
93
+ pxi = (int)(alpha*patch_size),
94
+ pyi = (int)(alpha*patch_size),
95
+ pzi = 2; //Define the size of the neighborhood in z
96
+ for (int zi = 0; zi<depth(); ++zi) {
97
+ #if cimg_debug>=1
98
+ std::fprintf(stderr,"\rProcessing : %3d %%",(int)((float)zi/(float)depth()*100.));fflush(stdout);
99
+ #endif
100
+ for (int yi = 0; yi<height(); ++yi)
101
+ for (int xi = 0; xi<width(); ++xi) {
102
+ cimg_forC(*this,v) uhat[v] = 0;
103
+ float sw = 0, wmax = -1;
104
+ for (int zj = std::max(0,zi - pzi); zj<std::min(depth(),zi + pzi + 1); ++zj)
105
+ for (int yj = std::max(0,yi - pyi); yj<std::min(height(),yi + pyi + 1); ++yj)
106
+ for (int xj = std::max(0,xi - pxi); xj<std::min(width(),xi + pxi + 1); ++xj)
107
+ if (cimg::abs(P(xi,yi,zi) - P(xj,yj,zj))/sig<3) {
108
+ double d = 0;
109
+ int n = 0;
110
+ if (xi!=xj && yi!=yj && zi!=zj){
111
+ for (int kz = -patch_size_z; kz<patch_size_z + 1; kz+=sampling) {
112
+ int
113
+ zj_ = zj + kz,
114
+ zi_ = zi + kz;
115
+ if (zj_>=0 && zj_<depth() && zi_>=0 && zi_<depth())
116
+ for (int ky = -patch_size; ky<=patch_size; ky+=sampling) {
117
+ int
118
+ yj_ = yj + ky,
119
+ yi_ = yi + ky;
120
+ if (yj_>=0 && yj_<height() && yi_>=0 && yi_<height())
121
+ for (int kx = -patch_size; kx<=patch_size; kx+=sampling) {
122
+ int
123
+ xj_ = xj + kx,
124
+ xi_ = xi + kx;
125
+ if (xj_>=0 && xj_<width() && xi_>=0 && xi_<width())
126
+ cimg_forC(*this,v) {
127
+ double d1 = (*this)(xj_,yj_,zj_,v) - (*this)(xi_,yi_,zi_,v);
128
+ d+=d1*d1;
129
+ ++n;
130
+ }
131
+ }
132
+ }
133
+ }
134
+ float w = (float)std::exp(d*h2);
135
+ wmax = w>wmax?w:wmax;
136
+ cimg_forC(*this,v) uhat[v]+=w*(*this)(xj,yj,zj,v);
137
+ sw+=w;
138
+ }
139
+ }
140
+ // add the central pixel
141
+ cimg_forC(*this,v) uhat[v]+=wmax*(*this)(xi,yi,zi,v);
142
+ sw+=wmax;
143
+ if (sw) cimg_forC(*this,v) dest(xi,yi,zi,v) = (T)(uhat[v]/=sw);
144
+ else cimg_forC(*this,v) dest(xi,yi,zi,v) = (*this)(xi,yi,zi,v);
145
+ }
146
+ }
147
+ }
148
+ else { // 2D case
149
+ const CImg<> P = (*this).get_blur(1); // inspired from Mahmoudi&Sapiro SPletter dec 05
150
+ const int n_simu = 512;
151
+ CImg<> tmp(n_simu,n_simu);
152
+ const double sig = std::sqrt(tmp.fill(0.f).noise(sigma).blur(1).pow(2.).sum()/(n_simu*n_simu));
153
+ const int
154
+ pxi = (int)(alpha*patch_size),
155
+ pyi = (int)(alpha*patch_size); //Define the size of the neighborhood
156
+ for (int yi = 0; yi<height(); ++yi) {
157
+ #if cimg_debug>=1
158
+ std::fprintf(stderr,"\rProcessing : %3d %%",(int)((float)yi/(float)height()*100.));fflush(stdout);
159
+ #endif
160
+ for (int xi = 0; xi<width(); ++xi) {
161
+ cimg_forC(*this,v) uhat[v] = 0;
162
+ float sw = 0, wmax = -1;
163
+ for (int yj = std::max(0,yi - pyi); yj<std::min(height(),yi + pyi + 1); ++yj)
164
+ for (int xj = std::max(0,xi - pxi); xj<std::min(width(),xi + pxi + 1); ++xj)
165
+ if (cimg::abs(P(xi,yi) - P(xj,yj))/sig<3.) {
166
+ double d = 0;
167
+ int n = 0;
168
+ if (!(xi==xj && yi==yj)) //{
169
+ for (int ky = -patch_size; ky<patch_size + 1; ky+=sampling) {
170
+ int
171
+ yj_ = yj + ky,
172
+ yi_ = yi + ky;
173
+ if (yj_>=0 && yj_<height() && yi_>=0 && yi_<height())
174
+ for (int kx = -patch_size; kx<patch_size + 1; kx+=sampling) {
175
+ int
176
+ xj_ = xj + kx,
177
+ xi_ = xi + kx;
178
+ if (xj_>=0 && xj_<width() && xi_>=0 && xi_<width())
179
+ cimg_forC(*this,v) {
180
+ double d1 = (*this)(xj_,yj_,v) - (*this)(xi_,yi_,v);
181
+ d+=d1*d1;
182
+ n++;
183
+ }
184
+ }
185
+ //}
186
+ float w = (float)std::exp(d*h2);
187
+ cimg_forC(*this,v) uhat[v]+=w*(*this)(xj,yj,v);
188
+ wmax = w>wmax?w:wmax; // Store the maximum of the weights
189
+ sw+=w; // Compute the sum of the weights
190
+ }
191
+ }
192
+ // add the central pixel with the maximum weight
193
+ cimg_forC(*this,v) uhat[v]+=wmax*(*this)(xi,yi,v);
194
+ sw+=wmax;
195
+
196
+ // Compute the estimate for the current pixel
197
+ if (sw) cimg_forC(*this,v) dest(xi,yi,v) = (T)(uhat[v]/=sw);
198
+ else cimg_forC(*this,v) dest(xi,yi,v) = (*this)(xi,yi,v);
199
+ }
200
+ } // main loop
201
+ } // 2d
202
+ delete [] uhat;
203
+ dest.move_to(*this);
204
+ #if cimg_debug>=1
205
+ std::fprintf(stderr,"\n"); // make a new line
206
+ #endif
207
+ } // is empty
208
+ return *this;
209
+ }
210
+
211
+ //! Get the result of the NL-Means denoising algorithm.
212
+ /**
213
+ \param patch_size = radius of the patch (1=3x3 by default)
214
+ \param lambda = bandwidth ( -1 by default : automatic selection)
215
+ \param alpha = size of the region where similar patch are searched (3 x patch_size = 9x9 by default)
216
+ \param sigma = noise standard deviation (-1 = estimation)
217
+ \param sampling = sampling of the patch (1 = uses all point, 2 = uses one point on 4, etc)
218
+ If the image has three dimensions then the patch is only in 2D and the neighborhood extent in time is only 5.
219
+ If the image has several channel (color images), the distance between the two patch is computed using
220
+ all the channels.
221
+ The greater the patch is the best is the result.
222
+ Lambda parameter is function of the size of the patch size. The automatic Lambda parameter is taken
223
+ in the Chi2 table at a significiance level of 0.01. This diffear from the original paper [1].
224
+ The weighted average becomes then:
225
+ \f$$ \hat{f}(x,y) = \sum_{x',y'} \frac{1}{Z} exp(\frac{P(x,y)-P(x',y')}{2 \lambda \sigma^2}) f(x',y') $$\f
226
+ where \f$ P(x,y) $\f denotes the patch in (x,y) location.
227
+
228
+ An a priori is also used to increase the speed of the algorithm in the spirit of Sapiro et al. SPletter dec 05
229
+
230
+ This very basic version of the Non-Local Means algorithm provides an output image which contains
231
+ some residual noise with a relatively small variance (\f$\sigma<5$\f).
232
+
233
+ [1] A non-local algorithm for image denoising
234
+ Buades, A.; Coll, B.; Morel, J.-M.;
235
+ Computer Vision and Pattern Recognition, 2005. CVPR 2005. IEEE Computer Society Conference on
236
+ Volume 2, 20-25 June 2005 Page(s):60 - 65 vol. 2
237
+ **/
238
+ CImg<T> get_nlmeans( int patch_size=1, double lambda=-1, double alpha=3 ,double sigma=-1, int sampling=1) const {
239
+ return CImg<T>(*this).nlmeans(patch_size,lambda,alpha,sigma,sampling);
240
+ }
241
+
242
+ #endif /* cimg_plugin_nlmeans */