From b638185132d88acd5b557cd183a00983797ca1e3 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Wed, 19 Sep 2001 10:59:41 +0000 Subject: [PATCH] implement unsharp mask --- Changes | 1 + Imager.pm | 18 +++++++++++++ Imager.xs | 6 +++++ filters.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ image.h | 1 + t/t61filters.t | 4 ++- 6 files changed, 100 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index e94d7bce..19c2b63f 100644 --- 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 ================================================================= diff --git a/Imager.pm b/Imager.pm index ccdb4679..a5d9c048 100644 --- 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, I) controls the origin of the noise, and I 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 controls the stddev parameter of the gaussian blur. Each +output pixel is: in + I * (in - blurred). + =item watermark applies I as a watermark on the image with strength I, diff --git a/Imager.xs b/Imager.xs index ea122a14..11e090a3 100644 --- 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 diff --git a/filters.c b/filters.c index 473176db..37de5cd7 100644 --- 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(©, im); + i_gaussian(©, 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(©, 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(©, 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(©); +} + 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 d3ed9c54..d669021d 100644 --- 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); diff --git a/t/t61filters.t b/t/t61filters.t index 136b7230..0a51fc8d 100644 --- a/t/t61filters.t +++ b/t/t61filters.t @@ -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) = @_; -- 2.39.5