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

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Wed Dec 17 07:27:35 PST 2008


Author: xiphmont
Date: 2008-12-17 07:27:34 -0800 (Wed, 17 Dec 2008)
New Revision: 15587

Modified:
   trunk/gimp-montypak/Makefile
   trunk/gimp-montypak/denoise.c
   trunk/gimp-montypak/scanclean.c
   trunk/gimp-montypak/wavelet.c
Log:
Filter in YCbCr instead of RGB.  Small change, major 
improvement in results.


Modified: trunk/gimp-montypak/Makefile
===================================================================
--- trunk/gimp-montypak/Makefile	2008-12-16 00:55:09 UTC (rev 15586)
+++ trunk/gimp-montypak/Makefile	2008-12-17 15:27:34 UTC (rev 15587)
@@ -14,7 +14,6 @@
 LDCONFIG  = /sbin/ldconfig
 
 TARGETS   = denoise scanclean
-#TARGETS   = denoise scanclean
 VERSION   = $(MAJOR).$(MINOR).$(SUBMINOR)
 BINDIR    = $(PREFIX)/plug-ins
 

Modified: trunk/gimp-montypak/denoise.c
===================================================================
--- trunk/gimp-montypak/denoise.c	2008-12-16 00:55:09 UTC (rev 15586)
+++ trunk/gimp-montypak/denoise.c	2008-12-17 15:27:34 UTC (rev 15587)
@@ -36,7 +36,7 @@
 
 #define PLUG_IN_PROC    "plug-in-denoise"
 #define PLUG_IN_BINARY  "denoise"
-#define PLUG_IN_VERSION "15 Dec 2008"
+#define PLUG_IN_VERSION "17 Dec 2008"
 
 /*
  * Local functions...
@@ -71,7 +71,8 @@
 
 typedef struct
 {
-  float filter;
+  float filterY;
+  float filterC;
   int soft;
   int multiscale;
   float f1;
@@ -84,7 +85,7 @@
 
 static DenoiseParams denoise_params =
 {
-  20, 0, 0,
+  20,30, 0,0,
   0.,0.,0.,0.,
   0,0.
 };
@@ -94,8 +95,9 @@
 static GtkObject    *madj[4];
 static GtkObject    *ladj[1];
 static guchar *preview_cache_blit=NULL;
-static guchar *preview_cache_filter=NULL;
 static float  *preview_cache_luma=NULL;
+static float  *preview_cache_Pb=NULL;
+static float  *preview_cache_Pr=NULL;
 static int     preview_cache_x;
 static int     preview_cache_y;
 static int     preview_cache_w;
@@ -125,6 +127,7 @@
     { GIMP_PDB_FLOAT,    "f4",            "Coarse adjust"                     },
     { GIMP_PDB_INT32,    "lowlight",      "Low light noise mode"              },
     { GIMP_PDB_FLOAT,    "lowlight_adj",  "Low light threshold adj"           },
+    { GIMP_PDB_FLOAT,    "chroma_ratio",  "Chroma smoothing ratio"            },
 
   };
 
@@ -200,18 +203,19 @@
       /*
        * Make sure all the arguments are present...
        */
-      if (nparams != 12)
+      if (nparams != 13)
         status = GIMP_PDB_CALLING_ERROR;
       else{
-        denoise_params.filter = param[3].data.d_float;
-	denoise_params.soft   = param[4].data.d_int32;
-	denoise_params.multiscale = param[5].data.d_int32;
-        denoise_params.f1 = param[6].data.d_float;
-        denoise_params.f2 = param[7].data.d_float;
-        denoise_params.f3 = param[8].data.d_float;
-        denoise_params.f4 = param[9].data.d_float;
-        denoise_params.lowlight = param[10].data.d_int32;
-        denoise_params.lowlight_adj = param[11].data.d_float;
+        denoise_params.filterY = param[3].data.d_float;
+        denoise_params.filterC = param[4].data.d_float;
+	denoise_params.soft   = param[5].data.d_int32;
+	denoise_params.multiscale = param[6].data.d_int32;
+        denoise_params.f1 = param[7].data.d_float;
+        denoise_params.f2 = param[8].data.d_float;
+        denoise_params.f3 = param[9].data.d_float;
+        denoise_params.f4 = param[10].data.d_float;
+        denoise_params.lowlight = param[11].data.d_int32;
+        denoise_params.lowlight_adj = param[12].data.d_float;
       }
       break;
 
