[xiph-commits] r15583 - trunk/gimp-montypak

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Mon Dec 15 02:14:47 PST 2008


Author: xiphmont
Date: 2008-12-15 02:14:46 -0800 (Mon, 15 Dec 2008)
New Revision: 15583

Modified:
   trunk/gimp-montypak/Makefile
   trunk/gimp-montypak/denoise.c
   trunk/gimp-montypak/wavelet.c
Log:
Major improvements to dialog responsiveness through caching
Some minor free rearrangements in wavelet.c to reduce temp memusage 
slightly.


Modified: trunk/gimp-montypak/Makefile
===================================================================
--- trunk/gimp-montypak/Makefile	2008-12-14 10:58:16 UTC (rev 15582)
+++ trunk/gimp-montypak/Makefile	2008-12-15 10:14:46 UTC (rev 15583)
@@ -25,7 +25,7 @@
 
 all:    
 	pkg-config --cflags $(PKGARG) 1>/dev/null
-	$(MAKE) montypak CFLAGS='-O2 -g $(GCF) '
+	$(MAKE) montypak CFLAGS='-O3 -g $(GCF) '
 
 debug:
 	pkg-config --cflags $(PKGARG) 1>/dev/null
@@ -33,7 +33,7 @@
 
 profile:
 	pkg-config --cflags $(PKGARG) 1>/dev/null
-	$(MAKE) montypak CFLAGS='-g -pg -O2 $(GCF) '
+	$(MAKE) montypak CFLAGS='-g -pg -O3 $(GCF) '
 
 clean:
 	rm -f *.o *.d *.d.* *.pc gmon.out $(TARGETS)

Modified: trunk/gimp-montypak/denoise.c
===================================================================
--- trunk/gimp-montypak/denoise.c	2008-12-14 10:58:16 UTC (rev 15582)
+++ trunk/gimp-montypak/denoise.c	2008-12-15 10:14:46 UTC (rev 15583)
@@ -24,7 +24,6 @@
 
 
 #include <string.h>
-#include <string.h>
 #include <stdlib.h>
 
 #include <gtk/gtk.h>
@@ -37,7 +36,7 @@
 
 #define PLUG_IN_PROC    "plug-in-denoise"
 #define PLUG_IN_BINARY  "denoise"
-#define PLUG_IN_VERSION "14 Dec 2008"
+#define PLUG_IN_VERSION "15 Dec 2008"
 
 /*
  * Local functions...
@@ -54,7 +53,7 @@
 static void     denoise_pre    (GimpDrawable *drawable);
 
 static gboolean denoise_dialog (GimpDrawable *drawable);
-static int      denoise_work(int w, int h, int bpp, guchar *buffer, int progress, int(*interrupt)(void));
+static void     denoise_work(int w, int h, int bpp, guchar *buffer);
 
 static void     preview_update (GtkWidget  *preview, GtkWidget *dialog);
 
@@ -91,15 +90,19 @@
 };
 
 static GtkWidget    *preview;
+static GtkToggleButton *preview_toggle=NULL;
 static GtkObject    *madj[4];
 static GtkObject    *ladj[1];
-static guchar *preview_cache_buffer=NULL;
+static guchar *preview_cache_blit=NULL;
+static guchar *preview_cache_filter=NULL;
+static float  *preview_cache_luma=NULL;
 static int     preview_cache_x;
 static int     preview_cache_y;
 static int     preview_cache_w;
 static int     preview_cache_h;
 
 static int     variance_median=0;
+static int     pre_run=0;
 
 MAIN ()
 
@@ -174,9 +177,6 @@
   drawable = gimp_drawable_get (param[2].data.d_drawable);
   gimp_tile_cache_ntiles (2 * drawable->ntile_cols);
 
-  /* math that has to be done ahead of time */
-  denoise_pre(drawable);
-
   /*
    * See how we will run
    */
@@ -295,7 +295,8 @@
   /***************************************/
   buffer = g_new (guchar, w * h * bpp);
   gimp_pixel_rgn_get_rect (&src_rgn, buffer, x1, y1, w, h);
-  denoise_work(w,h,bpp,buffer,1,NULL);
+  if(!pre_run) denoise_pre(drawable);
+  denoise_work(w,h,bpp,buffer);
   gimp_pixel_rgn_set_rect (&dst_rgn, buffer, x1, y1, w, h);
   /**************************************/
 
