-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathompsdenoise.m
352 lines (305 loc) · 10.8 KB
/
ompsdenoise.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
function [y,nz] = ompsdenoise(params,msgdelta)
%OMPSDENOISE Sparse OMP denoising.
% Y = OMPSDENOISE(PARAMS) denoises a 2-D or 3-D signal using Sparse OMP
% denoising. OMPSDENOISE first denoises each block of the noisy signal
% individually, then combines the denoised blocks, averaging overlapping
% blocks. A single block is denoised by removing its mean, applying Sparse
% OMP, and restoring its mean.
%
% Y = OMPSDENOISE(PARAMS,MSGDELTA) specifies the frequency of message
% printing during the process. MSGDELTA should be a positive number
% representing the interval in seconds between messages. A zero or
% negative value cancels these messages. Default is MSGDELTA=5.
%
% [Y,NZ] = OMPSDENOISE(...) also returns the average number of non-zero
% coefficients in the representations of the denoised blocks.
%
%
% Required fields in PARAMS:
% --------------------------
%
% 'x' - Noisy signal.
% The 2-D or 3-D signal to denoise. Should be of type double, and (for
% PSNR computations) with values within [0,1] (to specify a different
% range, see parameter 'maxval' below).
%
% 'blocksize' - Size of block.
% Indicates the size of the blocks to operate on. Should be either an
% array of the form [N1 N2 ... Np], where p=2,3 is the number of
% dimensions of x, or simply a scalar N, representing the square block
% [N N ... N]. See parameter 'stepsize' below to specify the amount of
% overlap between the blocks.
%
% 'basedict' - Separable base dictionary.
% Specifies the base dictionary. OMPSDENOISE supports separable base
% dictionaries of either 2 or 3 dimensions, specified as a 2 or 3
% element cell array. The base dictionary for the i-th dimension is
% given in basedict{i}. See 'help sparsedict' for more information.
%
% 'A' - Sparse dictionary representation matrix.
% The matrix containing the sparse representations of the dictionary
% atoms over the base dictionary. Should be a sparse matrix. See 'help
% sparsedict' for more information.
%
% 'psnr' / 'sigma' - Noise power.
% Specifies the noise power in dB (psnr) or the noise standard
% deviation (sigma), used to determine the target error for
% sparse-coding each block. If both fields are present, sigma is used
% unless the field 'noisemode' is specified (below). When specifying
% the noise power in psnr, make sure to set the 'maxval' parameter
% as well (below) if the signal values are not within [0,1].
%
%
% Optional fields in PARAMS:
% --------------------------
%
% 'stepsize' - Interval between neighboring blocks.
% Specifies the interval (in pixels/voxels) between neighboring blocks
% to denoise. By default, all overlapping blocks are denoised and
% averaged. This can be changed by specifying an alternate stepsize,
% as an array of the form [S1 S2 ... Sp] (where p=2,3 is the number of
% dimensions of x). This sets the distance between neighboring blocks
% to be Si in the i-th dimension. Stepsize can also be a scalar S,
% corresponding to the step size [S S ... S]. Each Si must be >= 1,
% and, to ensure coverage of the entire noisy signal, size(x,i)-Ni
% should be a multiple of Si for all i. The default stepsize is 1.
%
% 'maxval' - Maximal intensity value.
% Specifies the range of the signal values. Used to determine the
% noise standard deviation when the noise power is specified in psnr.
% By default, the signal values are assumed to be within [0,1]. When
% 'maxval' is specified, this range changes to [0,maxval].
%
% 'memusage' - Memory usage.
% This parameter controls memory usage of the function. 'memusage'
% should be one of the strings 'high', 'normal' (default) or 'low'.
% When set to 'low', the matrix G=D'*D is not precomputed before
% calling OMP, which reduces memory consumption when memory resources
% are low. This, however, will dramatically increase runtime and is
% not recommended for normal use. The 'high' and 'normal' modes are
% equivalent settings in this function.
%
%
% Optional fields in PARAMS - advanced:
% -------------------------------------
%
% 'noisemode' - Noise power mode.
% Specifies whether the 'psnr' or 'sigma' fields should be used to
% determine the noise power. This is useful when both fields are
% present in PARAMS. 'noisemode' should be one of the string 'psnr' or
% 'sigma'. If it is not present, and both fields are specified,
% 'sigma' is used.
%
% 'gain' - Noise gain.
% A positive value (usually near 1) controlling the target error for
% sparse-coding each block. When gain=1, the target error is precisely
% the value derived from the psnr/sigma fields. When gain is different
% from 1, the target error is multiplied by this value. The default
% value is gain = 1.15.
%
% 'lambda' - Weight of the input signal.
% For each output sample, covered by K overlapping blocks, its final
% value is obtained as a weighted average of the K denoised values and
% the original noisy value. In the averaging, each denoised value is
% attributed a weight of 1, and the noisy value is attributed a weight
% of lambda. In this way, samples with less confidence (covered by
% less blocks) are regularized by giving larger weight to the original
% sample. Default value for lambda is 0.1*(maxval/sigma), where sigma
% is the standard deviation of the noise. Specifying lambda=0 means
% that the noisy signal is not averaged into the result.
%
% 'maxatoms' - Maximal number of atoms.
% This parameter can be used to specify a hard limit on the number of
% atoms used to sparse-code each block (see parameter 'maxatoms' in
% OMPS2 for more details). Default value is prod(blocksize)/2, i.e.
% half the number of samples in a block.
%
%
% Summary of all fields in PARAMS:
% --------------------------------
%
% Required:
% 'x' signal to denoise
% 'blocksize' size of block to process
% 'basedict' separable base dictionary
% 'A' sparse dictionary representation matrix
% 'psnr' / 'sigma' noise power in dB / standard deviation
%
% Optional (default values in parentheses):
% 'stepsize' distance between neighboring blocks (1)
% 'maxval' maximal intensity value (1)
% 'memusage' 'low, 'normal' or 'high' ('normal')
% 'noisemode' 'psnr' or 'sigma' ('sigma')
% 'gain' noise gain (1.15)
% 'lambda' weight of input signal (0.1*maxval/sigma)
% 'maxatoms' max # of atoms per block (prod(blocksize)/2)
%
%
% References:
% [1] M. Elad and M. Aharon, "Image Denoising via Sparse and Redundant
% representations over Learned Dictionaries", the IEEE Trans. on Image
% Processing, Vol. 15, no. 12, pp. 3736-3745, December 2006.
% [2] R. Rubinstein, M. Zibulevsky, and M. Elad, "Learning Sparse
% Dictionaries for Sparse Signal Approximation", Technical Report -
% CS, Technion, June 2009.
%
% See also OMPSDENOISE2, OMPSDENOISE3, KSVDSDENOISE, OMPS, OMPS2,
% SPARSEDICT.
% Ron Rubinstein
% Computer Science Department
% Technion, Haifa 32000 Israel
% ronrubin@cs
%
% August 2009
% parse input arguments %
x = params.x;
blocksize = params.blocksize;
basedict = params.basedict;
A = params.A;
p = ndims(x);
if (p<2 || p>3)
error('OMPSDENOISE only supports 2-D and 3-D signals.');
end
% blocksize %
if (numel(blocksize)==1)
blocksize = ones(1,p)*blocksize;
end
% maxval %
if (isfield(params,'maxval'))
maxval = params.maxval;
else
maxval = 1;
end
% gain %
if (isfield(params,'gain'))
gain = params.gain;
else
gain = 1.15;
end
% maxatoms %
if (isfield(params,'maxatoms'))
maxatoms = params.maxatoms;
else
maxatoms = floor(prod(blocksize)/2);
end
% stepsize %
if (isfield(params,'stepsize'))
stepsize = params.stepsize;
if (numel(stepsize)==1)
stepsize = ones(1,p)*stepsize;
end
else
stepsize = ones(1,p);
end
if (any(stepsize<1))
error('Invalid step size.');
end
% noise mode %
if (isfield(params,'noisemode'))
switch lower(params.noisemode)
case 'psnr'
sigma = maxval / 10^(params.psnr/20);
case 'sigma'
sigma = params.sigma;
otherwise
error('Invalid noise mode specified');
end
elseif (isfield(params,'sigma'))
sigma = params.sigma;
elseif (isfield(params,'psnr'))
sigma = maxval / 10^(params.psnr/20);
else
error('Noise strength not specified');
end
% lambda %
if (isfield(params,'lambda'))
lambda = params.lambda;
else
lambda = maxval/(10*sigma);
end
% msgdelta %
if (nargin <2)
msgdelta = 5;
end
if (msgdelta<=0)
msgdelta = -1;
end
epsilon = sqrt(prod(blocksize)) * sigma * gain; % target error for omp
MEM_LOW = 1;
MEM_NORMAL = 2;
MEM_HIGH = 3;
if (isfield(params,'memusage'))
switch lower(params.memusage)
case 'low'
memusage = MEM_LOW;
case 'normal'
memusage = MEM_NORMAL;
case 'high'
memusage = MEM_HIGH;
otherwise
error('Invalid memory usage mode');
end
else
memusage = MEM_NORMAL;
end
% compute G %
G = [];
if (memusage >= MEM_NORMAL)
G = dicttsep(basedict,A,dictsep(basedict,A,speye(size(A,2))));
end
% verify dictionary normalization %
if (isempty(G))
atomnorms = zeros(1,size(A,2));
gamma = speye(size(A,2));
for i = 1:size(A,2)
atomnorms(i) = sum(dictsep(basedict,A,gamma(:,i)).^2);
end
else
atomnorms = diag(G);
end
if (any(abs(atomnorms-1) > 1e-2))
error('Dictionary atoms are not normalized to unit length');
end
% denoise the signal %
y = zeros(size(x));
% ids{} contains the indices of the current block
ids = cell(p,1);
for j = 1:p
ids{j} = 1:blocksize(j);
end
% lastids contains the indices of the last block in each dimension
lastids = stepsize .* floor((size(x)-blocksize)./stepsize) + 1;
blocknum = prod(floor((size(x)-blocksize)./stepsize) + 1);
tid = timerinit('ompsdenoise', blocknum); lastmsgcheck = 0;
nz = 0; % count non-zeros in block representations
for i = 1 : blocknum
block = x(ids{:});
block = block(:);
dc = mean(block);
block = block-dc;
gamma = omps2(basedict,A,block,G,epsilon,'maxatoms',maxatoms,'checkdict','off');
nz = nz + nnz(gamma);
y(ids{:}) = y(ids{:}) + reshape(dictsep(basedict,A,gamma),blocksize) + dc;
% increment block ids
if (i<blocknum)
j = 1;
while (ids{j}(1) == lastids(j))
ids{j} = 1:blocksize(j);
j = j+1;
end
ids{j} = ids{j}+stepsize(j);
end
% display status
if (msgdelta>0 && i-lastmsgcheck>=30)
lastmsgcheck=i;
timereta(tid, i, msgdelta);
end
end
if (msgdelta>0)
timereta(tid, i);
end
nz = nz/blocknum; % average number of non-zeros
% average the denoised and noisy signals
cnt = countcover(size(x),blocksize,stepsize);
y = (y+lambda*x)./(cnt + lambda);
y = reshape(y,size(params.x));