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.
- package/CImg.h +70659 -0
- package/Licence_CeCILL-C_V1-en.txt +508 -0
- package/Licence_CeCILL_V2-en.txt +504 -0
- package/README.md +44 -0
- package/README.txt +180 -0
- package/package.json +15 -0
- package/plugins/add_fileformat.h +79 -0
- package/plugins/bayer.h +212 -0
- package/plugins/chlpca.h +323 -0
- package/plugins/cvMat.h +350 -0
- package/plugins/draw_gradient.h +269 -0
- package/plugins/inpaint.h +508 -0
- package/plugins/ipl.h +309 -0
- package/plugins/ipl_alt.h +122 -0
- package/plugins/jpeg_buffer.h +377 -0
- package/plugins/loop_macros.h +24166 -0
- package/plugins/matlab.h +287 -0
- package/plugins/nlmeans.h +242 -0
- package/plugins/skeleton.h +587 -0
- package/plugins/tiff_stream.h +196 -0
- package/plugins/tinymatwriter.h +109 -0
- package/plugins/vrml.h +894 -0
- package/plugins/vtk.h +103 -0
package/plugins/matlab.h
ADDED
|
@@ -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 */
|