@@ -311,15 +312,29 @@
   g_free(buffer);
 }
 
+static void dialog_filter_callback (GtkWidget *widget,
+				    gpointer   data)
+{
+  if(preview_cache_filter)
+    g_free(preview_cache_filter);
+  preview_cache_filter=NULL;
+  if(!preview_toggle->active){
+    if(preview_cache_blit)
+      g_free(preview_cache_blit);
+    preview_cache_blit=NULL;
+  }
+}
+
 static void dialog_soft_callback (GtkWidget *widget,
-                          gpointer   data)
+				  gpointer   data)
 {
   denoise_params.soft = (GTK_TOGGLE_BUTTON (widget)->active);
-  if(denoise_params.filter>0.)
+  if(denoise_params.filter>0.){
+    dialog_filter_callback(widget,data);
     gimp_preview_invalidate (GIMP_PREVIEW (preview));
+  }
 }
 
-
 static void dialog_multiscale_callback (GtkWidget *widget,
                           gpointer   data)
 {
@@ -331,30 +346,43 @@
   if(denoise_params.f1!=0. ||
      denoise_params.f2!=0. ||
      denoise_params.f3!=0. ||
-     denoise_params.f4!=0.)
+     denoise_params.f4!=0.){
+    dialog_filter_callback(widget,data);
     gimp_preview_invalidate (GIMP_PREVIEW (preview));
+  }
 }
 
+static void dialog_luma_callback (GtkWidget *widget,
+				  gpointer   data)
+{
+  if(!preview_toggle->active){
+    if(preview_cache_blit)
+      g_free(preview_cache_blit);
+    preview_cache_blit=NULL;
+  }
+}
+
 static void dialog_lowlight_callback (GtkWidget *widget,
 				      gpointer   data)
 {
   denoise_params.lowlight = (GTK_TOGGLE_BUTTON (widget)->active);
   gimp_scale_entry_set_sensitive(ladj[0],denoise_params.lowlight);
+  dialog_luma_callback(widget,data);
   gimp_preview_invalidate (GIMP_PREVIEW (preview));
 }
 
-static void dump_cache(GtkWidget *widget, gpointer dummy){
-  if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))){
-    if(preview_cache_buffer)
-      g_free(preview_cache_buffer);
-    preview_cache_buffer=NULL;
-  }
+static void find_preview_toggle(GtkWidget *widget, gpointer dummy){
+  if(!preview_toggle)
+    preview_toggle = GTK_TOGGLE_BUTTON(widget);
 }
 
-static void decache_on_toggle(GtkWidget *widget, gpointer dummy){
-  g_signal_connect (widget, "toggled",
-                    G_CALLBACK (dump_cache),
-		    NULL);
+static void set_busy(GtkWidget *preview, GtkWidget *dialog){
+  GdkDisplay    *display = gtk_widget_get_display (dialog);
+  GdkCursor     *cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+  gdk_window_set_cursor(preview->window, cursor);
+  gdk_window_set_cursor(gimp_preview_get_area(GIMP_PREVIEW(preview))->window, cursor);
+  gdk_window_set_cursor(dialog->window, cursor);
+  gdk_cursor_unref(cursor);
 }
 
 static gboolean denoise_dialog (GimpDrawable *drawable)
@@ -397,7 +425,7 @@
                     G_CALLBACK (preview_update),
                     dialog);
   gtk_container_foreach(GTK_CONTAINER(gimp_preview_get_controls(GIMP_PREVIEW(preview))),
-			decache_on_toggle,NULL);
+			find_preview_toggle,NULL);
 
   /* Main filter strength adjust */
   table = gtk_table_new (1, 3, FALSE);
@@ -417,6 +445,7 @@
   g_signal_connect_swapped (adj, "value-changed",
                             G_CALLBACK (gimp_preview_invalidate),
                             preview);
+  g_signal_connect (adj, "value-changed",G_CALLBACK (dialog_filter_callback),NULL);
 
 
   /* Threshold shape */
@@ -425,9 +454,7 @@
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
                                 denoise_params.soft);
   gtk_widget_show (button);
