From: Tony Cook Date: Sun, 31 Mar 2002 12:41:54 +0000 (+0000) Subject: difference() method X-Git-Tag: Imager-0.48^2~398 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/dff75dee0255929e855abe605d59732f7ed392d4 difference() method --- diff --git a/Changes b/Changes index c7b13bea..a5cded8d 100644 --- a/Changes +++ b/Changes @@ -625,6 +625,7 @@ Revision history for Perl extension Imager. prevent pointer vs int size warnings on 64-bit builds of perl. - add our own INT2PTR and PTR2IV definitions when perl doesn't supply them + - difference() method ================================================================= diff --git a/Imager.pm b/Imager.pm index 2b283a4f..41d687f0 100644 --- a/Imager.pm +++ b/Imager.pm @@ -2402,6 +2402,27 @@ sub map { return $self; } +sub difference { + my ($self, %opts) = @_; + + defined $opts{mindist} or $opts{mindist} = 0; + + defined $opts{other} + or return $self->_set_error("No 'other' parameter supplied"); + defined $opts{other}{IMG} + or return $self->_set_error("No image data in 'other' image"); + + $self->{IMG} + or return $self->_set_error("No image data"); + + my $result = Imager->new; + $result->{IMG} = i_diff_image($self->{IMG}, $opts{other}{IMG}, + $opts{mindist}) + or return $self->_set_error($self->_error_as_msg()); + + return $result; +} + # destructive border - image is shrunk by one pixel all around sub border { @@ -2516,6 +2537,7 @@ sub _set_error { else { $ERRSTR = $msg; } + return; } # Default guess for the type of an image from extension diff --git a/Imager.xs b/Imager.xs index 69450220..3db907f5 100644 --- a/Imager.xs +++ b/Imager.xs @@ -2773,6 +2773,11 @@ i_gradgen(im, ...) myfree(yo); myfree(ival); +Imager::ImgRaw +i_diff_image(im, im2, mindist=0) + Imager::ImgRaw im + Imager::ImgRaw im2 + int mindist void i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs) diff --git a/filters.c b/filters.c index 51993c77..e801488e 100644 --- a/filters.c +++ b/filters.c @@ -1197,6 +1197,100 @@ void i_unsharp_mask(i_img *im, double stddev, double scale) { i_img_exorcise(©); } +/* +=item i_diff_image(im1, im2, mindiff) + +Creates a new image that is transparent, except where the pixel in im2 +is different from im1, where it is the pixel from im2. + +The samples must differ by at least mindiff to be considered different. + +=cut +*/ + +i_img * +i_diff_image(i_img *im1, i_img *im2, int mindiff) { + i_img *out; + int outchans, diffchans; + int xsize, ysize; + i_img temp; + + i_clear_error(); + if (im1->channels != im2->channels) { + i_push_error(0, "different number of channels"); + return NULL; + } + + outchans = diffchans = im1->channels; + if (outchans == 1 || outchans == 3) + ++outchans; + + xsize = min(im1->xsize, im2->xsize); + ysize = min(im1->ysize, im2->ysize); + + out = i_sametype_chans(im1, xsize, ysize, outchans); + + if (im1->bits == i_8_bits && im2->bits == i_8_bits) { + i_color *line1 = mymalloc(2 * xsize * sizeof(*line1)); + i_color *line2 = line1 + xsize; + i_color empty; + int x, y, ch; + + for (ch = 0; ch < MAXCHANNELS; ++ch) + empty.channel[ch] = 0; + + for (y = 0; y < ysize; ++y) { + i_glin(im1, 0, xsize, y, line1); + i_glin(im2, 0, xsize, y, line2); + for (x = 0; x < xsize; ++x) { + int diff = 0; + for (ch = 0; ch < diffchans; ++ch) { + if (line1[x].channel[ch] != line2[x].channel[ch] + && abs(line1[x].channel[ch] - line2[x].channel[ch]) > mindiff) { + diff = 1; + break; + } + } + if (!diff) + line2[x] = empty; + } + i_plin(out, 0, xsize, y, line2); + } + myfree(line1); + } + else { + i_fcolor *line1 = mymalloc(2 * xsize * sizeof(*line1)); + i_fcolor *line2 = line1 + xsize; + i_fcolor empty; + int x, y, ch; + double dist = mindiff / 255; + + for (ch = 0; ch < MAXCHANNELS; ++ch) + empty.channel[ch] = 0; + + for (y = 0; y < ysize; ++y) { + i_glinf(im1, 0, xsize, y, line1); + i_glinf(im2, 0, xsize, y, line2); + for (x = 0; x < xsize; ++x) { + int diff = 0; + for (ch = 0; ch < diffchans; ++ch) { + if (line1[x].channel[ch] != line2[x].channel[ch] + && abs(line1[x].channel[ch] - line2[x].channel[ch]) > dist) { + diff = 1; + break; + } + } + if (!diff) + line2[x] = empty; + } + i_plinf(out, 0, xsize, y, line2); + } + myfree(line1); + } + + return out; +} + 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.c b/image.c index 3fab8215..e3fa3a70 100644 --- a/image.c +++ b/image.c @@ -1071,6 +1071,32 @@ i_img *i_sametype(i_img *src, int xsize, int ysize) { } } +/* +=item i_sametype_chans(i_img *im, int xsize, int ysize, int channels) + +Returns an image of the same type (sample size). + +For paletted images the equivalent direct type is returned. + +=cut +*/ + +i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) { + if (src->bits == 8) { + return i_img_empty_ch(NULL, xsize, ysize, channels); + } + else if (src->bits == i_16_bits) { + return i_img_16_new(xsize, ysize, channels); + } + else if (src->bits == i_double_bits) { + return i_img_double_new(xsize, ysize, channels); + } + else { + i_push_error(0, "Unknown image bits"); + return NULL; + } +} + /* =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen) diff --git a/image.h b/image.h index 7e507fd8..25e231e4 100644 --- a/image.h +++ b/image.h @@ -58,6 +58,7 @@ void i_img_destroy(i_img *im); void i_img_info(i_img *im,int *info); extern i_img *i_sametype(i_img *im, int xsize, int ysize); +extern i_img *i_sametype_chans(i_img *im, int xsize, int ysize, int channels); i_img *i_img_pal_new(int x, int y, int ch, int maxpal); @@ -614,6 +615,7 @@ void i_radnoise(i_img *im,int xo,int yo,float rscale,float ascale); void i_turbnoise(i_img *im,float xo,float yo,float scale); void i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure); void i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure); +i_img *i_diff_image(i_img *im, i_img *im2, int mindist); typedef enum { i_fst_linear, i_fst_curved, diff --git a/lib/Imager/Filters.pod b/lib/Imager/Filters.pod index 134d00a8..f749de24 100644 --- a/lib/Imager/Filters.pod +++ b/lib/Imager/Filters.pod @@ -22,6 +22,7 @@ Imager::Filters - Entire Image Filtering Operations unload_plugin("dynfilt/dyntest.so") or die "unable to load plugin\n"; + $out = $img->difference(other=>$other_img); =head1 DESCRIPTION @@ -397,5 +398,21 @@ Note: This seems to test ok on the following systems: Linux, Solaris, HPUX, OpenBSD, FreeBSD, TRU64/OSF1, AIX. If you test this on other systems please let me know. +=head2 Image Difference + +You can create a new image that is the difference between 2 other images. + + my $diff = $img->difference(other=>$other_img); + +For each pixel in $img that is different to the pixel in $other_img, +the pixel from $other_img is given, otherwise the pixel is transparent +black. + +This can be used for debugging image differences ("Where are they +different?"), and for optimizing animated GIFs. + +Note that $img and $other_img must have the same number of channels. +The width and heigh of $diff will be the minimum of each of the width +and height of $img and $other_img. =cut diff --git a/t/t61filters.t b/t/t61filters.t index 8708f9bf..e1a64e0d 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..43\n"; +print "1..45\n"; test($imbase, 1, {type=>'autolevels'}, 'testout/t61_autolev.ppm'); @@ -91,6 +91,19 @@ test($imbase, 42, {type=>'fountain', xa=>75, ya=>75, xb=>90, yb=>15, segments=>$f4, super_sample=>'grid', ftype=>'linear', combine=>'color' }, 'testout/t61_regress_fount.ppm'); +my $im2 = $imbase->copy; +$im2->box(xmin=>20, ymin=>20, xmax=>40, ymax=>40, color=>'FF0000', filled=>1); +$im2->write(file=>'testout/t61_diff_base.ppm'); +my $im3 = Imager->new(xsize=>150, ysize=>150, channels=>3); +$im3->box(xmin=>20, ymin=>20, xmax=>40, ymax=>40, color=>'FF0000', filled=>1); +my $diff = $imbase->difference(other=>$im2); +print $diff ? "ok 44\n" : "not ok 44\n"; +if ($im3 && $diff) { + print Imager::i_img_diff($im3->{IMG}, $diff->{IMG}) ? "not ok 45\n" : "ok 45\n"; +} +else { + print "ok 45 # skip\n"; +} sub test { my ($in, $num, $params, $out) = @_;