@@ -312,12 +316,12 @@
   g_free(buffer);
 }
 
-static void dialog_filter_callback (GtkWidget *widget,
-				    gpointer   data)
+static void dialog_filterY_callback (GtkWidget *widget,
+				     gpointer   data)
 {
-  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;
   if(!preview_toggle->active){
     if(preview_cache_blit)
       g_free(preview_cache_blit);
@@ -325,18 +329,36 @@
   }
 }
 
+static void dialog_filterC_callback (GtkWidget *widget,
+				     gpointer   data)
+{
+  if(preview_cache_Pb)
+    g_free(preview_cache_Pb);
+  preview_cache_Pb=NULL;
+  if(preview_cache_Pr)
+    g_free(preview_cache_Pr);
+  preview_cache_Pr=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)
 {
   denoise_params.soft = (GTK_TOGGLE_BUTTON (widget)->active);
-  if(denoise_params.filter>0.){
-    dialog_filter_callback(widget,data);
+  if(denoise_params.filterY>0.)
+    dialog_filterY_callback(widget,data);
+  if(denoise_params.filterC>0.)
+    dialog_filterC_callback(widget,data);
+  if(denoise_params.filterY>0. || denoise_params.filterC>0.)
     gimp_preview_invalidate (GIMP_PREVIEW (preview));
-  }
 }
 
 static void dialog_multiscale_callback (GtkWidget *widget,
-                          gpointer   data)
+					gpointer   data)
 {
   denoise_params.multiscale = (GTK_TOGGLE_BUTTON (widget)->active);
   gimp_scale_entry_set_sensitive(madj[0],denoise_params.multiscale);
@@ -347,12 +369,26 @@
      denoise_params.f2!=0. ||
      denoise_params.f3!=0. ||
      denoise_params.f4!=0.){
-    dialog_filter_callback(widget,data);
-    gimp_preview_invalidate (GIMP_PREVIEW (preview));
+    if(denoise_params.filterY>0.)
+      dialog_filterY_callback(widget,data);
+    if(denoise_params.filterC>0.)
+      dialog_filterC_callback(widget,data);
+    if(denoise_params.filterY>0. || denoise_params.filterC>0.)
+      gimp_preview_invalidate (GIMP_PREVIEW (preview));
   }
 }
 
