redo im_abs as a class

This commit is contained in:
John Cupitt 2011-11-06 11:54:52 +00:00
parent ebc0e54217
commit 11d0a28ccb
11 changed files with 323 additions and 234 deletions

View File

@ -7,6 +7,7 @@
im_lintra(), im_lintra_vec(), im_black(), im_rot90, im_rot180(), im_rot270() im_lintra(), im_lintra_vec(), im_black(), im_rot90, im_rot180(), im_rot270()
im_sintra(), im_costra(), im_tantra(), im_asintra(), im_acostra(), im_sintra(), im_costra(), im_tantra(), im_asintra(), im_acostra(),
im_atantra(), im_exptra(), im_exp10tra(), im_logtra(), im_log10tra(), im_atantra(), im_exptra(), im_exp10tra(), im_logtra(), im_log10tra(),
im_abs()
redone as classes redone as classes
- added argument priorites to help control arg ordering - added argument priorites to help control arg ordering
- generate has a 'stop' param to signal successful early termination - generate has a 'stop' param to signal successful early termination

30
TODO
View File

@ -1,3 +1,30 @@
- try:
$ vips abs x.v
(null): too few arguments
not setting prg name?
- try:
$ vips abs x.v wdw dwdwwww
vips_format_for_name: "" is not a supported image format.
- see: vips_abs_build(), should that set an arithmetic member? ugly
- what about pipeline -> bandsplit -> min
will that eval the pipe once for each band, or will caching stop that?
- try: - try:
$ vips vips copy babe.png x.v $ vips vips copy babe.png x.v
@ -142,6 +169,9 @@
- add vips_init_argv() which processes argc/argv for you? handy for tiny - add vips_init_argv() which processes argc/argv for you? handy for tiny
progs, perhaps progs, perhaps
just saves 5 lines of code, don't bother

View File

@ -2,7 +2,7 @@ noinst_LTLIBRARIES = libarithmetic.la
libarithmetic_la_SOURCES = \ libarithmetic_la_SOURCES = \
arith_dispatch.c \ arith_dispatch.c \
im_abs.c \ abs.c \
im_bandmean.c \ im_bandmean.c \
im_cross_phase.c \ im_cross_phase.c \
im_deviate.c \ im_deviate.c \

263
libvips/arithmetic/abs.c Normal file
View File

