diff --git a/ChangeLog b/ChangeLog index 7f1a4ab2..7474138a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,8 @@ - skip oversized markers in jpeg write - jpeg exif tags saved as name rather than title - can now set any jpeg exif tag, not just modify existing tags +- add vips_hist_entropy() +- vips_log(), vips_log10() are zero-avoiding 7/5/15 started 8.0.3 - dzsave and tif pyr write could fail for some image dimensions, thanks Jonas diff --git a/libvips/histogram/Makefile.am b/libvips/histogram/Makefile.am index 4ceba837..bd903644 100644 --- a/libvips/histogram/Makefile.am +++ b/libvips/histogram/Makefile.am @@ -14,6 +14,7 @@ libhistogram_la_SOURCES = \ hist_local.c \ percent.c \ hist_ismonotonic.c \ + hist_entropy.c \ stdif.c AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ diff --git a/libvips/histogram/hist_entropy.c b/libvips/histogram/hist_entropy.c new file mode 100644 index 00000000..e6120ffd --- /dev/null +++ b/libvips/histogram/hist_entropy.c @@ -0,0 +1,157 @@ +/* estimate entropy + * + * Author: John Cupitt + * 11/8/15 + * - from hist_ismonotonic.c + */ + +/* + + 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 + +#include + +typedef struct _VipsHistEntropy { + VipsOperation parent_instance; + + VipsImage *in; + + double out; +} VipsHistEntropy; + +typedef VipsOperationClass VipsHistEntropyClass; + +G_DEFINE_TYPE( VipsHistEntropy, vips_hist_entropy, + VIPS_TYPE_OPERATION ); + +static int +vips_hist_entropy_build( VipsObject *object ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + VipsHistEntropy *entropy = (VipsHistEntropy *) object; + VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); + + double avg; + double sum; + + if( VIPS_OBJECT_CLASS( vips_hist_entropy_parent_class )-> + build( object ) ) + return( -1 ); + + if( vips_check_hist( class->nickname, entropy->in ) ) + return( -1 ); + + /* Compute: + * norm_hist = hist / sum( hist ) + * entropy = -sum( norm_hist * log2( norm_hist ) ) + */ + if( vips_avg( entropy->in, &avg, NULL ) ) + return( -1 ); + sum = avg * VIPS_IMAGE_N_PELS( entropy->in ) * entropy->in->Bands; + if( vips_linear1( entropy->in, &t[0], 1.0 / sum, 0, NULL ) || + vips_log( t[0], &t[1], 1.0 / sum, 0, NULL ) || + vips_linear1( t[1], &t[2], 1.0 / log( 2.0 ), 0, NULL ) || + vips_multiply( t[0], t[2], &t[3], NULL ) || + vips_avg( t[3], &avg, NULL ) ) + return( -1 ); + + g_object_set( entropy, + "out", -avg * + VIPS_IMAGE_N_PELS( entropy->in ) * entropy->in->Bands, + NULL ); + + return( 0 ); +} + +static void +vips_hist_entropy_class_init( VipsHistEntropyClass *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_entropy"; + object_class->description = _( "estimate image entropy" ); + object_class->build = vips_hist_entropy_build; + + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), + _( "Input histogram image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsHistEntropy, in ) ); + + VIPS_ARG_DOUBLE( class, "out", 1, + _( "Output" ), + _( "Output value" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsHistEntropy, out ), + -INFINITY, INFINITY, 0.0 ); + +} + +static void +vips_hist_entropy_init( VipsHistEntropy *entropy ) +{ +} + +/** + * vips_hist_entropy: + * @in: input histogram + * @out: image entropy + * @...: %NULL-terminated list of optional named arguments + * + * Estimate image entropy from a histogram. Entropy is calculated as: + * + * |[ + * -sum( p * log2( p ) ) + * ]| + * + * where p is histogram-value / sum-of-histogram-values. + * + * Returns: 0 on success, -1 on error + */ +int +vips_hist_entropy( VipsImage *in, double *out, ... ) +{ + va_list ap; + int result; + + va_start( ap, out ); + result = vips_call_split( "hist_entropy", ap, in, out ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/histogram/hist_ismonotonic.c b/libvips/histogram/hist_ismonotonic.c index bb1a032e..ba0e735e 100644 --- a/libvips/histogram/hist_ismonotonic.c +++ b/libvips/histogram/hist_ismonotonic.c @@ -136,7 +136,7 @@ vips_hist_ismonotonic_init( VipsHistIsmonotonic *ismonotonic ) /** * vips_hist_ismonotonic: * @in: lookup-table to test - * @monotonic: set non-zero if @in is monotonic + * @out: set non-zero if @in is monotonic * @...: %NULL-terminated list of optional named arguments * * Test @in for monotonicity. @out is set non-zero if @in is monotonic. @@ -144,13 +144,13 @@ vips_hist_ismonotonic_init( VipsHistIsmonotonic *ismonotonic ) * Returns: 0 on success, -1 on error */ int -vips_hist_ismonotonic( VipsImage *in, gboolean *monotonic, ... ) +vips_hist_ismonotonic( VipsImage *in, gboolean *out, ... ) { va_list ap; int result; - va_start( ap, monotonic ); - result = vips_call_split( "hist_ismonotonic", ap, in, monotonic ); + va_start( ap, out ); + result = vips_call_split( "hist_ismonotonic", ap, in, out ); va_end( ap ); return( result ); diff --git a/libvips/histogram/histogram.c b/libvips/histogram/histogram.c index 7e670276..9a931ef7 100644 --- a/libvips/histogram/histogram.c +++ b/libvips/histogram/histogram.c @@ -258,6 +258,7 @@ vips_histogram_operation_init( void ) extern GType vips_hist_match_get_type( void ); extern GType vips_hist_local_get_type( void ); extern GType vips_hist_ismonotonic_get_type( void ); + extern GType vips_hist_entropy_get_type( void ); extern GType vips_stdif_get_type( void ); vips_maplut_get_type(); @@ -270,4 +271,5 @@ vips_histogram_operation_init( void ) vips_hist_match_get_type(); vips_hist_local_get_type(); vips_hist_ismonotonic_get_type(); + vips_hist_entropy_get_type(); } diff --git a/libvips/histogram/stdif.c b/libvips/histogram/stdif.c index 86521614..6f0977b3 100644 --- a/libvips/histogram/stdif.c +++ b/libvips/histogram/stdif.c @@ -380,8 +380,10 @@ vips_stdif_init( VipsStdif *stdif ) * * At point (i,j) the output is given by the equation: * + * |[ * vout(i,j) = @a * @m0 + (1 - @a) * meanv + * (vin(i,j) - meanv) * (@b * @s0) / (@s0 + @b * stdv) + * ]| * * Values @a, @m0, @b and @s0 are entered, while meanv and stdv are the values * calculated over a moving window of size @width, @height centred on pixel @@ -390,7 +392,9 @@ vips_stdif_init( VipsStdif *stdif ) * * Try: * + * |[ * vips stdif $VIPSHOME/pics/huysum.v fred.v 0.5 128 0.5 50 11 11 + * ]| * * The operation works on one-band uchar images only, and writes a one-band * uchar image as its result. The output image has the same size as the diff --git a/libvips/include/vips/histogram.h b/libvips/include/vips/histogram.h index fe5ec4c7..53d46b15 100644 --- a/libvips/include/vips/histogram.h +++ b/libvips/include/vips/histogram.h @@ -57,7 +57,9 @@ int vips_hist_match( VipsImage *in, VipsImage *ref, VipsImage **out, ... ) int vips_hist_local( VipsImage *in, VipsImage **out, int width, int height, ... ) __attribute__((sentinel)); -int vips_hist_ismonotonic( VipsImage *in, gboolean *monotonic, ... ) +int vips_hist_ismonotonic( VipsImage *in, gboolean *out, ... ) + __attribute__((sentinel)); +int vips_hist_entropy( VipsImage *in, double *out, ... ) __attribute__((sentinel)); #ifdef __cplusplus