-static void dialog_luma_callback (GtkWidget *widget,
+static void dialog_multiadj_callback (GtkWidget *widget,
+				      gpointer data){
+  if(denoise_params.filterY>0.)
+    dialog_filterY_callback(widget,data);
+  if(denoise_params.filterC>0.)
+    dialog_filterC_callback(widget,data);
+  if(denoise_params.filterY>0. || denoise_params.filterC>0.)
+    gimp_preview_invalidate (GIMP_PREVIEW (preview));
+}
+
+static void dialog_mask_callback (GtkWidget *widget,
 				  gpointer   data)
 {
   if(!preview_toggle->active){
@@ -367,7 +403,7 @@
 {
   denoise_params.lowlight = (GTK_TOGGLE_BUTTON (widget)->active);
   gimp_scale_entry_set_sensitive(ladj[0],denoise_params.lowlight);
-  dialog_luma_callback(widget,data);
+  dialog_mask_callback(widget,data);
   gimp_preview_invalidate (GIMP_PREVIEW (preview));
 }
 
@@ -393,7 +429,7 @@
   GtkWidget *button;
   GtkObject *adj;
   gboolean   run;
-
+  gint       planes = gimp_drawable_bpp (drawable->drawable_id);
   gimp_ui_init (PLUG_IN_BINARY, TRUE);
 
   dialog = gimp_dialog_new ("Denoise", PLUG_IN_BINARY,
@@ -427,27 +463,46 @@
   gtk_container_foreach(GTK_CONTAINER(gimp_preview_get_controls(GIMP_PREVIEW(preview))),
 			find_preview_toggle,NULL);
 
-  /* Main filter strength adjust */
-  table = gtk_table_new (1, 3, FALSE);
+  /* Filter strength adjust */
+  table = gtk_table_new (1+(planes>2), 3, FALSE);
   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
   gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
   gtk_widget_show (table);
 
+  /* Luma denoise */
   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
-                              "_Denoise", 300, 0,
-                              denoise_params.filter,
+			      (planes>2?"Luma _Denoise":"_Denoise"),
+                              300, 0,
+                              denoise_params.filterY,
                               0, 100, 1, 10, 0,
                               TRUE, 0, 0,
                               NULL, NULL);
   g_signal_connect (adj, "value-changed",
                     G_CALLBACK (gimp_float_adjustment_update),
-                    &denoise_params.filter);
+                    &denoise_params.filterY);
   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);
+  g_signal_connect (adj, "value-changed",G_CALLBACK (dialog_filterY_callback),NULL);
 
 
+  /* Chroma filter strength adjust */
+  if(planes>2){
+    adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
+				"_Chroma Denoise", 300, 0,
+				denoise_params.filterC,
+				0, 100, 1, 10, 0,
+				TRUE, 0, 0,
+				NULL, NULL);
+    g_signal_connect (adj, "value-changed",
+                    G_CALLBACK (gimp_float_adjustment_update),
+                    &denoise_params.filterC);
+    g_signal_connect_swapped (adj, "value-changed",
+			      G_CALLBACK (gimp_preview_invalidate),
+			      preview);
+    g_signal_connect (adj, "value-changed",G_CALLBACK (dialog_filterC_callback),NULL);
+  }
+
   /* Threshold shape */
   button = gtk_check_button_new_with_mnemonic ("So_ft thresholding");
   gtk_box_pack_start (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
@@ -484,7 +539,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);
+  g_signal_connect (adj, "value-changed",G_CALLBACK (dialog_mask_callback),NULL);
   gimp_scale_entry_set_sensitive(ladj[0],denoise_params.lowlight);
 
   /* multiscale adjust select */
@@ -514,10 +569,7 @@
   g_signal_connect (adj, "value-changed",
                     G_CALLBACK (gimp_float_adjustment_update),
                     &denoise_params.f1);
-  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);
+  g_signal_connect (adj,"value-changed",G_CALLBACK(dialog_multiadj_callback),NULL);
 
   /* detail adjust */
   madj[1] = adj = gimp_scale_entry_new (GTK_TABLE (table), 1, 1,
@@ -529,10 +581,7 @@
   g_signal_connect (adj, "value-changed",
                     G_CALLBACK (gimp_float_adjustment_update),
                     &denoise_params.f2);
-  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);
+  g_signal_connect (adj,"value-changed",G_CALLBACK(dialog_multiadj_callback),NULL);
 
   /* mid adjust */
   madj[2] = adj = gimp_scale_entry_new (GTK_TABLE (table), 1, 2,
@@ -544,11 +593,8 @@
   g_signal_connect (adj, "value-changed",
                     G_CALLBACK (gimp_float_adjustment_update),
                     &denoise_params.f3);
-  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);
-
+  g_signal_connect (adj,"value-changed",G_CALLBACK(dialog_multiadj_callback),NULL);
+  
   /* Coarse adjust */
   madj[3] = adj = gimp_scale_entry_new (GTK_TABLE (table), 1, 3,
 					"_Coarse denoise:", 300, 0,
@@ -559,10 +605,7 @@
   g_signal_connect (adj, "value-changed",
                     G_CALLBACK (gimp_float_adjustment_update),
                     &denoise_params.f4);
-  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);
+  g_signal_connect (adj,"value-changed",G_CALLBACK(dialog_multiadj_callback),NULL);
 
   gimp_scale_entry_set_sensitive(madj[0],denoise_params.multiscale);
   gimp_scale_entry_set_sensitive(madj[1],denoise_params.multiscale);
