im_divide() -> VipsDivide

This commit is contained in:
John Cupitt 2011-11-06 22:24:42 +00:00
parent 1fd1559bb5
commit e5b5bed428
7 changed files with 201 additions and 134 deletions

View File

@ -7,7 +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(), im_sign(), im_max(), im_maxpos(), im_deviate() im_abs(), im_sign(), im_max(), im_maxpos(), im_deviate(), im_divide()
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

View File

@ -6,7 +6,7 @@ libarithmetic_la_SOURCES = \
im_bandmean.c \ im_bandmean.c \
im_cross_phase.c \ im_cross_phase.c \
deviate.c \ deviate.c \
im_divide.c \ divide.c \
im_recomb.c \ im_recomb.c \
im_linreg.c \ im_linreg.c \
im_maxpos_avg.c \ im_maxpos_avg.c \

View File

@ -502,8 +502,9 @@ void
vips_arithmetic_operation_init( void ) vips_arithmetic_operation_init( void )
{ {
extern GType vips_add_get_type( void ); extern GType vips_add_get_type( void );
extern GType vips_invert_get_type( void );
extern GType vips_subtract_get_type( void ); extern GType vips_subtract_get_type( void );
extern GType vips_divide_get_type( void );
extern GType vips_invert_get_type( void );
extern GType vips_avg_get_type( void ); extern GType vips_avg_get_type( void );
extern GType vips_min_get_type( void ); extern GType vips_min_get_type( void );
extern GType vips_max_get_type( void ); extern GType vips_max_get_type( void );
@ -514,8 +515,9 @@ vips_arithmetic_operation_init( void )
extern GType vips_sign_get_type( void ); extern GType vips_sign_get_type( void );
vips_add_get_type(); vips_add_get_type();
vips_invert_get_type();
vips_subtract_get_type(); vips_subtract_get_type();
vips_divide_get_type();
vips_invert_get_type();
vips_avg_get_type(); vips_avg_get_type();
vips_min_get_type(); vips_min_get_type();
vips_max_get_type(); vips_max_get_type();

View File

@ -1,4 +1,4 @@
/* im_divide.c /* Divide two images
* *
* Copyright: 1990, N. Dessipris. * Copyright: 1990, N. Dessipris.
* *
@ -26,23 +26,25 @@
* 31/7/10 * 31/7/10
* - remove liboil support * - remove liboil support
* - avoid /0 * - avoid /0
* 6/11/11
* - rewrite as a class
*/ */
/* /*
This file is part of VIPS. Copyright (C) 1991-2005 The National Gallery
VIPS is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -54,6 +56,10 @@
*/ */
/*
#define DEBUG
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
@ -62,123 +68,14 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <assert.h>
#include <vips/vips.h> #include <vips/vips.h>
#include <vips/internal.h>
/* Complex divide. #include "arithmetic.h"
*/ #include "binary.h"
#ifdef USE_MODARG_DIV
/* This is going to be much slower */
#define CLOOP( TYPE ) { \
TYPE *X = (TYPE *) in[0]; \
TYPE *Y = (TYPE *) in[1]; \
TYPE *Z = (TYPE *) out; \
int i; \
\
for( i = 0; i < sz; i++ ) { \
double arg = atan2( X[1], X[0] ) - atan2( Y[1], Y[0] ); \
double mod = hypot( X[1], X[0] ) / hypot( Y[1], Y[0] ); \
\
Z[0] = mod * cos( arg ); \
Z[1] = mod * sin( arg ); \
\
X += 2; \
Y += 2; \
Z += 2; \
} \
}
#else /* USE_MODARG_DIV */
#define CLOOP( TYPE ) { \
TYPE *X = (TYPE *) in[0]; \
TYPE *Y = (TYPE *) in[1]; \
TYPE *Z = (TYPE *) out; \
int i; \
\
for( i = 0; i < sz; i++ ) { \
if( fabs( Y[0] ) > fabs( Y[1] ) ) { \
double a = Y[1] / Y[0]; \
double b = Y[0] + Y[1] * a; \
\
Z[0] = (X[0] + X[1] * a) / b; \
Z[1] = (X[1] - X[0] * a) / b; \
} \
else { \
double a = Y[0] / Y[1]; \
double b = Y[1] + Y[0] * a; \
\
Z[0] = (X[0] * a + X[1]) / b; \
Z[1] = (X[1] * a - X[0]) / b; \
} \
\
X += 2; \
Y += 2; \
Z += 2; \
} \
}
#endif /* USE_MODARG_DIV */
/* Real divide.
*/
#define RLOOP( IN, OUT ) { \
IN *p1 = (IN *) in[0]; \
IN *p2 = (IN *) in[1]; \
OUT *q = (OUT *) out; \
\
for( x = 0; x < sz; x++ ) \
if( p2[x] == 0.0 ) \
q[x] = 0; \
else \
q[x] = p1[x] / p2[x]; \
}
static void
divide_buffer( PEL **in, PEL *out, int width, IMAGE *im )
{
int x;
int sz = width * im->Bands;
/* Divide all input types.
*/
switch( im->BandFmt ) {
case IM_BANDFMT_CHAR: RLOOP( signed char, float ); break;
case IM_BANDFMT_UCHAR: RLOOP( unsigned char, float ); break;
case IM_BANDFMT_SHORT: RLOOP( signed short, float ); break;
case IM_BANDFMT_USHORT: RLOOP( unsigned short, float ); break;
case IM_BANDFMT_INT: RLOOP( signed int, float ); break;
case IM_BANDFMT_UINT: RLOOP( unsigned int, float ); break;
case IM_BANDFMT_FLOAT: RLOOP( float, float ); break;
case IM_BANDFMT_DOUBLE: RLOOP( double, double ); break;
case IM_BANDFMT_COMPLEX:CLOOP( float ); break;
case IM_BANDFMT_DPCOMPLEX:CLOOP( double ); break;
default:
assert( 0 );
}
}
/* Save a bit of typing.
*/
#define F IM_BANDFMT_FLOAT
#define X IM_BANDFMT_COMPLEX
#define D IM_BANDFMT_DOUBLE
#define DX IM_BANDFMT_DPCOMPLEX
/* Type promotion for division. Sign and value preserving. Make sure
* these match the case statement in divide_buffer() above.
*/
static int bandfmt_divide[10] = {
/* UC C US S UI I F X D DX */
F, F, F, F, F, F, F, X, D, DX
};
/** /**
* im_divide: * VipsDivide::
* @in1: input #IMAGE 1 * @in1: input #IMAGE 1
* @in2: input #IMAGE 2 * @in2: input #IMAGE 2
* @out: output #IMAGE * @out: output #IMAGE
@ -256,15 +153,165 @@ static int bandfmt_divide[10] = {
* In other words, the output type is just large enough to hold the whole * In other words, the output type is just large enough to hold the whole
* range of possible values. * range of possible values.
* *
* See also: im_multiply(), im_lintra(). * See also: #VipsAdd, #VipsSubtract.
*
* Returns: 0 on success, -1 on error
*/ */
int
im_divide( IMAGE *in1, IMAGE *in2, IMAGE *out ) typedef VipsBinary VipsDivide;
{ typedef VipsBinaryClass VipsDivideClass;
return( im__arith_binary( "im_divide",
in1, in2, out, G_DEFINE_TYPE( VipsDivide, vips_divide, VIPS_TYPE_BINARY );
bandfmt_divide,
(im_wrapmany_fn) divide_buffer, NULL ) ); /* Complex divide.
*/
#ifdef USE_MODARG_DIV
/* This is going to be much slower */
#define CLOOP( TYPE ) { \
TYPE *left = (TYPE *) in[0]; \
TYPE *right = (TYPE *) in[1]; \
TYPE *q = (TYPE *) out; \
int i; \
\
for( i = 0; i < sz; i++ ) { \
double arg = atan2( left[1], left[0] ) - \
atan2( right[1], right[0] ); \
double mod = hypot( left[1], left[0] ) / \
hypot( right[1], right[0] ); \
\
q[0] = mod * cos( arg ); \
q[1] = mod * sin( arg ); \
\
left += 2; \
right += 2; \
q += 2; \
} \
}
#else /* USE_MODARG_DIV */
#define CLOOP( TYPE ) { \
TYPE *left = (TYPE *) in[0]; \
TYPE *right = (TYPE *) in[1]; \
TYPE *q = (TYPE *) out; \
int i; \
\
for( i = 0; i < sz; i++ ) { \
if( fabs( right[0] ) > fabs( right[1] ) ) { \
double a = right[1] / right[0]; \
double b = right[0] + right[1] * a; \
\
q[0] = (left[0] + left[1] * a) / b; \
q[1] = (left[1] - left[0] * a) / b; \
} \
else { \
double a = right[0] / right[1]; \
double b = right[1] + right[0] * a; \
\
q[0] = (left[0] * a + left[1]) / b; \
q[1] = (left[1] * a - left[0]) / b; \
} \
\
left += 2; \
right += 2; \
q += 2; \
} \
}
#endif /* USE_MODARG_DIV */
/* Real divide.
*/
#define RLOOP( IN, OUT ) { \
IN *left = (IN *) in[0]; \
IN *right = (IN *) in[1]; \
OUT *q = (OUT *) out; \
\
for( x = 0; x < sz; x++ ) \
if( right[x] == 0.0 ) \
q[x] = 0; \
else \
q[x] = left[x] / right[x]; \
}
static void
vips_divide_buffer( VipsArithmetic *arithmetic,
PEL *out, PEL **in, int width )
{
VipsImage *im = arithmetic->ready[0];
const int sz = width * vips_image_get_bands( im );
int x;
/* Keep types here in sync with bandfmt_divide[]
* below.
*/
switch( vips_image_get_format( im ) ) {
case VIPS_FORMAT_CHAR: RLOOP( signed char, signed short ); break;
case VIPS_FORMAT_UCHAR: RLOOP( unsigned char, signed short ); break;
case VIPS_FORMAT_SHORT: RLOOP( signed short, signed int ); break;
case VIPS_FORMAT_USHORT:RLOOP( unsigned short, signed int ); break;
case VIPS_FORMAT_INT: RLOOP( signed int, signed int ); break;
case VIPS_FORMAT_UINT: RLOOP( unsigned int, signed int ); break;
case VIPS_FORMAT_FLOAT: RLOOP( float, float ); break;
case VIPS_FORMAT_DOUBLE: RLOOP( double, double ); break;
case VIPS_FORMAT_COMPLEX: CLOOP( float ); break;
case VIPS_FORMAT_DPCOMPLEX: CLOOP( 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
/* Type promotion for division. Sign and value preserving. Make sure
* these match the case statement in divide_buffer() above.
*/
static int vips_bandfmt_divide[10] = {
/* UC C US S UI I F X D DX */
F, F, F, F, F, F, F, X, D, DX
};
static void
vips_divide_class_init( VipsDivideClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class );
object_class->nickname = "divide";
object_class->description = _( "divide two images" );
vips_arithmetic_set_format_table( aclass, vips_bandfmt_divide );
aclass->process_line = vips_divide_buffer;
}
static void
vips_divide_init( VipsDivide *divide )
{
}
int
vips_divide( VipsImage *left, VipsImage *right, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "divide", ap, left, right, out );
va_end( ap );
return( result );
} }

