]> git.imager.perl.org - imager.git/commitdiff
implement unsharp mask
authorTony Cook <tony@develop=help.com>
Wed, 19 Sep 2001 10:59:41 +0000 (10:59 +0000)
committerTony Cook <tony@develop=help.com>
Wed, 19 Sep 2001 10:59:41 +0000 (10:59 +0000)
Changes
Imager.pm
Imager.xs
filters.c
image.h
t/t61filters.t

diff --git a/Changes b/Changes
index e94d7bce5ef29af55bb97221d7e0b598b529f0b4..19c2b63fe20dcdd0575d346afb632b8e34bd84aa 100644 (file)
--- a/Changes
+++ b/Changes
@@ -514,6 +514,7 @@ Revision history for Perl extension Imager.
         - $img->arc() now calls i_circle_aa() if a complete circle is
           being drawn in a plain color
         - image based fills
+        - unsharp mask
 
 =================================================================
 
index ccdb4679be07a131e6ae543187fb7fa625dd7cec..a5d9c04881e8ef5ecc05ff55ccfc3816a81408d0 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -324,6 +324,16 @@ BEGIN {
                   $hsh{ssample_param}, $hsh{segments});
      },
     };
+  $filters{unsharpmask} =
+    {
+     callseq => [ qw(image stddev scale) ],
+     defaults => { stddev=>2.0, scale=>1.0 },
+     callsub => 
+     sub { 
+       my %hsh = @_;
+       i_unsharp_mask($hsh{image}, $hsh{stddev}, $hsh{scale});
+     },
+    };
 
   $FORMATGUESS=\&def_guess_type;
 }
@@ -3022,6 +3032,7 @@ source.
   postlevels      levels(10)
   radnoise        xo(100) yo(100) ascale(17.0) rscale(0.02)
   turbnoise       xo(0.0) yo(0.0) scale(10.0)
+  unsharpmask     stddev(2.0) scale(1.0)
   watermark       wmark pixdiff(10) tx(0) ty(0)
 
 The default values are in parenthesis.  All parameters must have some
@@ -3260,6 +3271,13 @@ renders Perlin turbulent noise.  (I<xo>, I<yo>) controls the origin of
 the noise, and I<scale> the scale of the noise, with lower numbers
 giving more detail.
 
+=item unsharpmask
+
+performs an unsharp mask on the image.  This is the result of
+subtracting a gaussian blurred version of the image from the original.
+I<stddev> controls the stddev parameter of the gaussian blur.  Each
+output pixel is: in + I<scale> * (in - blurred).
+
 =item watermark
 
 applies I<wmark> as a watermark on the image with strength I<pixdiff>,
index ea122a14205f07c7194896e56951a7cf9b7ccf19..11e090a3d0212c69b6d990ae874ffc95019a8331 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -1022,6 +1022,12 @@ i_gaussian(im,stdev)
     Imager::ImgRaw     im
             float     stdev
 
+void
+i_unsharp_mask(im,stdev,scale)
+    Imager::ImgRaw     im
+            float     stdev
+             double    scale
+
 void
 i_conv(im,pcoef)
     Imager::ImgRaw     im
index 473176dbcf2a182041cbb82c7b248e6f9f86a47e..37de5cd70a9b6fdbbd184dcbe8cab537df48190f 100644 (file)
--- a/filters.c
+++ b/filters.c
@@ -13,6 +13,7 @@ filters.c - implements filters that operate on images
   
   i_contrast(im, 0.8);
   i_hardinvert(im);
+  i_unsharp_mask(im, 2.0, 1.0);
   // and more
 
 =head1 DESCRIPTION
@@ -918,6 +919,76 @@ i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasur
   i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
 }
 
