From 15dcb2791670a6d487c4d98a0daad7101dd4b91b Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 13 Aug 2013 15:33:29 +0100 Subject: [PATCH] redo im_histnorm() as a class also deprecate im_histeq() (it's just cum + norm) --- ChangeLog | 2 +- libvips/deprecated/vips7compat.c | 30 ++++++ libvips/histogram/Makefile.am | 2 +- libvips/histogram/hist_norm.c | 142 +++++++++++++---------------- libvips/histogram/histogram.c | 2 + libvips/histogram/im_histeq.c | 142 ----------------------------- libvips/histogram/maplut.c | 8 +- libvips/include/vips/histogram.h | 4 +- libvips/include/vips/vips7compat.h | 2 + 9 files changed, 103 insertions(+), 231 deletions(-) delete mode 100644 libvips/histogram/im_histeq.c diff --git a/ChangeLog b/ChangeLog index 4ac5be27..5e4a7c82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,7 +3,7 @@ - rename image arrays as image matrices ... INTERPRETATION_ARRAY -> INTERPRETATION_MATRIX etc. - rewrite im_buildlut(), im_identity*(), im_maplut(), im_falsecolour(), - im_gammacorrect(), im_histgr(), im_histcum() as classes + im_gammacorrect(), im_histgr(), im_histcum(), im_histnorm() as classes - added vips_error_freeze() / vips_error_thaw() - used freeze() / thaw() to stop file format sniffers logging spurious errors - vipsthumbnail uses embedded jpg thumbnails if it can diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 02b5b946..6842828d 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -3341,6 +3341,36 @@ im_histcum( IMAGE *in, IMAGE *out ) return( 0 ); } +int +im_histnorm( IMAGE *in, IMAGE *out ) +{ + VipsImage *x; + + if( vips_hist_norm( in, &x, NULL ) ) + return( -1 ); + + if( im_copy( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} + +int +im_histeq( IMAGE *in, IMAGE *out ) +{ + IMAGE *t1; + + if( !(t1 = im_open_local( out, "im_histeq", "p" )) || + im_histcum( in, t1 ) || + im_histnorm( t1, out ) ) + return( -1 ); + + return( 0 ); +} + int im_hist( IMAGE *in, IMAGE *out, int bandno ) { diff --git a/libvips/histogram/Makefile.am b/libvips/histogram/Makefile.am index 706dcfed..443c4df2 100644 --- a/libvips/histogram/Makefile.am +++ b/libvips/histogram/Makefile.am @@ -7,10 +7,10 @@ libhistogram_la_SOURCES = \ hist_buffer.c \ hist_buffer.h \ hist_cum.c \ + hist_norm.c \ \ hist_dispatch.c \ im_heq.c \ - im_histeq.c \ im_histnD.c \ im_histplot.c \ im_histindexed.c \ diff --git a/libvips/histogram/hist_norm.c b/libvips/histogram/hist_norm.c index f1724fda..ac6e6177 100644 --- a/libvips/histogram/hist_norm.c +++ b/libvips/histogram/hist_norm.c @@ -8,7 +8,7 @@ * - smartened up again * - now works for hists >256 elements * 3/3/01 JC - * - broken into cum and norm ... helps im_histspec() + * - broken into norm and norm ... helps im_histspec() * - better behaviour for >8 bit hists * 31/10/05 JC * - was broken for vertical histograms, gah @@ -16,12 +16,12 @@ * 23/7/07 * - eek, off by 1 for more than 1 band hists * 12/5/08 - * - histcum works for signed hists now as well + * - histnorm works for signed hists now as well * 24/3/10 * - gtkdoc * - small cleanups * 12/8/13 - * - redone im_histcum() as a class, vips_hist_cum() + * - redone im_histnorm() as a class, vips_hist_norm() */ /* @@ -62,117 +62,97 @@ #include "phistogram.h" -typedef VipsHistogram VipsHistCum; -typedef VipsHistogramClass VipsHistCumClass; +typedef VipsHistogram VipsHistNorm; +typedef VipsHistogramClass VipsHistNormClass; -G_DEFINE_TYPE( VipsHistCum, vips_hist_cum, VIPS_TYPE_HISTOGRAM ); +G_DEFINE_TYPE( VipsHistNorm, vips_hist_norm, VIPS_TYPE_HISTOGRAM ); -#define ACCUMULATE( ITYPE, OTYPE ) { \ - for( b = 0; b < nb; b++ ) { \ - ITYPE *p = (ITYPE *) in; \ - OTYPE *q = (OTYPE *) out; \ - OTYPE total; \ - \ - total = 0; \ - for( x = b; x < mx; x += nb ) { \ - total += p[x]; \ - q[x] = total; \ - } \ - } \ -} - -static void -vips_hist_cum_buffer( VipsHistogram *histogram, - VipsPel *out, VipsPel *in, int width ) +static int +vips_hist_norm_build( VipsObject *object ) { - const int bands = vips_image_get_bands( histogram->in ); - const int nb = vips_bandfmt_iscomplex( histogram->in->BandFmt ) ? - bands * 2 : bands; - int mx = width * nb; + VipsHistogram *histogram = VIPS_HISTOGRAM( object ); + VipsImage **t = (VipsImage **) vips_object_local_array( object, 3 ); - int x, b; + guint64 px; + int bands; + double *a, *b; + int y; + VipsBandFormat fmt; - switch( vips_image_get_format( histogram->in ) ) { - case VIPS_FORMAT_CHAR: - ACCUMULATE( signed char, signed int ); break; - case VIPS_FORMAT_UCHAR: - ACCUMULATE( unsigned char, unsigned int ); break; - case VIPS_FORMAT_SHORT: - ACCUMULATE( signed short, signed int ); break; - case VIPS_FORMAT_USHORT: - ACCUMULATE( unsigned short, unsigned int ); break; - case VIPS_FORMAT_INT: - ACCUMULATE( signed int, signed int ); break; - case VIPS_FORMAT_UINT: - ACCUMULATE( unsigned int, unsigned int ); break; + if( VIPS_OBJECT_CLASS( vips_hist_norm_parent_class )->build( object ) ) + return( -1 ); - case VIPS_FORMAT_FLOAT: - case VIPS_FORMAT_COMPLEX: - ACCUMULATE( float, float ); break; - case VIPS_FORMAT_DOUBLE: - case VIPS_FORMAT_DPCOMPLEX: - ACCUMULATE( double, double ); break; + /* Need max for each channel. + */ + if( vips_stats( histogram->in, &t[0], NULL ) ) + return( -1 ); - default: - g_assert( 0 ); - } + /* Scale each channel by px / channel max + */ + px = VIPS_IMAGE_N_PELS( histogram->in ); + bands = histogram->in->Bands; + if( !(a = VIPS_ARRAY( object, bands, double )) || + !(b = VIPS_ARRAY( object, bands, double )) ) + return( -1 ); + for( y = 0; y < bands; y++ ) { + a[y] = px / *VIPS_MATRIX( t[0], 1, y + 1 ); + b[y] = 0; + } + + if( vips_linear( histogram->in, &t[1], a, b, bands, NULL ) ) + return( -1 ); + + /* Make output format as small as we can. + */ + if( px <= 256 ) + fmt = VIPS_FORMAT_UCHAR; + else if( px <= 65536 ) + fmt = VIPS_FORMAT_USHORT; + else + fmt = VIPS_FORMAT_UINT; + + if( vips_cast( t[1], &t[2], fmt, NULL ) || + vips_image_write( t[2], histogram->out ) ) + return( -1 ); + + return( 0 ); } -/* Save a bit of typing. - */ -#define UC VIPS_FORMAT_UCHAR -#define C VIPS_FORMAT_CHAR -#define US VIPS_FORMAT_USHORT -#define S VIPS_FORMAT_SHORT -#define UI VIPS_FORMAT_UINT -#define I VIPS_FORMAT_INT -#define F VIPS_FORMAT_FLOAT -#define X VIPS_FORMAT_COMPLEX -#define D VIPS_FORMAT_DOUBLE -#define DX VIPS_FORMAT_DPCOMPLEX - -static const VipsBandFormat vips_bandfmt_hist_cum[10] = { -/* UC C US S UI I F X D DX */ - UI, I, UI, I, UI, I, F, F, D, D -}; - static void -vips_hist_cum_class_init( VipsHistCumClass *class ) +vips_hist_norm_class_init( VipsHistNormClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; - VipsHistogramClass *hclass = VIPS_HISTOGRAM_CLASS( class ); - object_class->nickname = "hist_cum"; - object_class->description = _( "form cumulative histogram" ); - - hclass->format_table = vips_bandfmt_hist_cum; - hclass->process = vips_hist_cum_buffer; + object_class->nickname = "hist_norm"; + object_class->description = _( "normalise histogram" ); + object_class->build = vips_hist_norm_build; } static void -vips_hist_cum_init( VipsHistCum *hist_cum ) +vips_hist_norm_init( VipsHistNorm *hist_norm ) { } /** - * vips_hist_cum: + * vips_hist_norm: * @in: input image * @out: output image * - * Form cumulative histogram. + * Normalise histogram ... normalise range to make it square (ie. max == + * number of elements). Normalise each band separately. * - * See also: vips_hist_norm(). + * See also: vips_hist_cum(). * * Returns: 0 on success, -1 on error */ int -vips_hist_cum( VipsImage *in, VipsImage **out, ... ) +vips_hist_norm( VipsImage *in, VipsImage **out, ... ) { va_list ap; int result; va_start( ap, out ); - result = vips_call_split( "hist_cum", ap, in, out ); + result = vips_call_split( "hist_norm", ap, in, out ); va_end( ap ); return( result ); diff --git a/libvips/histogram/histogram.c b/libvips/histogram/histogram.c index ee6cef43..9e962457 100644 --- a/libvips/histogram/histogram.c +++ b/libvips/histogram/histogram.c @@ -135,7 +135,9 @@ vips_histogram_operation_init( void ) { extern GType vips_maplut_get_type( void ); extern GType vips_hist_cum_get_type( void ); + extern GType vips_hist_norm_get_type( void ); vips_maplut_get_type(); vips_hist_cum_get_type(); + vips_hist_norm_get_type(); } diff --git a/libvips/histogram/im_histeq.c b/libvips/histogram/im_histeq.c deleted file mode 100644 index eb64c7c9..00000000 --- a/libvips/histogram/im_histeq.c +++ /dev/null @@ -1,142 +0,0 @@ -/* histogram normalisation and cumulativisation - * - * Author: N. Dessipris - * Written on: 02/08/1990 - * 24/5/95 JC - * - tidied up and ANSIfied - * 20/7/95 JC - * - smartened up again - * - now works for hists >256 elements - * 3/3/01 JC - * - broken into cum and norm ... helps im_histspec() - * - better behaviour for >8 bit hists - * 31/10/05 JC - * - was broken for vertical histograms, gah - * - neater im_histnorm() - * 23/7/07 - * - eek, off by 1 for more than 1 band hists - * 12/5/08 - * - histcum works for signed hists now as well - * 24/3/10 - * - gtkdoc - * - small cleanups - */ - -/* - - This file is part of VIPS. - - VIPS 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 of the License, or - (at your option) any later version. - - This program 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 program; 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 - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include - -#include - -/** - * im_histnorm: - * @in: input image - * @out: output image - * - * Normalise histogram ... normalise range to make it square (ie. max == - * number of elements). Normalise each band separately. - * - * See also: im_histcum(). - * - * Returns: 0 on success, -1 on error - */ -int -im_histnorm( IMAGE *in, IMAGE *out ) -{ - const guint64 px = VIPS_IMAGE_N_PELS( in ); - DOUBLEMASK *stats; - double *a, *b; - int y; - IMAGE *t1; - int fmt; - - /* Need max for each channel. - */ - if( !(a = IM_ARRAY( out, in->Bands, double )) || - !(b = IM_ARRAY( out, in->Bands, double )) || - !(stats = im_stats( in )) ) - return( -1 ); - - /* Scale each channel by px / channel max - */ - for( y = 0; y < in->Bands; y++ ) { - a[y] = px / VIPS_MASK( stats, 1, y + 1 ); - b[y] = 0; - } - - im_free_dmask( stats ); - - if( !(t1 = im_open_local( out, "im_histnorm:2", "p" )) || - im_lintra_vec( in->Bands, a, in, b, t1 ) ) - return( -1 ); - - /* Make output format as small as we can. - */ - if( px <= 256 ) - fmt = IM_BANDFMT_UCHAR; - else if( px <= 65536 ) - fmt = IM_BANDFMT_USHORT; - else - fmt = IM_BANDFMT_UINT; - - if( im_clip2fmt( t1, out, fmt ) ) - return( -1 ); - - return( 0 ); -} - -/** - * im_histeq: - * @in: input image - * @out: output image - * - * Histogram equalisation: normalised cumulative histogram. - * - * See also: im_heq(). - * - * Returns: 0 on success, -1 on error - */ -int -im_histeq( IMAGE *in, IMAGE *out ) -{ - IMAGE *t1; - - /* Normalised cumulative. - */ - if( !(t1 = im_open_local( out, "im_histeq", "p" )) || - im_histcum( in, t1 ) || - im_histnorm( t1, out ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libvips/histogram/maplut.c b/libvips/histogram/maplut.c index afc260c1..56f0ced8 100644 --- a/libvips/histogram/maplut.c +++ b/libvips/histogram/maplut.c @@ -595,15 +595,15 @@ static void vips_maplut_class_init( VipsMaplutClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); - VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class ); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; - vobject_class->nickname = "maplut"; - vobject_class->description = _( "map an image though a lut" ); - vobject_class->build = vips_maplut_build; + object_class->nickname = "maplut"; + object_class->description = _( "map an image though a lut" ); + object_class->build = vips_maplut_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; diff --git a/libvips/include/vips/histogram.h b/libvips/include/vips/histogram.h index 03d27ebd..b9293f64 100644 --- a/libvips/include/vips/histogram.h +++ b/libvips/include/vips/histogram.h @@ -42,6 +42,8 @@ int vips_maplut( VipsImage *in, VipsImage **out, VipsImage *lut, ... ) __attribute__((sentinel)); int vips_hist_cum( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_hist_norm( VipsImage *in, VipsImage **out, ... ) + __attribute__((sentinel)); int im_histnD( VipsImage *in, VipsImage *out, int bins ); @@ -50,8 +52,6 @@ int im_hist_indexed( VipsImage *index, VipsImage *value, VipsImage *out ); int im_invertlut( DOUBLEMASK *input, VipsImage *output, int lut_size ); int im_project( VipsImage *in, VipsImage *hout, VipsImage *vout ); -int im_histnorm( VipsImage *in, VipsImage *out ); -int im_histeq( VipsImage *in, VipsImage *out ); int im_histspec( VipsImage *in, VipsImage *ref, VipsImage *out ); int im_ismonotonic( VipsImage *lut, int *out ); int im_histplot( VipsImage *in, VipsImage *out ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 97d83c68..77cdc62f 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -853,6 +853,8 @@ int im_maplut( VipsImage *in, VipsImage *out, VipsImage *lut ); int im_hist( VipsImage *in, VipsImage *out, int bandno ); int im_histgr( VipsImage *in, VipsImage *out, int bandno ); int im_histcum( VipsImage *in, VipsImage *out ); +int im_histnorm( VipsImage *in, VipsImage *out ); +int im_histeq( VipsImage *in, VipsImage *out ); /* ruby-vips uses this */