@@ -578,13 +621,16 @@
     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;
+  if(preview_cache_Pb)
+    g_free(preview_cache_Pb);
+  preview_cache_Pb=NULL;
+  if(preview_cache_Pr)
+    g_free(preview_cache_Pr);
+  preview_cache_Pr=NULL;
+
   return run;
 }
 
@@ -600,6 +646,12 @@
 #include "varmean.c"
 #define clamp(x) ((x)<0?0:((x)>255?255:(x)))
 
+#define Kr 0.2126f
+#define Kb 0.0722f
+#define Kg (1.f-Kr-Kb)
+#define Ir (2.f*Kr-2.f)
+#define Ib (2.f*Kb-2.f)
+
 static void compute_luma(guchar *buffer, guchar *luma, int width, int height, int planes){
   int i;
   switch(planes){
@@ -613,41 +665,68 @@
     break;
   case 3:
     for(i=0;i<width*height;i++)
-      luma[i]=buffer[i*3]*.2126 + buffer[i*3+1]*.7152 + buffer[i*3+2]*.0722;
+      luma[i]=clamp(rint(buffer[i*3]*Kr + 
+			 buffer[i*3+1]*Kg + 
+			 buffer[i*3+2]*Kb));
     break;
   case 4:
     for(i=0;i<width*height;i++)
-      luma[i]=buffer[i*4]*.2126 + buffer[i*4+1]*.7152 + buffer[i*4+2]*.0722;
+      luma[i]=clamp(rint(buffer[i*4]*Kr + 
+			 buffer[i*4+1]*Kg + 
+			 buffer[i*4+2]*Kb));
     break;
   }
 }
 
-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;
+static int compute_YPbPr(guchar *buffer, float *luma, float *Pb, float *Pr, 
+			 int width, int height, int planes, int (*check)(void)){
+  int i,j;
+  if(!check && planes>2)
+    gimp_progress_init( "Converting colorspace...");
+
+  for(j=0;j<height*width;j+=width){
+    switch(planes){
+    case 1:
+      for(i=j;i<j+width;i++)
+	if(luma)luma[i]=buffer[i];
+      break;
+    case 2: 
+      for(i=j;i<j+width;i++)
+	if(luma)luma[i]=buffer[i<<1];
+      break;
+    case 3:
+      for(i=j;i<j+width;i++){
+	float Y = buffer[i*3]*Kr + buffer[i*3+1]*Kg + buffer[i*3+2]*Kb;
+	if(luma)luma[i]=Y;
+	if(Pb) Pb[i] = (buffer[i*3+2] - Y) * (.5f / (1.f - Kb));
+	if(Pr) Pr[i] = (buffer[i*3] - Y) * (.5f / (1.f - Kr));
+      }
+      if(!check && planes>2)
+	gimp_progress_update((float)i/(width*height));
+      break;
+    case 4:
+      for(i=j;i<j+width;i++){
+	float Y = buffer[i*4]*Kr + buffer[i*4+1]*Kg + buffer[i*4+2]*Kb;
+	if(luma) luma[i]=Y;
+	if(Pb) Pb[i] = (buffer[i*4+2] - Y) * (.5f / (1.f - Kb));
+	if(Pr) Pr[i] = (buffer[i*4] - Y) * (.5f / (1.f - Kr)); 
+      }
+      if(!check && planes>2)
+	gimp_progress_update((float)i/(width*height));
+      break;
+    }
+
+    if(check && check())return 1;
   }
+  if(!check && planes>2)
+    gimp_progress_end();
+  return 0;
 }
 
