im_stats() redone as a class
This commit is contained in:
parent
90849a44c5
commit
ff2e7b26de
@ -8,7 +8,7 @@
|
||||
im_sintra(), im_costra(), im_tantra(), im_asintra(), im_acostra(),
|
||||
im_atantra(), im_exptra(), im_exp10tra(), im_logtra(), im_log10tra(),
|
||||
im_abs(), im_sign(), im_max(), im_maxpos(), im_deviate(), im_divide(),
|
||||
im_multiply()
|
||||
im_multiply(), im_stats()
|
||||
redone as classes
|
||||
- added argument priorites to help control arg ordering
|
||||
- generate has a 'stop' param to signal successful early termination
|
||||
|
15
TODO
15
TODO
@ -1,5 +1,20 @@
|
||||
- add an INTERPRETATION for "array"
|
||||
|
||||
can move the whole of mask, plus headers, plus conversion/im_vips2mask and
|
||||
mask2vips to deprecated
|
||||
|
||||
- try:
|
||||
|
||||
$ vips stats babe.jpg
|
||||
|
||||
reports leaks, we need to unref more stuff
|
||||
|
||||
- try:
|
||||
|
||||
$ vips add babe.jpg
|
||||
|
||||
GLib-GObject-CRITICAL **: g_o ....
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@ libarithmetic_la_SOURCES = \
|
||||
im_point_bilinear.c \
|
||||
im_remainder.c \
|
||||
sign.c \
|
||||
im_stats.c \
|
||||
stats.c \
|
||||
statistic.c \
|
||||
statistic.h \
|
||||
avg.c \
|
||||
|
@ -514,6 +514,7 @@ vips_arithmetic_operation_init( void )
|
||||
extern GType vips_math_get_type( void );
|
||||
extern GType vips_abs_get_type( void );
|
||||
extern GType vips_sign_get_type( void );
|
||||
extern GType vips_stats_get_type( void );
|
||||
|
||||
vips_add_get_type();
|
||||
vips_subtract_get_type();
|
||||
@ -528,5 +529,6 @@ vips_arithmetic_operation_init( void )
|
||||
vips_math_get_type();
|
||||
vips_abs_get_type();
|
||||
vips_sign_get_type();
|
||||
vips_stats_get_type();
|
||||
}
|
||||
|
||||
|
@ -1,351 +0,0 @@
|
||||
/* im_stats.c
|
||||
*
|
||||
(C) Kirk Martinez 1993
|
||||
23/4/93 J.Cupitt
|
||||
- adapted to partial images
|
||||
- special struct abandoned; now returns DOUBLEMASK.
|
||||
1/7/93 JC
|
||||
- adapted for partial v2
|
||||
- ANSIfied
|
||||
27/7/93 JC
|
||||
- init of mask changed to use actual values, not IM_MAXDOUBLE and
|
||||
(-IM_MAXDOUBLE). These caused problems when assigned to floats.
|
||||
funny business with offset==42, yuk!
|
||||
31/8/93 JC
|
||||
- forgot to init global max/min properly! sorry.
|
||||
21/6/95 JC
|
||||
- still did not init max and min correctly --- now fixed for good
|
||||
|
||||
* 13/1/05
|
||||
* - use 64 bit arithmetic
|
||||
* 1/9/09
|
||||
* - argh nope min/max was broken again for >1CPU in short pipelines on
|
||||
* some architectures
|
||||
* 7/9/09
|
||||
* - rework based on new im__wrapscan() / im_max() ideas for a proper fix
|
||||
* - gtkdoc comment
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
typedef struct _Wrapscan {
|
||||
IMAGE *in;
|
||||
im_start_fn start;
|
||||
im__wrapscan_fn scan;
|
||||
im_stop_fn stop;
|
||||
void *a;
|
||||
void *b;
|
||||
} Wrapscan;
|
||||
|
||||
static void *
|
||||
wrapscan_start( VipsImage *in, void *a, void *b )
|
||||
{
|
||||
Wrapscan *wrapscan = (Wrapscan *) a;
|
||||
|
||||
return( wrapscan->start( in, wrapscan->a, wrapscan->b ) );
|
||||
}
|
||||
|
||||
static int
|
||||
wrapscan_stop( void *seq, void *a, void *b )
|
||||
{
|
||||
Wrapscan *wrapscan = (Wrapscan *) a;
|
||||
|
||||
return( wrapscan->stop( seq, wrapscan->a, wrapscan->b ) );
|
||||
}
|
||||
|
||||
static int
|
||||
wrapscan_scan( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
Wrapscan *wrapscan = (Wrapscan *) a;
|
||||
Rect *r = ®->valid;
|
||||
int lsk = IM_REGION_LSKIP( reg );
|
||||
|
||||
int y;
|
||||
PEL *p;
|
||||
|
||||
p = (PEL *) IM_REGION_ADDR( reg, r->left, r->top );
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
if( wrapscan->scan( p, r->width, seq,
|
||||
wrapscan->a, wrapscan->b ) )
|
||||
return( -1 );
|
||||
p += lsk;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Like vips_sink(), but the scan function works a line at a time, like
|
||||
* im_wrap*(). Shared with im_min(), im_deviate() etc.
|
||||
*/
|
||||
int
|
||||
im__wrapscan( VipsImage *in,
|
||||
VipsStartFn start, im__wrapscan_fn scan, VipsStopFn stop,
|
||||
void *a, void *b )
|
||||
{
|
||||
Wrapscan wrapscan;
|
||||
|
||||
wrapscan.in = in;
|
||||
wrapscan.start = start;
|
||||
wrapscan.scan = scan;
|
||||
wrapscan.stop = stop;
|
||||
wrapscan.a = a;
|
||||
wrapscan.b = b;
|
||||
|
||||
return( vips_sink( in,
|
||||
wrapscan_start, wrapscan_scan, wrapscan_stop,
|
||||
&wrapscan, NULL ) );
|
||||
}
|
||||
|
||||
/* Get the value of pixel (0, 0). Use this to init the min/max value for
|
||||
* im_max()/im_stats()/etc.
|
||||
*/
|
||||
int
|
||||
im__value( IMAGE *im, double *value )
|
||||
{
|
||||
IMAGE *t;
|
||||
|
||||
if( !(t = im_open_local( im, "im__value", "p" )) ||
|
||||
im_extract_areabands( im, t, 0, 0, 1, 1, 0, 1 ) ||
|
||||
im_avg( t, value ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
/* Track min/max/sum/sum-of-squares for each thread during a scan.
|
||||
*/
|
||||
static void *
|
||||
stats_start( IMAGE *im, void *a, void *b )
|
||||
{
|
||||
double *global_stats = (double *) b;
|
||||
|
||||
double *stats;
|
||||
int i;
|
||||
|
||||
if( !(stats = IM_ARRAY( NULL, 4 * im->Bands, double )) )
|
||||
return( NULL );
|
||||
|
||||
for( i = 0; i < 4 * im->Bands; i++ )
|
||||
stats[i] = global_stats[i];
|
||||
|
||||
return( stats );
|
||||
}
|
||||
|
||||
/* Merge a thread's output back into the global stats.
|
||||
*/
|
||||
static int
|
||||
stats_stop( void *seq, void *a, void *b )
|
||||
{
|
||||
const IMAGE *im = (IMAGE *) a;
|
||||
double *global_stats = (double *) b;
|
||||
double *stats = (double *) seq;
|
||||
|
||||
int i;
|
||||
|
||||
for( i = 0; i < 4 * im->Bands; i += 4 ) {
|
||||
global_stats[0] = IM_MIN( global_stats[0], stats[0] );
|
||||
global_stats[1] = IM_MAX( global_stats[1], stats[1] );
|
||||
global_stats[2] += stats[2];
|
||||
global_stats[3] += stats[3];
|
||||
|
||||
global_stats += 4;
|
||||
stats += 4;
|
||||
}
|
||||
|
||||
im_free( seq );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* We scan lines bands times to avoid repeating band loops.
|
||||
* Use temp variables of same type for min/max for faster comparisons.
|
||||
*/
|
||||
#define LOOP( TYPE ) { \
|
||||
for( z = 0; z < im->Bands; z++ ) { \
|
||||
TYPE *q = (TYPE *) in + z; \
|
||||
double *row = stats + z * 4; \
|
||||
TYPE small, big; \
|
||||
double sum, sum2; \
|
||||
\
|
||||
small = row[0]; \
|
||||
big = row[1]; \
|
||||
sum = row[2]; \
|
||||
sum2 = row[3]; \
|
||||
\
|
||||
for( x = 0; x < n; x++ ) { \
|
||||
TYPE value = *q; \
|
||||
\
|
||||
sum += value;\
|
||||
sum2 += (double) value * (double) value;\
|
||||
if( value > big ) \
|
||||
big = value; \
|
||||
else if( value < small ) \
|
||||
small = value;\
|
||||
\
|
||||
q += im->Bands; \
|
||||
} \
|
||||
\
|
||||
row[0] = small; \
|
||||
row[1] = big; \
|
||||
row[2] = sum; \
|
||||
row[3] = sum2; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Loop over region, adding to seq.
|
||||
*/
|
||||
static int
|
||||
stats_scan( void *in, int n, void *seq, void *a, void *b )
|
||||
{
|
||||
const IMAGE *im = (IMAGE *) a;
|
||||
|
||||
double *stats = (double *) seq;
|
||||
|
||||
int x, z;
|
||||
|
||||
/* Now generate code for all types.
|
||||
*/
|
||||
switch( im->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR: LOOP( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR: LOOP( signed char ); break;
|
||||
case IM_BANDFMT_USHORT: LOOP( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT: LOOP( signed short ); break;
|
||||
case IM_BANDFMT_UINT: LOOP( unsigned int ); break;
|
||||
case IM_BANDFMT_INT: LOOP( signed int ); break;
|
||||
case IM_BANDFMT_DOUBLE: LOOP( double ); break;
|
||||
case IM_BANDFMT_FLOAT: LOOP( float ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_stats:
|
||||
* @in: image to scan
|
||||
*
|
||||
* Find many image statistics in a single pass through the data. Returns a
|
||||
* #DOUBLEMASK of 6 columns by n + 1 (where n is number of bands in image @in)
|
||||
* rows. Columns are statistics, and are, in order: minimum, maximum, sum,
|
||||
* sum of squares, mean, standard deviation. Row 0 has statistics for all
|
||||
* bands together, row 1 has stats for band 1, and so on.
|
||||
*
|
||||
* See also: im_maxpos(), im_min(), im_deviate().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
DOUBLEMASK *
|
||||
im_stats( IMAGE *im )
|
||||
{
|
||||
DOUBLEMASK *out;
|
||||
double *row;
|
||||
gint64 pels, vals;
|
||||
double *global_stats;
|
||||
int i, j;
|
||||
double value;
|
||||
|
||||
if( im_pincheck( im ) ||
|
||||
im_check_noncomplex( "im_stats", im ) ||
|
||||
im_check_uncoded( "im_stats", im ) )
|
||||
return( NULL );
|
||||
|
||||
if( !(global_stats = IM_ARRAY( im, 4 * im->Bands, double )) )
|
||||
return( NULL );
|
||||
if( im__value( im, &value ) )
|
||||
return( NULL );
|
||||
for( i = 0; i < 4 * im->Bands; i += 4 ) {
|
||||
global_stats[i + 0] = value;
|
||||
global_stats[i + 1] = value;
|
||||
global_stats[i + 2] = 0.0;
|
||||
global_stats[i + 3] = 0.0;
|
||||
}
|
||||
|
||||
/* Loop over input, calculating min, max, sum, sum^2 for each band
|
||||
* separately.
|
||||
*/
|
||||
if( im__wrapscan( im, stats_start, stats_scan, stats_stop,
|
||||
im, global_stats ) )
|
||||
return( NULL );
|
||||
|
||||
/* Calculate mean, deviation, plus overall stats.
|
||||
*/
|
||||
if( !(out = im_create_dmask( "stats", 6, im->Bands + 1 )) )
|
||||
return( NULL );
|
||||
|
||||
/* Init global max/min/sum/sum2.
|
||||
*/
|
||||
out->coeff[0] = value;
|
||||
out->coeff[1] = value;
|
||||
out->coeff[2] = 0.0;
|
||||
out->coeff[3] = 0.0;
|
||||
|
||||
pels = (gint64) im->Xsize * im->Ysize;
|
||||
vals = pels * im->Bands;
|
||||
|
||||
for( i = 0; i < im->Bands; i++ ) {
|
||||
row = out->coeff + (i + 1) * 6;
|
||||
for( j = 0; j < 4; j++ )
|
||||
row[j] = global_stats[i * 4 + j];
|
||||
|
||||
out->coeff[0] = IM_MIN( out->coeff[0], row[0] );
|
||||
out->coeff[1] = IM_MAX( out->coeff[1], row[1] );
|
||||
out->coeff[2] += row[2];
|
||||
out->coeff[3] += row[3];
|
||||
row[4] = row[2] / pels;
|
||||
row[5] = sqrt( fabs( row[3] - (row[2] * row[2] / pels) ) /
|
||||
(pels - 1) );
|
||||
}
|
||||
out->coeff[4] = out->coeff[2] / vals;
|
||||
out->coeff[5] = sqrt( fabs( out->coeff[3] -
|
||||
(out->coeff[2] * out->coeff[2] / vals) ) / (vals - 1) );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "im_stats:\n" );
|
||||
im_print_dmask( out );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( out );
|
||||
}
|
@ -113,7 +113,7 @@ enum {
|
||||
COL_XMAX = 8,
|
||||
COL_YMAX = 9,
|
||||
COL_LAST = 10
|
||||
}
|
||||
};
|
||||
|
||||
/* Address a double in our array image.
|
||||
*/
|
||||
@ -125,10 +125,15 @@ vips_stats_build( VipsObject *object )
|
||||
VipsStatistic *statistic = VIPS_STATISTIC( object );
|
||||
VipsStats *stats = (VipsStats *) object;
|
||||
|
||||
gint64 vals;
|
||||
gint64 vals, pels;
|
||||
double *row0;
|
||||
int b;
|
||||
|
||||
if( statistic->in ) {
|
||||
int bands = vips_image_get_bands( statistic->in->Bands ) : 0;
|
||||
int bands = vips_image_get_bands( statistic->in );
|
||||
|
||||
if( vips_check_noncomplex( "VipsStats", statistic->in ) )
|
||||
return( -1 );
|
||||
|
||||
g_object_set( object,
|
||||
"out", vips_image_new_array( COL_LAST, bands + 1 ),
|
||||
@ -138,32 +143,34 @@ vips_stats_build( VipsObject *object )
|
||||
if( VIPS_OBJECT_CLASS( vips_stats_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
vals = (gint64)
|
||||
pels = (gint64)
|
||||
vips_image_get_width( statistic->in ) *
|
||||
vips_image_get_height( statistic->in ) *
|
||||
vips_image_get_bands( statistic->in );
|
||||
vips_image_get_height( statistic->in );
|
||||
vals = pels * vips_image_get_bands( statistic->in );
|
||||
|
||||
row0 = ARY( stats->out, 0, 0 );
|
||||
|
||||
row0[COL_MIN] = *ARY( stats->out, 0, COL_MIN );
|
||||
row0[COL_MAX] = *ARY( stats->out, 0, COL_MAX );
|
||||
row0[COL_SUM] = 0;
|
||||
row0[COL_SUM2] = 0;
|
||||
|
||||
for( b = 0; b < vips_image_get_bands( statistic->in ); b++ ) {
|
||||
double *row = ARY( stats->out, 0, b + 1 );
|
||||
|
||||
row0[COL_MIN] = VIPS_MIN( row0[COL_MIN], row[COL_MIN] );
|
||||
row0[COL_MAX] = VIPS_MAX( row0[COL_MAX], row[COL_MAX] );
|
||||
row0[COL_SUM] += row[COL_SUM];
|
||||
row0[COL_SUM2] += row[COL_SUM2];
|
||||
|
||||
row[COL_AVG] = row[COL_SUM] / pels;
|
||||
row[COL_SD] = sqrt( fabs( row[COL_SUM2] -
|
||||
(row[COL_SUM] * row[COL_SUM] / pels) ) / (pels - 1) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
row = out->coeff + (i + 1) * 6;
|
||||
for( j = 0; j < 4; j++ )
|
||||
row[j] = global_stats[i * 4 + j];
|
||||
|
||||
out->coeff[0] = IM_MIN( out->coeff[0], row[0] );
|
||||
out->coeff[1] = IM_MAX( out->coeff[1], row[1] );
|
||||
out->coeff[2] += row[2];
|
||||
out->coeff[3] += row[3];
|
||||
row[4] = row[2] / pels;
|
||||
row[5] = sqrt( fabs( row[3] - (row[2] * row[2] / pels) ) /
|
||||
(pels - 1) );
|
||||
}
|
||||
out->coeff[4] = out->coeff[2] / vals;
|
||||
out->coeff[5] = sqrt( fabs( out->coeff[3] -
|
||||
(out->coeff[2] * out->coeff[2] / vals) ) / (vals - 1) );
|
||||
row0[COL_AVG] = row0[COL_SUM] / vals;
|
||||
row0[COL_SD] = sqrt( fabs( row0[COL_SUM2] -
|
||||
(row0[COL_SUM] * row0[COL_SUM] / vals) ) / (vals - 1) );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -173,7 +180,7 @@ vips_stats_build( VipsObject *object )
|
||||
static int
|
||||
vips_stats_stop( VipsStatistic *statistic, void *seq )
|
||||
{
|
||||
int bands = vips_image_get_bands( statistic->in->Bands );
|
||||
int bands = vips_image_get_bands( statistic->in );
|
||||
VipsStats *global = (VipsStats *) statistic;
|
||||
VipsStats *local = (VipsStats *) seq;
|
||||
|
||||
@ -184,10 +191,10 @@ vips_stats_stop( VipsStatistic *statistic, void *seq )
|
||||
double *p = ARY( local->out, 0, b + 1 );
|
||||
double *q = ARY( global->out, 0, b + 1 );
|
||||
|
||||
p[COL_MIN] = q[COL_MIN];
|
||||
p[COL_MAX] = q[COL_MAX];
|
||||
p[COL_SUM] = q[COL_SUM];
|
||||
p[COL_SUM2] = q[COL_SUM2];
|
||||
q[COL_MIN] = p[COL_MIN];
|
||||
q[COL_MAX] = p[COL_MAX];
|
||||
q[COL_SUM] = p[COL_SUM];
|
||||
q[COL_SUM2] = p[COL_SUM2];
|
||||
}
|
||||
|
||||
global->set = TRUE;
|
||||
@ -215,7 +222,7 @@ vips_stats_stop( VipsStatistic *statistic, void *seq )
|
||||
static void *
|
||||
vips_stats_start( VipsStatistic *statistic )
|
||||
{
|
||||
int bands = vips_image_get_bands( statistic->in->Bands );
|
||||
int bands = vips_image_get_bands( statistic->in );
|
||||
|
||||
VipsStats *stats;
|
||||
|
||||
@ -332,7 +339,7 @@ vips_stats_init( VipsStats *stats )
|
||||
}
|
||||
|
||||
int
|
||||
vips_stats( VipsImage *in, double *out, ... )
|
||||
vips_stats( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
@ -725,7 +725,7 @@ im__dmsprint( im_object obj )
|
||||
band minimum maximum sum sum^2 mean deviation\
|
||||
\n" );
|
||||
for( j = 0; j < mask->ysize; j++ ) {
|
||||
row = mask->coeff + j * 6;
|
||||
row = mask->coeff + j * mask->xsize;
|
||||
if( j == 0 )
|
||||
printf( "all" );
|
||||
else
|
||||
|
@ -1604,3 +1604,21 @@ im_exp10tra( IMAGE *in, IMAGE *out )
|
||||
{
|
||||
return( vips__math( in, out, VIPS_MATH_OPERATION_EXP10 ) );
|
||||
}
|
||||
|
||||
DOUBLEMASK *
|
||||
im_stats( VipsImage *in )
|
||||
{
|
||||
VipsImage *t;
|
||||
DOUBLEMASK *msk;
|
||||
|
||||
if( vips_stats( in, &t,
|
||||
NULL ) )
|
||||
return( NULL );
|
||||
if( !(msk = im_vips2mask( t, "im_stats" )) ) {
|
||||
g_object_unref( t );
|
||||
return( NULL );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( msk );
|
||||
}
|
||||
|
@ -96,6 +96,8 @@ int vips_abs( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_sign( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_stats( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
|
||||
|
||||
@ -104,7 +106,6 @@ DOUBLEMASK *im_measure_area( VipsImage *im,
|
||||
int left, int top, int width, int height,
|
||||
int h, int v,
|
||||
int *sel, int nsel, const char *name );
|
||||
DOUBLEMASK *im_stats( VipsImage *in );
|
||||
int im_maxpos_avg( VipsImage *im, double *xpos, double *ypos, double *out );
|
||||
int im_maxpos_vec( VipsImage *im, int *xpos, int *ypos, double *maxima, int n );
|
||||
int im_minpos_vec( VipsImage *im, int *xpos, int *ypos, double *minima, int n );
|
||||
|
@ -535,6 +535,7 @@ int im_lintra( double a, VipsImage *in, double b, VipsImage *out );
|
||||
int im_lintra_vec( int n, double *a, VipsImage *in, double *b, VipsImage *out );
|
||||
int im_abs( VipsImage *in, VipsImage *out );
|
||||
int im_sign( VipsImage *in, VipsImage *out );
|
||||
DOUBLEMASK *im_stats( VipsImage *in );
|
||||
|
||||
int im_sintra( VipsImage *in, VipsImage *out );
|
||||
int im_costra( VipsImage *in, VipsImage *out );
|
||||
|
@ -388,7 +388,8 @@ vips_warn( const char *domain, const char *fmt, ... )
|
||||
* @Varargs: arguments to the format string
|
||||
*
|
||||
* Sends a formatted error message to stderr, then sends the contents of the
|
||||
* error buffer, if any, then terminates the program with an error code.
|
||||
* error buffer, if any, then shuts down vips and terminates the program with
|
||||
* an error code.
|
||||
*
|
||||
* @fmt may be %NULL, in which case only the error buffer is printed before
|
||||
* exiting.
|
||||
@ -412,6 +413,8 @@ vips_error_exit( const char *fmt, ... )
|
||||
|
||||
fprintf( stderr, "%s", vips_error_buffer() );
|
||||
|
||||
vips_shutdown();
|
||||
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
|
@ -1850,6 +1850,7 @@ vips_object_print_all_cb( VipsObject *object, int *n )
|
||||
*n, G_OBJECT_TYPE_NAME( object ), object );
|
||||
|
||||
class->print_class( class, &buf );
|
||||
vips_buf_appends( &buf, " " );
|
||||
class->print( object, &buf );
|
||||
fprintf( stderr, "%s\n", vips_buf_all( &buf ) );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user