much better int mask creation

removes some banding from the orc path for reducev
This commit is contained in:
John Cupitt 2016-04-02 18:46:10 +01:00
parent 5f24468dba
commit bc320f1090
3 changed files with 82 additions and 19 deletions

10
TODO
View File

@ -1,4 +1,12 @@
- seeing some horizontal stripes on some kevill8 !
- try
vips reducev ~/pics/babe.jpg x.png 2.666
get 254 for white, some rounding problem
- I like the new int mask creator in reducev, can we use it in vips2mask as
well?
- try SEQ_UNBUFFERED on jpg source, get out of order error?

View File

@ -6,6 +6,9 @@
* - add other kernels
* 21/3/16
* - add vector path
* 2/4/16
* - better int mask creation ... we now adjust the scale to keep the sum
* equal to the target scale
*/
/*
@ -219,6 +222,10 @@ vips_reducev_compile_section( VipsReducev *reducev, Pass *pass, gboolean first )
ASM3( "mulsbw", "value", "valueb", coeff );
ASM3( "addssw", "sum", "sum", "value" );
/* We've used this coeff.
*/
pass->last = i;
if( vips_vector_full( v ) )
break;
@ -229,12 +236,10 @@ vips_reducev_compile_section( VipsReducev *reducev, Pass *pass, gboolean first )
break;
}
pass->last = i;
/* If this is the end of the mask, we write the 8-bit result to the
* image, otherwise write the 16-bit intermediate to our temp buffer.
*/
if( i >= reducev->n_point - 1 ) {
if( pass->last >= reducev->n_point - 1 ) {
char sixteen[256];
char five[256];
char zero[256];
@ -286,7 +291,6 @@ vips_reducev_compile( VipsReducev *reducev )
reducev->n_pass += 1;
pass->first = i;
pass->last = i;
pass->r = -1;
pass->d2 = -1;
pass->n_param = 0;
@ -677,6 +681,63 @@ vips_reducev_vector_gen( VipsRegion *out_region, void *vseq,
return( 0 );
}
/* Make a fixed-point version of a mask. Each out[i] = rint(in[i] * adj_scale),
* where adj_scale is selected so that sum(out) = sum(in) * scale.
*
* Because of the vagaries of rint(), we can't just calc this, we have to
* iterate and converge on the best value for adj_scale.
*/
static void
vips_reducev_intize( double *in, int *out, int n, int scale )
{
double fsum;
int target;
int sum;
double high;
double low;
double guess;
fsum = 0.0;
for( int i = 0; i < n; i++ )
fsum += in[i];
target = VIPS_RINT( fsum * scale );
/* As we rint() each scale element, we can get up to 0.5 error.
* Therefore, by the end of the mask, we can be off by up to n/2. Our
* high and low guesses are therefore n/2 either side of the obvious
* answer.
*/
high = scale + n / 2;
low = scale - n / 2;
do {
guess = (high + low) / 2.0;
for( int i = 0; i < n; i++ )
out[i] = VIPS_RINT( in[i] * guess );
sum = 0;
for( int i = 0; i < n; i++ )
sum += out[i];
if( sum == target )
break;
if( sum < target )
low = guess;
if( sum > target )
high = guess;
} while( high - low > 0.01 );
if( sum != target )
/* We're as close as we can get ... add the remaining error to
* the centre element. Hopefully we'll get slight sharpness
* changes rather than slight brightness changes and it'll
* be less visible.
*/
out[n / 2] += target - sum;
}
static int
vips_reducev_raw( VipsReducev *reducev, VipsImage *in )
{
@ -714,10 +775,9 @@ vips_reducev_raw( VipsReducev *reducev, VipsImage *in )
if( !reducev->matrixi[y] )
return( -1 );
for( int i = 0; i < reducev->n_point; i++ )
reducev->matrixi[y][i] =
reducev->matrixf[y][i] *
VIPS_INTERPOLATE_SCALE;
vips_reducev_intize(
reducev->matrixf[y], reducev->matrixi[y],
reducev->n_point, VIPS_INTERPOLATE_SCALE );
}
/* And we need an 2.6 version if we will use the vector path.
@ -730,9 +790,9 @@ vips_reducev_raw( VipsReducev *reducev, VipsImage *in )
if( !reducev->matrixo[y] )
return( -1 );
for( int i = 0; i < reducev->n_point; i++ )
reducev->matrixo[y][i] = VIPS_RINT(
reducev->matrixf[y][i] * 64.0 );
vips_reducev_intize(
reducev->matrixf[y], reducev->matrixo[y],
reducev->n_point, 64 );
}
/* Try to build a vector version, if we can.

View File

@ -227,13 +227,8 @@ thumbnail_find_jpegshrink( VipsImage *im )
return( 1 );
/* Shrink-on-load is a simple block shrink and will add quite a bit of
* extra sharpness to the image. We want to block shrink to a size a
* bit above our target, then vips_resize() to the target.
*
* For example, consider making a 400-pixel-across image from an
* 800-pixel image. If we load at 1/2 size, we could find ourselves
* doing no further processing, which would make a 400-px version look
* very different from a 450-px version.
* extra sharpness to the image. We want to block shrink to a
* bit above our target, then vips_resize() to the final size.
*/
if( shrink >= 10 )
return( 8 );