Hi,
I implemented new gaussian filter for Noisereduction, so that Noisereduction is equal to current gimp-plugin dcamnoise2-0.64. I am aware that this is a quick'n dirty implementation. However I wish, that the filter makes the best image quality possible when it is released to the public. I intend a complete rewrite that implements 2-dimensional filtering, but this will not be ready for next beta release - too much work. While I developed the gimp-plugin-algorithm I did about 10 times fundamental changes to the algorithm, and this is, why current code is very confused, I hope to deliver better quality and portability when I rewrite it. ============================================================= Changes to noisereduction.cpp & noisereduction.h: Implemented fir filter, removed iir filter. Partially removed sharpening filter, because new noise-filter has better sharpness. Tried to speed up mypow(). Changes to imageeffect_noisereduction.cpp: Set default for threshold to 0.13 to take different (improved) filter behaviour in account. Set precision for Luminance and Color rubbers to "2" so that finer adjustment is possible. (In the gimp plugin I used logarithmic rubbers, because high ajustment accuracy often is needed for very low values) ============================================================== Remaining bugs: Sometimes mousepointer stays connected with a rubber. The only way to cure this, is to restart the plugin. Progress-bar is almost unvisible, because it is only 3-4 mm long. I cannot find errors in my code, that could be the reason. Possibly one reason is, that the filter is slow compared to other filters and the mouse and rubber can move while the filter is busy and another reason could be, that I use a preemptive linux-kernel. Possibly these bugs have to do with my Qt-version, I use: Qt: 3.3.5 KDE: 3.5.2-0.1.fc5 Red Hat Greetings, Peter Index: noisereduction.cpp =================================================================== --- noisereduction.cpp (Revision 535178) +++ noisereduction.cpp (Arbeitskopie) @@ -25,14 +25,7 @@ * * ============================================================ */ -#define IIR1(dest,src) (dest) = (d3 = ((((src) * b + d3) * b3 + d2) * b2 + d1) * b1) -#define IIR2(dest,src) (dest) = (d2 = ((((src) * b + d2) * b3 + d1) * b2 + d3) * b1) -#define IIR3(dest,src) (dest) = (d1 = ((((src) * b + d1) * b3 + d3) * b2 + d2) * b1) -#define IIR1A(dest,src) (dest) = fabs(d3 = ((((src) * b + d3) * b3 + d2) * b2 + d1) * b1) -#define IIR2A(dest,src) (dest) = fabs(d2 = ((((src) * b + d2) * b3 + d1) * b2 + d3) * b1) -#define IIR3A(dest,src) (dest) = fabs(d1 = ((((src) * b + d1) * b3 + d3) * b2 + d2) * b1) - #define FR 0.212671 #define FG 0.715160 #define FB 0.072169 @@ -48,31 +41,25 @@ namespace DigikamNoiseReductionImagesPlugin { + + NoiseReduction::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) : Digikam::DImgThreadedFilter(orgImage, parent, "NoiseReduction") { - m_radius = radius; /* default radius default = 1.0 */ + m_radius = radius; /* default radius default = 5.0 */ m_sharp = sharp; /* Sharpness factor default = 0.25 */ m_lsmooth = lsmooth; /* Luminance Tolerance default = 1.0 */ - m_effect = effect; /* Adaptive filter-effect threshold default = 0.08 */ + m_effect = effect; /* Adaptive filter-effect threshold default = 1.13 */ m_texture = texture; /* Texture Detail default = 0.0 */ m_csmooth = csmooth; /* RGB Tolerance default = 1.0 */ m_lookahead = lookahead; /* Lookahead default = 2.0 */ - m_gamma = gamma; /* Filter gamma default = 1.0 */ + m_gamma = gamma; /* Filter gamma default = 1.4 */ m_damping = damping; /* Phase jitter Damping default = 5.0 */ m_phase = phase; /* Area Noise Clip default = 1.0 */ - m_iir.B = 0.0; - m_iir.b1 = 0.0; - m_iir.b2 = 0.0; - m_iir.b3 = 0.0; - m_iir.b0 = 0.0; - m_iir.r = 0.0; - m_iir.q = 0.0; - m_iir.p = 0; m_clampMax = m_orgImage.sixteenBit() ? 65535 : 255; @@ -114,16 +101,16 @@ float *buffer = new float[ QMAX (width, height) + 2*w ]; float *rbuf = new float[ QMAX (width, height) + 2*w ]; float *tbuf = new float[ QMAX (width, height) + 2*w ]; + m_scratch = new float[ QMAX (width, height) + 2*w ]; memset (src, 0, QMAX (width, height) * bytes); memset (dest, 0, QMAX (width, height) * bytes); for (i=0 ; i < QMAX(width,height)+2*w-1 ; i++) - data[i] = data2[i] = buffer[i] = rbuf[i] = tbuf[i] = 0.0; + data[i] = data2[i] = buffer[i] = rbuf[i] = tbuf[i] = m_scratch[i] = 0.0; // Initialize the damping filter coefficients - iir_init(m_radius); // blur the rows @@ -184,7 +171,7 @@ float t2 = m_lsmooth; // Values are squared, so that sliders get a nonlinear chracteristic - // for better adjustment accuracy when values are small. + // for better adjustment accuracy when values are small. t*=t; t2*=t2; @@ -240,7 +227,7 @@ // So bright tones will be corrected more (get more luminance noise and -information) than // darker values because bright parts of image generally are less noisy, this is what we want. - dl *= pow(lum2/0.5, m_gamma-1.0); + dl *= mypow(lum2/0.5, m_gamma-1.0); if (t2 > 0.0) dl *= (1.0 - exp(-dl*dl/(2.0*t2*t2))); @@ -264,7 +251,7 @@ // So midtones will stay unchanged, darker values get more blur and brighter values get less blur // when we increase gamma. - diff *= pow(mvalue/0.5, m_gamma-1.0); + diff *= mypow(mvalue/0.5, m_gamma-1.0); // Calculate noise probability for pixel // TODO : probably it's not probability but an arbitrary curve. @@ -323,6 +310,8 @@ delete [] tbuf; delete [] dest; delete [] src; + delete [] m_scratch; + } // This function is written as if it is blurring a column at a time, @@ -389,30 +378,10 @@ } } } +#if 0 -void NoiseReduction::iir_init(double r) -{ - if (m_iir.r == r) - return; - - // damping settings; - m_iir.r = r; +//unused. Maybe it is needed later or for algorithm-testing purposes. - double q; - - if ( r >= 2.5) - q = 0.98711 * r - 0.96330; - else - q = 3.97156 - 4.14554 * sqrt(1.0 - 0.26891 * r); - - m_iir.q = q; - m_iir.b0 = 1.57825 + ((0.422205 * q + 1.4281) * q + 2.44413) * q; - m_iir.b1 = ((1.26661 * q +2.85619) * q + 2.44413) * q / m_iir.b0; - m_iir.b2 = - ((1.26661*q +1.4281) * q * q ) / m_iir.b0; - m_iir.b3 = 0.422205 * q * q * q / m_iir.b0; - m_iir.B = 1.0 - (m_iir.b1 + m_iir.b2 + m_iir.b3); -} - void NoiseReduction::box_filter(double *src, double *end, double *dest, double radius) { int boxwidth = 1; @@ -434,167 +403,124 @@ box = box - (src[-bh]) + (src[bh1]); } } +#endif -// Bidirectional IIR-filter, speed optimized -void NoiseReduction::iir_filter(float* const start, float* const end, float* dstart, - double radius, const int type) + + + +void NoiseReduction::fir_filter(float* const start, float* const end, float* dstart, + float radius, const int type) + // 4-pass-forward-backward boxfilter + // This is a pretty good approximation for a gaussian filter + // Opposed to an iir - filter it has the advantages that impulse response is + // finite and can be calculated and it has 100% numeric stability + { - if (!dstart) - dstart = start; - - int width; - float *src = start; - float *dest = dstart; - float *dend = dstart + (end - start); + if (!dstart) dstart = start; + float *src = start; + float *dest = dstart; + float *dend = dstart + (end - start); + float gain; - radius = floor((radius + 0.1) / 0.5) * 0.5; + if (type == Highpass) + memcpy(m_scratch,start,sizeof(*start)*(end-start)); - // NOTE: commented from original implementation - // gfloat boxwidth = radius * 2.0; - // gint bw = (gint) boxwidth; - - int ofs = (int)radius; - if (ofs < 1) ofs = 1; - - double d1, d2, d3; - - width = end - start + 1; + { + const float boxwidth = radius *2.0; + const int intboxwidth = (int) boxwidth; + const float fracboxwidth = boxwidth-(float) intboxwidth; + const int tail=intboxwidth+1; + float box = *src; + //forward pass 1 + for (int i = 0; i < intboxwidth;i++) + box += *(++src); - if (radius < 0.25) - { - if ( start != dest ) - { - memcpy(dest, start, width*sizeof(*dest)); - return; - } + dest += intboxwidth; + while (++src <=end ) + { + box = box - src[-tail]+src[0]; + (++dest)[-tail] = box +src[-tail]*fracboxwidth; } - - iir_init(radius); + for (dest -= tail,src -= tail; src <= end; src++,dest++) + *dest = *src * boxwidth; - const double b1 = m_iir.b1; - const double b2 = m_iir.b2 / m_iir.b1; - const double b3 = m_iir.b3 / m_iir.b2; - const double b = m_iir.B / m_iir.b3; - - switch(type) + // backward pass 1 + box = *(--dest); + for (int i = 0; i < intboxwidth;i++) + box += *(--dest); + + while (--dest >= dstart ) { - case Gaussian: - - d1 = d2 = d3 = *dest; - dend -= 6; - src--; - dest--; + box = box - dest[tail]+dest[0]; + dest[tail] = box + dest[tail]*fracboxwidth; + } + for (dest += tail; dest >= dstart;dest--) + *dest *= boxwidth; - while (dest < dend) - { - IIR1(*(++dest), *(++src)); - IIR2(*(++dest), *(++src)); - IIR3(*(++dest), *(++src)); - IIR1(*(++dest), *(++src)); - IIR2(*(++dest), *(++src)); - IIR3(*(++dest), *(++src)); - } + gain= sq(1.0+boxwidth); + } - dend += 6; + { + const float boxwidth = radius*1.5; + const int intboxwidth = (int) boxwidth; + const float fracboxwidth = boxwidth-(float) intboxwidth; + const int tail=intboxwidth+1; + float box = 0.0; + gain *= sq(1.0+boxwidth); + const float gaincompensation = 1.0/gain; - while (1) - { - if (++dest > dend) break; - IIR1(*dest,*(++src)); - if (++dest > dend) break; - IIR2(*dest,*(++src)); - if (++dest > dend) break; - IIR3(*dest,*(++src)); - } - - d1 = d2 = d3 = dest[-1]; - dstart += 6; - - while (dest > dstart) - { - --dest, IIR1(*dest, *dest); - --dest, IIR2(*dest, *dest); - --dest, IIR3(*dest, *dest); - --dest, IIR1(*dest, *dest); - --dest, IIR2(*dest, *dest); - --dest, IIR3(*dest, *dest); - } - - dstart -= 6; - - while (1) - { - if (--dest < dstart) break; - IIR1(*dest, *dest); - if (--dest < dstart) break; - IIR2(*dest, *dest); - if (--dest < dstart) break; - IIR3(*dest, *dest); - } - - break; - - case SecondDerivative: // rectified and filtered second derivative, source and dest may be equal - - d1 = d2 = d3 = 0.0; - dest[0] = dest[ofs] = 0.0; - dend -= 6; - dest--; - src--; - - while (dest < dend) - { - ++src, IIR1(*(++dest), src[ofs]-src[0]); - ++src, IIR2(*(++dest), src[ofs]-src[0]); - ++src, IIR3(*(++dest), src[ofs]-src[0]); - ++src, IIR1(*(++dest), src[ofs]-src[0]); - ++src, IIR2(*(++dest), src[ofs]-src[0]); - ++src, IIR3(*(++dest), src[ofs]-src[0]); - } - - dend += 6; + // forward pass 2 + box = *(++dest); + for (int i = 0; i < intboxwidth;i++) + box += *(++dest); - while (1) - { - if (++dest > dend) break; - ++src, IIR1(*dest, src[ofs]-src[0]); - if (++dest > dend) break; - ++src, IIR2(*dest, src[ofs]-src[0]); - if (++dest > dend) break; - ++src, IIR3(*dest, src[ofs]-src[0]); - } - - d1 = d2 = d3 = 0.0; - dest[-1] = dest[-ofs-1] = 0.0; - dstart += 6; - - while (dest > dstart) - { - --dest, IIR1A(*dest, dest[0]-dest[-ofs]); - --dest, IIR2A(*dest, dest[0]-dest[-ofs]); - --dest, IIR3A(*dest, dest[0]-dest[-ofs]); - --dest, IIR1A(*dest, dest[0]-dest[-ofs]); - --dest, IIR2A(*dest, dest[0]-dest[-ofs]); - --dest, IIR3A(*dest, dest[0]-dest[-ofs]); - } + while (++dest <= dend ) + { + box = box - dest[-tail]+dest[0]; + dest[-tail] = box + dest[-tail]*fracboxwidth; + } + for (dest -= tail; dest <= dend;dest++) + *dest *= boxwidth; - dstart -= 6; + //backward pass 2 + box = *(--dest); + for (int i = 0; i < intboxwidth;i++) + box += *(--dest); - while (1) - { - if (--dest < dstart) break; - IIR1A(*dest, dest[0]-dest[-ofs]); - if (--dest < dstart) break; - IIR2A(*dest, dest[0]-dest[-ofs]); - if (--dest < dstart) break; - IIR3A(*dest, dest[0]-dest[-ofs]); - } - + while (--dest >= dstart ) + { + box = box - dest[tail]+dest[0]; + dest[tail] = (box + dest[tail]*fracboxwidth)*gaincompensation; + } + for (dest += tail; dest >= dstart;dest--) + *dest *= boxwidth; + + switch(type) + { + + case Gaussian: break; + // Unsharp-Mask type highpass-filter + case Highpass: + // Here we subtract filter input from filter output + // That is, we subtract low frequency from input signal and in + // effect we get a highpass. + // (Thats the same technique as used in classic unsharp mask filter) + + src = m_scratch; + dest = dstart; + for ( ;dest<=dend;dest++,src++) + { + *dest = fabs(*dest - *src); + } break; + } + + } } + // A forward-backward box filter is used here and the radius is adapted to luminance jump. // Radius is calculated fron 1st and 2nd derivative of intensity values. // (Its not exactly 2nd derivative, but something similar, optimized by experiment) @@ -646,7 +572,7 @@ *p2 = (sharp+1.0) * p1[0] - sharp * 0.5 * (p1[-ofs]+p1[ofs]); } - iir_filter(rbuflp-w, rbufrp+w, blp-w, m_lookahead, SecondDerivative); + fir_filter(rbuflp-w, rbufrp+w, blp-w, m_lookahead, Highpass); // Mirror image edges @@ -656,12 +582,7 @@ for (i = 1 ; i <= w ; i++) brp[i] = brp[-i]; - // boost high frequency in rbuf - - for (p1 = blp, p2 = rbuflp ; p1 <= brp ; p1++, p2++) - { - *p2 = ((sharp+1.0) * (p1[0]) - sharp * 0.5 * ((p1[-ofs2])+(p1[ofs2]))); - } + memcpy(rbuflp,blp,(brp-blp)*sizeof(*blp)); // Mirror rbuf edges @@ -673,7 +594,7 @@ // Lowpass (gauss) filter rbuf, remove phase jitter - iir_filter(rbuflp-w+5, rbufrp+w-5, rbuflp-w+5, m_damping, Gaussian); + fir_filter(rbuflp-w+5, rbufrp+w-5, rbuflp-w+5, m_damping, Gaussian); for (i = -w+5; i < width-1+w-5 ; i++) { @@ -689,7 +610,7 @@ val = rfact/val; // NOTE: commented from original implementation - // val = pow(val/fradius,m_phase)*fradius; + // val = mypow(val/fradius,m_phase)*fradius; if (val < 0.5) val = 0.5; @@ -709,7 +630,7 @@ // Calc lowpass filtered input signal - iir_filter(blp-w+1, brp+w-1, lp2-w+1, m_radius, Gaussian); + fir_filter(blp-w+1, brp+w-1, lp2-w+1, m_radius, Gaussian); // Subtract low frequency from input signal (aka original image data) // and predistort this signal @@ -801,7 +722,7 @@ blp[i] += lp2[i]; // NOTE: commented from original implementation - // if (blp[i] >= 0.0) blp[i] = pow(blp[i],val); + // if (blp[i] >= 0.0) blp[i] = mypow(blp[i],val); // else blp[i] = 0.0; } } Index: noisereduction.h =================================================================== --- noisereduction.h (Revision 535178) +++ noisereduction.h (Arbeitskopie) @@ -37,162 +37,6 @@ #include <digikamheaders.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 supress 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 dont 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 overriden 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 supressed 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 dont 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 { @@ -208,20 +52,13 @@ private: - struct iir_param - { - double B, b1, b2, b3, b0, r, q; - double *p; - } m_iir; - enum IIRFilteringMode { Gaussian=0, - SecondDerivative + Highpass }; int m_clampMax; - double m_radius; double m_lsmooth; double m_csmooth; @@ -232,14 +69,13 @@ double m_phase; double m_texture; double m_sharp; - + float *m_scratch; 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 fir_filter(float* const start, float* const end, float* dstart, float 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); @@ -247,9 +83,14 @@ 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); + if (val > 0.0) return exp2(log2(val)*ex); + return -exp2(log2(-val)*ex); }; + + inline float sq(float val) + { + return val*val; + } }; Index: imageeffect_noisereduction.cpp =================================================================== --- imageeffect_noisereduction.cpp (Revision 535178) +++ imageeffect_noisereduction.cpp (Arbeitskopie) @@ -147,7 +147,7 @@ m_sharpnessInput = new KDoubleNumInput(firstPage); m_sharpnessInput->setPrecision(2); - m_sharpnessInput->setRange(0.0, 1.0, 0.1, true); + m_sharpnessInput->setRange(0.0, 1.0, 0.01, true); QWhatsThis::add( m_sharpnessInput, i18n("<p><b>Sharpness</b>: " "This value improves the frequency response for the filter. " "When it is too strong then not all noise can be removed, or spike noise may appear. " @@ -199,8 +199,8 @@ QLabel *label2 = new QLabel(i18n("Luminance:"), secondPage); m_lumToleranceInput = new KDoubleNumInput(secondPage); - m_lumToleranceInput->setPrecision(1); - m_lumToleranceInput->setRange(0.0, 1.0, 0.1, true); + m_lumToleranceInput->setPrecision(2); + m_lumToleranceInput->setRange(0.0, 1.0, 0.01, true); QWhatsThis::add( m_lumToleranceInput, i18n("<p><b>Luminance</b>: this control set the luminance tolerance " "of image. It's recommended to use only <b>Color</b> or <b>Luminance</b> tolerance " "settings to make an image correction, not the both at the same time. This settings " @@ -214,8 +214,8 @@ QLabel *label6 = new QLabel(i18n("Color:"), secondPage); m_csmoothInput = new KDoubleNumInput(secondPage); - m_csmoothInput->setPrecision(1); - m_csmoothInput->setRange(0.0, 1.0, 0.1, true); + m_csmoothInput->setPrecision(2); + m_csmoothInput->setRange(0.0, 1.0, 0.01, true); QWhatsThis::add( m_csmoothInput, i18n("<p><b>Color</b>: this control set the color tolerance of image. " "It's recommended to use only <b>Color</b> or <b>Luminance</b> tolerance settings to " "make an image correction, not the both at the same time. This settings don't influence " @@ -244,7 +244,7 @@ m_dampingInput = new KDoubleNumInput(secondPage); m_dampingInput->setPrecision(1); - m_dampingInput->setRange(0.5, 20.0, 0.5, true); + m_dampingInput->setRange(0.5, 20.0, 0.1, true); QWhatsThis::add( m_dampingInput, i18n("<p><b>Damping</b>: this control set the phase jitter damping adjustement. " "This value defines how fast the adaptive filter-radius reacts to luminance variations. " "If increased, then edges appear smoother, if too high, then blur may occur. If at " @@ -324,7 +324,7 @@ m_radiusInput->setValue(5.0); m_lumToleranceInput->setValue(1.0); - m_thresholdInput->setValue(0.08); + m_thresholdInput->setValue(0.13); m_textureInput->setValue(0.0); m_sharpnessInput->setValue(0.25); m_csmoothInput->setValue(1.0); _______________________________________________ Digikam-devel mailing list [hidden email] https://mail.kde.org/mailman/listinfo/digikam-devel |
Le Vendredi 28 Avril 2006 23:16, Peter Heckert a écrit :
> Hi, > > I implemented new gaussian filter for Noisereduction, so that > Noisereduction is equal to > current gimp-plugin dcamnoise2-0.64. > > I am aware that this is a quick'n dirty implementation. However I wish, > that the filter > makes the best image quality possible when it is released to the public. > I intend a complete rewrite that implements 2-dimensional filtering, but > this will not be > ready for next beta release - too much work. > While I developed the gimp-plugin-algorithm I did about 10 times > fundamental changes > to the algorithm, and this is, why current code is very confused, I > hope to deliver > better quality and portability when I rewrite it. > > ============================================================= > Changes to noisereduction.cpp & noisereduction.h: > Implemented fir filter, removed iir filter. > Partially removed sharpening filter, because new noise-filter has better > sharpness. > Tried to speed up mypow(). > > Changes to imageeffect_noisereduction.cpp: > > Set default for threshold to 0.13 to take different (improved) filter > behaviour in account. > Set precision for Luminance and Color rubbers to "2" so that finer > adjustment is possible. > (In the gimp plugin I used logarithmic rubbers, because high ajustment > accuracy often > is needed for very low values) > ============================================================== > Remaining bugs: > Sometimes mousepointer stays connected with a rubber. The only way to > cure this, is > to restart the plugin. > Progress-bar is almost unvisible, because it is only 3-4 mm long. > > I cannot find errors in my code, that could be the reason. > Possibly one reason is, that the filter is slow compared to other > filters and the mouse and > rubber can move while the filter is busy and another > reason could be, that I use a preemptive linux-kernel. > > Possibly these bugs have to do with my Qt-version, I use: > Qt: 3.3.5 > KDE: 3.5.2-0.1.fc5 Red Hat > > Greetings, > > Peter Peter, i'm busy this week end (i search a new home). I will trying to check your code sunday or monday Gilles _______________________________________________ Digikam-devel mailing list [hidden email] https://mail.kde.org/mailman/listinfo/digikam-devel |
Hello Gilles,
Gilles Caulier wrote: > Peter, i'm busy this week end (i search a new home). Wish you good luck for this. > I will trying to check your code sunday or monday > The diff-files look rather horrible.... Essentially I did only one thing: replaced iir_filter() with new code and renamed it to fir_filter() Then I deleted a lot of superfluous stuff and renamed some variables to take the modifications in account. Also I allocated a new scratch-buffer. It's carefully checked, there cannot be any memory leaks ;-) It really improves quality and gives somewhat easier adjustment-behaviour. Currently I use kdesvn and this displays the modifications using Kompare, thats really nice. I will not do other improvements for this onedimensional filter version. (Apart from bughunting) A complete rewrite for the filter core will be necessary for the next version. wish you a good weekend, Peter _______________________________________________ Digikam-devel mailing list [hidden email] https://mail.kde.org/mailman/listinfo/digikam-devel |
In reply to this post by Gilles Caulier-2
El Sábado, 29 de Abril de 2006 10:41, Gilles Caulier escribió:
> > Peter, i'm busy this week end (i search a new home). I will trying to check Good luck Gilles, I hope you find the best :-) Paco _______________________________________________ Digikam-devel mailing list [hidden email] https://mail.kde.org/mailman/listinfo/digikam-devel |
Free forum by Nabble | Edit this page |