diff -ubr Imager-1.011-ORIG/Imager.pm Imager-1.011-PG/Imager.pm
--- Imager-1.011-ORIG/Imager.pm 2019-03-06 22:15:05.000000000 -0500
+++ Imager-1.011-PG/Imager.pm 2020-03-12 13:29:09.224962719 -0400
@@ -49,6 +49,7 @@
i_count_colors
i_gaussian
+ i_gaussian2
i_conv
i_convert
@@ -279,6 +280,11 @@
defaults => { },
callsub => sub { my %hsh = @_; i_gaussian($hsh{image}, $hsh{stddev}); },
};
+ $filters{gaussian2} = {
+ callseq => [ 'image', 'stddevX', 'stddevY' ],
+ defaults => { },
+ callsub => sub { my %hsh = @_; i_gaussian2($hsh{image}, $hsh{stddevX}, $hsh{stddevY}); },
+ };
$filters{mosaic} =
{
callseq => [ qw(image size) ],
Only in Imager-1.011-PG/: Imager.pm~
diff -ubr Imager-1.011-ORIG/Imager.xs Imager-1.011-PG/Imager.xs
--- Imager-1.011-ORIG/Imager.xs 2019-03-06 19:03:57.000000000 -0500
+++ Imager-1.011-PG/Imager.xs 2020-03-12 13:07:13.526887687 -0400
@@ -2251,9 +2251,15 @@
RETVAL
undef_int
-i_gaussian(im,stdev)
+i_gaussian(im,stddev)
Imager::ImgRaw im
- im_double stdev
+ im_double stddev
+
+undef_int
+i_gaussian2(im,stddevX,stddevY)
+ Imager::ImgRaw im
+ im_double stddevX
+ im_double stddevY
void
i_unsharp_mask(im,stdev,scale)
diff -ubr Imager-1.011-ORIG/gaussian.im Imager-1.011-PG/gaussian.im
--- Imager-1.011-ORIG/gaussian.im 2014-01-10 04:46:40.000000000 -0500
+++ Imager-1.011-PG/gaussian.im 2020-03-12 15:16:11.036095579 -0400
@@ -19,28 +19,22 @@
int
i_gaussian(i_img *im, double stddev) {
- int i, c, ch;
- i_img_dim x, y;
- double pc;
- double *coeff;
- double res[MAXCHANNELS];
- i_img *timg;
- int radius, diameter;
- dIMCTXim(im);
+ return i_gaussian2( im, stddev, stddev );
+}
- im_log((aIMCTX, 1,"i_gaussian(im %p, stdev %.2f)\n",im,stddev));
- i_clear_error();
+typedef struct s_gauss_coeff {
+ int diameter;
+ int radius;
+ double *coeff;
+} t_gauss_coeff;
- if (stddev <= 0) {
- i_push_error(0, "stddev must be positive");
- return 0;
- }
- /* totally silly cutoff */
- if (stddev > 1000) {
- stddev = 1000;
- }
- timg = i_sametype(im, im->xsize, im->ysize);
+static t_gauss_coeff *build_coeff( i_img *im, double stddev ) {
+ double *coeff = NULL;
+ double pc;
+ int radius, diameter, i;
+ t_gauss_coeff *ret = mymalloc(sizeof(struct s_gauss_coeff));
+ ret->coeff = NULL;
if (im->bits <= 8)
radius = ceil(2 * stddev);
@@ -53,25 +47,98 @@
for(i=0;i <= radius;i++)
coeff[radius + i]=coeff[radius - i]=gauss(i, stddev);
- pc=0;
+ pc=0.0;
for(i=0; i < diameter; i++)
pc+=coeff[i];
- for(i=0;i < diameter;i++)
+ for(i=0;i < diameter;i++) {
coeff[i] /= pc;
+ // im_log((aIMCTX, 1, "i_gaussian2 Y i=%i coeff=%.2f\n", i, coeff[i] ));
+ }
+
+ ret->diameter = diameter;
+ ret->radius = radius;
+ ret->coeff = coeff;
+ return ret;
+}
+
+static void free_coeff(t_gauss_coeff *co ) {
+
+ if( co->coeff != NULL )
+ myfree( co->coeff );
+ myfree( co );
+}
+
+#define img_copy(dest, src) i_copyto( (dest), (src), 0,0, (src)->xsize,(src)->ysize, 0,0);
+
+
+
+int
+i_gaussian2(i_img *im, double stddevX, double stddevY) {
+ int c, ch;
+ i_img_dim x, y;
+ double pc;
+ t_gauss_coeff *co = NULL;
+ double res[MAXCHANNELS];
+ i_img *timg;
+ dIMCTXim(im);
+
+ im_log((aIMCTX, 1,"i_gaussian2(im %p, stddev %.2f,%.2f)\n",im,stddevX,stddevY));
+ i_clear_error();
+
+ if (stddevX < 0) {
+ i_push_error(0, "stddevX must be positive");
+ return 0;
+ }
+ if (stddevY < 0) {
+ i_push_error(0, "stddevY must be positive");
+ return 0;
+ }
+
+ if( stddevX == stddevY && stddevY == 0 ) {
+ i_push_error(0, "stddevX or stddevY must be positive");
+ return 0;
+ }
+
+
+ /* totally silly cutoff */
+ if (stddevX > 1000) {
+ stddevX = 1000;
+ }
+ if (stddevY > 1000) {
+ stddevY = 1000;
+ }
+ timg = i_sametype(im, im->xsize, im->ysize);
+
+ if( stddevX > 0 ) {
+ /* Build Y coefficient matrix */
+ co = build_coeff( im, stddevX );
+ im_log((aIMCTX, 1, "i_gaussian2 X coeff radius=%i diamter=%i coeff=%p\n", co->radius, co->diameter, co->coeff));
+ }
+ else {
+ im_log((aIMCTX, 1, "i_gaussian2 X coeff is unity\n"));
+ }
#code im->bits <= 8
IM_COLOR rcolor;
+ i_img *yin;
+ i_img *yout;
+
+ if( stddevX > 0 ) {
+ /******************/
+ /* Process X blur */
+ im_log((aIMCTX, 1, "i_gaussian2 X blur from im=%p to timg=%p\n", im, timg));
+
for(y = 0; y < im->ysize; y++) {
for(x = 0; x < im->xsize; x++) {
pc=0.0;
for(ch=0;ch<im->channels;ch++)
res[ch]=0;
- for(c = 0;c < diameter; c++)
- if (IM_GPIX(im,x+c-radius,y,&rcolor)!=-1) {
+ for(c = 0;c < co->diameter; c++)
+ if (IM_GPIX(im,x+c-co->radius,y,&rcolor)!=-1) {
for(ch=0;ch<im->channels;ch++)
- res[ch]+= rcolor.channel[ch] * coeff[c];
- pc+=coeff[c];
+ res[ch]+= rcolor.channel[ch] * co->coeff[c];
+ pc+=co->coeff[c];
}
for(ch=0;ch<im->channels;ch++) {
double value = res[ch] / pc;
@@ -80,27 +147,73 @@
IM_PPIX(timg, x, y, &rcolor);
}
}
+ /* processing is im -> timg=yin -> im=yout */
+ yin = timg;
+ yout = im;
+ }
+ else {
+ /* processing is im=yin -> timg=yout -> im */
+ yin = im;
+ yout = timg;
+ }
+ if( stddevY > 0 ) {
+ if( stddevX != stddevY ) {
+ if( co != NULL ) {
+ free_coeff(co);
+ co = NULL;
+ }
+
+ /* Build Y coefficient matrix */
+ co = build_coeff( im, stddevY );
+ im_log((aIMCTX, 1, "i_gaussian2 Y coeff radius=%i diamter=%i coeff=%p\n", co->radius, co->diameter, co->coeff));
+ }
+
+ /******************/
+ /* Process Y blur */
+ im_log((aIMCTX, 1, "i_gaussian2 Y blur from yin=%p to yout=%p\n", yin, yout));
for(x = 0;x < im->xsize; x++) {
for(y = 0; y < im->ysize; y++) {
pc=0.0;
for(ch=0; ch<im->channels; ch++)
res[ch]=0;
- for(c=0; c < diameter; c++)
- if (IM_GPIX(timg, x, y+c-radius, &rcolor)!=-1) {
- for(ch=0;ch<im->channels;ch++)
- res[ch]+= rcolor.channel[ch] * coeff[c];
- pc+=coeff[c];
+ for(c=0; c < co->diameter; c++)
+ if (IM_GPIX(yin, x, y+c-co->radius, &rcolor)!=-1) {
+ for(ch=0;ch<yin->channels;ch++)
+ res[ch]+= rcolor.channel[ch] * co->coeff[c];
+ pc+=co->coeff[c];
}
- for(ch=0;ch<im->channels;ch++) {
+ for(ch=0;ch<yin->channels;ch++) {
double value = res[ch]/pc;
rcolor.channel[ch] = value > IM_SAMPLE_MAX ? IM_SAMPLE_MAX : IM_ROUND(value);
}
- IM_PPIX(im, x, y, &rcolor);
+ IM_PPIX(yout, x, y, &rcolor);
+ }
}
+ if( im != yout ) {
+ im_log((aIMCTX, 1, "i_gaussian2 copying yout=%p to im=%p\n", yout, im));
+ img_copy( im, yout );
}
+ }
+ else {
+ im_log((aIMCTX, 1, "i_gaussian2 Y coeff is unity\n"));
+ if( yin==timg ) {
+ im_log((aIMCTX, 1, "i_gaussian2 copying timg=%p to im=%p\n", timg, im));
+ img_copy( im, timg );
+ }
+ }
+
+ im_log((aIMCTX, 1, "i_gaussian2 im=%p\n", im));
+ im_log((aIMCTX, 1, "i_gaussian2 timg=%p\n", timg));
+ im_log((aIMCTX, 1, "i_gaussian2 yin=%p\n", yin));
+ im_log((aIMCTX, 1, "i_gaussian2 yout=%p\n", yout));
+
+
+
#/code
- myfree(coeff);
+ if( co != NULL )
+ free_coeff(co);
+
i_img_destroy(timg);
return 1;
diff -ubr Imager-1.011-ORIG/imager.h Imager-1.011-PG/imager.h
--- Imager-1.011-ORIG/imager.h 2019-03-06 19:03:57.000000000 -0500
+++ Imager-1.011-PG/imager.h 2020-03-12 13:08:14.292872226 -0400
@@ -178,7 +178,8 @@
/* image processing functions */
-int i_gaussian (i_img *im, double stdev);
+int i_gaussian (i_img *im, double stddev);
+int i_gaussian2 (i_img *im, double stddevX, double stddevY);
int i_conv (i_img *im,const double *coeff,int len);
void i_unsharp_mask(i_img *im, double stddev, double scale);
diff -ubr Imager-1.011-ORIG/lib/Imager/Filters.pod Imager-1.011-PG/lib/Imager/Filters.pod
--- Imager-1.011-ORIG/lib/Imager/Filters.pod 2014-04-12 18:12:11.000000000 -0400
+++ Imager-1.011-PG/lib/Imager/Filters.pod 2020-03-12 14:13:09.642294725 -0400
@@ -101,6 +101,9 @@
gaussian stddev
+ gaussian2 stddevX
+ stddevY
+
gradgen xo yo colors
dist 0
@@ -456,6 +459,26 @@
$img->filter(type=>"gaussian", stddev=>5)
or die $img->errstr;
+=item gaussian2
+
+performs a Gaussian blur of the image, using C<stddevX>, C<stddevY> as the
+standard deviation of the curve used to combine pixels on the X and Y axis,
+respectively. Larger values give bigger blurs. For a definition of Gaussian
+Blur, see:
+
+
http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node99.html
+
+Values of C<stddevX> or C<stddevY> around 0.5 provide a barely noticeable blur,
+values around 5 provide a very strong blur.
+
+ # only slightly blurred
+ $img->filter(type=>"gaussian2", stddevX=>0.5, stddevY=>0.5)
+ or die $img->errstr;
+
+ # blur an image in the Y axis
+ $img->filter(type=>"gaussian", stddevX=>0, stddevY=>5 )
+ or die $img->errstr;
+
=item gradgen
renders a gradient, with the given I<colors> at the corresponding
diff -ubr Imager-1.011-ORIG/t/400-filter/010-filters.t Imager-1.011-PG/t/400-filter/010-filters.t
--- Imager-1.011-ORIG/t/400-filter/010-filters.t 2014-04-12 18:12:11.000000000 -0400
+++ Imager-1.011-PG/t/400-filter/010-filters.t 2020-03-12 15:11:52.293117482 -0400
@@ -1,7 +1,7 @@
#!perl -w
use strict;
use Imager qw(:handy);
-use Test::More tests => 124;
+use Test::More tests => 136;
-d "testout" or mkdir "testout";
@@ -67,6 +67,34 @@
is_image_similar($gauss, $gauss16, 250000, "8 and 16 gaussian match");
}
+{
+ my $imbase = Imager->new( xsize=>150, ysize=>150 );
+ $imbase->box( filled=>1, color=>'white', box=>[ 70, 24, 80, 124 ] );
+ $imbase->box( filled=>1, color=>'red', box=>[ 70, 24, 124, 30 ] );
+ $imbase->write( file=>"testout/t61_gaussian2-base.ppm" );
+
+ my $gauss = test($imbase, {type=>'gaussian2', stddevY=>5, stddevX=>0 },
+ 'testout/t61_gaussianY.ppm');
+
+ my $imbase16 = $imbase->to_rgb16;
+ my $gauss16 = test($imbase16, {type=>'gaussian2', stddevY=>5, stddevX=>0.1 },
+ 'testout/t61_gaussianY-16.ppm');
+ is_image_similar($gauss, $gauss16, 250000, "8 and 16 gaussian match");
+
+
+ test($imbase, {type=>'gaussian2', stddevX=>5, stddevY=>5 },
+ 'testout/t61_gaussian_both.ppm');
+
+
+ $gauss = test($imbase, {type=>'gaussian2', stddevX=>5, stddevY=>0 },
+ 'testout/t61_gaussianX.ppm');
+
+ $imbase16 = $imbase->to_rgb16;
+ $gauss16 = test($imbase16, {type=>'gaussian2', stddevX=>5, stddevY=>0.1 },
+ 'testout/t61_gaussianX-16.ppm');
+ is_image_similar($gauss, $gauss16, 250000, "8 and 16 gaussian match");
+}
+
test($imbase, { type=>'gradgen', dist=>1,
xo=>[ 10, 10, 120 ],