-  g_signal_connect (button, "toggled",
-                    G_CALLBACK (dialog_soft_callback),
-                    NULL);
+  g_signal_connect (button, "toggled", G_CALLBACK (dialog_soft_callback), NULL);
 
   /* Low-light mode */
   button = gtk_check_button_new_with_mnemonic ("_Low-light noise mode");
@@ -435,9 +462,7 @@
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
                                 denoise_params.lowlight);
   gtk_widget_show (button);
-  g_signal_connect (button, "toggled",
-                    G_CALLBACK (dialog_lowlight_callback),
-                    NULL);
+  g_signal_connect (button, "toggled", G_CALLBACK (dialog_lowlight_callback),NULL);
 
   /* Subadjustments for lowlight mode */
   table = gtk_table_new (1, 4, FALSE);
@@ -459,6 +484,7 @@
   g_signal_connect_swapped (adj, "value-changed",
                             G_CALLBACK (gimp_preview_invalidate),
                             preview);
+  g_signal_connect (adj, "value-changed",G_CALLBACK (dialog_luma_callback),NULL);
   gimp_scale_entry_set_sensitive(ladj[0],denoise_params.lowlight);
 
   /* multiscale adjust select */
@@ -491,6 +517,7 @@
   g_signal_connect_swapped (adj, "value-changed",
                             G_CALLBACK (gimp_preview_invalidate),
                             preview);
+  g_signal_connect (adj,"value-changed",G_CALLBACK(dialog_filter_callback),NULL);
 
   /* detail adjust */
   madj[1] = adj = gimp_scale_entry_new (GTK_TABLE (table), 1, 1,
@@ -505,6 +532,7 @@
   g_signal_connect_swapped (adj, "value-changed",
                             G_CALLBACK (gimp_preview_invalidate),
                             preview);
+  g_signal_connect (adj,"value-changed",G_CALLBACK(dialog_filter_callback),NULL);
 
   /* mid adjust */
   madj[2] = adj = gimp_scale_entry_new (GTK_TABLE (table), 1, 2,
@@ -519,6 +547,7 @@
   g_signal_connect_swapped (adj, "value-changed",
                             G_CALLBACK (gimp_preview_invalidate),
                             preview);
+  g_signal_connect (adj,"value-changed",G_CALLBACK(dialog_filter_callback),NULL);
 
   /* Coarse adjust */
   madj[3] = adj = gimp_scale_entry_new (GTK_TABLE (table), 1, 3,
@@ -533,6 +562,7 @@
   g_signal_connect_swapped (adj, "value-changed",
                             G_CALLBACK (gimp_preview_invalidate),
                             preview);
+  g_signal_connect (adj,"value-changed",G_CALLBACK(dialog_filter_callback),NULL);
 
   gimp_scale_entry_set_sensitive(madj[0],denoise_params.multiscale);
   gimp_scale_entry_set_sensitive(madj[1],denoise_params.multiscale);
@@ -540,14 +570,21 @@
   gimp_scale_entry_set_sensitive(madj[3],denoise_params.multiscale);
 
   gtk_widget_show (dialog);
-
   run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
 
   gtk_widget_destroy (dialog);
 
-  if(preview_cache_buffer)
-    g_free(preview_cache_buffer);
-  preview_cache_buffer=NULL;
+  if(preview_cache_blit)
+    g_free(preview_cache_blit);
+  preview_cache_blit=NULL;
+
+  if(preview_cache_filter)
+    g_free(preview_cache_filter);
+  preview_cache_filter=NULL;
+
+  if(preview_cache_luma)
+    g_free(preview_cache_luma);
+  preview_cache_luma=NULL;
   return run;
 }
 
@@ -560,80 +597,6 @@
   return denoise_active_interrupt;
 }
 
-static int set_busy(GtkWidget *preview, GtkWidget *dialog){
-  GdkDisplay    *display = gtk_widget_get_display (dialog);
-  GdkCursor     *cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
-  gdk_window_set_cursor(preview->window, cursor);
-  gdk_window_set_cursor(gimp_preview_get_area(GIMP_PREVIEW(preview))->window, cursor);
-  gdk_window_set_cursor(dialog->window, cursor);
-  gdk_cursor_unref(cursor);
-}
-
-static void preview_update (GtkWidget *preview, GtkWidget *dialog){
-
-  GimpDrawable *drawable;
-  GimpPixelRgn  rgn;            /* previw region */
-  gint          x1, y1;
-  gint          w,h;
-  guchar       *buffer=NULL;
-  gint          bpp;        /* Bytes-per-pixel in image */
-
-  /* because we allow async event processing, a stray expose of the
-     GimpPreviewArea will cause it reload the original unfiltered
-     data, which is annoying when doing small parameter tweaks.  Make
-     sure the previous run's data is blitted in if it can be */
-  drawable = gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));
-  bpp = gimp_drawable_bpp (drawable->drawable_id);
-  gimp_preview_get_position (GIMP_PREVIEW(preview), &x1, &y1);
-  gimp_preview_get_size (GIMP_PREVIEW(preview), &w, &h);
-
-  if(preview_cache_buffer &&
-     x1 == preview_cache_x &&
-     y1 == preview_cache_y &&
-     w == preview_cache_w &&
-     h == preview_cache_h){
-    
-    gimp_preview_draw_buffer (GIMP_PREVIEW(preview), preview_cache_buffer, w*bpp);
-  }else{
-    if(preview_cache_buffer)
-      g_free(preview_cache_buffer);
-    preview_cache_buffer=NULL;
-  }
-
-  denoise_active_interrupt=1;
-  if(denoise_active_interruptable) return;
-  denoise_active_interruptable = 1;
-
-  while(denoise_active_interrupt){
-    denoise_active_interrupt=0;
-
-    set_busy(preview,dialog);
-
-    gimp_preview_get_position (GIMP_PREVIEW(preview), &x1, &y1);
-    gimp_preview_get_size (GIMP_PREVIEW(preview), &w, &h);
-    gimp_pixel_rgn_init (&rgn, drawable,
-			 x1, y1, w, h,
-			 FALSE, FALSE);
-    if(buffer) g_free (buffer);
-    buffer = g_new (guchar, w * h * bpp);
-    gimp_pixel_rgn_get_rect (&rgn, buffer, x1, y1, w, h);
-    if(!denoise_work(w,h,bpp,buffer,0,check_recompute)){
-      gimp_preview_draw_buffer (GIMP_PREVIEW(preview), buffer, w*bpp);
-      gimp_drawable_flush (drawable);
-    }
-  }
-  
-  if(preview_cache_buffer)
-    g_free(preview_cache_buffer);
-  preview_cache_buffer = buffer;
-  preview_cache_x = x1;
-  preview_cache_y = y1;
-  preview_cache_w = w;
-  preview_cache_h = h;
-
-  denoise_active_interruptable = 0;
-}
-
 #include "varmean.c"
 #define clamp(x) ((x)<0?0:((x)>255?255:(x)))
 