+#define computeR(Y,Pb,Pr) ((Y) - Ir*(Pr))
+#define computeG(Y,Pb,Pr) ((Y) + (Ir*Kr/Kg)*(Pr) + (Ib*Kb/Kg)*(Pb))
+#define computeB(Y,Pb,Pr) ((Y) - Ib*(Pb))
+
 /* find the variance median for the whole image, not just preview, not just the selection */
 static void denoise_pre(GimpDrawable *drawable){
 
@@ -697,103 +776,120 @@
   }
 }
 
-static float *compute_smoothed_luma(guchar *buffer, int w, int h, int p, 
-				    int pr, int (*check)(void)){
+static int compute_filter(float *buffer, int w, int h, float f, int (*check)(void), char *m){
   int i;
   float T[16];
-  float *luma = g_new(float,w*h);
 
-  if(pr)gimp_progress_init( "Analyzing luma...");
-  
-  compute_luma_f(buffer,luma,w,h,p);
-  if(check && check()){
-    g_free(luma);
-    return NULL;
-  } 
+  if(!buffer)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(f>0){
+    
+    for(i=0;i<16;i++)
+      T[i]=f*.2;
+    
+    if(denoise_params.multiscale){
+      T[0]*=(denoise_params.f1+100)*.01;
+      T[1]*=(denoise_params.f2+100)*.01;
+      T[2]*=(denoise_params.f3+100)*.01;
+      for(i=3;i<16;i++)
+	T[i]*=(denoise_params.f4+100)*.01;
+      
+      for(i=0;i<16;i++)
+	if(T[i]!=0.f) break;
+      if(i==16) return 0;
+    }
+    
+    if(m)gimp_progress_init(m);
+    i = wavelet_filter(w, h, buffer, (m!=NULL), T, denoise_params.soft, check);
+    if(m)gimp_progress_end();
+    return i;
   }
-  
-  if(pr)gimp_progress_end();
-  return luma;
+  return 0;
 }
 
-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++)
-    T[i]=denoise_params.filter*.2;
-  
-  if(denoise_params.multiscale){
-    T[0]*=(denoise_params.f1+100)*.01;
-    T[1]*=(denoise_params.f2+100)*.01;
-    T[2]*=(denoise_params.f3+100)*.01;
-    for(i=3;i<16;i++)
-      T[i]*=(denoise_params.f4+100)*.01;
-  }
-  
-  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(pr)gimp_progress_end();
-  return filtered;
-}
-
-static int combine_filter_luma(guchar *buffer, guchar *filtered, float *luma,
-			       int w, int h, int p, int pr, int(*check)(void)){
-  int i,j,k;
-  
+static int compute_mask(guchar *buffer, float *luma, float *Pb, float *Pr,
+			int w, int h, int p, int(*check)(void)){
+  int i,j;
   if(denoise_params.lowlight){
     float l = denoise_params.lowlight_adj*.01;
-    float med = variance_median*(8.f/255.f);
+    float med = variance_median*8.f;
 
-    if(pr)gimp_progress_init( "Merging...");
+    if(!check)gimp_progress_init( "Masking and unconverting...");
 
     if(l>0){
-      med += (1.-med)*l;
+      med += (255.-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;
+    switch(p){
+    case 1:case 2:
+      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;	
+	  buffer[j*p] = clamp(rint(luma[j]*mask + (1.f-mask)*buffer[j*p]));
+	}
+	if(!check)gimp_progress_update((gfloat)(i+w)/(w*h));
+	if(check && check()){
+	  if(!check)gimp_progress_end();
+	  return 1;
+	}
       }
-      if(pr)gimp_progress_update((gfloat)(i+w)/(w*h));
-      if(check && check()){
-	if(pr)gimp_progress_end();
-	return 1;
+      break;
+    case 3:case 4:
+      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;	
+	  buffer[j*p]   = clamp(rint(computeR(luma[j],Pb[j],Pr[j])*mask + (1.f-mask)*buffer[j*p]));
+	  buffer[j*p+1] = clamp(rint(computeG(luma[j],Pb[j],Pr[j])*mask + (1.f-mask)*buffer[j*p+1]));
+	  buffer[j*p+2] = clamp(rint(computeB(luma[j],Pb[j],Pr[j])*mask + (1.f-mask)*buffer[j*p+2]));
+	}
+	if(!check)gimp_progress_update((gfloat)(i+w)/(w*h));
+	if(check && check()){
+	  if(!check)gimp_progress_end();
+	  return 1;
+	}
       }
+      break;
     }
-    if(pr)gimp_progress_end();
+    if(!check)gimp_progress_end();
   }else{
-    memcpy(buffer,filtered,sizeof(*buffer)*w*h*p);
+
+    if(!check)gimp_progress_init( "Unconverting...");
+
+    switch(p){
+    case 1:case 2:
+      for(i=0;i<w*h;i+=w){
+	for(j=i;j<i+w;j++){
+	  buffer[j*p] = clamp(rint(luma[j]));
+	}
+	if(!check)gimp_progress_update((gfloat)(i+w)/(w*h));
+	if(check && check()){
+	  if(!check)gimp_progress_end();
+	  return 1;
+	}
+      }
+      break;
+    case 3:case 4:
+      for(i=0;i<w*h;i+=w){
+	for(j=i;j<i+w;j++){
+	  buffer[j*p]   = clamp(rint(computeR(luma[j],Pb[j],Pr[j])));
+	  buffer[j*p+1] = clamp(rint(computeG(luma[j],Pb[j],Pr[j])));
+	  buffer[j*p+2] = clamp(rint(computeB(luma[j],Pb[j],Pr[j])));
+	}
+	if(!check)gimp_progress_update((gfloat)(i+w)/(w*h));
+	if(check && check()){
+	  if(!check)gimp_progress_end();
+	  return 1;
+	}
+      }
+      break;
+    }
+    if(!check)gimp_progress_end();
   }
   return 0;
 }