@ -0,0 +1,263 @@
/* im_abs()
*
* Copyright: 1990, N. Dessipris, based on im_powtra()
* Author: Nicos Dessipris
* Written on: 02/05/1990
* Modified on:
* 5/5/93 J.Cupitt
* - adapted from im_lintra to work with partial images
* - complex and signed support added
* 30/6/93 JC
* - adapted for partial v2
* - ANSI conversion
* - spe29873r6k3h()**!@lling errors removed
* 9/2/95 JC
* - adapted for im_wrap...
* 20/6/02 JC
* - tiny speed up
* 8/12/06
* - add liboil support
* 28/8/09
* - gtkdoc
* - tiny polish
* 31/7/10
* - remove liboil
* 6/11/11
* - redone as a class
*/
/*
Copyright (C) 1991-2005 The National Gallery
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU 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 "arithmetic.h"
#include "unary.h"
/**
* VipsAbs:
* @in: input #VipsImage
* @out: output #VipsImage
*
* For unsigned formats, this operation calculates (max - @in), eg. (255 -
* @in) for uchar. For signed and float formats, this operation calculates (-1
* * @in).
*
* See also: im_lintra().
*
* Returns: 0 on success, -1 on error
*/
typedef VipsUnary VipsAbs;
typedef VipsUnaryClass VipsAbsClass;
G_DEFINE_TYPE( VipsAbs, vips_abs, VIPS_TYPE_UNARY );
static int
vips_abs_build( VipsObject *object )
{
VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object );
VipsUnary *unary = (VipsUnary *) object;
if( unary->in &&
vips_band_format_isuint( unary->in->BandFmt ) ) {
/* This isn't set by arith until build(), so we have to set
* again here.
*
* Should arith set out in _init()?
*/
g_object_set( arithmetic, "out", vips_image_new(), NULL );
return( vips_image_write( unary->in, arithmetic->out ) );
}
if( VIPS_OBJECT_CLASS( vips_abs_parent_class )->build( object ) )
return( -1 );
return( 0 );
}
/* Integer abs operation: just test and negate.
*/
#define ABS_INT( TYPE ) { \
TYPE *p = (TYPE *) in[0]; \
TYPE *q = (TYPE *) out; \
int x; \
\
for( x = 0; x < sz; x++ ) { \
TYPE v = p[x]; \
\
if( v < 0 ) \
q[x] = 0 - v; \
else \
q[x] = v; \
} \
}
/* Float abs operation: call fabs().
*/
#define ABS_FLOAT( TYPE ) { \
TYPE *p = (TYPE *) in[0]; \
TYPE *q = (TYPE *) out; \
int x; \
\
for( x = 0; x < sz; x++ ) \
q[x] = fabs( p[x] ); \
}
/* Complex abs operation: calculate modulus.
*/
#ifdef HAVE_HYPOT
#define ABS_COMPLEX( TYPE ) { \
TYPE *p = (TYPE *) in[0]; \
TYPE *q = (TYPE *) out; \
int x; \
\
for( x = 0; x < sz; x++ ) { \
q[x] = hypot( p[0], p[1] ); \
p += 2; \
} \
}
#else /*HAVE_HYPOT*/
#define ABS_COMPLEX( TYPE ) { \
TYPE *p = (TYPE *) in[0]; \
TYPE *q = (TYPE *) out; \
int x; \
\
for( x = 0; x < sz; x++ ) { \
double rp = p[0]; \
double ip = p[1]; \
double abs_rp = fabs( rp ); \
double abs_ip = fabs( ip ); \
\
if( abs_rp > abs_ip ) { \
double temp = ip / rp; \
\
q[x]= abs_rp * sqrt( 1.0 + temp * temp ); \
} \
else { \
double temp = rp / ip; \
\
q[x]= abs_ip * sqrt( 1.0 + temp * temp ); \
} \
\
p += 2; \
} \
}
#endif /*HAVE_HYPOT*/
static void
vips_abs_buffer( VipsArithmetic *arithmetic, PEL *out, PEL **in, int width )
{
VipsImage *im = arithmetic->ready[0];
int sz = width * im->Bands;
/* Abs all input types.
*/
switch( im->BandFmt ) {
case VIPS_FORMAT_CHAR: ABS_INT( signed char ); break;
case VIPS_FORMAT_SHORT: ABS_INT( signed short ); break;
case VIPS_FORMAT_INT: ABS_INT( signed int ); break;
case VIPS_FORMAT_FLOAT: ABS_FLOAT( float ); break;
case VIPS_FORMAT_DOUBLE: ABS_FLOAT( float ); break;
case VIPS_FORMAT_COMPLEX: ABS_COMPLEX( float ); break;
case VIPS_FORMAT_DPCOMPLEX: ABS_COMPLEX( double ); break;
default:
g_assert( 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
/* Format doesn't change with abs.
*/
static const VipsBandFormat vips_bandfmt_abs[10] = {
/* UC C US S UI I F X D DX */
UC, C, US, S, UI, I, F, X, D, DX
};
static void
vips_abs_class_init( VipsAbsClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class );
object_class->nickname = "abs";
object_class->description = _( "absolute value of an image" );
object_class->build = vips_abs_build;
vips_arithmetic_set_format_table( aclass, vips_bandfmt_abs );
aclass->process_line = vips_abs_buffer;
}
static void
vips_abs_init( VipsAbs *abs )
{
}
int
vips_abs( VipsImage *in, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "abs", ap, in, out );
va_end( ap );
return( result );
}

View File

@ -508,6 +508,7 @@ vips_arithmetic_operation_init( void )
extern GType vips_min_get_type( void ); extern GType vips_min_get_type( void );
extern GType vips_linear_get_type( void ); extern GType vips_linear_get_type( void );
extern GType vips_math_get_type( void ); extern GType vips_math_get_type( void );
extern GType vips_abs_get_type( void );
vips_add_get_type(); vips_add_get_type();
vips_invert_get_type(); vips_invert_get_type();
@ -516,5 +517,6 @@ vips_arithmetic_operation_init( void )
vips_min_get_type(); vips_min_get_type();
vips_linear_get_type(); vips_linear_get_type();
vips_math_get_type(); vips_math_get_type();
vips_abs_get_type();
} }

View File