@@ -641,7 +604,8 @@
   int i;
   switch(planes){
   case 1:
-    memcpy(luma,buffer,sizeof(*luma)*width*height);
+    for(i=0;i<width*height;i++)
+      luma[i]=buffer[i];
     break;
   case 2: 
     for(i=0;i<width*height;i++)
@@ -658,8 +622,34 @@
   }
 }
 
+static void compute_luma_f(guchar *buffer, float *luma, int width, int height, int planes){
+  int i;
+  switch(planes){
+  case 1:
+    for(i=0;i<width*height;i++)
+      luma[i]=buffer[i]*(1.f/255.f);
+    break;
+  case 2: 
+    for(i=0;i<width*height;i++)
+      luma[i]=buffer[i<<1]*(1.f/255.f);
+    break;
+  case 3:
+    for(i=0;i<width*height;i++)
+      luma[i]=buffer[i*3]*(.2126f/255.f) + 
+	buffer[i*3+1]*(.7152f/255.f) + 
+	buffer[i*3+2]*(.0722f/255.f);
+    break;
+  case 4:
+    for(i=0;i<width*height;i++)
+      luma[i]=buffer[i*4]*(.2126f/255.f) + 
+	buffer[i*4+1]*(.7152f/255.f) + 
+	buffer[i*4+2]*(.0722f/255.f);
+    break;
+  }
+}
+
+/* find the variance median for the whole image, not just preview, not just the selection */
 static void denoise_pre(GimpDrawable *drawable){
-  /* find the variance median for the whole image, not just preview, not just the selection */
 
   GimpPixelRgn  rgn;
   gint          w = gimp_drawable_width(drawable->drawable_id);
@@ -667,10 +657,11 @@
   gint          bpp = gimp_drawable_bpp (drawable->drawable_id);
   guchar       *buffer;
   guchar       *luma;
-  float       *v;
+  float        *v;
   long          d[256];
-  int           i,a,a2,med;
-
+  int           i,a,a2;
+  
+  pre_run = 1;
   gimp_pixel_rgn_init (&rgn, drawable,
                        0, 0, w, h, FALSE, FALSE);
   buffer = g_new (guchar, w * h * bpp);
@@ -688,7 +679,7 @@
   memset(d,0,sizeof(d));
     
   for(i=0;i<w*h;i++){
-    int val = clamp(sqrt(v[i]));
+    int val = clamp(rint(sqrt(v[i])));
     d[val]++;
   }
   g_free(v);
@@ -706,58 +697,45 @@
   }
 }
 