View File

@ -928,6 +928,22 @@ im_subtract( IMAGE *in1, IMAGE *in2, IMAGE *out )
return( 0 ); return( 0 );
} }
int
im_divide( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
VipsImage *x;
if( vips_call( "divide", in1, in2, &x, NULL ) )
return( -1 );
if( im_copy( x, out ) ) {
g_object_unref( x );
return( -1 );
}
g_object_unref( x );
return( 0 );
}
int int
im_avg( IMAGE *in, double *out ) im_avg( IMAGE *in, double *out )
{ {

View File

@ -70,6 +70,8 @@ int vips_add( VipsImage *left, VipsImage *right, VipsImage **out, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_subtract( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) int vips_subtract( VipsImage *in1, VipsImage *in2, VipsImage **out, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_divide( VipsImage *left, VipsImage *right, VipsImage **out, ... )
__attribute__((sentinel));
int vips_avg( VipsImage *in, double *out, ... ) int vips_avg( VipsImage *in, double *out, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_deviate( VipsImage *in, double *out, ... ) int vips_deviate( VipsImage *in, double *out, ... )
@ -107,7 +109,6 @@ int im_minpos_vec( VipsImage *im, int *xpos, int *ypos, double *minima, int n );
int im_bandmean( VipsImage *in, VipsImage *out ); int im_bandmean( VipsImage *in, VipsImage *out );
int im_multiply( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_multiply( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_divide( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_remainder( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_remainder( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_remainder_vec( VipsImage *in, VipsImage *out, int n, double *c ); int im_remainder_vec( VipsImage *in, VipsImage *out, int n, double *c );
int im_remainderconst( VipsImage *in, VipsImage *out, double c ); int im_remainderconst( VipsImage *in, VipsImage *out, double c );

View File

@ -522,6 +522,7 @@ size_t im_ref_string_get_length( const GValue *value );
int im_add( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_add( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_subtract( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_subtract( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_divide( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_min( VipsImage *in, double *out ); int im_min( VipsImage *in, double *out );
int im_minpos( VipsImage *in, int *xpos, int *ypos, double *out ); int im_minpos( VipsImage *in, int *xpos, int *ypos, double *out );
int im_max( VipsImage *in, double *out ); int im_max( VipsImage *in, double *out );