@@ -834,14 +930,18 @@
       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;
 
+    if(preview_cache_Pb)
+      g_free(preview_cache_Pb);
+    preview_cache_Pb=NULL;
+
+    if(preview_cache_Pr)
+      g_free(preview_cache_Pr);
+    preview_cache_Pr=NULL;
+
   }
 
   denoise_active_interrupt=1;
@@ -860,36 +960,57 @@
     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 */
-    }
+    /* compute what filtered planes we actually need */
+    {
+      float *tempY = NULL;
+      float *tempPb = NULL;
+      float *tempPr = NULL;
 
-    /* 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 */
+      if(preview_cache_luma == NULL) tempY = g_new(float,w*h);
+      if(bpp > 2 && preview_cache_Pb == NULL) tempPb = g_new(float,w*h);
+      if(bpp > 2 && preview_cache_Pr == NULL) tempPr = g_new(float,w*h);
+ 
+      compute_YPbPr(buffer,tempY,tempPb,tempPr,w,h,bpp, check_recompute);
+
+      if(!compute_filter(tempY, w, h, denoise_params.filterY, check_recompute, NULL)){
+	preview_cache_luma = tempY;
+	tempY = NULL;
+      }
+	
+      if(!compute_filter(tempPb, w, h, denoise_params.filterC, check_recompute, NULL)){
+	preview_cache_Pb = tempPb;
+	tempPb = NULL;
+      }
+
+      if(!compute_filter(tempPr, w, h, denoise_params.filterC, check_recompute, NULL)){
+	preview_cache_Pr = tempPr;
+	tempPr = NULL;
+      }
+
+      if(tempY) g_free(tempY);
+      if(tempPb) g_free(tempPb);
+      if(tempPr) g_free(tempPr);
+
+      if(check_recompute())continue;
     }