-static int denoise_work(int width, int height, int planes, guchar *buffer, int pr, int(*check)(void)){
+static float *compute_smoothed_luma(guchar *buffer, int w, int h, int p, 
+				    int pr, int (*check)(void)){
   int i;
   float T[16];
-  guchar *mask=NULL;
+  float *luma = g_new(float,w*h);
 
-  if(denoise_params.lowlight){
-    float l = denoise_params.lowlight_adj*.01;
-    int med = variance_median*8;
-    if(pr)gimp_progress_init( "Masking luma...");
+  if(pr)gimp_progress_init( "Masking luma...");
+  
+  compute_luma_f(buffer,luma,w,h,p);
+  if(check && check()){
+    g_free(luma);
+    return NULL;
+  } 
 
-    mask = g_new(guchar,width*height);
-    compute_luma(buffer,mask,width,height,planes);
-
-    if(l>0){
-      med += (255-med)*l;
-    }else{
-      med += med*l;
-    }
-
-    if(check && check()){
-      g_free(mask);
-      return 1;
-    } 
-
-    /* adjust luma into mask form */
-    for(i=0;i<width*height;i++){
-      if(mask[i]<med){
-	mask[i]=255;
-      }else if(mask[i]>=med*2){
-	mask[i]=0;
-      }else{
-	float del = (float)(mask[i]-med)/med;
-	mask[i]=255-255*del;
-      }
-    }
-
-    if(check && check()){
-      g_free(mask);
-      return 1;
-    } 
-
-    /* smooth the luma plane */
-    for(i=0;i<16;i++)
-      T[i]=10.;
-    if(wavelet_filter(width, height, 1, mask, NULL, pr, T, denoise_params.soft, check)){
-      g_free(mask);
-      return 1;
-    }
-
+  /* smooth the luma plane */
+  for(i=0;i<16;i++)
+    T[i]=10./255.f;
+  if(wavelet_filter_f(w, h, luma, pr, T, denoise_params.soft, check)){
+    g_free(luma);
     if(pr)gimp_progress_end();
+    return NULL;
   }
+  
+  if(pr)gimp_progress_end();
+  return luma;
+}
 
+static guchar *compute_filter(guchar *buffer, int w, int h, int p, 
+			      int inplace, int pr, int (*check)(void)){
+  int i;
+  float T[16];
+  guchar *filtered;
+  if(inplace){
+    filtered = buffer;
+  }else{
+    filtered = g_new(guchar,w*h*p);
+    memcpy(filtered,buffer,sizeof(*filtered)*w*h*p);
+  }
+
   if(pr)gimp_progress_init( "Denoising...");
   
   for(i=0;i<16;i++)
@@ -771,14 +749,155 @@
       T[i]*=(denoise_params.f4+100)*.01;
   }
   
-  if(wavelet_filter(width, height, planes, buffer, mask, pr, T, denoise_params.soft, check)){
-    if(mask)g_free(mask);
-    return 1;
+  if(wavelet_filter_c(w, h, p, filtered, pr, T, denoise_params.soft, check)){
+    if(!inplace)g_free(filtered);
+    if(pr)gimp_progress_end();
+    return NULL;
   }
 
-  if(mask)
-    g_free(mask);
- 
+  if(pr)gimp_progress_end();
+  return filtered;
+}
+
+static int combine_filter_luma(guchar *buffer, guchar *filtered, float *luma,
+			       int w, int h, int p, int(*check)(void)){
+  int i,j,k;
+  
+  if(denoise_params.lowlight){
+    float l = denoise_params.lowlight_adj*.01;
+    float med = variance_median*(8.f/255.f);
+
+    if(l>0){
+      med += (1.-med)*l;
+    }else{
+      med += med*l;
+    }
+  
+    for(i=0;i<w*h;i+=w){
+      for(j=i;j<i+w;j++){
+	float mask = 1.f - (luma[j]-med)/med;
+	if(mask<0.f)mask=0.f;
+	if(mask>1.f)mask=1.f;
+	for(k=0;k<p;k++)
+	  buffer[k] = clamp(rint(filtered[k]*mask + (1.f-mask)*buffer[k]));
+	buffer+=p;
+	filtered+=p;
+      }
+      if(check && check()) return 1;
+    }
+  }else{
+    memcpy(buffer,filtered,sizeof(*buffer)*w*h*p);
+  }
   return 0;
 }
 
+static void preview_update (GtkWidget *preview, GtkWidget *dialog){
+
+  GimpDrawable *drawable;
+  GimpPixelRgn  rgn;            /* previw region */
+  gint          x, y, w, h;
+  gint          bpp;        /* Bytes-per-pixel in image */
+  guchar       *buffer = NULL;
+
+  /* Because we do async event processing in this plugin (so that the
+     UI doesn't freeze during long comutation times), a stray expose
+     of the GimpPreviewArea already queud after this update call
+     causes it to reload the original unfiltered data, which is
+     annoying when doing small parameter tweaks.  Make sure the
+     previous run's data is blitted in if appropriate. */
+  drawable = gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));
+  bpp = gimp_drawable_bpp (drawable->drawable_id);
+  gimp_preview_get_position (GIMP_PREVIEW(preview), &x, &y);
+  gimp_preview_get_size (GIMP_PREVIEW(preview), &w, &h);
+  if(!pre_run) denoise_pre(drawable);
+
+  if(x == preview_cache_x &&
+     y == preview_cache_y &&
+     w == preview_cache_w &&
+     h == preview_cache_h){
+
+    if(preview_cache_blit)
+      gimp_preview_draw_buffer (GIMP_PREVIEW(preview), preview_cache_blit, w*bpp);
+
+  }else{
+
+    /* the preview pane has shifted; dump all caches */
+
+    if(preview_cache_blit)
+      g_free(preview_cache_blit);
+    preview_cache_blit=NULL;
+
+    if(preview_cache_filter)
+      g_free(preview_cache_filter);
+    preview_cache_filter=NULL;
+
+    if(preview_cache_luma)
+      g_free(preview_cache_luma);
+    preview_cache_luma=NULL;
+
+  }
+
+  denoise_active_interrupt=1;
+  if(denoise_active_interruptable) return;
+  denoise_active_interruptable = 1;
+
+  while(denoise_active_interrupt){
+    denoise_active_interrupt=0;
+    set_busy(preview,dialog);
+
+    gimp_preview_get_position (GIMP_PREVIEW(preview), &x, &y);
+    gimp_preview_get_size (GIMP_PREVIEW(preview), &w, &h);
+    gimp_pixel_rgn_init (&rgn, drawable, x, y, w, h, FALSE, FALSE);
+
+    if(buffer) g_free (buffer);
+    buffer = g_new (guchar, w * h * bpp);
+    gimp_pixel_rgn_get_rect (&rgn, buffer, x, y, w, h);
+
+    /* do we need to compute a smoothed luma plane? */
+    if(preview_cache_luma == NULL){ 
+      preview_cache_luma = compute_smoothed_luma(buffer, w, h, bpp, 0, check_recompute);
+      if(!preview_cache_luma)continue; /* interrupted */
+    }
+
+    /* do we need to filter/refilter the image? */
+    if(preview_cache_filter == NULL){
+      preview_cache_filter = compute_filter(buffer, w, h, bpp, 0, 0, check_recompute);
+      if(!preview_cache_filter)continue; /* interrupted */
+    }
+
+    /* new blit */
+    if(preview_cache_filter && preview_cache_luma){
+      if(combine_filter_luma(buffer, preview_cache_filter, 
+			     preview_cache_luma, w, h, bpp, check_recompute))
+	continue; /* interrupted */
+
+      if(preview_cache_blit)
+	g_free(preview_cache_blit);
+      preview_cache_x = x;
+      preview_cache_y = y;
+      preview_cache_w = w;
+      preview_cache_h = h;
+      preview_cache_blit = buffer;
+      buffer = NULL;
+
+      gimp_preview_draw_buffer (GIMP_PREVIEW(preview), preview_cache_blit, w*bpp);
+      gimp_drawable_flush (drawable);
+    }
+  }
+  
+  if(buffer) g_free(buffer);
+  denoise_active_interruptable = 0;
+}
+
+static void denoise_work(int w, int h, int p, guchar *buffer){
+  if(denoise_params.lowlight){
+    float *l = compute_smoothed_luma(buffer, w, h, p, 1, NULL);
+    guchar *f = compute_filter(buffer, w, h, p, 0, 1, NULL);
+    combine_filter_luma(buffer, f, l, w, h, p, NULL);
+    g_free(f);
+    g_free(l);
+  }else{
+    compute_filter(buffer, w, h, p, 1, 1, NULL);
+  }
+}
+

