SOURCES: dcamnoise2-0.63.c (NEW) - plugin for removing noise intro...

freetz freetz at pld-linux.org
Mon Nov 21 22:51:07 CET 2005


Author: freetz                       Date: Mon Nov 21 21:51:07 2005 GMT
Module: SOURCES                       Tag: HEAD
---- Log message:
- plugin for removing noise introduced by digital cameras

---- Files affected:
SOURCES:
   dcamnoise2-0.63.c (NONE -> 1.1)  (NEW)

---- Diffs:

================================================================
Index: SOURCES/dcamnoise2-0.63.c
diff -u /dev/null SOURCES/dcamnoise2-0.63.c:1.1
--- /dev/null	Mon Nov 21 22:51:07 2005
+++ SOURCES/dcamnoise2-0.63.c	Mon Nov 21 22:51:02 2005
@@ -0,0 +1,1544 @@
+/*
+ * Copyright (C) 2005 Peter Heckert
+ *                    <peter /dot/ heckert /at/ arcor /dot/ de>
+ *
+ * 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 of the License, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+ /*
+  * =========Version History=============
+  *
+  *
+  * 13. July, Version 0.62
+  *
+  * All radius,lookahead, and Phase Jitter damping params are internally processed with pixel granularity.
+  * (This is unvisible at user interface level, because the step_increment param for gimp_scale_entry_new()
+  *  apparently doesnt work as advertised)
+  *
+  * This prepares for an important change: I will go from double float to single float and I will use
+  * an FIR quad boxfilter instead of an IIR gauss. This should give considerable speedup.
+  *
+  * Introduced new param "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. Use it only as last ressort.
+  *
+  * Using this params at the above mentioned ISO 800 Image I got better results than noise ninja:
+  * Radius 4, Thresh. 0.15 , Texture -0.42, Sharpness 0.5, Erosion 3, gamma 1.9, other params default.
+  *
+  * Updated usage instructions.
+  *
+  * 5. Aug, Version 0.63
+  * Better Filter effect. Internaly a noise clipping threshold is used.
+  * If you used previous versions then jugde yourself.
+  * Possibly I will make this param adjudstable, it depend on future experiments and on user-feedback 
+  *
+  * Speeded up the gaussian filter. Now it should be the fastest and the best gauss filter in the west ;-)
+  * Therefore I dropped any plans to use boxfilters.
+  * Found out that the main speed-bottleneck is gimps plugin-interface.
+  * Need for 16 Bit. The filter can not only remove sensor noise, it can remove 8-bit quantization noise.
+  * So it should be possible to convert an 8-Bit image into a pseudo-16 Bit image which would allow
+  * color and gradadation manipulations which are impossible now.
+  * Thinking about porting the whole thing to cinepaint, to overcome the speed-bottleneck and the 8-Bit
+  * bottleneck 
+  *
+  * 6. Aug Version 0.63
+  * Corrected minor error in code, uploaded again, without version change
+  */
+
+
+  
+  
+  
+/* ========= SHORT DESCRIPTION AND REQUIREMENTS ==================================================================
+  * This is a gimp plugin to remove typical digital camera noise.  
+ *
+ * Gimp >= 2.2 is required. 
+ *
+ * If you use windows, then possibly you cannot compile it.
+ *
+ * By courtesy of Michael Schumacher, there is a windows binary for dcamnoise2-0.54.
+ *
+ * For windows there also are commercial alternatives:
+ * Look at http://www.imagenomic.com, they have a very nice denoising tool
+ * for windows, in a commercial and in a light free version.
+ * (This is my personal opinion, there are other tools (neatimage,noiseninja....)
+ * Of course they all have disadvantages: They are not gimp-plugins.
+ *
+ * And possibly my tool does a better job in preserving sharpness without artifacts and segmentation, because I
+ * do not use something artificial like edge recognition. 
+ *
+ * There is another tool "Picture cooler" at <http://beam.to/picturecooler> that looks very 
+ * interesting. Presently it is beta and free.
+ *
+ * Code for dcamnoise2.c is derived from common unsharp-plugin for gimp-2.2.
+ * I used this as a sceleton, but idea and core code are basing on my own
+ * ideas and work.
+ * It is still very experimental code and a little bit chaotic.
+ * It has undergone a lot of changes in the last weeks.
+ *
+ * ======== INSTALLATION =========================================================================================
+ * Installation hints for  Linux systems:
+ * INSTALL with: $ gimptool  --install dcamnoise2-#.##.c (#.## is the version number)
+ * (gimp-devel must be installed before)
+ * (This is for a rpm-based system, if you use Debian or else, I dont know exactly)
+ *
+ * It will install in Gimp under "Filter->Verbessern"  
+ * (This should be "Filters->Enhance" in the english version)
+ * To uninstall, simply delete it from  ~/.gimp-2.2/plugins
+ * or type gimptool --uninstall-bin dcamnoise2-#.## 
+ * Or type gimptool --help and learn about it ;-)
+ * On some sytems you must use "gimptool-2.2" instead of "gimptool" to compile and install it.
+ *
+ * =========USAGE ================================================================================================
+ * 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.
+ * It can destroy your computer and can kill cats :-)
+ *------------------------------------------------------------------------------------------------------------
+ *
+ * "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.
+ *
+ *------------------------------------------------------------------------------------------------------------
+ *
+ * Introduced new param "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)
+ *
+ * It can make beautyful skin :-)
+ *------------------------------------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------------------------------------
+ * 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!  
+ *
+ *
+ * ============== THANKS ======================================================================================
+ * 
+ * Thanks go to the gimp-developers for their very fine work!
+ * I got a lot of positive feedback for this plugin, thanks!
+ * 
+ */ 
+
+/* 
+ * ================ 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.
+ *
+ */
+
+#define STANDALONE
+
+
+#ifndef STANDALONE
+#include "config.h"
+#endif
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+
+#ifdef STANDALONE
+
+#define INIT_I18N voidproc
+void voidproc(void){};
+#define _(x) (x)
+#define N_(x)  (x)
+
+#else
+
+#include "libgimp/stdplugins-intl.h"
+
+#endif
+
+
+#define PLUG_IN_VERSION "0.63"
+
+#define SCALE_WIDTH   150
+#define ENTRY_WIDTH     4
+
+// This is for testing only!
+//#define float double
+//#define gfloat gdouble
+
+/* Uncomment this line to get a rough estimate of how long the plug-in
+ * takes to run.
+ */
+
+/*  #define TIMER  */
+
+
+typedef struct
+{
+  gdouble  radius;
+  gdouble  lsmooth;
+  gdouble  csmooth;
+  gdouble  effect;
+  gdouble  lookahead;
+  gdouble  gamma;
+  gdouble  damping;
+  gdouble phase;
+  gdouble texture;
+  gdouble sharp;
+  gboolean update_preview;
+
+} UnsharpMaskParams;
+
+typedef struct
+{
+  gboolean  run;
+} UnsharpMaskInterface;
+
+/* local function prototypes */
+static void      query (void);
+static void      run   (const gchar      *name,
+                        gint              nparams,
+                        const GimpParam  *param,
+                        gint             *nreturn_vals,
+                        GimpParam       **return_vals);
+
+static void      blur_line           (gfloat  * const data,
+                                      gfloat  * const data2,
+                                      gfloat  * const buffer,
+                                      gfloat *rbuf,
+                                      gfloat *tbuf,
+                                      const guchar   *src,
+                                      guchar         *dest,
+                                      gint            len,
+                                      glong           bytes);
+
+static void      unsharp_region      (GimpPixelRgn   *srcPTR,
+                                      GimpPixelRgn   *dstPTR,
+                                      gint            bytes,
+                                      gdouble         radius,
+                                      gdouble         lsmooth,
+                                      gint            x1,
+                                      gint            x2,
+                                      gint            y1,
+                                      gint            y2,
+                                      gboolean        show_progress);
+
+static void      unsharp_mask        (GimpDrawable   *drawable,
+                                      gdouble         radius,
+                                      gdouble         lsmooth);
+
+static gboolean  unsharp_mask_dialog (GimpDrawable   *drawable);
+static void      preview_update      (GimpPreview    *preview);
+
+
+/* create a few globals, set default values */
+static UnsharpMaskParams unsharp_params =
+  {
+    5.0, /* default radius = 5 */
+    1.0, /* Luminance Tolerance */
+    1.0, /* RGB Tolerance  */
+    0.08, /* Adaptive filter-effect threshold */
+    2.0, /* Lookahead */ 
+    1.0, /* Filter gamma */
+    5.0,  /* Phase jitter Damping  */
+    1.0,  /* Area Noise Clip */
+    0.0,  /* Texture Detail */
+    0.25,  /* Sharpness factor */  
+    TRUE /* default is to update the preview */
+  /* These values are values that I used for a test image with some success. 
+     They are not optimal for every image*/
+  
+  };
+
+/* Setting PLUG_IN_INFO */
+GimpPlugInInfo PLUG_IN_INFO =
+  {
+    NULL,  /* init_proc  */
+    NULL,  /* quit_proc  */
+    query, /* query_proc */
+    run,   /* run_proc   */
+  };
+
+
+gfloat lut_gamma, inv_gamma;  
+  
+gfloat lut[256];  
+  
+static void 
+lut_init(gfloat g)
+{
+ int i;
+ 
+ for (i = 1; i< 255; i++) lut[i] = pow((gfloat) i/255.0, g);
+ lut[0]= 0.0;
+ lut[255] = 1.0;
+
+ lut_gamma = g;
+ inv_gamma = 1.0/g;
+
+}
+
+
+
+
+MAIN ()
+
+static void
+query (void)
+{
+  static GimpParamDef args[] =
+    {
+      { GIMP_PDB_INT32,    "run_mode",  "Interactive, non-interactive" },
+      { GIMP_PDB_IMAGE,    "image",     "(unused)" },
+      { GIMP_PDB_DRAWABLE, "drawable",  "Drawable to draw on" },
+      { GIMP_PDB_FLOAT,    "radius",    "Radius of gaussian blur (in pixels)" },
+      { GIMP_PDB_FLOAT,    "lsmooth",    "Luminance Tolerance" },
+      { GIMP_PDB_FLOAT,    "csmooth", "Color Tolerance" },
+      { GIMP_PDB_FLOAT,    "effect", "Threshold for 2nd derivative of luminance" },      
+      { GIMP_PDB_FLOAT,    "lookahead", "Sharpness" } ,      
+      
+      { GIMP_PDB_FLOAT,    "gamma", "Gamma" } ,      
+      
+      { GIMP_PDB_FLOAT,    "damping", "Phase jitter damping" },      
+      { GIMP_PDB_FLOAT,    "phase", "Phase shift for edges" },      
+      { GIMP_PDB_FLOAT,    "texture", "Texture accuracy" },      
+      { GIMP_PDB_FLOAT,    "sharp", "Edge accuracy" }      
+    
+    
+    };
+
+  gimp_install_procedure ("plug_in_dcamnoise2-"PLUG_IN_VERSION,
+                          "A Digital Camera Noise filter",
+                          "It is commonly "
+                          "used on photographic images, and is provides a much "
+                          "more pleasing result than the standard denoising "
+                          "filters.",
+
+                          "This is an experimental version. ",
+			  "",
+			  "",
+			    
+
+			  N_("_Dcam Noise 2 "PLUG_IN_VERSION" ..."),
+                          "GRAY*, RGB*",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (args), 0,
+                          args, NULL);
+
+  gimp_plugin_menu_register ("plug_in_dcamnoise2-"PLUG_IN_VERSION,
+                             "<Image>/Filters/Enhance");
+}
+
+static void
+run (const gchar      *name,
+     gint              nparams,
+     const GimpParam  *param,
+     gint             *nreturn_vals,
+     GimpParam       **return_vals)
+{
+  static GimpParam   values[1];
+  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
+  GimpDrawable      *drawable;
+  GimpRunMode        run_mode;
+#ifdef TIMER
+  GTimer            *timer = g_timer_new ();
+#endif
+
+  run_mode = param[0].data.d_int32;
+
+  *return_vals  = values;
+  *nreturn_vals = 1;
+
+  values[0].type          = GIMP_PDB_STATUS;
+  values[0].data.d_status = status;
+
+  INIT_I18N ();
+
+  /*
+   * Get drawable information...
+   */
+  drawable = gimp_drawable_get (param[2].data.d_drawable);
+  gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
+
+  switch (run_mode)
+    {
+    case GIMP_RUN_INTERACTIVE:
+      gimp_get_data ("plug_in_dcamnoise2-"PLUG_IN_VERSION, &unsharp_params);
+      /* Reset default values show preview unmodified */
+
+      /* initialize pixel regions and buffer */
+      if (! unsharp_mask_dialog (drawable))
+        return;
+
+      break;
+
+    case GIMP_RUN_NONINTERACTIVE:
+      if (nparams != 13)
+        {
+          status = GIMP_PDB_CALLING_ERROR;
+        }
+      else
+        {
+          unsharp_params.radius = param[3].data.d_float;
+          unsharp_params.lsmooth = param[4].data.d_float;
+          unsharp_params.csmooth = param[5].data.d_float;
+          unsharp_params.effect = param[6].data.d_float;
+          unsharp_params.lookahead = param[7].data.d_float;
+          unsharp_params.gamma = param[8].data.d_float;
+          unsharp_params.damping = param[9].data.d_float; 
+          unsharp_params.phase = param[10].data.d_float; 
+          unsharp_params.texture = param[11].data.d_float; 
+          unsharp_params.sharp = param[12].data.d_float; 
+          
+          /* make sure there are legal values */
+          if ((unsharp_params.radius < 0.0) ||
+              (unsharp_params.lsmooth < 0.0))
+            status = GIMP_PDB_CALLING_ERROR;
+        }
+      break;
+
+    case GIMP_RUN_WITH_LAST_VALS:
+      gimp_get_data ("plug_in_dcamnoise2-"PLUG_IN_VERSION, &unsharp_params);
+      break;
+
+    default:
+      break;
+    }
+
+  if (status == GIMP_PDB_SUCCESS)
+    {
+      drawable = gimp_drawable_get (param[2].data.d_drawable);
+
+      /* here we go */
+      unsharp_mask (drawable, unsharp_params.radius, unsharp_params.lsmooth);
+
+      gimp_displays_flush ();
+
+      /* set data for next use of filter */
+      gimp_set_data ("plug_in_dcamnoise2-"PLUG_IN_VERSION, &unsharp_params,
+                     sizeof (UnsharpMaskParams));
+
+      gimp_drawable_detach(drawable);
+      values[0].data.d_status = status;
+    }
+
+#ifdef TIMER
+  g_printerr ("%f seconds\n", g_timer_elapsed (timer, NULL));
+  g_timer_destroy (timer);
+#endif
+}
+
+
+static struct iir_param
+{
+ gdouble B,b1,b2,b3,b0,r,q;
+ gdouble *p;
+} iir; 
+#define GAUSS
+#define PI 3.141592653  
+static void iir_init(double r)
+{
+  if (iir.r == r) return;
+  iir.r = r; // = unsharp_params.damping;
+  gdouble q,l;
+  
+  if ( r >= 2.5) q = 0.98711 * r - 0.96330;
<<Diff was trimmed, longer than 597 lines>>



More information about the pld-cvs-commit mailing list