From 333d15aed0508a7584f75c99862bf004aedd7312 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 3 Sep 2013 14:49:57 +0100 Subject: [PATCH] new hist class structure --- TODO | 9 ++ libvips/arithmetic/arithmetic.c | 10 +- libvips/arithmetic/unary.c | 2 +- libvips/histogram/Makefile.am | 4 +- libvips/histogram/hist_buffer.c | 117 ------------------ libvips/histogram/hist_cum.c | 23 ++-- libvips/histogram/hist_equal.c | 40 ++++-- libvips/histogram/hist_norm.c | 42 +++++-- libvips/histogram/hist_plot.c | 34 ++++- libvips/histogram/hist_unary.c | 99 +++++++++++++++ .../histogram/{hist_buffer.h => hist_unary.h} | 51 ++++---- libvips/histogram/histogram.c | 108 +++++++++++++++- libvips/histogram/maplut.c | 77 +++++++----- libvips/histogram/phistogram.h | 27 +++- libvips/iofuncs/object.c | 9 +- 15 files changed, 412 insertions(+), 240 deletions(-) delete mode 100644 libvips/histogram/hist_buffer.c create mode 100644 libvips/histogram/hist_unary.c rename libvips/histogram/{hist_buffer.h => hist_unary.h} (53%) diff --git a/TODO b/TODO index 55396302..6f88139b 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,12 @@ +- VipsHistogram takes many inputs, all of them hists and includes a + buffer-processing class member + + VipsHistUnary adds a single input + + VipsHistNorm subclasses that + + + - im_histspec() is a binary hist operator ... need many inputs for VipsHistogram and VipsHistBuffer diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index 53e62db3..dcd9be02 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -545,13 +545,15 @@ vips_arithmetic_build( VipsObject *object ) */ arithmetic->ready = size; - if( vips_image_copy_fields_array( arithmetic->out, size ) ) + if( vips_image_copy_fields_array( arithmetic->out, + arithmetic->ready ) ) return( -1 ); vips_demand_hint_array( arithmetic->out, - VIPS_DEMAND_STYLE_THINSTRIP, size ); + VIPS_DEMAND_STYLE_THINSTRIP, arithmetic->ready ); - arithmetic->out->Bands = size[0]->Bands; - arithmetic->out->BandFmt = aclass->format_table[size[0]->BandFmt]; + arithmetic->out->Bands = arithmetic->ready[0]->Bands; + arithmetic->out->BandFmt = + aclass->format_table[arithmetic->ready[0]->BandFmt]; if( vips_image_generate( arithmetic->out, vips_start_many, vips_arithmetic_gen, vips_stop_many, diff --git a/libvips/arithmetic/unary.c b/libvips/arithmetic/unary.c index 17843e4c..5beee6e8 100644 --- a/libvips/arithmetic/unary.c +++ b/libvips/arithmetic/unary.c @@ -86,7 +86,7 @@ vips_unary_class_init( VipsUnaryClass *class ) VIPS_ARG_IMAGE( class, "in", 1, _( "Input" ), - _( "Input image argument" ), + _( "Input image" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsUnary, in ) ); diff --git a/libvips/histogram/Makefile.am b/libvips/histogram/Makefile.am index 99305665..c2e6e089 100644 --- a/libvips/histogram/Makefile.am +++ b/libvips/histogram/Makefile.am @@ -4,8 +4,8 @@ libhistogram_la_SOURCES = \ histogram.c \ phistogram.h \ maplut.c \ - hist_buffer.c \ - hist_buffer.h \ + hist_unary.c \ + hist_unary.h \ hist_cum.c \ hist_norm.c \ hist_equal.c \ diff --git a/libvips/histogram/hist_buffer.c b/libvips/histogram/hist_buffer.c deleted file mode 100644 index 5a59f958..00000000 --- a/libvips/histogram/hist_buffer.c +++ /dev/null @@ -1,117 +0,0 @@ -/* a hist operation implemented as a buffer processor - * - * properties: - * - single hist to single hist - */ - -/* - - Copyright (C) 1991-2005 The National Gallery - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -/* -#define DEBUG - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include - -#include -#include - -#include "phistogram.h" -#include "hist_buffer.h" - -G_DEFINE_ABSTRACT_TYPE( VipsHistBuffer, vips_hist_buffer, VIPS_TYPE_HISTOGRAM ); - -static int -vips_hist_buffer_build( VipsObject *object ) -{ - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); - VipsHistogram *histogram = VIPS_HISTOGRAM( object ); - VipsHistBuffer *hist_buffer = VIPS_HIST_BUFFER( object ); - VipsHistBufferClass *hclass = VIPS_HIST_BUFFER_GET_CLASS( hist_buffer ); - - VipsPel *outbuf; - -#ifdef DEBUG - printf( "vips_hist_buffer_build: " ); - vips_object_print_name( object ); - printf( "\n" ); -#endif /*DEBUG*/ - - if( VIPS_OBJECT_CLASS( vips_hist_buffer_parent_class )-> - build( object ) ) - return( -1 ); - - if( vips_check_hist( class->nickname, histogram->in ) || - vips_check_uncoded( class->nickname, histogram->in ) ) - return( -1 ); - - if( vips_image_wio_input( histogram->in ) || - vips_image_copy_fields( histogram->out, histogram->in ) ) - return( -1 ); - - histogram->out->Xsize = VIPS_IMAGE_N_PELS( histogram->in ); - histogram->out->Ysize = 1; - if( hclass->format_table ) - histogram->out->BandFmt = - hclass->format_table[histogram->in->BandFmt]; - - if( !(outbuf = vips_malloc( object, - VIPS_IMAGE_SIZEOF_LINE( histogram->out ))) ) - return( -1 ); - - hclass->process( hist_buffer, - outbuf, VIPS_IMAGE_ADDR( histogram->in, 0, 0 ), - histogram->in->Xsize ); - - if( vips_image_write_line( histogram->out, 0, outbuf ) ) - return( -1 ); - - return( 0 ); -} - -static void -vips_hist_buffer_class_init( VipsHistBufferClass *class ) -{ - VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - - vobject_class->nickname = "hist_buffer"; - vobject_class->description = _( "hist_buffer operations" ); - vobject_class->build = vips_hist_buffer_build; - -} - -static void -vips_hist_buffer_init( VipsHistBuffer *hist_buffer ) -{ -} diff --git a/libvips/histogram/hist_cum.c b/libvips/histogram/hist_cum.c index 49d5e0b5..bfc950f8 100644 --- a/libvips/histogram/hist_cum.c +++ b/libvips/histogram/hist_cum.c @@ -61,16 +61,16 @@ #include #include "phistogram.h" -#include "hist_buffer.h" +#include "hist_unary.h" -typedef VipsHistBuffer VipsHistCum; -typedef VipsHistBufferClass VipsHistCumClass; +typedef VipsHistUnary VipsHistCum; +typedef VipsHistUnaryClass VipsHistCumClass; -G_DEFINE_TYPE( VipsHistCum, vips_hist_cum, VIPS_TYPE_HIST_BUFFER ); +G_DEFINE_TYPE( VipsHistCum, vips_hist_cum, VIPS_TYPE_HIST_UNARY ); #define ACCUMULATE( ITYPE, OTYPE ) { \ for( b = 0; b < nb; b++ ) { \ - ITYPE *p = (ITYPE *) in; \ + ITYPE *p = (ITYPE *) in[0]; \ OTYPE *q = (OTYPE *) out; \ OTYPE total; \ \ @@ -83,18 +83,17 @@ G_DEFINE_TYPE( VipsHistCum, vips_hist_cum, VIPS_TYPE_HIST_BUFFER ); } static void -vips_hist_cum_buffer( VipsHistBuffer *hist_buffer, - VipsPel *out, VipsPel *in, int width ) +vips_hist_cum_buffer( VipsHistogram *histogram, + VipsPel *out, VipsPel **in, int width ) { - VipsHistogram *histogram = VIPS_HISTOGRAM( hist_buffer ); - const int bands = vips_image_get_bands( histogram->in ); - const int nb = vips_bandfmt_iscomplex( histogram->in->BandFmt ) ? + const int bands = vips_image_get_bands( histogram->ready[0] ); + const int nb = vips_bandfmt_iscomplex( histogram->ready[0]->BandFmt ) ? bands * 2 : bands; int mx = width * nb; int x, b; - switch( vips_image_get_format( histogram->in ) ) { + switch( vips_image_get_format( histogram->ready[0] ) ) { case VIPS_FORMAT_CHAR: ACCUMULATE( signed char, signed int ); break; case VIPS_FORMAT_UCHAR: @@ -142,7 +141,7 @@ static void vips_hist_cum_class_init( VipsHistCumClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsHistBufferClass *hclass = VIPS_HIST_BUFFER_CLASS( class ); + VipsHistogramClass *hclass = VIPS_HISTOGRAM_CLASS( class ); object_class->nickname = "hist_cum"; object_class->description = _( "form cumulative histogram" ); diff --git a/libvips/histogram/hist_equal.c b/libvips/histogram/hist_equal.c index 32efa294..a6cfd683 100644 --- a/libvips/histogram/hist_equal.c +++ b/libvips/histogram/hist_equal.c @@ -53,37 +53,39 @@ #include -#include "phistogram.h" - typedef struct _VipsHistEqual { - VipsHistogram parent_instance; + VipsOperation parent_instance; + + VipsImage *in; + VipsImage *out; /* -1 for all bands, or the band we scan. */ int which; } VipsHistEqual; -typedef VipsHistogramClass VipsHistEqualClass; +typedef VipsOperationClass VipsHistEqualClass; -G_DEFINE_TYPE( VipsHistEqual, vips_hist_equal, VIPS_TYPE_HISTOGRAM ); +G_DEFINE_TYPE( VipsHistEqual, vips_hist_equal, VIPS_TYPE_OPERATION ); static int vips_hist_equal_build( VipsObject *object ) { - VipsHistogram *histogram = VIPS_HISTOGRAM( object ); - VipsHistEqual *hist_equal = (VipsHistEqual *) histogram; + VipsHistEqual *equal = (VipsHistEqual *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); + g_object_set( equal, "out", vips_image_new(), NULL ); + if( VIPS_OBJECT_CLASS( vips_hist_equal_parent_class )->build( object ) ) return( -1 ); - if( vips_hist_find( histogram->in, &t[0], - "band", hist_equal->which, + if( vips_hist_find( equal->in, &t[0], + "band", equal->which, NULL ) || vips_hist_cum( t[0], &t[1], NULL ) || vips_hist_norm( t[1], &t[2], NULL ) || - vips_maplut( histogram->in, &t[3], t[2], NULL ) || - vips_image_write( t[3], histogram->out ) ) + vips_maplut( equal->in, &t[3], t[2], NULL ) || + vips_image_write( t[3], equal->out ) ) return( -1 ); return( 0 ); @@ -102,6 +104,18 @@ vips_hist_equal_class_init( VipsHistEqualClass *class ) object_class->description = _( "histogram equalisation" ); object_class->build = vips_hist_equal_build; + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), + _( "Input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsHistEqual, in ) ); + + VIPS_ARG_IMAGE( class, "out", 2, + _( "Output" ), + _( "Output image" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsHistEqual, out ) ); + VIPS_ARG_INT( class, "band", 110, _( "Band" ), _( "Equalise with this band" ), @@ -111,9 +125,9 @@ vips_hist_equal_class_init( VipsHistEqualClass *class ) } static void -vips_hist_equal_init( VipsHistEqual *hist_equal ) +vips_hist_equal_init( VipsHistEqual *equal ) { - hist_equal->which = -1; + equal->which = -1; } /** diff --git a/libvips/histogram/hist_norm.c b/libvips/histogram/hist_norm.c index ac6e6177..ef1041ca 100644 --- a/libvips/histogram/hist_norm.c +++ b/libvips/histogram/hist_norm.c @@ -60,17 +60,21 @@ #include -#include "phistogram.h" +typedef struct _VipsHistNorm { + VipsOperation parent_instance; -typedef VipsHistogram VipsHistNorm; -typedef VipsHistogramClass VipsHistNormClass; + VipsImage *in; + VipsImage *out; +} VipsHistNorm; -G_DEFINE_TYPE( VipsHistNorm, vips_hist_norm, VIPS_TYPE_HISTOGRAM ); +typedef VipsOperationClass VipsHistNormClass; + +G_DEFINE_TYPE( VipsHistNorm, vips_hist_norm, VIPS_TYPE_OPERATION ); static int vips_hist_norm_build( VipsObject *object ) { - VipsHistogram *histogram = VIPS_HISTOGRAM( object ); + VipsHistNorm *norm = (VipsHistNorm *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 3 ); guint64 px; @@ -79,18 +83,20 @@ vips_hist_norm_build( VipsObject *object ) int y; VipsBandFormat fmt; + g_object_set( norm, "out", vips_image_new(), NULL ); + if( VIPS_OBJECT_CLASS( vips_hist_norm_parent_class )->build( object ) ) return( -1 ); /* Need max for each channel. */ - if( vips_stats( histogram->in, &t[0], NULL ) ) + if( vips_stats( norm->in, &t[0], NULL ) ) return( -1 ); /* Scale each channel by px / channel max */ - px = VIPS_IMAGE_N_PELS( histogram->in ); - bands = histogram->in->Bands; + px = VIPS_IMAGE_N_PELS( norm->in ); + bands = norm->in->Bands; if( !(a = VIPS_ARRAY( object, bands, double )) || !(b = VIPS_ARRAY( object, bands, double )) ) return( -1 ); @@ -99,7 +105,7 @@ vips_hist_norm_build( VipsObject *object ) b[y] = 0; } - if( vips_linear( histogram->in, &t[1], a, b, bands, NULL ) ) + if( vips_linear( norm->in, &t[1], a, b, bands, NULL ) ) return( -1 ); /* Make output format as small as we can. @@ -112,7 +118,7 @@ vips_hist_norm_build( VipsObject *object ) fmt = VIPS_FORMAT_UINT; if( vips_cast( t[1], &t[2], fmt, NULL ) || - vips_image_write( t[2], histogram->out ) ) + vips_image_write( t[2], norm->out ) ) return( -1 ); return( 0 ); @@ -121,11 +127,27 @@ vips_hist_norm_build( VipsObject *object ) static void vips_hist_norm_class_init( VipsHistNormClass *class ) { + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + object_class->nickname = "hist_norm"; object_class->description = _( "normalise histogram" ); object_class->build = vips_hist_norm_build; + + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), + _( "Input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsHistNorm, in ) ); + + VIPS_ARG_IMAGE( class, "out", 2, + _( "Output" ), + _( "Output image" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsHistNorm, out ) ); } static void diff --git a/libvips/histogram/hist_plot.c b/libvips/histogram/hist_plot.c index 1ac4a65f..7b52e9fe 100644 --- a/libvips/histogram/hist_plot.c +++ b/libvips/histogram/hist_plot.c @@ -298,20 +298,28 @@ im_histplot( IMAGE *in, IMAGE *out ) return( 0 ); } -typedef VipsHistogram VipsHistPlot; -typedef VipsHistogramClass VipsHistPlotClass; +typedef struct _VipsHistPlot { + VipsOperation parent_instance; -G_DEFINE_TYPE( VipsHistPlot, vips_hist_plot, VIPS_TYPE_HISTOGRAM ); + VipsImage *in; + VipsImage *out; +} VipsHistPlot; + +typedef VipsOperationClass VipsHistPlotClass; + +G_DEFINE_TYPE( VipsHistPlot, vips_hist_plot, VIPS_TYPE_OPERATION ); static int vips_hist_plot_build( VipsObject *object ) { - VipsHistogram *histogram = VIPS_HISTOGRAM( object ); + VipsHistPlot *plot = (VipsHistPlot *) object; + + g_object_set( plot, "out", vips_image_new(), NULL ); if( VIPS_OBJECT_CLASS( vips_hist_plot_parent_class )->build( object ) ) return( -1 ); - if( im_histplot( histogram->in, histogram->out ) ) + if( im_histplot( plot->in, plot->out ) ) return( -1 ); return( 0 ); @@ -320,11 +328,27 @@ vips_hist_plot_build( VipsObject *object ) static void vips_hist_plot_class_init( VipsHistPlotClass *class ) { + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *object_class = (VipsObjectClass *) class; + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + object_class->nickname = "hist_plot"; object_class->description = _( "plot histogram" ); object_class->build = vips_hist_plot_build; + + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), + _( "Input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsHistPlot, in ) ); + + VIPS_ARG_IMAGE( class, "out", 2, + _( "Output" ), + _( "Output image" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsHistPlot, out ) ); } static void diff --git a/libvips/histogram/hist_unary.c b/libvips/histogram/hist_unary.c new file mode 100644 index 00000000..055c7225 --- /dev/null +++ b/libvips/histogram/hist_unary.c @@ -0,0 +1,99 @@ +/* a hist operation implemented as a unary processor + * + * properties: + * - single hist to single hist + */ + +/* + + Copyright (C) 1991-2005 The National Gallery + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +/* +#define DEBUG + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include + +#include +#include + +#include "phistogram.h" +#include "hist_unary.h" + +G_DEFINE_ABSTRACT_TYPE( VipsHistUnary, vips_hist_unary, VIPS_TYPE_HISTOGRAM ); + +static int +vips_hist_unary_build( VipsObject *object ) +{ + VipsHistogram *histogram = VIPS_HISTOGRAM( object ); + VipsHistUnary *unary = VIPS_HIST_UNARY( object ); + + histogram->n = 1; + histogram->in = (VipsImage **) vips_object_local_array( object, 1 ); + histogram->in[0] = unary->in; + + if( histogram->in[0] ) + g_object_ref( histogram->in[0] ); + + if( VIPS_OBJECT_CLASS( vips_hist_unary_parent_class )-> + build( object ) ) + return( -1 ); + + return( 0 ); +} + +static void +vips_hist_unary_class_init( VipsHistUnaryClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->nickname = "hist_unary"; + vobject_class->description = _( "hist_unary operations" ); + vobject_class->build = vips_hist_unary_build; + + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), + _( "Input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsHistUnary, in ) ); + +} + +static void +vips_hist_unary_init( VipsHistUnary *hist_unary ) +{ +} diff --git a/libvips/histogram/hist_buffer.h b/libvips/histogram/hist_unary.h similarity index 53% rename from libvips/histogram/hist_buffer.h rename to libvips/histogram/hist_unary.h index 80468ba1..aaf416aa 100644 --- a/libvips/histogram/hist_buffer.h +++ b/libvips/histogram/hist_unary.h @@ -1,4 +1,4 @@ -/* base class for all hist_buffer operations +/* base class for all hist_unary operations */ /* @@ -28,8 +28,8 @@ */ -#ifndef VIPS_PHIST_BUFFER_H -#define VIPS_PHIST_BUFFER_H +#ifndef VIPS_PHIST_UNARY_H +#define VIPS_PHIST_UNARY_H #ifdef __cplusplus extern "C" { @@ -37,46 +37,39 @@ extern "C" { #include -#define VIPS_TYPE_HIST_BUFFER (vips_hist_buffer_get_type()) -#define VIPS_HIST_BUFFER( obj ) \ +#define VIPS_TYPE_HIST_UNARY (vips_hist_unary_get_type()) +#define VIPS_HIST_UNARY( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ - VIPS_TYPE_HIST_BUFFER, VipsHistBuffer )) -#define VIPS_HIST_BUFFER_CLASS( klass ) \ + VIPS_TYPE_HIST_UNARY, VipsHistUnary )) +#define VIPS_HIST_UNARY_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ - VIPS_TYPE_HIST_BUFFER, VipsHistBufferClass)) -#define VIPS_IS_HIST_BUFFER( obj ) \ - (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_HIST_BUFFER )) -#define VIPS_IS_HIST_BUFFER_CLASS( klass ) \ - (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_HIST_BUFFER )) -#define VIPS_HIST_BUFFER_GET_CLASS( obj ) \ + VIPS_TYPE_HIST_UNARY, VipsHistUnaryClass)) +#define VIPS_IS_HIST_UNARY( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_HIST_UNARY )) +#define VIPS_IS_HIST_UNARY_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_HIST_UNARY )) +#define VIPS_HIST_UNARY_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ - VIPS_TYPE_HIST_BUFFER, VipsHistBufferClass )) + VIPS_TYPE_HIST_UNARY, VipsHistUnaryClass )) -struct _VipsHistBuffer; -typedef void (*VipsHistBufferProcessFn)( struct _VipsHistBuffer *hist_buffer, - VipsPel *out, VipsPel *in, int width ); - -typedef struct _VipsHistBuffer { +typedef struct _VipsHistUnary { VipsHistogram parent_instance; -} VipsHistBuffer; + VipsImage *in; -typedef struct _VipsHistBufferClass { +} VipsHistUnary; + +typedef struct _VipsHistUnaryClass { VipsHistogramClass parent_class; - /* For each input format, what output format. - */ - const VipsBandFormat *format_table; +} VipsHistUnaryClass; - VipsHistBufferProcessFn process; -} VipsHistBufferClass; - -GType vips_hist_buffer_get_type( void ); +GType vips_hist_unary_get_type( void ); #ifdef __cplusplus } #endif /*__cplusplus*/ -#endif /*VIPS_PHIST_BUFFER_H*/ +#endif /*VIPS_PHIST_UNARY_H*/ diff --git a/libvips/histogram/histogram.c b/libvips/histogram/histogram.c index 52d0c00c..89717c38 100644 --- a/libvips/histogram/histogram.c +++ b/libvips/histogram/histogram.c @@ -76,10 +76,50 @@ G_DEFINE_ABSTRACT_TYPE( VipsHistogram, vips_histogram, VIPS_TYPE_OPERATION ); +/* sizealike by expanding in just one dimension. + */ +static int +vips__hist_sizealike_vec( VipsImage **in, VipsImage **out, int n ) +{ + int i; + int max_size; + + g_assert( n >= 1 ); + + max_size = VIPS_MAX( in[0]->Xsize, in[0]->Ysize ); + for( i = 1; i < n; i++ ) + max_size = VIPS_MAX( max_size, + VIPS_MAX( in[0]->Xsize, in[0]->Ysize ) ); + + for( i = 0; i < n; i++ ) + if( in[i]->Ysize == 1 ) { + if( vips_embed( in[i], &out[i], + 0, 0, max_size, 1, NULL ) ) + return( -1 ); + } + else { + if( vips_embed( in[i], &out[i], + 0, 0, 1, max_size, NULL ) ) + return( -1 ); + } + + return( 0 ); +} + static int vips_histogram_build( VipsObject *object ) { VipsHistogram *histogram = VIPS_HISTOGRAM( object ); + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + VipsHistogramClass *hclass = VIPS_HISTOGRAM_GET_CLASS( histogram ); + + VipsImage **format; + VipsImage **band; + VipsImage **size; + + VipsPel *outbuf; + VipsPel **inbuf; + int i; #ifdef DEBUG printf( "vips_histogram_build: " ); @@ -90,8 +130,64 @@ vips_histogram_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_histogram_parent_class )->build( object ) ) return( -1 ); + g_assert( histogram->n > 0 ); + + /* Must be NULL-terminated. + */ + g_assert( !histogram->in[histogram->n] ); + + format = (VipsImage **) vips_object_local_array( object, histogram->n ); + band = (VipsImage **) vips_object_local_array( object, histogram->n ); + size = (VipsImage **) vips_object_local_array( object, histogram->n ); + g_object_set( histogram, "out", vips_image_new(), NULL ); + for( i = 0; i < histogram->n; i++ ) + if( vips_check_uncoded( class->nickname, histogram->in[i] ) || + vips_check_hist( class->nickname, histogram->in[i] ) ) + return( -1 ); + + /* Cast our input images up to a common format, bands and size. + */ + if( vips__formatalike_vec( histogram->in, format, histogram->n ) || + vips__bandalike_vec( class->nickname, + format, band, histogram->n, 1 ) || + vips__hist_sizealike_vec( band, size, histogram->n ) ) + return( -1 ); + + /* Keep a copy of the processed images here for subclasses. + */ + histogram->ready = size; + + if( vips_image_copy_fields_array( histogram->out, histogram->ready ) ) + return( -1 ); + vips_demand_hint_array( histogram->out, + VIPS_DEMAND_STYLE_THINSTRIP, histogram->ready ); + + histogram->out->Xsize = VIPS_IMAGE_N_PELS( histogram->ready[0] ); + histogram->out->Ysize = 1; + if( hclass->format_table ) + histogram->out->BandFmt = + hclass->format_table[histogram->ready[0]->BandFmt]; + + if( !(outbuf = vips_malloc( object, + VIPS_IMAGE_SIZEOF_LINE( histogram->out ))) ) + return( -1 ); + + if( !(inbuf = VIPS_ARRAY( object, histogram->n + 1, VipsPel * )) ) + return( -1 ); + for( i = 0; i < histogram->n; i++ ) { + if( vips_image_wio_input( histogram->ready[i] ) ) + return( -1 ); + inbuf[i] = VIPS_IMAGE_ADDR( histogram->in[i], 0, 0 ); + } + inbuf[i] = NULL; + + hclass->process( histogram, outbuf, inbuf, histogram->ready[0]->Xsize ); + + if( vips_image_write_line( histogram->out, 0, outbuf ) ) + return( -1 ); + return( 0 ); } @@ -108,13 +204,10 @@ vips_histogram_class_init( VipsHistogramClass *class ) vobject_class->description = _( "histogram operations" ); vobject_class->build = vips_histogram_build; - VIPS_ARG_IMAGE( class, "in", 0, - _( "Input" ), - _( "Input image" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsHistogram, in ) ); + /* Inputs set by subclassess. + */ - VIPS_ARG_IMAGE( class, "out", 1, + VIPS_ARG_IMAGE( class, "out", 10, _( "Output" ), _( "Output image" ), VIPS_ARGUMENT_REQUIRED_OUTPUT, @@ -125,6 +218,9 @@ vips_histogram_class_init( VipsHistogramClass *class ) static void vips_histogram_init( VipsHistogram *histogram ) { + /* Sanity check this above. + */ + histogram->n = -1; } /* Called from iofuncs to init all operations in this dir. Use a plugin system diff --git a/libvips/histogram/maplut.c b/libvips/histogram/maplut.c index 56f0ced8..56f408fc 100644 --- a/libvips/histogram/maplut.c +++ b/libvips/histogram/maplut.c @@ -71,11 +71,11 @@ #include -#include "phistogram.h" - typedef struct _VipsMaplut { - VipsHistogram parent_instance; + VipsOperation parent_instance; + VipsImage *in; + VipsImage *out; VipsImage *lut; int fmt; /* LUT image BandFmt */ @@ -88,9 +88,9 @@ typedef struct _VipsMaplut { } VipsMaplut; -typedef VipsHistogramClass VipsMaplutClass; +typedef VipsOperationClass VipsMaplutClass; -G_DEFINE_TYPE( VipsMaplut, vips_maplut, VIPS_TYPE_HISTOGRAM ); +G_DEFINE_TYPE( VipsMaplut, vips_maplut, VIPS_TYPE_OPERATION ); static void vips_maplut_preeval( VipsImage *image, VipsProgress *progress, @@ -410,26 +410,26 @@ vips_maplut_start( VipsImage *out, void *a, void *b ) */ #define outer_switch( UCHAR_F, UCHAR_FC, GEN_F, GEN_FC ) \ switch( maplut->fmt ) { \ - case VIPS_FORMAT_UCHAR: inner_switch( UCHAR_F, GEN_F, \ - unsigned char ); break; \ - case VIPS_FORMAT_CHAR: inner_switch( UCHAR_F, GEN_F, \ - char ); break; \ - case VIPS_FORMAT_USHORT: inner_switch( UCHAR_F, GEN_F, \ - unsigned short ); break; \ - case VIPS_FORMAT_SHORT: inner_switch( UCHAR_F, GEN_F, \ - short ); break; \ - case VIPS_FORMAT_UINT: inner_switch( UCHAR_F, GEN_F, \ - unsigned int ); break; \ - case VIPS_FORMAT_INT: inner_switch( UCHAR_F, GEN_F, \ - int ); break; \ - case VIPS_FORMAT_FLOAT: inner_switch( UCHAR_F, GEN_F, \ - float ); break; \ - case VIPS_FORMAT_DOUBLE: inner_switch( UCHAR_F, GEN_F, \ - double ); break; \ - case VIPS_FORMAT_COMPLEX: inner_switch( UCHAR_FC, GEN_FC, \ - float ); break; \ - case VIPS_FORMAT_DPCOMPLEX: inner_switch( UCHAR_FC, GEN_FC, \ - double ); break; \ + case VIPS_FORMAT_UCHAR: \ + inner_switch( UCHAR_F, GEN_F, unsigned char ); break; \ + case VIPS_FORMAT_CHAR:\ + inner_switch( UCHAR_F, GEN_F, char ); break; \ + case VIPS_FORMAT_USHORT: \ + inner_switch( UCHAR_F, GEN_F, unsigned short ); break; \ + case VIPS_FORMAT_SHORT: \ + inner_switch( UCHAR_F, GEN_F, short ); break; \ + case VIPS_FORMAT_UINT: \ + inner_switch( UCHAR_F, GEN_F, unsigned int ); break; \ + case VIPS_FORMAT_INT: \ + inner_switch( UCHAR_F, GEN_F, int ); break; \ + case VIPS_FORMAT_FLOAT: \ + inner_switch( UCHAR_F, GEN_F, float ); break; \ + case VIPS_FORMAT_DOUBLE: \ + inner_switch( UCHAR_F, GEN_F, double ); break; \ + case VIPS_FORMAT_COMPLEX: \ + inner_switch( UCHAR_FC, GEN_FC, float ); break; \ + case VIPS_FORMAT_DPCOMPLEX: \ + inner_switch( UCHAR_FC, GEN_FC, double ); break; \ default: \ g_assert( 0 ); \ } @@ -507,7 +507,6 @@ static int vips_maplut_build( VipsObject *object ) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); - VipsHistogram *histogram = VIPS_HISTOGRAM( object ); VipsMaplut *maplut = (VipsMaplut *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 ); @@ -519,7 +518,7 @@ vips_maplut_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_maplut_parent_class )->build( object ) ) return( -1 ); - in = histogram->in; + in = maplut->in; lut = maplut->lut; if( vips_check_hist( class->nickname, lut ) || @@ -538,17 +537,17 @@ vips_maplut_build( VipsObject *object ) vips_image_pio_input( in ) ) return( -1 ); - if( vips_image_copy_fieldsv( histogram->out, in, lut, NULL ) ) + if( vips_image_copy_fieldsv( maplut->out, in, lut, NULL ) ) return( -1 ); - vips_demand_hint( histogram->out, VIPS_DEMAND_STYLE_THINSTRIP, + vips_demand_hint( maplut->out, VIPS_DEMAND_STYLE_THINSTRIP, in, lut, NULL ); - histogram->out->BandFmt = lut->BandFmt; + maplut->out->BandFmt = lut->BandFmt; /* Output has same number of bands as LUT, unless LUT has 1 band, in * which case output has same number of bands as input. */ if( lut->Bands != 1 ) - histogram->out->Bands = lut->Bands; + maplut->out->Bands = lut->Bands; g_signal_connect( in, "preeval", G_CALLBACK( vips_maplut_preeval ), maplut ); @@ -583,7 +582,7 @@ vips_maplut_build( VipsObject *object ) q += maplut->es; } - if( vips_image_generate( histogram->out, + if( vips_image_generate( maplut->out, vips_maplut_start, vips_maplut_gen, vips_maplut_stop, in, maplut ) ) return( -1 ); @@ -607,7 +606,19 @@ vips_maplut_class_init( VipsMaplutClass *class ) operation_class->flags = VIPS_OPERATION_SEQUENTIAL; - VIPS_ARG_IMAGE( class, "lut", 2, + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), + _( "Input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMaplut, in ) ); + + VIPS_ARG_IMAGE( class, "out", 2, + _( "Output" ), + _( "Output image" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsMaplut, out ) ); + + VIPS_ARG_IMAGE( class, "lut", 3, _( "LUT" ), _( "Look-up table image" ), VIPS_ARGUMENT_REQUIRED_INPUT, diff --git a/libvips/histogram/phistogram.h b/libvips/histogram/phistogram.h index b623bd85..37d4a518 100644 --- a/libvips/histogram/phistogram.h +++ b/libvips/histogram/phistogram.h @@ -1,4 +1,6 @@ /* base class for all histogram operations + * + * many hists in, one hist out, a buffer processing function in the class */ /* @@ -52,18 +54,35 @@ extern "C" { (G_TYPE_INSTANCE_GET_CLASS( (obj), \ VIPS_TYPE_HISTOGRAM, VipsHistogramClass )) -typedef struct _VipsHistogram { - VipsOperation parent_instance; +typedef struct _VipsHistogram VipsHistogram; - VipsImage *in; +typedef void (*VipsHistogramProcessFn)( VipsHistogram *histogram, + VipsPel *out, VipsPel **in, int width ); + +struct _VipsHistogram { + VipsOperation parent_instance; VipsImage *out; -} VipsHistogram; + /* NULL-terminated array of input images. + */ + VipsImage **in; + int n; + + /* ... and transformed ready for processing. + */ + VipsImage **ready; +}; typedef struct _VipsHistogramClass { VipsOperationClass parent_class; + /* For each input format, what output format. + */ + const VipsBandFormat *format_table; + + VipsHistogramProcessFn process; + } VipsHistogramClass; GType vips_histogram_get_type( void ); diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index d8111cee..a39c459f 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -2370,10 +2370,11 @@ vips_object_local_array_cb( GObject *parent, VipsObjectLocal *local ) * @n: array size * * Make an array of NULL VipsObject pointers. When @parent closes, every - * non-NULL pointer in the array will be unreffed and the arraqy will be - * freed. - * Handy for creating a - * set of temporary images for a function. + * non-NULL pointer in the array will be unreffed and the array will be + * freed. Handy for creating a set of temporary images for a function. + * + * The array is NULL-terminated, ie. contains an extra NULL element at the + * end. * * Example: *