Modified: trunk/gimp-montypak/wavelet.c
===================================================================
--- trunk/gimp-montypak/wavelet.c	2008-12-14 10:58:16 UTC (rev 15582)
+++ trunk/gimp-montypak/wavelet.c	2008-12-15 10:14:46 UTC (rev 15583)
@@ -737,14 +737,14 @@
   for(i=0;i<4;i++){
     deconvolve_transpose_padded(temp2[i],tempw[i],sf[i&1][0], pt, pc, check);
     if(check && check())goto cleanup;
+    free_m2D(tempw+i);
     deconvolve_padded(y[i],temp2[i],sf[i>>1][2], pt, pc, check);
     if(check && check())goto cleanup;
+    free_m2D(temp2+i);
     temp[i]   = convolve_transpose_padded(x[i], af[i>>1][1], pt, pc, check);
     if(check && check())goto cleanup;
-    free_m2D(temp2+i);
     temp2[i]  = alloc_m2D(c*2 - FSZ*3 + 2, r);
     if(check && check())goto cleanup;
-    free_m2D(tempw+i);
     tempw[i]  = convolve_padded(temp[i], af[i&1][2], pt, pc, check); /* w4 */
     if(check && check())goto cleanup;
   }
@@ -775,15 +775,15 @@
   for(i=0;i<4;i++){
     deconvolve_transpose_padded(temp2[i],tempw[i],sf[i&1][0], pt, pc, check);
     if(check && check())goto cleanup;
+    free_m2D(tempw+i);
     deconvolve_padded(y[i],temp2[i],sf[i>>1][1], pt, pc, check);
     if(check && check())goto cleanup;
+    free_m2D(temp2+i);
     temp[i]  = convolve_transpose_padded(x[i], af[i>>1][0], pt, pc, check);
     if(check && check())goto cleanup;
     if(free_input) free_m2D(x+i);
-    free_m2D(temp2+i);
     temp2[i] = alloc_m2D(c*2 - FSZ*3 + 2, r);
     if(check && check())goto cleanup;
-    free_m2D(tempw+i);
     tempw[i] = convolve_padded(temp[i], af[i&1][2], pt, pc, check); /* w1 */
     if(check && check())goto cleanup;
   }
