summaryrefslogtreecommitdiffstats
path: root/digikam/imageplugins/noisereduction/noisereduction.h
blob: 0d9aafda6cfd6b6ab302e8aa95da14af354a3ec7 (plain)
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
/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2005-05-25
 * Description : Noise Reduction threaded image filter.
 * 
 * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
 * 
 * Original Noise Filter algorithm copyright (C) 2005 
 * Peter Heckert <peter dot heckert at arcor dot de>
 * from dcamnoise2 gimp plugin available at this url :
 * http://home.arcor.de/peter.heckert/dcamnoise2-0.63.c
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General
 * Public License as published by the Free Software Foundation;
 * either version 2, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * ============================================================ */
  
#ifndef NOISE_REDUCTION_H
#define NOISE_REDUCTION_H

// C++ includes.

#include <cmath>

// Digikam includes.

#include "dimgthreadedfilter.h"

/**============= NOTICE TO USE THE FILTER ===============================================================
 *
 * Let me explain, how the filter works, some understanding is necessary to use it:
 *
 * Hint for the novice user:
 * In most cases only Filter Max Radius, Filter treshold and Texture Detail are needed and the other
 * params can be left at their default setting.
 *
 * Main Filter (Preprocessing) 
 * First, a filtered template is generated, using an adaptive filter.
 * To see this template, we must set _Luminance tolerance,  _Color tolerance to 1.0.
 *------------------------------------------------------------------------------------------------------------
 *
 * "Filter max. Radius" is preset to 5.0 
 * This is good for most noise situations. 
 * In any case it must be about the same size as noise granularity ore somewhat more.
 * If it is set higher than necessary, then it can cause unwanted blur.
 *------------------------------------------------------------------------------------------------------------
 *
 * "Filter Threshold" should be set so that edges are clearly visible and noise is  smoothed out. 
 * This threshold value is not bound to any intensity value, it is bound to the second derivative of
 * intensity values.
 * Simply adjust it and watch the preview. Adjustment must be made carefully, because the gap
 * between "noisy", "smooth", and "blur" is very small. Adjust it as carefully as you would adjust
 * the focus of a camera.
 *------------------------------------------------------------------------------------------------------------
 *
 * "Lookahead" defines the pixel distance in which the filter looks ahead for luminance variations
 * Normally the default value should do.
 * When _Lookahead is increased, then spikenoise is erased. 
 * Eventually readjust Filter treshold, when you changed lookahead.
 * When the value is to high, then the adaptive filter cannot longer accurately track image details, and
 * noise can reappear or blur can occur.
 *
 * Minimum value is 1.0, this gives best accuracy when blurring very weak noise.
 *
 * I never had good success with other values than 2.0.
 * However, for images with extemely high or low resolution another value possibly is better.
 * Use it only as a last ressort.
 *------------------------------------------------------------------------------------------------------------
 *
 * "Phase Jitter Damping" defines how fast the adaptive filter-radius reacts to luminance variations.
 * I have preset a value, that should do in most cases.
 * If increased, then edges appear smoother, if too high, then blur may occur.
 * If at minimum then noise and phase jitter at edges can occur.
 * It can suppress Spike noise when increased and this is the preferred method to remove spike noise.
 *------------------------------------------------------------------------------------------------------------
 *
 * "Sharpness" does just what it says, it improves sharpness. It improves the frequency response for the filter.
 * When it is too strong then not all noise can be removed, or spike noise may appear.
 * Set it near to maximum, if you want to remove weak noise or JPEG-artifacts, without loosing detail.
 *------------------------------------------------------------------------------------------------------------
 *
 * "Erosion". The new filter gives better sharpness and this also gives problems
 * with spike noise. The Erosion param erodes singular spikes and it has a smooth effect to edges, and sharpens
 * edges by erosion, so noise at edges is eroded.  
 * The effect is dependant from sharpness,phase-jitter damping and lookahead.
 * Set it to minimum (zero), if you want to remove weak noise or JPEG-artifacts.
 * When "Erosion" is increased, then also increasing "Phase Jitter Damping" is often useful 
 *
 * It works nicely. Apart from removing spike noise it has a sharpening and antialiasing effect to edges 
 * (Sharpening occurs by erosion, not by deconvolution) 
 *------------------------------------------------------------------------------------------------------------
 * 
 * "Texture Detail" can be used, to get more or less texture accuracy.
 * When decreased, then noise and texture are blurred out, when increased then texture is
 * amplified, but also noise will increase.
 * It has almost no effect to image edges, opposed to Filter theshold, which would blur edges, when increased.  
 *
 * E.g. if Threshold is adjusted in away so that edges are sharp, and there is still too much area noise, then
 * Texture detail could be used to reduce noise without blurring edges.
 * (Another way would be to decrease radius and to increase threshold)
 *
 *------------------------------------------------------------------------------------------------------------
 *
 * The filtered image that is now seen in the preview, is used as template for the following processing steps,
 * therefore it is  important to do this adjustment in first place and to do it as good as possible.
 *------------------------------------------------------------------------------------------------------------
 * 
 * Combining original image and filtered image, using tolerance thresholds (Postprocessing)
 * This can give a final touch of sharpness to your image. 
 * It is not necessary to do this, if you want to reduce JPEG-artifacts or weak noise.
 * It's purpose is to master strong noise without loosing too much sharpness.
 *
 * Note, that this all is done in one filter invocation. Preprocessing and postprocessing is done in one run,
 * but logically and in the algorithm they are different and ordered processes.
 *
 *
 * Adjust _Color tolerance or/and Luminance tolerance, (if necessary) so that you get the final image.
 * I recommend to use only one, either _Color  or _Luminance. 
 * These settings do not influence the main smoothing process. What they really do is this:
 *
 * The tolerance values are used as error-thresholds to compare the filtered template with the original
 * image. The plugin algorithm uses them to combine the filtered template with the original image
 * so that  noise and filter errors (blur) are thrown out.
 * A filtered pixel, that is too far away from the original pixel will be overridden by original image content. 
 *
 * Hint:
 * If you cange other sliders, like lookahead or Texture Detail, then you should set color tolerance and 
 * luminance tolerance to 1.0 (right end), because otherwise the filtered template is partially hidden 
 * and e.g. the effects for the damping filter cant be seen clearly and cant be optimized. 
 *------------------------------------------------------------------------------------------------------------
 *
 * _Gamma can be used to increase the tolerance values for darker areas (which commonly are more noisy)
 * This results in more blur for shadow areas.
 *
 * Hint for users of previous versions:
 * Gamma also influences the main-filter process. While the previous version did not have this feature,
 * I have reimplemented it, however, the algorithm used is totally new.
 * 
 *
 * Keep in mind, how the filter works, then usage should be easy!  
 *
 *
 * ================ THEORY AND TECHNIC =======================================================================
 *
 * Some interesting things (theoretic and technic)
 * This plugin bases on the assumption, that noise has no 2-dimensional correlation and therefore
 * can be removed in a 1-dimensional process.
 * To remove noise, I use a four-times  boxfilter with variable radius.
 *
 * The radius is calculated from 2nd derivative of pixeldata.
 * A gauss filter is used to calculte 2nd derivative.
 * The filter has some inbuilt features to clip low amplitude noise to clip very high values that would
 * slow down response time.
 * The 2nd derivative is lowpassfiltered and then radius is calculated as (Filter Treshold)/2nd_derivative. 
 * The radius modulation data is precalulated and buffered an is used to steer filter radius when
 * the actual filtering occurs.
 *
 * Noise and texture can be further suppressed by nonlinear distortion before adaptive filtering.
 * To make this possible I subtract low frequency from image data before denoising, so that I get a 
 * bipolar, zerosymmetric image signal.
 *
 * The filter works in a /one-dimensional/ way. It is applied to x and then to y axis.
 *
 * After filtering a zerodimensional point operator  (pixel by pixel comparison)  is used, where 
 * filter-errors are thrown out.
 * This is meant to limit and control filter errors,it can give "final touch" to the image, but it has 
 * nothing to do with the main filter process. 
 *
 * I do not know if something like this filter already exists.
 * It is all based on my own ideas and experiments.
 * Possibly a separable adaptive gauss-filter is a new thing.
 * Also it is an impossible thing, from a mathemathical point of view ;-)
 * It is possible only for bandwidth limited images.
 * Happyly most photographic images are bandwidth limited, or when they are noisy then we want
 * to limit banwith locally. And this is, what the filter does: It limits bandwidth locally, dependent
 * from (approximately) 2nd derivative of intensity.
 * 
 * Because gauss filtering is essentially linear diffusion, and because this filter uses a variable
 * nonlinear modulated gaussfilter (four box passes are almost gauss) we could say, that this filter
 * implements a special subclass of nonlinear adaptive diffusion, which is separable, and indeed, 
 * results are very similar to nonlinear diffusion filters.
 * However, because the filter is separable, it is much faster and needs less memory.
 */

