diff --git a/Imager.pm b/Imager.pm index 1204a638..d7504acf 100644 --- a/Imager.pm +++ b/Imager.pm @@ -3942,6 +3942,26 @@ sub difference { return $result; } +sub rgb_difference { + my ($self, %opts) = @_; + + $self->_valid_image("rgb_difference") + or return; + + defined $opts{other} + or return $self->_set_error("No 'other' parameter supplied"); + unless ($opts{other}->_valid_image("rgb_difference")) { + $self->_set_error($opts{other}->errstr . " (other image)"); + return; + } + + my $result = Imager->new; + $result->{IMG} = i_rgbdiff_image($self->{IMG}, $opts{other}{IMG}) + or return $self->_set_error($self->_error_as_msg()); + + return $result; +} + # destructive border - image is shrunk by one pixel all around sub border { @@ -4980,6 +5000,9 @@ register_reader() - L register_writer() - L +rgb_difference() - L - produce a difference +images from two input images. + rotate() - L rubthrough() - L - draw an image diff --git a/Imager.xs b/Imager.xs index 9e492986..e9363db7 100644 --- a/Imager.xs +++ b/Imager.xs @@ -3051,6 +3051,11 @@ i_diff_image(im, im2, mindist=0) Imager::ImgRaw im2 im_double mindist +Imager::ImgRaw +i_rgbdiff_image(im, im2) + Imager::ImgRaw im + Imager::ImgRaw im2 + undef_int i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs) Imager::ImgRaw im diff --git a/filters.im b/filters.im index 7c23a5a5..2f6aa163 100644 --- a/filters.im +++ b/filters.im @@ -1447,7 +1447,7 @@ i_diff_image(i_img *im1, i_img *im2, double mindist) { ysize = i_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(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */ i_color *line2 = mymalloc(xsize * sizeof(*line1)); /* checked 17feb2005 tonyc */ @@ -1524,6 +1524,61 @@ i_diff_image(i_img *im1, i_img *im2, double mindist) { return out; } +/* +=item i_rgbdiff_image(im1, im2) + +Creates a new image that is black, except where the pixel in im2 is +different from im1, where it is the arithmetical difference to im2 per +color. + +=cut +*/ + +i_img * +i_rgbdiff_image(i_img *im1, i_img *im2) { + i_img *out; + int outchans, diffchans; + i_img_dim xsize, ysize; + dIMCTXim(im1); + + i_clear_error(); + if (im1->channels != im2->channels) { + i_push_error(0, "different number of channels"); + return NULL; + } + + outchans = diffchans = im1->channels; + if (outchans == 2 || outchans == 4) + --outchans; + + xsize = i_min(im1->xsize, im2->xsize); + ysize = i_min(im1->ysize, im2->ysize); + + out = i_sametype_chans(im1, xsize, ysize, outchans); + +#code im1->bits == i_8_bits && im2->bits == i_8_bits + IM_COLOR *line1 = mymalloc(xsize * sizeof(*line1)); + IM_COLOR *line2 = mymalloc(xsize * sizeof(*line1)); + i_img_dim x, y; + int ch; + + for (y = 0; y < ysize; ++y) { + IM_GLIN(im1, 0, xsize, y, line1); + IM_GLIN(im2, 0, xsize, y, line2); + for (x = 0; x < xsize; ++x) { + for (ch = 0; ch < outchans; ++ch) { + line2[x].channel[ch] = IM_ABS(line1[x].channel[ch] - line2[x].channel[ch]); + } + } + IM_PLIN(out, 0, xsize, y, line2); + } + myfree(line1); + myfree(line2); +#/code + + 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/imager.h b/imager.h index 6a217657..c9472c87 100644 --- a/imager.h +++ b/imager.h @@ -293,6 +293,7 @@ void i_turbnoise(i_img *im,double xo,double yo,double scale); void i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure); int i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int dmeasure); i_img *i_diff_image(i_img *im, i_img *im2, double mindist); +i_img *i_rgbdiff_image(i_img *im, i_img *im2); int i_fountain(i_img *im, double xa, double ya, double xb, double yb, i_fountain_type type, i_fountain_repeat repeat, diff --git a/lib/Imager/Filters.pod b/lib/Imager/Filters.pod index 4cb271d7..8d4fb4d1 100644 --- a/lib/Imager/Filters.pod +++ b/lib/Imager/Filters.pod @@ -808,6 +808,35 @@ For large sample images this is scaled down to the range 0 .. 1. =back +=item rgb_difference() + +You can create a new image that is the difference between 2 other images. + + my $diff = $img->rgb_difference(other=>$other_img); + +For each pixel in $img that is different to the pixel in $other_img, +the arithmetic difference for the value of the pixel in $img from +$other_img per color is given. Transparency is ignored. + +This can be used for measuring image differences ("How much are they +different?"). + +Note that $img and $other_img must have the same number of channels. +The width and height of $diff will be the minimum of each of the width +and height of $img and $other_img. + +Parameters: + +=over + +=item * + +C - the other image object to compare against + +=back + +=back + =head1 AUTHOR Arnar M. Hrafnkelsson, Tony Cook . diff --git a/lib/Imager/Preprocess.pm b/lib/Imager/Preprocess.pm index 40eaaaae..b211c338 100644 --- a/lib/Imager/Preprocess.pm +++ b/lib/Imager/Preprocess.pm @@ -139,6 +139,7 @@ sub byte_samples { s/\bIM_LIMIT\(/IM_LIMIT_8(/g; s/\bIM_RENDER_LINE\(/i_render_line(/g; s/\bIM_FILL_COMBINE_F\b/i_fill_combine_f/g; + s/\bIM_ABS\b/abs/g; } @lines; @@ -168,6 +169,7 @@ sub double_samples { s/\bIM_LIMIT\(/IM_LIMIT_double(/g; s/\bIM_RENDER_LINE\(/i_render_linef(/g; s/\bIM_FILL_COMBINE_F\b/i_fill_combinef_f/g; + s/\bIM_ABS\b/fabs/g; } @lines; @@ -281,6 +283,10 @@ object. =item * +IM_ABS(sample) - calculate the absolute value of an IM_WORK_T value. + +=item * + IM_SAMPLE_MAX - maximum value for a sample =item * diff --git a/t/400-filter/010-filters.t b/t/400-filter/010-filters.t index 1ec6e199..93ac3380 100644 --- a/t/400-filter/010-filters.t +++ b/t/400-filter/010-filters.t @@ -1,7 +1,7 @@ #!perl -w use strict; use Imager qw(:handy); -use Test::More tests => 136; +use Test::More tests => 137; -d "testout" or mkdir "testout"; @@ -430,6 +430,19 @@ is($name, "test gradient", "check the name matches"); my $cmp2 = Imager->new(xsize => 3, ysize => 2, channels => 4); $cmp2->setpixel(x => 2, 'y' => 0, color => '#FF02FF'); is_image($diff2, $cmp2, "difference() - check image with mindist 1"); + + $im1 = Imager->new(xsize => 3, ysize => 2, channels => 4); + $im2 = $im1->copy; + $im1->setpixel(x => 1, 'y' => 0, color => 'FF00FF80'); + $im2->setpixel(x => 1, 'y' => 0, color => 'FF01FF84'); + $im1->setpixel(x => 2, 'y' => 0, color => 'FF00FF80'); + $im2->setpixel(x => 2, 'y' => 0, color => 'FF02FF84'); + my $diff3 = $im1->rgb_difference(other => $im2); + my $cmp3 = Imager->new(xsize => 3, ysize => 2, channels => 3); + $cmp3->box(filled => 1, color => '#000000'); + $cmp3->setpixel(x => 1, 'y' => 0, color => '#000100'); + $cmp3->setpixel(x => 2, 'y' => 0, color => '#000200'); + is_image($diff3, $cmp3, "rgb_difference() - check image"); } {