From de65da85b96398ad76e33095c576cb28d515a48b Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 6 Nov 2015 14:29:23 +0000 Subject: [PATCH] smarter conversion of float masks to int we were just rint()ing masks going from float -> int, but this could give bad results in some cases, with output images becoming darker or lighter, as individual elemets moved up or down now we adjust the output scale to try to keep the overall brightness the same, if we can see: https://github.com/jcupitt/libvips/issues/344 --- TODO | 19 +------------- libvips/deprecated/im_vips2mask.c | 41 +++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/TODO b/TODO index 3f02126a..5cc732f3 100644 --- a/TODO +++ b/TODO @@ -2,24 +2,7 @@ https://github.com/jcupitt/libvips/issues/347 -- convert float mask to int for int convolution has rounding problems - - we do rint() all elements, and rint(scale) - - we ought to sum all float elements and take the ratio of the scale to the sum - - then rint all elements, sum, and scale the sum by the ratio to get the int - scale - - same for offset - -- recent imagemagick seems to have link problems - - see: - - http://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=28603 - - need to fix fairly soon, vips can't build against current IM + oh argh out of order reads ... but why would they add a few black tiles? - add bandjoinconst ... append a band (or bands?) from a constant diff --git a/libvips/deprecated/im_vips2mask.c b/libvips/deprecated/im_vips2mask.c index b172d22f..baa28a61 100644 --- a/libvips/deprecated/im_vips2mask.c +++ b/libvips/deprecated/im_vips2mask.c @@ -145,6 +145,8 @@ im_vips2imask( IMAGE *in, const char *filename ) double *data; int x, y; + double double_ratio; + int int_ratio; /* double* only: cast if necessary. */ @@ -191,6 +193,22 @@ im_vips2imask( IMAGE *in, const char *filename ) if( !(out = im_create_imask( filename, width, height )) ) return( NULL ); + /* We want to make an intmask which has the same input to output ratio + * as the double image. + * + * Imagine convolving with the double image, what's the ratio of + * brightness between input and output? We want the same ratio for the + * int version, if we can. + * + * Imaging an input image where every pixel is 1, what will the output + * be? + */ + double_ratio = 0; + for( y = 0; y < height; y++ ) + for( x = 0; x < width; x++ ) + double_ratio += data[x + width * y]; + double_ratio /= vips_image_get_scale( in ); + for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) if( in->Bands > 1 && in->Ysize == 1 ) @@ -203,8 +221,27 @@ im_vips2imask( IMAGE *in, const char *filename ) out->coeff[x + y * width] = VIPS_RINT( data[x + y * width] ); - out->scale = vips_image_get_scale( in ); - out->offset = vips_image_get_offset( in ); + out->scale = VIPS_RINT( vips_image_get_scale( in ) ); + out->offset = VIPS_RINT( vips_image_get_offset( in ) ); + + /* Now convolve a 1 everywhere image with the int version we've made, + * what do we get? + */ + int_ratio = 0; + for( y = 0; y < height; y++ ) + for( x = 0; x < width; x++ ) + int_ratio += out->coeff[x + width * y]; + int_ratio /= out->scale; + + /* And adjust the scale to get as close to a match as we can. + */ + out->scale = VIPS_RINT( out->scale * int_ratio / double_ratio ); + if( out->scale == 0 ) { + out->scale = 1; + } + + /* We should probably do the same for offset, somehow. + */ return( out ); }