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
This commit is contained in:
John Cupitt 2015-11-06 14:29:23 +00:00
parent d38a78d0ea
commit de65da85b9
2 changed files with 40 additions and 20 deletions

19
TODO
View File

@ -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

View File

@ -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 );
}