-
+    
     /* new blit */
-    if(preview_cache_filter && preview_cache_luma){
-      if(combine_filter_luma(buffer, preview_cache_filter, 
-			     preview_cache_luma, w, h, bpp, 0, check_recompute))
-	continue; /* interrupted */
+    if(compute_mask(buffer, preview_cache_luma, preview_cache_Pb, preview_cache_Pr, 
+		    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;
+    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);
-    }
+    gimp_preview_draw_buffer (GIMP_PREVIEW(preview), preview_cache_blit, w*bpp);
+    gimp_drawable_flush (drawable);
+
   }
   
   if(buffer) g_free(buffer);
@@ -897,14 +1018,20 @@
 }
 
 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, 1, NULL);
-    g_free(f);
-    g_free(l);
-  }else{
-    compute_filter(buffer, w, h, p, 1, 1, NULL);
-  }
+  float *Y = g_new(float,w*h);
+  float *Pb = (p<3 ? NULL : g_new(float,w*h));
+  float *Pr = (p<3 ? NULL : g_new(float,w*h));
+ 
+  compute_YPbPr(buffer,Y,Pb,Pr,w,h,p,NULL);
+  compute_filter(Y, w, h, denoise_params.filterY, NULL, (p>2?"Filtering luma...":"Filtering..."));
+  compute_filter(Pb, w, h, denoise_params.filterC, NULL, "Filtering blue difference...");
+  compute_filter(Pr, w, h, denoise_params.filterC, NULL, "Filtering red difference...");
+
+  compute_mask(buffer, Y, Pb, Pr, w, h, p, NULL);
+
+  if(Y)g_free(Y);
+  if(Pb)g_free(Pb);
+  if(Pr)g_free(Pr);
+
 }
 

Modified: trunk/gimp-montypak/scanclean.c
===================================================================
--- trunk/gimp-montypak/scanclean.c	2008-12-16 00:55:09 UTC (rev 15586)
+++ trunk/gimp-montypak/scanclean.c	2008-12-17 15:27:34 UTC (rev 15587)
@@ -680,7 +680,7 @@
 #include "blur.c"
 
 /* sliding window mean/variance collection */
