]> 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
         - $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});
      },
     };
                   $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;
 }
 
   $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)
   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
   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.
 
 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>,
 =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
 
     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
 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_contrast(im, 0.8);
   i_hardinvert(im);
+  i_unsharp_mask(im, 2.0, 1.0);
   // and more
 
 =head1 DESCRIPTION
   // 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);
 }
 
   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);
 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_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);
 
 /* 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);
 
 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');
 
 
 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');
                     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) = @_;
 
 sub test {
   my ($in, $num, $params, $out) = @_;