From daf578ca421e76ad390bccea080be52419f9146c Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 18 Aug 2019 16:35:28 +0100 Subject: [PATCH] seems to work now a switch/case pair --- libvips/conversion/switch.c | 5 +- libvips/histogram/case.c | 144 ++++++++++++++++--------------- libvips/histogram/histogram.c | 4 +- libvips/include/vips/histogram.h | 3 +- 4 files changed, 81 insertions(+), 75 deletions(-) diff --git a/libvips/conversion/switch.c b/libvips/conversion/switch.c index ceec8c88..055b372b 100644 --- a/libvips/conversion/switch.c +++ b/libvips/conversion/switch.c @@ -119,6 +119,9 @@ vips_switch_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_switch_parent_class )->build( object ) ) return( -1 ); + /* 255 rather than 256, since we want to reserve +1 as the no + * match value. + */ tests = vips_area_get_data( &swit->tests->area, NULL, &swit->n, NULL, NULL ); if( swit->n > 255 || @@ -149,7 +152,7 @@ vips_switch_build( VipsObject *object ) /* Images must match in size and bands. */ if( vips__bandalike_vec( class->nickname, tests, band, swit->n, 1 ) || - vips__sizealike_vec( band, size, swit->n + 1 ) ) + vips__sizealike_vec( band, size, swit->n ) ) return( -1 ); tests = size; diff --git a/libvips/histogram/case.c b/libvips/histogram/case.c index ee7cf37b..8ed97a97 100644 --- a/libvips/histogram/case.c +++ b/libvips/histogram/case.c @@ -46,9 +46,9 @@ typedef struct _VipsCase { VipsOperation parent_instance; - VipsImage *in; + VipsImage *index; + VipsArrayImage *cases; VipsImage *out; - VipsArrayImage *lut; int n; } VipsCase; @@ -57,8 +57,6 @@ typedef VipsOperationClass VipsCaseClass; G_DEFINE_TYPE( VipsCase, vips_case, VIPS_TYPE_OPERATION ); -/* Do a map. - */ static int vips_case_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop ) @@ -68,7 +66,7 @@ vips_case_gen( VipsRegion *or, void *seq, void *a, void *b, VipsRect *r = &or->valid; VipsRegion *index = ar[cas->n]; - int x, y, i, j; + int x, y, i; VipsPel * restrict ip; VipsPel * restrict q; size_t ils; @@ -84,20 +82,23 @@ vips_case_gen( VipsRegion *or, void *seq, void *a, void *b, g_assert( index->im->BandFmt == VIPS_FORMAT_UCHAR ); g_assert( index->im->Bands == 1 ); - /* Histogram of input region, so we know which of our inputs we will + /* Histogram of index region, so we know which of our inputs we will * need to prepare. */ - memset( hist, 0, 256 * sizeof( int ) ); + memset( hist, 0, cas->n * sizeof( int ) ); ip = VIPS_REGION_ADDR( index, r->left, r->top ); ils = VIPS_REGION_LSKIP( index ); for( y = 0; y < r->height; y++ ) { - for( x = 0; x < r->width; x++ ) - hist[ip[x]] += 1; + for( x = 0; x < r->width; x++ ) { + int v = VIPS_MIN( ip[x], cas->n - 1 ); + + hist[v] += 1; + } ip += ils; } - for( i = 0; i < 256; i++ ) + for( i = 0; i < cas->n; i++ ) if( hist[i] ) { if( vips_region_prepare( ar[i], r ) ) return( -1 ); @@ -110,19 +111,24 @@ vips_case_gen( VipsRegion *or, void *seq, void *a, void *b, qls = VIPS_REGION_LSKIP( or ); ps = VIPS_IMAGE_SIZEOF_PEL( or->im ); for( y = 0; y < r->height; y++ ) { - i = 0; + int k; + + k = 0; for( x = 0; x < r->width; x++ ) { - VipsPel * restrict pv = p[ip[x]]; + int v = VIPS_MIN( ip[x], cas->n - 1 ); + VipsPel * restrict pv = p[v]; + + int j; for( j = 0; j < ps; j++ ) { - q[i] = pv[i]; - i += 1; + q[k] = pv[k]; + k += 1; } } ip += ils; q += qls; - for( i = 0; i < 256; i++ ) + for( i = 0; i < cas->n; i++ ) if( hist[i] ) p[i] += ls[i]; } @@ -137,8 +143,8 @@ vips_case_build( VipsObject *object ) VipsCase *cas = (VipsCase *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); - VipsImage *in; - VipsImage **lut; + VipsImage *index; + VipsImage **cases; VipsImage **decode; VipsImage **format; VipsImage **band; @@ -150,24 +156,25 @@ vips_case_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_case_parent_class )->build( object ) ) return( -1 ); - in = cas->in; - lut = vips_area_get_data( &cas->lut->area, + index = cas->index; + cases = vips_area_get_data( &cas->cases->area, NULL, &cas->n, NULL, NULL ); - if( cas->n > 256 ) { - vips_error( class->nickname, "%s", _( "LUT too large" ) ); + if( cas->n > 256 || + cas->n < 1 ) { + vips_error( class->nickname, "%s", _( "bad number of cases" ) ); return( -1 ); } - if( in->Bands > 1 ) { + if( index->Bands > 1 ) { vips_error( class->nickname, "%s", _( "index image not 1-band" ) ); return( -1 ); } - /* Cast @in to u8 to make the index image. + /* Cast @index to u8 to make the index image. */ - if( vips_cast( in, &t[0], VIPS_FORMAT_UCHAR, NULL ) ) + if( vips_cast( index, &t[0], VIPS_FORMAT_UCHAR, NULL ) ) return( -1 ); - in = t[0]; + index = t[0]; decode = (VipsImage **) vips_object_local_array( object, cas->n ); format = (VipsImage **) vips_object_local_array( object, cas->n ); @@ -177,37 +184,35 @@ vips_case_build( VipsObject *object ) /* Decode RAD/LABQ etc. */ for( i = 0; i < cas->n; i++ ) - if( vips_image_decode( lut[i], &decode[i] ) ) + if( vips_image_decode( cases[i], &decode[i] ) ) return( -1 ); - lut = decode; + cases = decode; - /* LUT images must match in format, size and bands. + /* case images must match in format, size and bands. * * We want everything sized up to the size of the index image, so add * that to the end of the set of images for sizealike. */ - band[cas->n] = in; - g_object_ref( in ); - if( vips__formatalike_vec( lut, format, cas->n ) || + band[cas->n] = index; + g_object_ref( index ); + if( vips__formatalike_vec( cases, format, cas->n ) || vips__bandalike_vec( class->nickname, format, band, cas->n, 1 ) || vips__sizealike_vec( band, size, cas->n + 1 ) ) return( -1 ); - lut = size; - - cas->out->BandFmt = lut[0]->BandFmt; - cas->out->Bands = lut[0]->Bands; - cas->out->Type = lut[0]->Type; - cas->out->Xsize = in->Xsize; - cas->out->Ysize = in->Ysize; + cases = size; if( vips_image_pipeline_array( cas->out, - VIPS_DEMAND_STYLE_THINSTRIP, lut ) ) + VIPS_DEMAND_STYLE_THINSTRIP, cases ) ) return( -1 ); + cas->out->BandFmt = cases[0]->BandFmt; + cas->out->Bands = cases[0]->Bands; + cas->out->Type = cases[0]->Type; + if( vips_image_generate( cas->out, vips_start_many, vips_case_gen, vips_stop_many, - lut, cas ) ) + cases, cas ) ) return( -1 ); return( 0 ); @@ -225,30 +230,30 @@ vips_case_class_init( VipsCaseClass *class ) object_class->nickname = "case"; object_class->description = - _( "use pixel values to case between a set of images" ); + _( "use pixel values to pick cases from an array of images" ); object_class->build = vips_case_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; - VIPS_ARG_IMAGE( class, "in", 1, - _( "Input" ), - _( "Input image" ), + VIPS_ARG_IMAGE( class, "index", 1, + _( "index" ), + _( "Index image" ), VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsCase, in ) ); + G_STRUCT_OFFSET( VipsCase, index ) ); - VIPS_ARG_IMAGE( class, "out", 2, + VIPS_ARG_BOXED( class, "cases", 2, + _( "cases" ), + _( "Array of case images" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsCase, cases ), + VIPS_TYPE_ARRAY_IMAGE ); + + VIPS_ARG_IMAGE( class, "out", 3, _( "Output" ), _( "Output image" ), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET( VipsCase, out ) ); - VIPS_ARG_BOXED( class, "lut", 3, - _( "LUT" ), - _( "Look-up table of images" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsCase, lut ), - VIPS_TYPE_ARRAY_IMAGE ); - } static void @@ -257,14 +262,14 @@ vips_case_init( VipsCase *cas ) } static int -vips_casev( VipsImage *in, VipsImage **out, VipsImage **lut, int n, +vips_casev( VipsImage *index, VipsImage **cases, VipsImage **out, int n, va_list ap ) { VipsArrayImage *array; int result; - array = vips_array_image_new( lut, n ); - result = vips_call_split( "case", ap, in, out, array ); + array = vips_array_image_new( cases, n ); + result = vips_call_split( "case", ap, index, array, out ); vips_area_unref( VIPS_AREA( array ) ); return( result ); @@ -272,24 +277,21 @@ vips_casev( VipsImage *in, VipsImage **out, VipsImage **lut, int n, /** * vips_case: (method) - * @in: input image + * @index: index image + * @cases: (array length=n): array of case images * @out: (out): output image - * @lut: (array length=n): LUT of input images - * @n: number of input images + * @n: number of case images * @...: %NULL-terminated list of optional named arguments * - * Use pixel values to pick cases from an array of images. + * Use values in @index to select pixels from @cases. * - * Each value in @in is used to select an image from @lut, and the - * corresponding pixel is copied to the output. + * @index must have one band. @cases can have up to 256 elements. Values in + * @index greater than or equal to @n use the final image in @cases. The + * images in @cases must have either one band or the same number of bands. + * The output image is the same size as @index. Images in @cases are + * expanded to the smallest common format and number of bands. * - * @in must have one band. @lut can have up to 256 elements. Values in @in - * greater than or equal to @n use the final image in @lut. The images in @lut - * must have either one band or the same number of bands. The output image is - * the same size as @in. Images in @lut are expanded to the smallest common - * format and number of bands. - * - * Combine this with vips_switch() to make something like a case statement, or + * Combine this with vips_switch() to make something like a case statement or * a multi-way vips_ifthenelse(). * * See also: vips_maplut(), vips_switch(), vips_ifthenelse(). @@ -297,13 +299,13 @@ vips_casev( VipsImage *in, VipsImage **out, VipsImage **lut, int n, * Returns: 0 on success, -1 on error */ int -vips_case( VipsImage *in, VipsImage **out, VipsImage **lut, int n, ... ) +vips_case( VipsImage *index, VipsImage **cases, VipsImage **out, int n, ... ) { va_list ap; int result; va_start( ap, n ); - result = vips_casev( in, out, lut, n, ap ); + result = vips_casev( index, cases, out, n, ap ); va_end( ap ); return( result ); diff --git a/libvips/histogram/histogram.c b/libvips/histogram/histogram.c index c0c97ea1..a7c51b15 100644 --- a/libvips/histogram/histogram.c +++ b/libvips/histogram/histogram.c @@ -251,7 +251,7 @@ void vips_histogram_operation_init( void ) { extern GType vips_maplut_get_type( void ); - extern GType vips_switch_get_type( void ); + extern GType vips_case_get_type( void ); extern GType vips_percent_get_type( void ); extern GType vips_hist_cum_get_type( void ); extern GType vips_hist_norm_get_type( void ); @@ -264,7 +264,7 @@ vips_histogram_operation_init( void ) extern GType vips_stdif_get_type( void ); vips_maplut_get_type(); - vips_switch_get_type(); + vips_case_get_type(); vips_percent_get_type(); vips_stdif_get_type(); vips_hist_cum_get_type(); diff --git a/libvips/include/vips/histogram.h b/libvips/include/vips/histogram.h index c7a2201d..039b9d94 100644 --- a/libvips/include/vips/histogram.h +++ b/libvips/include/vips/histogram.h @@ -64,7 +64,8 @@ int vips_hist_ismonotonic( VipsImage *in, gboolean *out, ... ) int vips_hist_entropy( VipsImage *in, double *out, ... ) __attribute__((sentinel)); -int vips_case( VipsImage *in, VipsImage **out, VipsImage **lut, int n, ... ) +int vips_case( VipsImage *index, VipsImage **cases, VipsImage **out, int n, + ... ) __attribute__((sentinel)); #ifdef __cplusplus