From 96b3bf1fcb707cb2dbf6cb3727f5cdd23b41695e Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 10 Sep 2013 20:19:11 +0100 Subject: [PATCH] im_stdif() -> a class also many bands support --- ChangeLog | 6 +- libvips/deprecated/vips7compat.c | 24 ++ libvips/histogram/Makefile.am | 2 +- libvips/histogram/hist_local.c | 5 - libvips/histogram/histogram.c | 2 + libvips/histogram/im_stdif.c | 290 -------------------- libvips/histogram/stdif.c | 412 +++++++++++++++++++++++++++++ libvips/include/vips/histogram.h | 6 +- libvips/include/vips/vips7compat.h | 2 + 9 files changed, 446 insertions(+), 303 deletions(-) delete mode 100644 libvips/histogram/im_stdif.c create mode 100644 libvips/histogram/stdif.c diff --git a/ChangeLog b/ChangeLog index de169c39..1e7165a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,9 +4,9 @@ INTERPRETATION_MATRIX etc. - rewrite im_buildlut(), im_identity*(), im_maplut(), im_falsecolour(), im_gammacorrect(), im_histgr(), im_histcum(), im_histnorm(), im_heq(), - im_histnD(), im_histindexed(), im_histspec(), im_invertlut(), im_lhisteq() - as classes -- vips_hist_local() does any number of bands + im_histnD(), im_histindexed(), im_histspec(), im_invertlut(), im_lhisteq(), + im_stdif() as classes +- vips_hist_local(), vips_stdif() do any number of bands - thin vips8 wrapper for im_histplot() - added vips_error_freeze() / vips_error_thaw() - used freeze() / thaw() to stop file format sniffers logging spurious errors diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 9c3b9d82..192d2c27 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -3445,6 +3445,30 @@ im_histgr( IMAGE *in, IMAGE *out, int bandno ) return( 0 ); } +int +im_stdif( IMAGE *in, IMAGE *out, + double a, double m0, double b, double s0, + int width, int height ) +{ + VipsImage *x; + + if( vips_stdif( in, &x, width, height, + "a", a, + "b", b, + "m0", m0, + "s0", s0, + NULL ) ) + return( -1 ); + + if( im_copy( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} + int im_lhisteq( VipsImage *in, VipsImage *out, int width, int height ) { diff --git a/libvips/histogram/Makefile.am b/libvips/histogram/Makefile.am index a9c456b4..8f0d5876 100644 --- a/libvips/histogram/Makefile.am +++ b/libvips/histogram/Makefile.am @@ -12,11 +12,11 @@ libhistogram_la_SOURCES = \ hist_plot.c \ hist_match.c \ hist_local.c \ + stdif.c \ \ hist_dispatch.c \ im_mpercent.c \ im_project.c \ - im_stdif.c \ tone.c AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ diff --git a/libvips/histogram/hist_local.c b/libvips/histogram/hist_local.c index cd5a22b6..70456091 100644 --- a/libvips/histogram/hist_local.c +++ b/libvips/histogram/hist_local.c @@ -243,11 +243,6 @@ vips_hist_local_build( VipsObject *object ) vips_error( class->nickname, "%s", _( "window too large" ) ); return( -1 ); } - if( local->width <= 0 || - local->height <= 0 ) { - vips_error( class->nickname, "%s", _( "window too small" ) ); - return( -1 ); - } /* Expand the input. */ diff --git a/libvips/histogram/histogram.c b/libvips/histogram/histogram.c index f6c395ec..a9efc7aa 100644 --- a/libvips/histogram/histogram.c +++ b/libvips/histogram/histogram.c @@ -239,6 +239,7 @@ vips_histogram_operation_init( void ) extern GType vips_hist_plot_get_type( void ); extern GType vips_hist_match_get_type( void ); extern GType vips_hist_local_get_type( void ); + extern GType vips_stdif_get_type( void ); vips_maplut_get_type(); vips_hist_cum_get_type(); @@ -247,4 +248,5 @@ vips_histogram_operation_init( void ) vips_hist_plot_get_type(); vips_hist_match_get_type(); vips_hist_local_get_type(); + vips_stdif_get_type(); } diff --git a/libvips/histogram/im_stdif.c b/libvips/histogram/im_stdif.c deleted file mode 100644 index 58138eda..00000000 --- a/libvips/histogram/im_stdif.c +++ /dev/null @@ -1,290 +0,0 @@ -/* statistical difference - * - * Copyright: 1990, N. Dessipris. - * - * Author: Nicos Dessipris - * Written on: 02/05/1990 - * Modified on : - * 6/8/93 JC - * - now works for odd window sizes - * - ANSIfication - * 25/5/95 JC - * - new IM_ARRAY() macro - * 25/1/96 JC - * - im_lhisteq() adapted to make new im_stdif() - * - now partial, plus rolling window - * - 5x faster, amazingly - * - works - * 7/4/04 - * - now uses im_embed() with edge stretching on the input, not - * the output - * 25/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 -#include - -#include - -/* Hold global stuff here. - */ -typedef struct { - int xwin, ywin; /* Parameters */ - double a, m0, b, s0; -} StdifInfo; - -/* stdif generate function. - */ -static int -stdif_gen( REGION *or, void *seq, void *a, void *b ) -{ - REGION *ir = (REGION *) seq; - StdifInfo *inf = (StdifInfo *) b; - int npel = inf->xwin * inf->ywin; - Rect *r = &or->valid; - - Rect irect; - int x, y, i, j; - int lsk; - int centre; /* Offset to move to centre of window */ - - /* What part of ir do we need? - */ - irect.left = or->valid.left; - irect.top = or->valid.top; - irect.width = or->valid.width + inf->xwin; - irect.height = or->valid.height + inf->ywin; - if( im_prepare( ir, &irect ) ) - return( -1 ); - - lsk = IM_REGION_LSKIP( ir ); - centre = lsk * (inf->ywin / 2) + inf->xwin / 2; - - for( y = 0; y < r->height; y++ ) { - /* Get input and output pointers for this line. - */ - VipsPel *p = IM_REGION_ADDR( ir, r->left, r->top + y ); - VipsPel *q = IM_REGION_ADDR( or, r->left, r->top + y ); - - /* Precompute some factors. - */ - double f1 = inf->a * inf->m0; - double f2 = 1.0 - inf->a; - double f3 = inf->b * inf->s0; - - VipsPel *p1; - int sum; - int sum2; - - /* Find sum, sum of squares for the start of this line. - */ - sum = 0; - sum2 = 0; - p1 = p; - for( j = 0; j < inf->ywin; j++ ) { - for( i = 0; i < inf->xwin; i++ ) { - int t = p1[i]; - - sum += t; - sum2 += t * t; - } - - p1 += lsk; - } - - /* Loop for output pels. - */ - for( x = 0; x < r->width; x++ ) { - /* Find stats. - */ - double mean = (double) sum / npel; - double var = (double) sum2 / npel - (mean * mean); - double sig = sqrt( var ); - - /* Transform. - */ - double res = f1 + f2 * mean + - ((double) p[centre] - mean) * - (f3 / (inf->s0 + inf->b * sig)); - - /* And write. - */ - if( res < 0.0 ) - q[x] = 0; - else if( res >= 256.0 ) - q[x] = 255; - else - q[x] = res + 0.5; - - /* Adapt sums - remove the pels from the left hand - * column, add in pels for a new right-hand column. - */ - p1 = p; - for( j = 0; j < inf->ywin; j++ ) { - int t1 = p1[0]; - int t2 = p1[inf->xwin]; - - sum -= t1; - sum2 -= t1 * t1; - - sum += t2; - sum2 += t2 * t2; - - p1 += lsk; - } - - p += 1; - } - } - - return( 0 ); -} - -int -im_stdif_raw( IMAGE *in, IMAGE *out, - double a, double m0, double b, double s0, - int xwin, int ywin ) -{ - StdifInfo *inf; - - if( xwin > in->Xsize || - ywin > in->Ysize ) { - im_error( "im_stdif", "%s", _( "window too large" ) ); - return( -1 ); - } - if( xwin <= 0 || - ywin <= 0 ) { - im_error( "im_lhisteq", "%s", _( "window too small" ) ); - return( -1 ); - } - if( m0 < 0 || m0 > 255 || a < 0 || a > 1.0 || b < 0 || b > 2 || - s0 < 0 || s0 > 255 ) { - im_error( "im_stdif", "%s", _( "parameters out of range" ) ); - return( -1 ); - } - if( im_check_format( "im_stdif", in, IM_BANDFMT_UCHAR ) || - im_check_uncoded( "im_stdif", in ) || - im_check_mono( "im_stdif", in ) || - im_piocheck( in, out ) ) - return( -1 ); - if( im_cp_desc( out, in ) ) - return( -1 ); - out->Xsize -= xwin; - out->Ysize -= ywin; - - /* Save parameters. - */ - if( !(inf = IM_NEW( out, StdifInfo )) ) - return( -1 ); - inf->xwin = xwin; - inf->ywin = ywin; - inf->a = a; - inf->m0 = m0; - inf->b = b; - inf->s0 = s0; - - /* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause - * too many recalculations on overlaps. - */ - if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) ) - return( -1 ); - - /* Write the hist. - */ - if( im_generate( out, - im_start_one, stdif_gen, im_stop_one, in, inf ) ) - return( -1 ); - - return( 0 ); -} - -/** - * im_stdif: - * @in: input image - * @out: output image - * @a: weight of new mean - * @m0: target mean - * @b: weight of new deviation - * @s0:target deviation - * @xwin: width of region - * @ywin: height of region - * - * im_stdif() preforms statistical differencing according to the formula - * given in page 45 of the book "An Introduction to Digital Image - * Processing" by Wayne Niblack. This transformation emphasises the way in - * which a pel differs statistically from its neighbours. It is useful for - * enhancing low-contrast images with lots of detail, such as X-ray plates. - * - * 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 @xwin, @ywin centred on pixel (i,j). - * @m0 is the new mean, @a is the weight given to it. @s0 is the new standard - * deviation, @b is the weight given to it. - * - * Try: - * - * vips im_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 - * input. - * - * See also: im_lhisteq(). - * - * Returns: 0 on success, -1 on error - */ -int -im_stdif( IMAGE *in, IMAGE *out, - double a, double m0, double b, double s0, - int xwin, int ywin ) -{ - IMAGE *t1; - - if( !(t1 = im_open_local( out, "im_stdif:1", "p" )) || - im_embed( in, t1, 1, xwin / 2, ywin / 2, - in->Xsize + xwin - 1, - in->Ysize + ywin - 1 ) || - im_stdif_raw( t1, out, a, m0, b, s0, xwin, ywin ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libvips/histogram/stdif.c b/libvips/histogram/stdif.c new file mode 100644 index 00000000..3765f427 --- /dev/null +++ b/libvips/histogram/stdif.c @@ -0,0 +1,412 @@ +/* statistical difference + * + * Copyright: 1990, N. Dessipris. + * + * Author: Nicos Dessipris + * Written on: 02/05/1990 + * Modified on : + * 6/8/93 JC + * - now works for odd window sizes + * - ANSIfication + * 25/5/95 JC + * - new IM_ARRAY() macro + * 25/1/96 JC + * - im_lhisteq() adapted to make new im_stdif() + * - now partial, plus rolling window + * - 5x faster, amazingly + * - works + * 7/4/04 + * - now uses im_embed() with edge stretching on the input, not + * the output + * 25/3/10 + * - gtkdoc + * - small cleanups + * 10/8/13 + * - wrapped as a class using hist_local.c + * - many bands + */ + +/* + + 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 +#include + +#include + +typedef struct _VipsStdif { + VipsOperation parent_instance; + + VipsImage *in; + VipsImage *out; + + int width; + int height; + + double a; + double m0; + double b; + double s0; + +} VipsStdif; + +typedef VipsOperationClass VipsStdifClass; + +G_DEFINE_TYPE( VipsStdif, vips_stdif, VIPS_TYPE_OPERATION ); + +/* How ugly and stupid. + */ +#define MAX_BANDS (100) + +static int +vips_stdif_generate( VipsRegion *or, + void *vseq, void *a, void *b, gboolean *stop ) +{ + VipsRect *r = &or->valid; + VipsRegion *ir = (VipsRegion *) vseq; + VipsImage *in = (VipsImage *) a; + VipsStdif *stdif = (VipsStdif *) b; + int bands = in->Bands; + int npel = stdif->width * stdif->width; + + VipsRect irect; + int y; + int lsk; + int centre; /* Offset to move to centre of window */ + + /* What part of ir do we need? + */ + irect.left = or->valid.left; + irect.top = or->valid.top; + irect.width = or->valid.width + stdif->width; + irect.height = or->valid.height + stdif->height; + if( vips_region_prepare( ir, &irect ) ) + return( -1 ); + + lsk = VIPS_REGION_LSKIP( ir ); + centre = lsk * (stdif->height / 2) + stdif->width / 2; + + for( y = 0; y < r->height; y++ ) { + /* Get input and output pointers for this line. + */ + VipsPel *p = VIPS_REGION_ADDR( ir, r->left, r->top + y ); + VipsPel *q = VIPS_REGION_ADDR( or, r->left, r->top + y ); + + double f1 = stdif->a * stdif->m0; + double f2 = 1.0 - stdif->a; + double f3 = stdif->b * stdif->s0; + + VipsPel *p1; + int x, i, j, b; + + /* We will get int overflow for windows larger than about 256 + * x 256, sadly. + */ + unsigned int sum[MAX_BANDS]; + unsigned int sum2[MAX_BANDS]; + + /* Find sum, sum of squares for the start of this line. + */ + for( b = 0; b < bands; b++ ) { + memset( sum, 0, bands * sizeof( unsigned int ) ); + memset( sum2, 0, bands * sizeof( unsigned int ) ); + } + p1 = p; + for( j = 0; j < stdif->height; j++ ) { + i = 0; + for( x = 0; x < stdif->width; x++ ) { + for( b = 0; b < bands; b++ ) { + int t = p1[i++]; + + sum[b] += t; + sum2[b] += t * t; + } + } + + p1 += lsk; + } + + /* Loop for output pels. + */ + for( x = 0; x < r->width; x++ ) { + for( b = 0; b < bands; b++ ) { + /* Find stats. + */ + double mean = (double) sum[b] / npel; + double var = (double) sum2[b] / npel - + (mean * mean); + double sig = sqrt( var ); + + /* Transform. + */ + double res = f1 + f2 * mean + + ((double) p[centre] - mean) * + (f3 / (stdif->s0 + stdif->b * sig)); + + /* And write. + */ + if( res < 0.0 ) + *q++ = 0; + else if( res >= 256.0 ) + *q++ = 255; + else + *q++ = res + 0.5; + + /* Adapt sums - remove the pels from the left + * hand column, add in pels for a new + * right-hand column. + */ + p1 = p; + for( j = 0; j < stdif->height; j++ ) { + int t1 = p1[0]; + int t2 = p1[bands * stdif->width]; + + sum[b] -= t1; + sum2[b] -= t1 * t1; + + sum[b] += t2; + sum2[b] += t2 * t2; + + p1 += lsk; + } + + p += 1; + } + } + } + + return( 0 ); +} + +static int +vips_stdif_build( VipsObject *object ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + VipsStdif *stdif = (VipsStdif *) object; + VipsImage **t = (VipsImage **) vips_object_local_array( object, 3 ); + + VipsImage *in; + + if( VIPS_OBJECT_CLASS( vips_stdif_parent_class )->build( object ) ) + return( -1 ); + + in = stdif->in; + + if( vips_check_uncoded( class->nickname, in ) || + vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) ) + return( -1 ); + + if( stdif->width > in->Xsize || + stdif->height > in->Ysize ) { + vips_error( class->nickname, "%s", _( "window too large" ) ); + return( -1 ); + } + if( in->Bands > MAX_BANDS ) { + vips_error( class->nickname, "%s", _( "too many bands" ) ); + return( -1 ); + } + + /* Expand the input. + */ + if( vips_embed( in, &t[0], + stdif->width / 2, stdif->height / 2, + in->Xsize + stdif->width - 1, in->Ysize + stdif->height - 1, + "extend", VIPS_EXTEND_COPY, + NULL ) ) + return( -1 ); + in = t[0]; + + g_object_set( object, "out", vips_image_new(), NULL ); + + if( vips_image_copy_fields( stdif->out, in ) ) + return( -1 ); + stdif->out->Xsize -= stdif->width - 1; + stdif->out->Ysize -= stdif->height - 1; + + /* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause + * too many recalculations on overlaps. + */ + vips_demand_hint( stdif->out, + VIPS_DEMAND_STYLE_FATSTRIP, in, NULL ); + + if( vips_image_generate( stdif->out, + vips_start_one, + vips_stdif_generate, + vips_stop_one, + in, stdif ) ) + return( -1 ); + + stdif->out->Xoffset = 0; + stdif->out->Yoffset = 0; + + return( 0 ); +} + +static void +vips_stdif_class_init( VipsStdifClass *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 = "stdif"; + object_class->description = _( "statistical difference" ); + object_class->build = vips_stdif_build; + + VIPS_ARG_IMAGE( class, "in", 1, + _( "Input" ), + _( "Input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsStdif, in ) ); + + VIPS_ARG_IMAGE( class, "out", 2, + _( "Output" ), + _( "Output image" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsStdif, out ) ); + + /* Windows larger than 256x256 will overflow sum2, see above. + */ + VIPS_ARG_INT( class, "width", 4, + _( "Width" ), + _( "Window width in pixels" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsStdif, width ), + 1, 256, 11 ); + + VIPS_ARG_INT( class, "height", 5, + _( "Height" ), + _( "Window height in pixels" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsStdif, height ), + 1, 256, 11 ); + + VIPS_ARG_DOUBLE( class, "a", 2, + _( "Mean weight" ), + _( "Weight of new mean" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsStdif, a ), + 0.0, 1.0, 0.5 ); + + VIPS_ARG_DOUBLE( class, "m0", 2, + _( "Mean" ), + _( "New mean" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsStdif, m0 ), + -INFINITY, INFINITY, 128 ); + + VIPS_ARG_DOUBLE( class, "b", 2, + _( "Deviation weight" ), + _( "Weight of new deviation" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsStdif, b ), + 0.0, 2.0, 0.5 ); + + VIPS_ARG_DOUBLE( class, "s0", 2, + _( "Deviation" ), + _( "New deviation" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsStdif, s0 ), + -INFINITY, INFINITY, 50 ); + +} + +static void +vips_stdif_init( VipsStdif *stdif ) +{ + stdif->width = 11; + stdif->height = 11; + stdif->a = 0.5; + stdif->m0 = 128.0; + stdif->b = 0.5; + stdif->s0 = 50.0; +} + +/** + * vips_stdif: + * @in: input image + * @out: output image + * @width: width of region + * @height: height of region + * + * Optional arguments: + * + * @a: weight of new mean + * @m0: target mean + * @b: weight of new deviation + * @s0: target deviation + * + * vips_stdif() preforms statistical differencing according to the formula + * given in page 45 of the book "An Introduction to Digital Image + * Processing" by Wayne Niblack. This transformation emphasises the way in + * which a pel differs statistically from its neighbours. It is useful for + * enhancing low-contrast images with lots of detail, such as X-ray plates. + * + * 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 + * (i,j). @m0 is the new mean, @a is the weight given to it. @s0 is the new + * standard deviation, @b is the weight given to it. + * + * 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 + * input. + * + * See also: vips_hist_local(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_stdif( VipsImage *in, VipsImage **out, int width, int height, ... ) +{ + va_list ap; + int result; + + va_start( ap, height ); + result = vips_call_split( "stdif", ap, in, out, width, height ); + va_end( ap ); + + return( result ); +} + diff --git a/libvips/include/vips/histogram.h b/libvips/include/vips/histogram.h index 69a50384..6a81b6d0 100644 --- a/libvips/include/vips/histogram.h +++ b/libvips/include/vips/histogram.h @@ -53,7 +53,8 @@ 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_stdif( VipsImage *in, VipsImage **out, int width, int height, ... ) + __attribute__((sentinel)); int im_project( VipsImage *in, VipsImage *hout, VipsImage *vout ); @@ -62,9 +63,6 @@ int im_ismonotonic( VipsImage *lut, int *out ); int im_mpercent( VipsImage *in, double percent, int *out ); int im_mpercent_hist( VipsImage *hist, double percent, int *out ); -int im_stdif( VipsImage *in, VipsImage *out, - double a, double m0, double b, double s0, int xwin, int ywin ); - int im_tone_build_range( VipsImage *out, int in_max, int out_max, double Lb, double Lw, double Ps, double Pm, double Ph, diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index ba466162..9a4013da 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -864,6 +864,8 @@ int im_histplot( VipsImage *in, VipsImage *out ); int im_hsp( VipsImage *in, VipsImage *ref, VipsImage *out ); int im_histspec( VipsImage *in, VipsImage *ref, VipsImage *out ); int im_lhisteq( VipsImage *in, VipsImage *out, int xwin, int ywin ); +int im_stdif( VipsImage *in, VipsImage *out, + double a, double m0, double b, double s0, int xwin, int ywin ); /* Not really correct, but who uses this. */