int vector path done
seems to sort-of work
This commit is contained in:
parent
bd7bad1916
commit
e45c5a587e
@ -100,6 +100,12 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define DEBUG_PIXELS
|
||||||
|
#define DEBUG
|
||||||
|
*/
|
||||||
|
#define DEBUG_COMPILE
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif /*HAVE_CONFIG_H*/
|
#endif /*HAVE_CONFIG_H*/
|
||||||
@ -176,6 +182,12 @@ typedef struct {
|
|||||||
VipsPel **pts; /* Per-non-zero mask element image pointers */
|
VipsPel **pts; /* Per-non-zero mask element image pointers */
|
||||||
|
|
||||||
int last_bpl; /* Avoid recalcing offsets, if we can */
|
int last_bpl; /* Avoid recalcing offsets, if we can */
|
||||||
|
|
||||||
|
/* We need a pair of intermediate buffers to keep the results of each
|
||||||
|
* vector conv pass.
|
||||||
|
*/
|
||||||
|
short *t1;
|
||||||
|
short *t2;
|
||||||
} VipsConviSequence;
|
} VipsConviSequence;
|
||||||
|
|
||||||
/* Free a sequence value.
|
/* Free a sequence value.
|
||||||
@ -186,6 +198,10 @@ vips_convi_stop( void *vseq, void *a, void *b )
|
|||||||
VipsConviSequence *seq = (VipsConviSequence *) vseq;
|
VipsConviSequence *seq = (VipsConviSequence *) vseq;
|
||||||
|
|
||||||
VIPS_UNREF( seq->ir );
|
VIPS_UNREF( seq->ir );
|
||||||
|
VIPS_FREE( seq->offsets );
|
||||||
|
VIPS_FREE( seq->pts );
|
||||||
|
VIPS_FREE( seq->t1 );
|
||||||
|
VIPS_FREE( seq->t2 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
@ -204,14 +220,38 @@ vips_convi_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
seq->convi = convi;
|
seq->convi = convi;
|
||||||
seq->ir = NULL;
|
seq->ir = NULL;
|
||||||
|
seq->offsets = NULL;
|
||||||
seq->pts = NULL;
|
seq->pts = NULL;
|
||||||
seq->last_bpl = -1;
|
seq->last_bpl = -1;
|
||||||
|
seq->t1 = NULL;
|
||||||
|
seq->t2 = NULL;
|
||||||
|
|
||||||
seq->ir = vips_region_new( in );
|
seq->ir = vips_region_new( in );
|
||||||
if( !(seq->offsets = VIPS_ARRAY( out, convi->nnz, int )) ||
|
|
||||||
!(seq->pts = VIPS_ARRAY( out, convi->nnz, VipsPel * )) ) {
|
/* C mode.
|
||||||
vips_convi_stop( seq, in, convi );
|
*/
|
||||||
return( NULL );
|
if( convi->nnz ) {
|
||||||
|
seq->offsets = VIPS_ARRAY( NULL, convi->nnz, int );
|
||||||
|
seq->pts = VIPS_ARRAY( NULL, convi->nnz, VipsPel * );
|
||||||
|
|
||||||
|
if( !seq->offsets ||
|
||||||
|
!seq->pts ) {
|
||||||
|
vips_convi_stop( seq, in, convi );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vector mode.
|
||||||
|
*/
|
||||||
|
if( convi->n_pass ) {
|
||||||
|
seq->t1 = VIPS_ARRAY( NULL, VIPS_IMAGE_N_ELEMENTS( in ), short );
|
||||||
|
seq->t2 = VIPS_ARRAY( NULL, VIPS_IMAGE_N_ELEMENTS( in ), short );
|
||||||
|
|
||||||
|
if( !seq->t1 ||
|
||||||
|
!seq->t2 ) {
|
||||||
|
vips_convi_stop( seq, in, convi );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return( (void *) seq );
|
return( (void *) seq );
|
||||||
@ -409,6 +449,64 @@ static int
|
|||||||
vips_convi_generate_vector( VipsRegion *or,
|
vips_convi_generate_vector( VipsRegion *or,
|
||||||
void *vseq, void *a, void *b, gboolean *stop )
|
void *vseq, void *a, void *b, gboolean *stop )
|
||||||
{
|
{
|
||||||
|
VipsConviSequence *seq = (VipsConviSequence *) vseq;
|
||||||
|
VipsConvi *convi = (VipsConvi *) b;
|
||||||
|
VipsConvolution *convolution = (VipsConvolution *) convi;
|
||||||
|
VipsImage *M = convolution->M;
|
||||||
|
VipsImage *in = (VipsImage *) a;
|
||||||
|
VipsRegion *ir = seq->ir;
|
||||||
|
VipsRect *r = &or->valid;
|
||||||
|
int ne = r->width * in->Bands;
|
||||||
|
|
||||||
|
VipsRect s;
|
||||||
|
int i, y;
|
||||||
|
VipsExecutor executor[MAX_PASS];
|
||||||
|
|
||||||
|
#ifdef DEBUG_PIXELS
|
||||||
|
printf( "vips_convi_generate_vector: generating %d x %d at %d x %d\n",
|
||||||
|
r->width, r->height, r->left, r->top );
|
||||||
|
#endif /*DEBUG_PIXELS*/
|
||||||
|
|
||||||
|
/* Prepare the section of the input image we need. A little larger
|
||||||
|
* than the section of the output image we are producing.
|
||||||
|
*/
|
||||||
|
s = *r;
|
||||||
|
s.width += M->Xsize - 1;
|
||||||
|
s.height += M->Ysize - 1;
|
||||||
|
if( vips_region_prepare( ir, &s ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
for( i = 0; i < convi->n_pass; i++ )
|
||||||
|
vips_executor_set_program( &executor[i],
|
||||||
|
convi->pass[i].vector, ne );
|
||||||
|
|
||||||
|
VIPS_GATE_START( "vips_convi_generate_vector: work" );
|
||||||
|
|
||||||
|
for( y = 0; y < r->height; y ++ ) {
|
||||||
|
VipsPel *q = VIPS_REGION_ADDR( or, r->left, r->top + y );
|
||||||
|
|
||||||
|
/* We run our n passes to generate this scanline.
|
||||||
|
*/
|
||||||
|
for( i = 0; i < convi->n_pass; i++ ) {
|
||||||
|
Pass *pass = &convi->pass[i];
|
||||||
|
|
||||||
|
vips_executor_set_scanline( &executor[i],
|
||||||
|
ir, r->left, r->top + y );
|
||||||
|
vips_executor_set_array( &executor[i],
|
||||||
|
pass->r, seq->t1 );
|
||||||
|
vips_executor_set_array( &executor[i],
|
||||||
|
pass->d2, seq->t2 );
|
||||||
|
vips_executor_set_destination( &executor[i], q );
|
||||||
|
vips_executor_run( &executor[i] );
|
||||||
|
|
||||||
|
VIPS_SWAP( signed short *, seq->t1, seq->t2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VIPS_GATE_STOP( "vips_convi_generate_vector: work" );
|
||||||
|
|
||||||
|
VIPS_COUNT_PIXELS( or, "vips_convi_generate_vector" );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,17 +797,50 @@ intize_to_fixed_point( VipsImage *in, int *out )
|
|||||||
*/
|
*/
|
||||||
for( i = 0; i < ne; i++ )
|
for( i = 0; i < ne; i++ )
|
||||||
if( scaled[i] >= 2.0 ||
|
if( scaled[i] >= 2.0 ||
|
||||||
scaled[i] < -2 )
|
scaled[i] < -2 ) {
|
||||||
|
#ifdef DEBUG_COMPILE
|
||||||
|
printf( "intize_to_fixed_point: out of range\n" );
|
||||||
|
#endif /*DEBUG_COMPILE*/
|
||||||
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The smallest coefficient we can manage is 1/64th, we'll just turn
|
||||||
|
* that into zero.
|
||||||
|
*/
|
||||||
|
for( i = 0; i < ne; i++ )
|
||||||
|
if( scaled[i] != 0.0 &&
|
||||||
|
VIPS_FABS( scaled[i] ) < 1.0 / FIXED_SCALE ) {
|
||||||
|
#ifdef DEBUG_COMPILE
|
||||||
|
printf( "intize_to_fixed_point: underflow\n" );
|
||||||
|
#endif /*DEBUG_COMPILE*/
|
||||||
|
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
vips_vector_to_fixed_point( scaled, out, ne, FIXED_SCALE );
|
vips_vector_to_fixed_point( scaled, out, ne, FIXED_SCALE );
|
||||||
|
|
||||||
|
#ifdef DEBUG_COMPILE
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
printf( "intize_to_fixed_point:\n" );
|
||||||
|
for( y = 0; y < t->Ysize; y++ ) {
|
||||||
|
printf( "\t" );
|
||||||
|
for( x = 0; x < t->Xsize; x++ )
|
||||||
|
printf( "%4d ", out[y * t->Xsize + x] );
|
||||||
|
printf( "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /*DEBUG_COMPILE*/
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vips_convi_build( VipsObject *object )
|
vips_convi_build( VipsObject *object )
|
||||||
{
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||||
VipsConvolution *convolution = (VipsConvolution *) object;
|
VipsConvolution *convolution = (VipsConvolution *) object;
|
||||||
VipsConvi *convi = (VipsConvi *) object;
|
VipsConvi *convi = (VipsConvi *) object;
|
||||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 );
|
VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 );
|
||||||
@ -742,8 +873,10 @@ vips_convi_build( VipsObject *object )
|
|||||||
in->BandFmt == VIPS_FORMAT_UCHAR ) {
|
in->BandFmt == VIPS_FORMAT_UCHAR ) {
|
||||||
if( (convi->fixed = VIPS_ARRAY( object, n_point, int )) &&
|
if( (convi->fixed = VIPS_ARRAY( object, n_point, int )) &&
|
||||||
!intize_to_fixed_point( M, convi->fixed ) &&
|
!intize_to_fixed_point( M, convi->fixed ) &&
|
||||||
!vips_convi_compile( convi, in ) )
|
!vips_convi_compile( convi, in ) ) {
|
||||||
generate = vips_convi_generate_vector;
|
generate = vips_convi_generate_vector;
|
||||||
|
vips_info( class->nickname, "using vector path" );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
vips_convi_compile_free( convi );
|
vips_convi_compile_free( convi );
|
||||||
}
|
}
|
||||||
@ -781,6 +914,7 @@ vips_convi_build( VipsObject *object )
|
|||||||
}
|
}
|
||||||
|
|
||||||
generate = vips_convi_generate;
|
generate = vips_convi_generate;
|
||||||
|
vips_info( class->nickname, "using C path" );
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_set( convi, "out", vips_image_new(), NULL );
|
g_object_set( convi, "out", vips_image_new(), NULL );
|
||||||
|
@ -534,6 +534,7 @@ void
|
|||||||
vips_vector_to_fixed_point( double *in, int *out, int n, int scale )
|
vips_vector_to_fixed_point( double *in, int *out, int n, int scale )
|
||||||
{
|
{
|
||||||
double fsum;
|
double fsum;
|
||||||
|
int i;
|
||||||
int target;
|
int target;
|
||||||
int sum;
|
int sum;
|
||||||
double high;
|
double high;
|
||||||
@ -541,7 +542,7 @@ vips_vector_to_fixed_point( double *in, int *out, int n, int scale )
|
|||||||
double guess;
|
double guess;
|
||||||
|
|
||||||
fsum = 0.0;
|
fsum = 0.0;
|
||||||
for( int i = 0; i < n; i++ )
|
for( i = 0; i < n; i++ )
|
||||||
fsum += in[i];
|
fsum += in[i];
|
||||||
target = VIPS_RINT( fsum * scale );
|
target = VIPS_RINT( fsum * scale );
|
||||||
|
|
||||||
@ -556,11 +557,11 @@ vips_vector_to_fixed_point( double *in, int *out, int n, int scale )
|
|||||||
do {
|
do {
|
||||||
guess = (high + low) / 2.0;
|
guess = (high + low) / 2.0;
|
||||||
|
|
||||||
for( int i = 0; i < n; i++ )
|
for( i = 0; i < n; i++ )
|
||||||
out[i] = VIPS_RINT( in[i] * guess );
|
out[i] = VIPS_RINT( in[i] * guess );
|
||||||
|
|
||||||
sum = 0;
|
sum = 0;
|
||||||
for( int i = 0; i < n; i++ )
|
for( i = 0; i < n; i++ )
|
||||||
sum += out[i];
|
sum += out[i];
|
||||||
|
|
||||||
if( sum == target )
|
if( sum == target )
|
||||||
@ -574,11 +575,31 @@ vips_vector_to_fixed_point( double *in, int *out, int n, int scale )
|
|||||||
*/
|
*/
|
||||||
} while( high - low > 0.01 );
|
} while( high - low > 0.01 );
|
||||||
|
|
||||||
if( sum != target )
|
if( sum != target ) {
|
||||||
/* We're as close as we can get ... add the remaining error to
|
/* Spread the error out thinly over the whole array. For
|
||||||
* the centre element. Hopefully we'll get slight sharpness
|
* example, consider the matrix:
|
||||||
* changes rather than slight brightness changes and it'll
|
*
|
||||||
* be less visible.
|
* 3 3 9 0
|
||||||
|
* 1 1 1
|
||||||
|
* 1 1 1
|
||||||
|
* 1 1 1
|
||||||
|
*
|
||||||
|
* being converted with scale = 64 (convi does this). We want
|
||||||
|
* to generate a mix of 7s and 8s.
|
||||||
*/
|
*/
|
||||||
out[n / 2] += target - sum;
|
int each_error = (target - sum) / n;
|
||||||
|
int extra_error = (target - sum) % n;
|
||||||
|
|
||||||
|
/* To share the residual error, we add or subtract 1 from the
|
||||||
|
* first abs(extra_error) elements.
|
||||||
|
*/
|
||||||
|
int direction = extra_error > 0 ? 1 : -1;
|
||||||
|
int n_elements = VIPS_ABS( extra_error );
|
||||||
|
|
||||||
|
for( i = 0; i < n; i++ )
|
||||||
|
out[i] += each_error;
|
||||||
|
|
||||||
|
for( i = 0; i < n_elements; i++ )
|
||||||
|
out[i] += direction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user