namespace DigikamNoiseReductionImagesPlugin
{

class NoiseReduction : public Digikam::DImgThreadedFilter
{

public:
    
    NoiseReduction(Digikam::DImg *orgImage, QObject *parent, 
                   double radius, double lsmooth, double effect, double texture, double sharp,
                   double csmooth, double lookahead, double gamma, double damping, double phase);
    ~NoiseReduction(){};
    
private:  

    void filterImage(void);

    void iir_init(double r);
    void box_filter(double *src, double *end, double *dest, double radius);
    void iir_filter(float* const start, float* const end, float* dstart, double radius, const int type);
    void filter(float *buffer, float *data, float *data2, float *rbuf, float *tbuf, int width, int color);
    void blur_line(float* const data, float* const data2, float* const buffer,
                   float* rbuf, float* tbuf, const uchar *src, uchar *dest, int len);

    inline double mypow(double val, double ex)
    {
        if (fabs(val) < 1e-16) return 0.0;
        if (val > 0.0) return exp(log(val)*ex);
        return -exp(log(-val)*ex);
    };
 
private:

    struct iir_param
    {
        double  B, b1, b2, b3, b0, r, q;
        double *p;
    } m_iir;

    enum IIRFilteringMode
    {
        Gaussian=0,
        SecondDerivative
    };
    
    int    m_clampMax;
    
    double m_radius;
    double m_lsmooth;
    double m_csmooth;
    double m_effect;
    double m_lookahead;
    double m_gamma;
    double m_damping;
    double m_phase;
    double m_texture;
    double m_sharp;
};

}  // NameSpace DigikamNoiseReductionImagesPlugin

#endif /* NOISE_REDUCTION_H */