From 1be426749237660b60bb842afb6c0187ab602d5d Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 15 Dec 2017 14:47:56 +0000 Subject: [PATCH] make bandrank work with many input images 400+ tested and seems to work see https://github.com/jcupitt/libvips/issues/822 --- libvips/conversion/bandary.c | 27 +++++++++++---------------- libvips/conversion/bandary.h | 22 +++++++++++++++++++++- libvips/conversion/bandbool.c | 3 ++- libvips/conversion/bandjoin.c | 7 +++++-- libvips/conversion/bandmean.c | 3 ++- libvips/conversion/bandrank.c | 17 ++++------------- libvips/conversion/extract.c | 3 ++- 7 files changed, 47 insertions(+), 35 deletions(-) diff --git a/libvips/conversion/bandary.c b/libvips/conversion/bandary.c index 097b8083..0b4151c4 100644 --- a/libvips/conversion/bandary.c +++ b/libvips/conversion/bandary.c @@ -79,21 +79,6 @@ G_DEFINE_ABSTRACT_TYPE( VipsBandary, vips_bandary, VIPS_TYPE_CONVERSION ); -/* Our sequence value. - */ -typedef struct { - VipsBandary *bandary; - - /* Set of input regions. - */ - VipsRegion **ir; - - /* For each input, an input pointer. - */ - VipsPel **p; - -} VipsBandarySequence; - static int vips_bandary_stop( void *vseq, void *a, void *b ) { @@ -108,6 +93,7 @@ vips_bandary_stop( void *vseq, void *a, void *b ) } VIPS_FREE( seq->p ); + VIPS_FREE( seq->pixels ); VIPS_FREE( seq ); @@ -129,6 +115,7 @@ vips_bandary_start( VipsImage *out, void *a, void *b ) seq->bandary = bandary; seq->ir = NULL; seq->p = NULL; + seq->pixels = NULL; /* How many images? */ @@ -158,6 +145,14 @@ vips_bandary_start( VipsImage *out, void *a, void *b ) return( NULL ); } + /* Pixel buffer. This is used as working space by some subclasses. + */ + if( !(seq->pixels = VIPS_ARRAY( NULL, + n * VIPS_IMAGE_SIZEOF_PEL( bandary->ready[0] ), VipsPel )) ) { + vips_bandary_stop( seq, NULL, NULL ); + return( NULL ); + } + return( seq ); } @@ -182,7 +177,7 @@ vips_bandary_gen( VipsRegion *or, void *vseq, void *a, void *b, gboolean *stop ) VIPS_GATE_START( "vips_bandary_gen: work" ); for( y = 0; y < r->height; y++ ) { - class->process_line( bandary, q, seq->p, r->width ); + class->process_line( seq, q, seq->p, r->width ); for( i = 0; i < bandary->n; i++ ) seq->p[i] += VIPS_REGION_LSKIP( seq->ir[i] ); diff --git a/libvips/conversion/bandary.h b/libvips/conversion/bandary.h index b26f537e..ab1283bc 100644 --- a/libvips/conversion/bandary.h +++ b/libvips/conversion/bandary.h @@ -53,7 +53,27 @@ extern "C" { VIPS_TYPE_BANDARY, VipsBandaryClass )) struct _VipsBandary; -typedef void (*VipsBandaryProcessFn)( struct _VipsBandary *bandary, + +/* Our sequence value. + */ +typedef struct { + struct _VipsBandary *bandary; + + /* Set of input regions. + */ + VipsRegion **ir; + + /* For each input, an input pointer. + */ + VipsPel **p; + + /* A memory area large enough to hold one pixel from each input image. + */ + VipsPel *pixels; + +} VipsBandarySequence; + +typedef void (*VipsBandaryProcessFn)( VipsBandarySequence *seq, VipsPel *out, VipsPel **in, int width ); typedef struct _VipsBandary { diff --git a/libvips/conversion/bandbool.c b/libvips/conversion/bandbool.c index 25e2f440..41c9d4da 100644 --- a/libvips/conversion/bandbool.c +++ b/libvips/conversion/bandbool.c @@ -146,9 +146,10 @@ vips_bandbool_build( VipsObject *object ) } static void -vips_bandbool_buffer( VipsBandary *bandary, +vips_bandbool_buffer( VipsBandarySequence *seq, VipsPel *out, VipsPel **in, int width ) { + VipsBandary *bandary = seq->bandary; VipsBandbool *bandbool = (VipsBandbool *) bandary; VipsImage *im = bandary->ready[0]; int bands = im->Bands; diff --git a/libvips/conversion/bandjoin.c b/libvips/conversion/bandjoin.c index 33275373..c2ce0505 100644 --- a/libvips/conversion/bandjoin.c +++ b/libvips/conversion/bandjoin.c @@ -88,8 +88,10 @@ typedef VipsBandaryClass VipsBandjoinClass; G_DEFINE_TYPE( VipsBandjoin, vips_bandjoin, VIPS_TYPE_BANDARY ); static void -vips_bandjoin_buffer( VipsBandary *bandary, VipsPel *q, VipsPel **p, int width ) +vips_bandjoin_buffer( VipsBandarySequence *seq, + VipsPel *q, VipsPel **p, int width ) { + VipsBandary *bandary = seq->bandary; VipsConversion *conversion = (VipsConversion *) bandary; VipsImage **in = bandary->ready; @@ -296,9 +298,10 @@ vips_bandjoin_const_finalize( GObject *object ) } static void -vips_bandjoin_const_buffer( VipsBandary *bandary, +vips_bandjoin_const_buffer( VipsBandarySequence *seq, VipsPel *q, VipsPel **p, int width ) { + VipsBandary *bandary = seq->bandary; VipsConversion *conversion = (VipsConversion *) bandary; VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) bandary; VipsImage *in = bandary->ready[0]; diff --git a/libvips/conversion/bandmean.c b/libvips/conversion/bandmean.c index f3f057fe..a955f856 100644 --- a/libvips/conversion/bandmean.c +++ b/libvips/conversion/bandmean.c @@ -120,9 +120,10 @@ G_DEFINE_TYPE( VipsBandmean, vips_bandmean, VIPS_TYPE_BANDARY ); } static void -vips_bandmean_buffer( VipsBandary *bandary, +vips_bandmean_buffer( VipsBandarySequence *seq, VipsPel *out, VipsPel **in, int width ) { + VipsBandary *bandary = seq->bandary; VipsImage *im = bandary->ready[0]; const int bands = im->Bands; const int sz = width * diff --git a/libvips/conversion/bandrank.c b/libvips/conversion/bandrank.c index 5256005a..eea50da9 100644 --- a/libvips/conversion/bandrank.c +++ b/libvips/conversion/bandrank.c @@ -147,18 +147,18 @@ G_DEFINE_TYPE( VipsBandrank, vips_bandrank, VIPS_TYPE_BANDARY ); /* Sort input band elements in the stack. Needs to be big enough for * sizeof(band-element) * number-of-images. */ -#define SORT_BUFFER (1024) - static void -vips_bandrank_buffer( VipsBandary *bandary, VipsPel *q, VipsPel **p, int width ) +vips_bandrank_buffer( VipsBandarySequence *seq, + VipsPel *q, VipsPel **p, int width ) { + VipsBandary *bandary = seq->bandary; VipsBandrank *bandrank = (VipsBandrank *) bandary; VipsImage **in = bandary->ready; int sz = width * in[0]->Bands; + VipsPel *sort_buffer = seq->pixels; int i, j, k; int x; - VipsPel sort_buffer[SORT_BUFFER]; /* Special-case max and min. */ @@ -196,15 +196,6 @@ vips_bandrank_build( VipsObject *object ) return( vips_bandary_copy( bandary ) ); } - /* We need to keep one band element for every input image - * on the stack. - */ - if( sizeof( double ) * n > SORT_BUFFER ) { - vips_error( class->nickname, - "%s", _( "too many input images" ) ); - return( -1 ); - } - if( vips__bandalike_vec( class->nickname, in, band, n, 0 ) ) return( -1 ); diff --git a/libvips/conversion/extract.c b/libvips/conversion/extract.c index 7448fdd4..7a60f877 100644 --- a/libvips/conversion/extract.c +++ b/libvips/conversion/extract.c @@ -337,9 +337,10 @@ typedef VipsBandaryClass VipsExtractBandClass; G_DEFINE_TYPE( VipsExtractBand, vips_extract_band, VIPS_TYPE_BANDARY ); static void -vips_extract_band_buffer( VipsBandary *bandary, +vips_extract_band_buffer( VipsBandarySequence *seq, VipsPel *out, VipsPel **in, int width ) { + VipsBandary *bandary = seq->bandary; VipsConversion *conversion = (VipsConversion *) bandary; VipsExtractBand *extract = (VipsExtractBand *) bandary; VipsImage *im = bandary->ready[0];