@ -1,225 +0,0 @@
/* im_abs()
*
* Copyright: 1990, N. Dessipris, based on im_powtra()
* Author: Nicos Dessipris
* Written on: 02/05/1990
* Modified on:
* 5/5/93 J.Cupitt
* - adapted from im_lintra to work with partial images
* - complex and signed support added
* 30/6/93 JC
* - adapted for partial v2
* - ANSI conversion
* - spe29873r6k3h()**!@lling errors removed
* 9/2/95 JC
* - adapted for im_wrap...
* 20/6/02 JC
* - tiny speed up
* 8/12/06
* - add liboil support
* 28/8/09
* - gtkdoc
* - tiny polish
* 31/7/10
* - remove liboil
*/
/*
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
*/
#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>
/* Integer abs operation: just test and negate.
*/
#define intabs(TYPE) { \
TYPE *p = (TYPE *) in; \
TYPE *q = (TYPE *) out; \
int x; \
\
for( x = 0; x < sz; x++ ) { \
TYPE v = p[x]; \
\
if( v < 0 ) \
q[x] = 0 - v; \
else \
q[x] = v; \
} \
}
/* Float abs operation: call fabs().
*/
#define floatabs(TYPE) { \
TYPE *p = (TYPE *) in; \
TYPE *q = (TYPE *) out; \
int x; \
\
for( x = 0; x < sz; x++ ) \
q[x] = fabs( p[x] ); \
}
/* Complex abs operation: calculate modulus.
*/
#ifdef HAVE_HYPOT
#define complexabs(TYPE) { \
TYPE *p = (TYPE *) in; \
TYPE *q = (TYPE *) out; \
int x; \
\
for( x = 0; x < sz; x++ ) { \
q[x] = hypot( p[0], p[1] ); \
p += 2; \
} \
}
#else /*HAVE_HYPOT*/
#define complexabs(TYPE) { \
TYPE *p = (TYPE *) in; \
TYPE *q = (TYPE *) out; \
int x; \
\
for( x = 0; x < sz; x++ ) { \
double rp = p[0]; \
double ip = p[1]; \
double abs_rp = fabs( rp ); \
double abs_ip = fabs( ip ); \
\
if( abs_rp > abs_ip ) { \
double temp = ip / rp; \
\
q[x]= abs_rp * sqrt( 1.0 + temp * temp ); \
} \
else { \
double temp = rp / ip; \
\
q[x]= abs_ip * sqrt( 1.0 + temp * temp ); \
} \
\
p += 2; \
} \
}
#endif /*HAVE_HYPOT*/
/* Abs a buffer of PELs.
*/
static void
abs_gen( PEL *in, PEL *out, int width, IMAGE *im )
{
int sz = width * im->Bands;
/* Abs all input types.
*/
switch( im->BandFmt ) {
case IM_BANDFMT_CHAR: intabs( signed char ); break;
case IM_BANDFMT_SHORT: intabs( signed short ); break;
case IM_BANDFMT_INT: intabs( signed int ); break;
case IM_BANDFMT_FLOAT: floatabs( float ); break;
case IM_BANDFMT_DOUBLE: floatabs( float ); break;
case IM_BANDFMT_COMPLEX: complexabs( float ); break;
case IM_BANDFMT_DPCOMPLEX: complexabs( double ); break;
default:
g_assert( 0 );
}
}
/**
* im_abs:
* @in: input #IMAGE
* @out: output #IMAGE
*
* This operation finds the absolute value of an image. It does a copy for
* unsigned integer types, negate for negative values in
* signed integer types, <function>fabs(3)</function> for
* float types, and calculate modulus for complex
* types.
*
* See also: im_exp10tra(), im_sign().
*
* Returns: 0 on success, -1 on error
*/
int
im_abs( IMAGE *in, IMAGE *out )
{
if( im_piocheck( in, out ) ||
im_check_uncoded( "im_abs", in ) )
return( -1 );
/* Is this one of the unsigned types? Degenerate to im_copy() if it
* is.
*/
if( vips_bandfmt_isuint( in->BandFmt ) )
return( im_copy( in, out ) );
/* Prepare output header. Output type == input type, except for
* complex.
*/
if( im_cp_desc( out, in ) )
return( -1 );
switch( in->BandFmt ) {
case IM_BANDFMT_CHAR:
case IM_BANDFMT_SHORT:
case IM_BANDFMT_INT:
case IM_BANDFMT_FLOAT:
case IM_BANDFMT_DOUBLE:
/* No action.
*/
break;
case IM_BANDFMT_COMPLEX:
out->BandFmt = IM_BANDFMT_FLOAT;
break;
case IM_BANDFMT_DPCOMPLEX:
out->BandFmt = IM_BANDFMT_DOUBLE;
break;
default:
im_error( "im_abs", "%s", _( "unknown input type" ) );
return( -1 );
}
/* Generate!
*/
if( im_wrapone( in, out,
(im_wrapone_fn) abs_gen, in, NULL ) )
return( -1 );
return( 0 );
}

View File