+/*
+=item i_unsharp_mask(im, stddev, scale)
+
+Perform an usharp mask, which is defined as subtracting the blurred
+image from double the original.
+
+=cut
+*/
+void i_unsharp_mask(i_img *im, double stddev, double scale) {
+  i_img copy;
+  int x, y, ch;
+
+  if (scale < 0)
+    return;
+  /* it really shouldn't ever be more than 1.0, but maybe ... */
+  if (scale > 100)
+    scale = 100;
+
+  i_copy(&copy, im);
+  i_gaussian(&copy, stddev);
+  if (im->bits == i_8_bits) {
+    i_color *blur = mymalloc(im->xsize * sizeof(i_color) * 2);
+    i_color *out = blur + im->xsize;
+
+    for (y = 0; y < im->ysize; ++y) {
+      i_glin(&copy, 0, copy.xsize, y, blur);
+      i_glin(im, 0, im->xsize, y, out);
+      for (x = 0; x < im->xsize; ++x) {
+        for (ch = 0; ch < im->channels; ++ch) {
+          /*int temp = out[x].channel[ch] + 
+            scale * (out[x].channel[ch] - blur[x].channel[ch]);*/
+          int temp = out[x].channel[ch] * 2 - blur[x].channel[ch];
+          if (temp < 0)
+            temp = 0;
+          else if (temp > 255)
+            temp = 255;
+          out[x].channel[ch] = temp;
+        }
+      }
+      i_plin(im, 0, im->xsize, y, out);
+    }
+
+    myfree(blur);
+  }
+  else {
+    i_fcolor *blur = mymalloc(im->xsize * sizeof(i_fcolor) * 2);
+    i_fcolor *out = blur + im->xsize;
+
+    for (y = 0; y < im->ysize; ++y) {
+      i_glinf(&copy, 0, copy.xsize, y, blur);
+      i_glinf(im, 0, im->xsize, y, out);
+      for (x = 0; x < im->xsize; ++x) {
+        for (ch = 0; ch < im->channels; ++ch) {
+          double temp = out[x].channel[ch] +
+            scale * (out[x].channel[ch] - blur[x].channel[ch]);
+          if (temp < 0)
+            temp = 0;
+          else if (temp > 1.0)
+            temp = 1.0;
+          out[x].channel[ch] = temp;
+        }
+      }
+      i_plinf(im, 0, im->xsize, y, out);
+    }
+
+    myfree(blur);
+  }
+  i_img_exorcise(&copy);
+}
+
 struct fount_state;
 static double linear_fount_f(double x, double y, struct fount_state *state);
 static double bilinear_fount_f(double x, double y, struct fount_state *state);
diff --git a/image.h b/image.h
index d3ed9c5485f9612bf6a4cb4597a65694180a64d5..d669021d5ce6602e328554b49984aa35b5ba496b 100644 (file)
--- a/image.h
+++ b/image.h
@@ -216,6 +216,7 @@ void i_flood_fill  (i_img *im,int seedx,int seedy,i_color *dcol);
 
 void i_gaussian    (i_img *im,float stdev);
 void i_conv        (i_img *im,float *coeff,int len);
+void i_unsharp_mask(i_img *im, double stddev, double scale);
 
 /* colour manipulation */
 extern int i_convert(i_img *im, i_img *src, float *coeff, int outchan, int inchan);
index 136b72300e53731baebabb81ac6b2909bb3919d8..0a51fc8db1aa7ad457f410c090afbae0f2b3a789 100644 (file)
@@ -9,7 +9,7 @@ $imbase->open(file=>'testout/t104.ppm') or die;
 my $im_other = Imager->new(xsize=>150, ysize=>150);
 $im_other->box(xmin=>30, ymin=>60, xmax=>120, ymax=>90, filled=>1);
 
-print "1..35\n";
+print "1..37\n";
 
 test($imbase, 1, {type=>'autolevels'}, 'testout/t61_autolev.ppm');
 
@@ -77,6 +77,8 @@ test($imbase, 34, { type=>'fountain', xa=>75, ya=>75, xb=>90, yb=>15,
                     segments=>$f3, super_sample=>'grid',
                     ftype=>'radial_square', combine=>'color' },
      'testout/t61_fount_gimp.ppm');
+test($imbase, 36, { type=>'unsharpmask', stddev=>2.0 },
+     'testout/t61_unsharp.ppm');
 
 sub test {
   my ($in, $num, $params, $out) = @_;