@@ -808,7 +808,6 @@
     lo[i] = convolve_padded(temp[i], af[i&1][0], pt, pc, check); /* lo */
     if(check && check())goto cleanup;
     free_m2D(temp+i);
-    if(check && check())goto cleanup;
   }
 
  cleanup:
@@ -893,9 +892,10 @@
   
 }
 
-static int wavelet_filter(int width, int height, int planes, guchar *buffer, guchar *mask,
-			  int pr, float T[16],int soft, int (*check)(void)){
+static int wavelet_filter_c(int width, int height, int planes, guchar *buffer,
+			    int pr, float T[16],int soft, int (*check)(void)){
 
+
   int J=4;
   int i,j,p;
   m2D xc={NULL,0,0};
@@ -965,28 +965,15 @@
     if(check && check())goto abort;
 
     /* pull filtered values back out of padded matrix */
-    {
-      int k=0;
-      ptr = buffer+p; 
-      for(i=0;i<height;i++){
-	float *row = yc.x + (i+FSZ-1)*yc.cols + FSZ-1;
-
-	if(mask){
-	  for(j=0;j<width;j++,k++){
-	    float del = mask[k]*.0039215686;
-	    int v = rint(del*row[j]*.5 + (1.-del)* *ptr);
-	    if(v>255)v=255;if(v<0)v=0;
-	    *ptr = v;
-	    ptr+=planes;
-	  }
-	}else{
-	  for(j=0;j<width;j++){
-	    int v = rint(row[j]*.5);
-	    if(v>255)v=255;if(v<0)v=0;
-	    *ptr = v;
-	    ptr+=planes;
-	  }
-	}
+    ptr = buffer+p; 
+    for(i=0;i<height;i++){
+      float *row = yc.x + (i+FSZ-1)*yc.cols + FSZ-1;
+      
+      for(j=0;j<width;j++){
+	int v = rint(row[j]*.5);
+	if(v>255)v=255;if(v<0)v=0;
+	*ptr = v;
+	ptr+=planes;
       }
     }
     
@@ -1001,3 +988,86 @@
   return (check && check());
 }
 
+static int wavelet_filter_f(int width, int height, float *buffer,
+			    int pr, float T[16],int soft, int (*check)(void)){
+
+  int J=4;
+  int i,j;
+  m2D xc={NULL,0,0};
+  m2D yc={NULL,0,0};
+  int pc=0;
+  int pt;
+  float *ptr = buffer; 
+
+  /* we want J to be as 'deep' as the image to eliminate
+     splotchiness with deep coarse settings */
+  
+  while(1){
+    int mult = 1 << (J+1);
+    if(width/mult < 1) break;
+    if(height/mult < 1) break;
+    J++;
+  }
+
+  if(J>15)J=15;
+  pt=(pr?J*108:0);
+  
+  /* Input matrix must be pre-padded for first stage convolutions;
+     odd->even padding goes on the bottom/right */
+
+  xc = alloc_m2D((height+1)/2*2+FSZ*2-2,
+		 (width+1)/2*2+FSZ*2-2),yc;
+  if(check && check())goto abort;
+  
+  /* populate and pad input matrix */
+  for(i=0;i<height;i++){
+    float *row=xc.x + (i+FSZ-1)*xc.cols;
+
+    /* X padding */
+    for(j=0;j<FSZ-1;j++)
+      row[j] = *ptr * .5f;
+
+    /* X filling */
+    for(;j<width+FSZ-1;j++){
+      row[j] = *ptr * .5f;
+      ptr++;
+    }
+    
+    /* X padding */
+    for(;j<xc.cols;j++)
+      row[j] = row[j-1];
+  }
+
+  /* Y padding */
+  for(i=FSZ-2;i>=0;i--){
+    float *pre=xc.x + (i+1)*xc.cols;
+    float *row=xc.x + i*xc.cols;
+    for(j=0;j<xc.cols;j++)
+      row[j]=pre[j];
+  }
+  for(i=xc.rows-FSZ+1;i<xc.rows;i++){
+    float *pre=xc.x + (i-1)*xc.cols;
+    float *row=xc.x + i*xc.cols;
+    for(j=0;j<xc.cols;j++)
+      row[j]=pre[j];
+  }
+
+  if(check && check())goto abort;
+  yc=transform_threshold(xc,J,T,soft,pt,&pc,check);
+  if(check && check())goto abort;
+  
+  /* pull filtered values back out of padded matrix */
+  ptr = buffer;
+  for(i=0;i<height;i++){
+    float *row = yc.x + (i+FSZ-1)*yc.cols + FSZ-1;
+    
+    for(j=0;j<width;j++)
+      *ptr++ = row[j]*.5f;
+  }
+
+ abort:
+  free_m2D(&yc);
+  free_m2D(&xc);
+  return (check && check());
+}
+



More information about the commits mailing list