@ -49,8 +49,6 @@ extern "C" {
typedef struct _VipsUnary { typedef struct _VipsUnary {
VipsArithmetic parent_instance; VipsArithmetic parent_instance;
/* The arg we get from the property.
*/
VipsImage *in; VipsImage *in;
} VipsUnary; } VipsUnary;

View File

@ -1392,6 +1392,23 @@ im_invert( IMAGE *in, IMAGE *out )
return( 0 ); return( 0 );
} }
int
im_abs( IMAGE *in, IMAGE *out )
{
VipsImage *t;
if( vips_abs( in, &t,
NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}
int int
im_lintra( double a, IMAGE *in, double b, IMAGE *out ) im_lintra( double a, IMAGE *in, double b, IMAGE *out )
{ {

View File

@ -84,6 +84,8 @@ int vips_linear1( VipsImage *in, VipsImage **out, double a, double b, ... )
int vips_math( VipsImage *in, VipsImage **out, int vips_math( VipsImage *in, VipsImage **out,
VipsMathOperation operation, ... ) VipsMathOperation operation, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_abs( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
@ -109,7 +111,6 @@ int im_remainderconst( VipsImage *in, VipsImage *out, double c );
int im_recomb( VipsImage *in, VipsImage *out, DOUBLEMASK *recomb ); int im_recomb( VipsImage *in, VipsImage *out, DOUBLEMASK *recomb );
int im_sign( VipsImage *in, VipsImage *out ); int im_sign( VipsImage *in, VipsImage *out );
int im_abs( VipsImage *in, VipsImage *out );
int im_floor( VipsImage *in, VipsImage *out ); int im_floor( VipsImage *in, VipsImage *out );
int im_rint( VipsImage *in, VipsImage *out ); int im_rint( VipsImage *in, VipsImage *out );
int im_ceil( VipsImage *in, VipsImage *out ); int im_ceil( VipsImage *in, VipsImage *out );

View File

@ -528,6 +528,7 @@ int im_avg( VipsImage *in, double *out );
int im_invert( VipsImage *in, VipsImage *out ); int im_invert( VipsImage *in, VipsImage *out );
int im_lintra( double a, VipsImage *in, double b, VipsImage *out ); 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_lintra_vec( int n, double *a, VipsImage *in, double *b, VipsImage *out );
int im_abs( VipsImage *in, VipsImage *out );
int im_sintra( VipsImage *in, VipsImage *out ); int im_sintra( VipsImage *in, VipsImage *out );
int im_costra( VipsImage *in, VipsImage *out ); int im_costra( VipsImage *in, VipsImage *out );

View File

@ -1024,7 +1024,7 @@ vips_object_real_new_from_string( const char *string )
/* The main arg selects the subclass. /* The main arg selects the subclass.
*/ */
if( !(type = vips_type_find( "VipsObject", string )) ) if( !(type = vips_type_find( NULL, string )) )
return( NULL ); return( NULL );
return( VIPS_OBJECT( g_object_new( type, NULL ) ) ); return( VIPS_OBJECT( g_object_new( type, NULL ) ) );
@ -1728,17 +1728,19 @@ test_name( VipsObjectClass *class, const char *nickname )
} }
/* Find a class ... search below base, return the first match on a nickname or /* Find a class ... search below base, return the first match on a nickname or
* a name. * a name. If basename is NULL, search all of VipsObject.
*/ */
VipsObjectClass * VipsObjectClass *
vips_class_find( const char *basename, const char *nickname ) vips_class_find( const char *basename, const char *nickname )
{ {
const char *classname = basename ? basename : "VipsObject";
VipsObjectClass *class; VipsObjectClass *class;
GType base; GType base;
if( !(base = g_type_from_name( basename )) ) { if( !(base = g_type_from_name( classname )) ) {
vips_error( "VipsObject", vips_error( "VipsObject",
_( "base class \"%s\" not found" ), basename ); _( "base class \"%s\" not found" ), classname );
return( NULL ); return( NULL );
} }
@ -1848,7 +1850,6 @@ vips_object_print_all_cb( VipsObject *object, int *n )
*n, G_OBJECT_TYPE_NAME( object ), object ); *n, G_OBJECT_TYPE_NAME( object ), object );
class->print_class( class, &buf ); class->print_class( class, &buf );
vips_buf_appendf( &buf, "\n" );
class->print( object, &buf ); class->print( object, &buf );
fprintf( stderr, "%s\n", vips_buf_all( &buf ) ); fprintf( stderr, "%s\n", vips_buf_all( &buf ) );