-#if 0
+#if 1
 static inline void collect_var(guchar *b, double *v, guchar *m, int w, int h, int n){
   int i;
   memcpy(m,b,sizeof(*b)*w*h);
@@ -1037,7 +1037,7 @@
     memcpy(filter,buffer,sizeof(*buffer)*w*h);
 
     /* var/mean for Niblack eqs. */
-    collect_var(buffer,variances,means,w,h,20);
+    collect_var(buffer,variances,means,w,h,10);
 
     /* Sauvola thresholding for background construction */
     for(i=0;i<w*h;i++){
@@ -1057,44 +1057,53 @@
     /* re-threshold */
     /* Subtly different from the Sauvola method above; although the
        equation looks the same, our threshold is being based on the
-       constructed background, *not* the means. */
+       constructed background, *not* the means. This means that
+       variance is lending some detection positive feedback */
 
     for(i=0;i<w*h;i++){
       foreground[i]=0;
-      if(filter[i] < background[i]*(1+.5*(sqrt(variances[i])/128-1.)))
+      if(filter[i] < background[i]*(1+.77*(sqrt(variances[i])/128-1.)))
 	foreground[i]=3;
     }
 
 
     for(i=0;i<w*h;i++){
       if(!foreground[i])
-	if(filter[i] < background[i]*(1+.15*(sqrt(variances[i])/128-1.)))
+	if(filter[i] < background[i]*(1+.25*(sqrt(variances[i])/128-1.)))
 	  foreground[i]=1;
       
     }
 
-    
-
-
-    /* flood fill 'sensitive' areas from 'insensitive' areas */
-    flood_foreground(foreground, w, h);
-
-    /* grow the outer foreground by two */
-    //grow_foreground(foreground,w,h);
-
     {
       /* compute global distance */
-
       int dn=0;
+      d=0;
       for(i=0;i<w*h;i++)
 	if(foreground[i]==3){
-	  d+=means[i]-filter[i];
+	  d+= (means[i]-filter[i])*(means[i]-filter[i]);
 	  dn++;
 	}
-      
       d/=dn;
+      d=sqrt(d);
     }
 
+    /* flood fill 'sensitive' areas from 'insensitive' areas */
+    flood_foreground(foreground, w, h);
+
+
+    for(i=0;i<w*h;i++){
+      if(foreground[i])
+	if(filter[i] > background[i]*(1-.05*(sqrt(variances[i])/128-1.)))
+	  foreground[i]=0;
+      
+    }
+
+
+
+
+    /* grow the outer foreground by two */
+    //grow_foreground(foreground,w,h);
+
     if(p.autoclean)
     {
       /* The immediate vicinity of a character needs a slight unsharp
@@ -1121,8 +1130,6 @@
 
     
 
-    
-
     {      
       //for(i=0;i<w*h;i++){
       //double white = background[i]-(1.-p.white_percent*.01)*d;
@@ -1133,7 +1140,9 @@
       //}
 
       for(i=0;i<w*h;i++){
-	if(foreground[i]){
+	if(foreground[i]==3){
+	  filter[i] = 0.;
+	}else if(foreground[i]){
 	  double white = means[i]-d*(1.-(p.white_percent*.01+.5));
 	  double black = means[i]-d + (p.black_percent*.01)*(means[i]-d);
 	  double dd = white-black;
@@ -1147,14 +1156,9 @@
     }
 
 
+    memcpy(buffer,filter,sizeof(guchar)*w*h);
 
-    if(p.autorotate)
-      for(i=0;i<w*h;i++)
-	buffer[i]=sqrt(variances[i]);
-    else
-      memcpy(buffer,filter,sizeof(guchar)*w*h);
 
-
   }
 
   if(p.autolevel)

Modified: trunk/gimp-montypak/wavelet.c
===================================================================
--- trunk/gimp-montypak/wavelet.c	2008-12-16 00:55:09 UTC (rev 15586)
+++ trunk/gimp-montypak/wavelet.c	2008-12-17 15:27:34 UTC (rev 15587)
@@ -893,107 +893,9 @@
   
 }
 
-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};
-  m2D yc={NULL,0,0};
-  int pc=0;
-  int pt=0;
-  /* we want J to be as 'deep' as the image to eliminate
-     splotchiness with deep coarse settings */
+static int wavelet_filter(int width, int height, float *buffer,
+			    int pr, float T[16], int soft, int (*check)(void)){
   
-  while(1){
-    int mult = 1 << (J+1);
-    if(width/mult < 1) break;
-    if(height/mult < 1) break;
-    J++;
-  }
-
-  if(J>15)J=15;
-  if(pr)
-    for(i=0;i<J && i<10;i++)
-      pt+=108*(1<<(9-i>0?(9-i)*2:1));
-  pt*=planes;
-  
-  /* 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;
-  
-  /* loop through planes */
-  for(p=0;p<planes;p++){
-    guchar *ptr = buffer+p; 
-    
-    /* 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 * .5;
-
-      /* X filling */
-      for(;j<width+FSZ-1;j++){
-	row[j] = *ptr * .5;
-	ptr+=planes;
-      }
-    
-      /* 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+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;
-      }
-    }
-    
-    if(check && check())goto abort;
-    free_m2D(&yc);
-    if(check && check())goto abort;
-  }
-
- abort:
-  free_m2D(&yc);
-  free_m2D(&xc);
-  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};
@@ -1002,6 +904,8 @@
   int pt=0;
   float *ptr = buffer; 
 
+  if(check && check())goto abort;
+
   /* we want J to be as 'deep' as the image to eliminate
      splotchiness with deep coarse settings */
   



More information about the commits mailing list