redone ifthenelse/blend as classes

relational/ can now go, woo
This commit is contained in:
John Cupitt 2011-11-15 21:49:49 +00:00
parent cf09916df9
commit 2f7de7f8d0
18 changed files with 969 additions and 1215 deletions

View File

@ -11,7 +11,7 @@
im_multiply(), im_stats(), im_measure(), im_recomb(), im_floor(), im_ceil(),
im_rint(), im_equal*(), im_notequal*(), im_less*(), im_lesseq*(), im_more*(),
im_moreeq*(), im_remainder*(), im_and*(), im_or*(), im_eor*(), im_shift*(),
im_pow*(), im_exp*()
im_pow*(), im_exp*(), im_ifthenelse(), im_blend()
redone as classes
- added argument priorites to help control arg ordering
- generate has a 'stop' param to signal successful early termination

14
TODO
View File

@ -1,26 +1,15 @@
- move ifthenelse / blend to conversion? or arithmetic?
not ternary arithmetic ops since the condition image is always ucharo
maybe a subclass of binary, since the then & else images do need to be
upcast to match
- try an area operation, like conv, VipsArea? oops no haha what name should we
use?
- test _O_TEMPORARY thing on Windows
- avg/dev etc. should uncode images? eg. labq2lab etc.
how about ifthenelse?
@ -30,7 +19,6 @@
- vipsimage should be cached too, eg.
VipsImage *a = vips_image_new_from_file( "poop.jpg" );

View File

@ -642,7 +642,6 @@ AC_OUTPUT([
libvips/morphology/Makefile
libvips/mosaicing/Makefile
libvips/other/Makefile
libvips/relational/Makefile
libvips/resample/Makefile
libvips/video/Makefile
libvipsCC/include/Makefile

View File

@ -26,7 +26,6 @@ SUBDIRS = \
morphology \
mosaicing \
other \
relational \
video \
.
@ -60,7 +59,6 @@ libvips_la_LIBADD = \
morphology/libmorphology.la \
mosaicing/libmosaicing.la \
other/libother.la \
relational/librelational.la \
video/libvideo.la \
@VIPS_LIBS@

View File

@ -1,229 +0,0 @@
/* im_ifthenelse.c --- use a condition image to join two images together
*
* Modified:
* 9/2/95 JC
* - partialed and ANSIfied
* 11/9/95 JC
* - return( 0 ) missing! oops
* 15/4/05
* - now just evals left/right if all zero/all one
* 7/10/06
* - set THINSTRIP
* 23/9/09
* - gtkdoc comment
* 23/9/09
* - use im_check*()
* - allow many-band conditional and single-band a/b
* - allow a/b to differ in format and bands
* 25/6/10
* - let the conditional image be any format by adding a (!=0) if
* necessary
* 17/5/11
* - added sizealike
* 14/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 <vips/vips.h>
#include "binary.h"
#include "unaryconst.h"
/**
* VipsIfthenelse:
* @left: left-hand input #VipsImage
* @right: right-hand input #VipsImage
* @out: output #VipsImage
* @ifthenelse: ifthenelse operation to perform
*
* Perform various ifthenelse operations on pairs of images.
*
* The output type is always uchar, with 0 for FALSE and 255 for TRUE.
*
* Less-than and greater-than for complex images compare the modulus.
*
* If the images differ in size, the smaller image is enlarged to match the
* larger by adding zero pixels along the bottom and right.
*
* If the number of bands differs, one of the images
* must have one band. In this case, an n-band image is formed from the
* one-band image by joining n copies of the one-band image together, and then
* the two n-band images are operated upon.
*
* The two input images are cast up to the smallest common type (see table
* Smallest common format in
* <link linkend="VIPS-arithmetic">arithmetic</link>).
*
* See also: #VipsBoolean, #VipsIfthenelseConst.
*/
typedef struct _VipsIfthenelse {
VipsBinary parent_instance;
/* The condition image is always uchar.
*/
VipsImage *condition;
} VipsIfthenelse;
typedef VipsBinaryClass VipsIfthenelseClass;
G_DEFINE_TYPE( VipsIfthenelse, vips_ifthenelse, VIPS_TYPE_BINARY );
static int
vips_ifthenelse_build( VipsObject *object )
{
VipsIfthenelse *ifthenelse = (VipsIfthenelse *) object;
VipsArithmetic *arithmetic = (VipsArithmetic *) object;
if( VIPS_OBJECT_CLASS( vips_ifthenelse_parent_class )->build( object ) )
return( -1 );
return( 0 );
}
#define RLOOP( TYPE, ROP ) { \
TYPE *left = (TYPE *) in[0]; \
TYPE *right = (TYPE *) in[1]; \
PEL *q = (PEL *) out; \
\
for( x = 0; x < sz; x++ ) \
q[x] = (left[x] ROP right[x]) ? 255 : 0; \
}
#define CLOOP( TYPE, COP ) { \
TYPE *left = (TYPE *) in[0]; \
TYPE *right = (TYPE *) in[1]; \
PEL *q = (PEL *) out; \
\
for( x = 0; x < sz; x++ ) { \
q[x] = COP( left[0], left[1], right[0], right[1]) ? 255 : 0; \
\
left += 2; \
right += 2; \
} \
}
static void
vips_ifthenelse_buffer( VipsArithmetic *arithmetic,
PEL *out, PEL **in, int width )
{
VipsIfthenelse *ifthenelse = (VipsIfthenelse *) arithmetic;
VipsImage *im = arithmetic->ready[0];
const int sz = width * vips_image_get_bands( im );
int x;
switch( vips_image_get_format( im ) ) {
case VIPS_FORMAT_UCHAR: R( unsigned char, ROP ); break;
case VIPS_FORMAT_CHAR: R( signed char, ROP ); break;
case VIPS_FORMAT_USHORT: R( unsigned short, ROP ); break;
case VIPS_FORMAT_SHORT: R( signed short, ROP ); break;
case VIPS_FORMAT_UINT: R( unsigned int, ROP ); break;
case VIPS_FORMAT_INT: R( signed int, ROP ); break;
case VIPS_FORMAT_FLOAT: R( float, ROP ); break;
case VIPS_FORMAT_DOUBLE: R( double, ROP ); break;
case VIPS_FORMAT_COMPLEX: C( float, COP ); break;
case VIPS_FORMAT_DPCOMPLEX: C( double, COP ); 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
static const VipsBandFormat vips_bandfmt_ifthenelse[10] = {
/* UC C US S UI I F X D DX */
UC, C, US, S, UI, I, F, X, D, DX
};
static void
vips_ifthenelse_class_init( VipsIfthenelseClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "ifthenelse";
object_class->description =
_( "a ifthenelse operation on a pair of images" );
object_class->build = vips_ifthenelse_build;
vips_arithmetic_set_format_table( aclass, vips_bandfmt_ifthenelse );
aclass->process_line = vips_ifthenelse_buffer;
}
static void
vips_ifthenelse_init( VipsIfthenelse *ifthenelse )
{
}
int
vips_ifthenelse( VipsImage *left, VipsImage *right, VipsImage **out,
VipsOperationIfthenelse ifthenelse, ... )
{
va_list ap;
int result;
va_start( ap, ifthenelse );
result = vips_call_split( "ifthenelse", ap, left, right, out,
ifthenelse );
va_end( ap );
return( result );
}

View File

@ -14,6 +14,7 @@ libconversion_la_SOURCES = \
bandjoin.c \
black.c \
rot.c \
ifthenelse.c \
conver_dispatch.c \
im_c2amph.c \
im_c2rect.c \

View File

@ -115,6 +115,7 @@ vips_conversion_operation_init( void )
extern GType vips_bandjoin_get_type( void );
extern GType vips_black_get_type( void );
extern GType vips_rot_get_type( void );
extern GType vips_ifthenelse_get_type( void );
vips_copy_get_type();
vips_embed_get_type();
@ -128,6 +129,7 @@ vips_conversion_operation_init( void )
vips_bandjoin_get_type();
vips_black_get_type();
vips_rot_get_type();
vips_ifthenelse_get_type();
}

View File

@ -0,0 +1,468 @@
/* ifthenelse.c --- use a condition image to join two images together
*
* Modified:
* 9/2/95 JC
* - partialed and ANSIfied
* 11/9/95 JC
* - return( 0 ) missing! oops
* 15/4/05
* - now just evals left/right if all zero/all one
* 7/10/06
* - set THINSTRIP
* 23/9/09
* - gtkdoc comment
* 23/9/09
* - use im_check*()
* - allow many-band conditional and single-band a/b
* - allow a/b to differ in format and bands
* 25/6/10
* - let the conditional image be any format by adding a (!=0) if
* necessary
* 17/5/11
* - added sizealike
* 14/11/11
* - redone as a class
*/
/*
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 VIPS_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>
#include <vips/debug.h>
#include "conversion.h"
/**
* VipsIfthenelse:
* @cond: condition #VipsImage
* @in1: then #VipsImage
* @in2: else #VipsImage
* @out: output #VipsImage
*
* This operation scans the condition image @cond
* and uses it to select pixels from either the then image @in1 or the else
* image @in2. Non-zero means @in1, 0 means @in2.
*
* Any image can have either 1 band or n bands, where n is the same for all
* the non-1-band images. Single band images are then effectively copied to
* make n-band images.
*
* Images @in1 and @in2 are cast up to the smallest common format. @cond is
* cast to uchar.
*
* If the images differ in size, the smaller images are enlarged to match the
* largest by adding zero pixels along the bottom and right.
*
* If @blend is %TRUE, then values in @out are smoothly blended between @in1
* and @in2 using the formula:
*
* @out = (@cond / 255) * @in1 + (1 - @cond / 255) * @in2
*
* See also: #VipsEqual.
*/
typedef struct _VipsIfthenelse {
VipsConversion parent_instance;
/* Params.
*/
VipsImage *cond;
VipsImage *in1;
VipsImage *in2;
gboolean blend;
} VipsIfthenelse;
typedef VipsConversionClass VipsIfthenelseClass;
G_DEFINE_TYPE( VipsIfthenelse, vips_ifthenelse, VIPS_TYPE_CONVERSION );
#define IBLEND1( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( i = 0, x = 0; x < n; i++, x += bands ) { \
const int v = c[i]; \
\
for( z = x; z < x + bands; z++ ) \
q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \
} \
}
#define IBLENDN( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( x = 0; x < n; x += bands ) { \
for( z = x; z < x + bands; z++ ) { \
const int v = c[z]; \
\
q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \
} \
} \
}
#define FBLEND1( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( i = 0, x = 0; x < n; i++, x += bands ) { \
const double v = c[i] / 255.0; \
\
for( z = x; z < x + bands; z++ ) \
q[z] = v * a[z] + (1.0 - v) * b[z]; \
} \
}
#define FBLENDN( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( x = 0; x < n; x += bands ) { \
for( z = x; z < x + bands; z++ ) { \
const double v = c[z] / 255.0; \
\
q[z] = v * a[z] + (1.0 - v) * b[z]; \
} \
} \
}
#define CBLEND1( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( i = 0, x = 0; x < n; i++, x += bands ) { \
const double v = c[i] / 255.0; \
\
for( z = x; z < x + 2 * bands; z++ ) \
q[z] = v * a[z] + (1.0 - v) * b[z]; \
} \
}
#define CBLENDN( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( x = 0; x < n; x += bands ) { \
for( z = x; z < x + bands; z++ ) { \
const double v = c[z] / 255.0; \
\
q[2 * z] = v * a[2 * z] + (1.0 - v) * b[2 * z]; \
q[2 * z + 1] = v * a[2 * z + 1] + \
(1.0 - v) * b[2 * z + 1]; \
} \
} \
}
/* Blend with a 1-band conditional image.
*/
static void
vips_blend1_buffer( PEL *qp, PEL *c, PEL *ap, PEL *bp, int width,
VipsImage *im )
{
int i, x, z;
const int bands = im->Bands;
const int n = width * bands;
switch( im->BandFmt ) {
case VIPS_FORMAT_UCHAR: IBLEND1( unsigned char ); break;
case VIPS_FORMAT_CHAR: IBLEND1( signed char ); break;
case VIPS_FORMAT_USHORT: IBLEND1( unsigned short ); break;
case VIPS_FORMAT_SHORT: IBLEND1( signed short ); break;
case VIPS_FORMAT_UINT: IBLEND1( unsigned int ); break;
case VIPS_FORMAT_INT: IBLEND1( signed int ); break;
case VIPS_FORMAT_FLOAT: FBLEND1( float ); break;
case VIPS_FORMAT_DOUBLE: FBLEND1( double ); break;
case VIPS_FORMAT_COMPLEX: CBLEND1( float ); break;
case VIPS_FORMAT_DPCOMPLEX: CBLEND1( double ); break;
default:
g_assert( 0 );
}
}
/* Blend with a many band conditional image.
*/
static void
vips_blendn_buffer( PEL *qp, PEL *c, PEL *ap, PEL *bp, int width,
VipsImage *im )
{
int x, z;
const int bands = im->Bands;
const int n = width * bands;
switch( im->BandFmt ) {
case VIPS_FORMAT_UCHAR: IBLENDN( unsigned char ); break;
case VIPS_FORMAT_CHAR: IBLENDN( signed char ); break;
case VIPS_FORMAT_USHORT: IBLENDN( unsigned short ); break;
case VIPS_FORMAT_SHORT: IBLENDN( signed short ); break;
case VIPS_FORMAT_UINT: IBLENDN( unsigned int ); break;
case VIPS_FORMAT_INT: IBLENDN( signed int ); break;
case VIPS_FORMAT_FLOAT: FBLENDN( float ); break;
case VIPS_FORMAT_DOUBLE: FBLENDN( double ); break;
case VIPS_FORMAT_COMPLEX: CBLENDN( float ); break;
case VIPS_FORMAT_DPCOMPLEX: CBLENDN( double ); break;
default:
g_assert( 0 );
}
}
static int
vips_ifthenelse_gen( VipsRegion *or, void *seq, void *client1, void *client2,
gboolean *stop )
{
VipsRegion **ir = (VipsRegion **) seq;
VipsIfthenelse *ifthenelse = (VipsIfthenelse *) client2;
VipsRect *r = &or->valid;
int le = r->left;
int to = r->top;
int bo = VIPS_RECT_BOTTOM( r );
VipsImage *c = ir[2]->im;
VipsImage *a = ir[0]->im;
int size, width;
int i, x, y, z;
int all0, alln0;
if( c->Bands == 1 ) {
/* Copying PEL-sized units with a one-band conditional.
*/
size = VIPS_IMAGE_SIZEOF_PEL( a );
width = r->width;
}
else {
/* Copying ELEMENT sized-units with an n-band conditional.
*/
size = VIPS_IMAGE_SIZEOF_ELEMENT( a );
width = r->width * a->Bands;
}
if( vips_region_prepare( ir[2], r ) )
return( -1 );
/* Is the conditional all zero or all non-zero? We can avoid asking
* for one of the inputs to be calculated.
*/
all0 = *((PEL *) VIPS_REGION_ADDR( ir[2], le, to )) == 0;
alln0 = *((PEL *) VIPS_REGION_ADDR( ir[2], le, to )) != 0;
for( y = to; y < bo; y++ ) {
PEL *p = (PEL *) VIPS_REGION_ADDR( ir[2], le, y );
for( x = 0; x < width; x++ ) {
all0 &= p[x] == 0;
alln0 &= p[x] != 0;
}
if( !all0 && !alln0 )
break;
}
if( alln0 ) {
/* All non-zero. Point or at the then image.
*/
if( vips_region_prepare( ir[0], r ) ||
vips_region_region( or, ir[0], r, r->left, r->top ) )
return( -1 );
}
else if( all0 ) {
/* All zero. Point or at the else image.
*/
if( vips_region_prepare( ir[1], r ) ||
vips_region_region( or, ir[1], r, r->left, r->top ) )
return( -1 );
}
else {
/* Mix of set and clear ... ask for both then and else parts
* and interleave.
*/
if( vips_region_prepare( ir[0], r ) ||
vips_region_prepare( ir[1], r ) )
return( -1 );
for( y = to; y < bo; y++ ) {
PEL *ap = (PEL *) VIPS_REGION_ADDR( ir[0], le, y );
PEL *bp = (PEL *) VIPS_REGION_ADDR( ir[1], le, y );
PEL *cp = (PEL *) VIPS_REGION_ADDR( ir[2], le, y );
PEL *q = (PEL *) VIPS_REGION_ADDR( or, le, y );
if( ifthenelse->blend ) {
if( c->Bands == 1 )
vips_blend1_buffer( q,
cp, ap, bp, r->width, a );
else
vips_blendn_buffer( q,
cp, ap, bp, r->width, a );
}
else {
for( x = 0, i = 0; i < width; i++, x += size )
if( cp[i] )
for( z = x; z < x + size; z++ )
q[z] = ap[z];
else
for( z = x; z < x + size; z++ )
q[z] = bp[z];
}
}
}
return( 0 );
}
static int
vips_ifthenelse_build( VipsObject *object )
{
VipsConversion *conversion = VIPS_CONVERSION( object );
VipsIfthenelse *ifthenelse = (VipsIfthenelse *) object;
VipsImage *all[3];
VipsImage **band = (VipsImage **) vips_object_local_array( object, 3 );
VipsImage **size = (VipsImage **) vips_object_local_array( object, 3 );
VipsImage **format =
(VipsImage **) vips_object_local_array( object, 3 );
if( VIPS_OBJECT_CLASS( vips_ifthenelse_parent_class )->build( object ) )
return( -1 );
/* We have to have the condition image last since we want the output
* image to inherit its properties from the then/else parts.
*/
all[0] = ifthenelse->in1;
all[1] = ifthenelse->in2;
all[2] = ifthenelse->cond;
/* No need to check input images, sizealike and friends will do this
* for us.
*/
/* Cast our input images up to a common bands and size.
*/
if( vips__bandalike_vec( "VipsIfthenelse", all, band, 3, 0 ) ||
vips__sizealike_vec( band, size, 3 ) )
return( -1 );
/* Condition is cast to uchar, then/else to a common type.
*/
if( vips_cast( size[2], &format[2], VIPS_FORMAT_UCHAR, NULL ) )
return( -1 );
if( vips__formatalike_vec( size, format, 2 ) )
return( -1 );
if( vips_image_copy_fields_array( conversion->out, format ) )
return( -1 );
vips_demand_hint_array( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, format );
if( vips_image_generate( conversion->out,
vips_start_many, vips_ifthenelse_gen, vips_stop_many,
format, ifthenelse ) )
return( -1 );
return( 0 );
}
static void
vips_ifthenelse_class_init( VipsIfthenelseClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VIPS_DEBUG_MSG( "vips_ifthenelse_class_init\n" );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
vobject_class->nickname = "ifthenelse";
vobject_class->description = _( "ifthenelse an image" );
vobject_class->build = vips_ifthenelse_build;
VIPS_ARG_IMAGE( class, "cond", -2,
_( "Condition" ),
_( "Condition input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsIfthenelse, cond ) );
VIPS_ARG_IMAGE( class, "in1", -1,
_( "Then image" ),
_( "Source for TRUE pixels" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsIfthenelse, in1 ) );
VIPS_ARG_IMAGE( class, "in2", 0,
_( "Else image" ),
_( "Source for FALSE pixels" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsIfthenelse, in2 ) );
VIPS_ARG_BOOL( class, "blend", 4,
_( "blend" ),
_( "Blend smoothly between then and else parts" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsIfthenelse, blend ),
FALSE );
}
static void
vips_ifthenelse_init( VipsIfthenelse *ifthenelse )
{
}
int
vips_ifthenelse( VipsImage *cond, VipsImage *in1, VipsImage *in2,
VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "ifthenelse", ap, cond, in1, in2, out );
va_end( ap );
return( result );
}

View File

@ -1486,12 +1486,20 @@ static im_function vips2mask_desc = {
/* One image plus one constant in, one image out.
*/
static im_arg_desc const_in_one_out[] = {
static im_arg_desc int_in_one_out[] = {
IM_INPUT_IMAGE( "in1" ),
IM_OUTPUT_IMAGE( "out" ),
IM_INPUT_INT( "c" )
};
/* One image plus one constant in, one image out.
*/
static im_arg_desc double_in_one_out[] = {
IM_INPUT_IMAGE( "in1" ),
IM_OUTPUT_IMAGE( "out" ),
IM_INPUT_DOUBLE( "c" )
};
/* One image plus doublevec in, one image out.
*/
static im_arg_desc vec_in_one_out[] = {
@ -1536,8 +1544,8 @@ static im_function andimageconst_desc = {
"bitwise and of an image with a constant",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
andimageconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
IM_NUMBER( int_in_one_out ), /* Size of arg list */
int_in_one_out /* Arg list */
};
/* Call im_andimage_vec via arg vector.
@ -1597,8 +1605,8 @@ static im_function orimageconst_desc = {
"bitwise or of an image with a constant",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
orimageconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
IM_NUMBER( int_in_one_out ), /* Size of arg list */
int_in_one_out /* Arg list */
};
/* Call im_orimage_vec via arg vector.
@ -1658,8 +1666,8 @@ static im_function eorimageconst_desc = {
"bitwise eor of an image with a constant",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
eorimageconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
IM_NUMBER( int_in_one_out ), /* Size of arg list */
int_in_one_out /* Arg list */
};
/* Call im_eorimage_vec via arg vector.
@ -1700,8 +1708,8 @@ static im_function shiftleft_desc = {
"shift image n bits to left",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
shiftleft_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
IM_NUMBER( int_in_one_out ), /* Size of arg list */
int_in_one_out /* Arg list */
};
/* Call im_shiftleft_vec via arg vector.
@ -1742,8 +1750,8 @@ static im_function shiftright_desc = {
"shift integer image n bits to right",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
shiftright_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
IM_NUMBER( int_in_one_out ), /* Size of arg list */
int_in_one_out /* Arg list */
};
/* Call im_shiftright_vec via arg vector.
@ -1767,6 +1775,420 @@ static im_function shiftright_vec_desc = {
vec_in_one_out /* Arg list */
};
/* Call im_equal via arg vector.
*/
static int
equal_vec( im_object *argv )
{
return( im_equal( argv[0], argv[1], argv[2] ) );
}
/* Description of im_equal.
*/
static im_function equal_desc = {
"im_equal", /* Name */
"two images equal in value", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
equal_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_equalconst via arg vector.
*/
static int
equalconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_equalconst( argv[0], argv[1], c ) );
}
/* Description of im_equalconst.
*/
static im_function equalconst_desc = {
"im_equalconst", /* Name */
"image equals const", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
equalconst_vec, /* Dispatch function */
IM_NUMBER( double_in_one_out ), /* Size of arg list */
double_in_one_out /* Arg list */
};
/* Call im_equal_vec via arg vector.
*/
static int
equal_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_equal_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_equal_vec.
*/
static im_function equal_vec_desc = {
"im_equal_vec", /* Name */
"image equals doublevec", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
equal_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_notequal via arg vector.
*/
static int
notequal_vec( im_object *argv )
{
return( im_notequal( argv[0], argv[1], argv[2] ) );
}
/* Description of im_notequal.
*/
static im_function notequal_desc = {
"im_notequal", /* Name */
"two images not equal in value",/* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
notequal_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_notequalconst via arg vector.
*/
static int
notequalconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_notequalconst( argv[0], argv[1], c ) );
}
/* Description of im_notequalconst.
*/
static im_function notequalconst_desc = {
"im_notequalconst", /* Name */
"image does not equal const", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
notequalconst_vec, /* Dispatch function */
IM_NUMBER( double_in_one_out ), /* Size of arg list */
double_in_one_out /* Arg list */
};
/* Call im_notequal_vec via arg vector.
*/
static int
notequal_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_notequal_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_notequal_vec.
*/
static im_function notequal_vec_desc = {
"im_notequal_vec", /* Name */
"image does not equal doublevec", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
notequal_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_less via arg vector.
*/
static int
less_vec( im_object *argv )
{
return( im_less( argv[0], argv[1], argv[2] ) );
}
/* Description of im_less.
*/
static im_function less_desc = {
"im_less", /* Name */
"in1 less than in2 in value", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
less_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_lessconst via arg vector.
*/
static int
lessconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_lessconst( argv[0], argv[1], c ) );
}
/* Description of im_lessconst.
*/
static im_function lessconst_desc = {
"im_lessconst", /* Name */
"in less than const", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
lessconst_vec, /* Dispatch function */
IM_NUMBER( double_in_one_out ), /* Size of arg list */
double_in_one_out /* Arg list */
};
/* Call im_less_vec via arg vector.
*/
static int
less_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_less_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_less_vec.
*/
static im_function less_vec_desc = {
"im_less_vec", /* Name */
"in less than doublevec", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
less_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_more via arg vector.
*/
static int
more_vec( im_object *argv )
{
return( im_more( argv[0], argv[1], argv[2] ) );
}
/* Description of im_more.
*/
static im_function more_desc = {
"im_more", /* Name */
"in1 more than in2 in value", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
more_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_moreconst via arg vector.
*/
static int
moreconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_moreconst( argv[0], argv[1], c ) );
}
/* Description of im_moreconst.
*/
static im_function moreconst_desc = {
"im_moreconst", /* Name */
"in more than const", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
moreconst_vec, /* Dispatch function */
IM_NUMBER( double_in_one_out ), /* Size of arg list */
double_in_one_out /* Arg list */
};
/* Call im_more_vec via arg vector.
*/
static int
more_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_more_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_more_vec.
*/
static im_function more_vec_desc = {
"im_more_vec", /* Name */
"in more than doublevec", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
more_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_moreeq via arg vector.
*/
static int
moreeq_vec( im_object *argv )
{
return( im_moreeq( argv[0], argv[1], argv[2] ) );
}
/* Description of im_moreeq.
*/
static im_function moreeq_desc = {
"im_moreeq", /* Name */
"in1 more than or equal to in2 in value",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
moreeq_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_moreeqconst via arg vector.
*/
static int
moreeqconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_moreeqconst( argv[0], argv[1], c ) );
}
/* Description of im_moreeqconst.
*/
static im_function moreeqconst_desc = {
"im_moreeqconst", /* Name */
"in more than or equal to const",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
moreeqconst_vec, /* Dispatch function */
IM_NUMBER( double_in_one_out ), /* Size of arg list */
double_in_one_out /* Arg list */
};
/* Call im_moreeq_vec via arg vector.
*/
static int
moreeq_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_moreeq_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_moreeq_vec.
*/
static im_function moreeq_vec_desc = {
"im_moreeq_vec", /* Name */
"in more than or equal to doublevec",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
moreeq_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_lesseq via arg vector.
*/
static int
lesseq_vec( im_object *argv )
{
return( im_lesseq( argv[0], argv[1], argv[2] ) );
}
/* Description of im_lesseq.
*/
static im_function lesseq_desc = {
"im_lesseq", /* Name */
"in1 less than or equal to in2 in value",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
lesseq_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_lesseqconst via arg vector.
*/
static int
lesseqconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_lesseqconst( argv[0], argv[1], c ) );
}
/* Description of im_lesseqconst.
*/
static im_function lesseqconst_desc = {
"im_lesseqconst", /* Name */
"in less than or equal to const",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
lesseqconst_vec, /* Dispatch function */
IM_NUMBER( double_in_one_out ), /* Size of arg list */
double_in_one_out /* Arg list */
};
/* Call im_lesseq_vec via arg vector.
*/
static int
lesseq_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_lesseq_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_lesseq_vec.
*/
static im_function lesseq_vec_desc = {
"im_lesseq_vec", /* Name */
"in less than or equal to doublevec",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
lesseq_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* If-then-else args.
*/
static im_arg_desc ifthenelse_args[] = {
IM_INPUT_IMAGE( "cond" ),
IM_INPUT_IMAGE( "in1" ),
IM_INPUT_IMAGE( "in2" ),
IM_OUTPUT_IMAGE( "out" )
};
/* Call im_blend via arg vector.
*/
static int
blend_vec( im_object *argv )
{
return( im_blend( argv[0], argv[1], argv[2], argv[3] ) );
}
/* Description of im_blend.
*/
static im_function blend_desc = {
"im_blend", /* Name */
"use cond image to blend between images in1 and in2",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
blend_vec, /* Dispatch function */
IM_NUMBER( ifthenelse_args ), /* Size of arg list */
ifthenelse_args /* Arg list */
};
/* Call im_ifthenelse via arg vector.
*/
static int
ifthenelse_vec( im_object *argv )
{
return( im_ifthenelse( argv[0], argv[1], argv[2], argv[3] ) );
}
/* Description of im_ifthenelse.
*/
static im_function ifthenelse_desc = {
"im_ifthenelse", /* Name */
"use cond image to choose pels from image in1 or in2",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
ifthenelse_vec, /* Dispatch function */
IM_NUMBER( ifthenelse_args ), /* Size of arg list */
ifthenelse_args /* Arg list */
};
/* Package up all these functions.
*/
static im_function *deprecated_list[] = {
@ -1833,7 +2255,27 @@ static im_function *deprecated_list[] = {
&shiftleft_vec_desc,
&shiftleft_desc,
&shiftright_vec_desc,
&shiftright_desc
&shiftright_desc,
&blend_desc,
&equal_desc,
&equal_vec_desc,
&equalconst_desc,
&ifthenelse_desc,
&less_desc,
&less_vec_desc,
&lessconst_desc,
&lesseq_desc,
&lesseq_vec_desc,
&lesseqconst_desc,
&more_desc,
&more_vec_desc,
&moreconst_desc,
&moreeq_desc,
&moreeq_vec_desc,
&moreeqconst_desc,
&notequal_desc,
&notequal_vec_desc,
&notequalconst_desc
};
/* Package of functions.

View File

@ -72,7 +72,6 @@ extern im_package im__mask;
extern im_package im__morphology;
extern im_package im__mosaicing;
extern im_package im__other;
extern im_package im__relational;
extern im_package im__resample;
extern im_package im__video;
@ -584,7 +583,6 @@ static im_package *built_in[] = {
&im__morphology,
&im__mosaicing,
&im__other,
&im__relational,
&im__resample,
&im__video
};

View File

@ -2042,3 +2042,37 @@ im_expntra( IMAGE *in, IMAGE *out, double c )
return( im_expntra_vec( in, out, 1, &c ) );
}
int
im_ifthenelse( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out )
{
VipsImage *t;
if( vips_ifthenelse( c, a, b, &t,
NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}
int
im_blend( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out )
{
VipsImage *t;
if( vips_ifthenelse( c, a, b, &t,
"blend", TRUE,
NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}

View File

@ -165,6 +165,9 @@ int vips_black( VipsImage **out, int width, int height, ... )
__attribute__((sentinel));
int vips_rot( VipsImage *in, VipsImage **out, VipsAngle angle, ... )
__attribute__((sentinel));
int vips_ifthenelse( VipsImage *cond, VipsImage *in1, VipsImage *in2,
VipsImage **out, ... )
__attribute__((sentinel));
int im_copy_file( VipsImage *in, VipsImage *out );

View File

@ -37,8 +37,6 @@
extern "C" {
#endif /*__cplusplus*/
int im_ifthenelse( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
int im_blend( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
#ifdef __cplusplus
}

View File

@ -635,6 +635,9 @@ int im_rot90( VipsImage *in, VipsImage *out );
int im_rot180( VipsImage *in, VipsImage *out );
int im_rot270( VipsImage *in, VipsImage *out );
int im_ifthenelse( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
int im_blend( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
DOUBLEMASK *im_vips2mask( VipsImage *in, const char *filename );
int im_mask2vips( DOUBLEMASK *in, VipsImage *out );

View File

@ -648,7 +648,8 @@ vips_region_image( VipsRegion *reg, VipsRect *r )
* Returns: 0 on success, or -1 for error.
*/
int
vips_region_region( VipsRegion *reg, VipsRegion *dest, VipsRect *r, int x, int y )
vips_region_region( VipsRegion *reg,
VipsRegion *dest, VipsRect *r, int x, int y )
{
VipsRect image;
VipsRect wanted;

View File

@ -1,8 +0,0 @@
noinst_LTLIBRARIES = librelational.la
librelational_la_SOURCES = \
im_ifthenelse.c \
im_blend.c \
relational_dispatch.c
INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@

View File

@ -1,404 +0,0 @@
/* im_blend.c --- blend images with a condition image
*
* Modified:
* 15/4/05
* - from im_ifthenelse()
* 8/7/05
* - oops, broken for some combinations of band differences (thanks Joe)
* 23/9/09
* - gtkdoc comments
* - use im_check*()
* - allow many-band conditional and single-band a/b
* - allow a/b to differ in format and bands
* 27/6/11
* - sizealike as well
*/
/*
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 <vips/vips.h>
#include <vips/internal.h>
#define iblend1( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( i = 0, x = 0; x < n; i++, x += bands ) { \
const int v = c[i]; \
\
for( z = x; z < x + bands; z++ ) \
q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \
} \
}
#define iblendn( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( x = 0; x < n; x += bands ) { \
for( z = x; z < x + bands; z++ ) { \
const int v = c[z]; \
\
q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \
} \
} \
}
#define fblend1( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( i = 0, x = 0; x < n; i++, x += bands ) { \
const double v = c[i] / 255.0; \
\
for( z = x; z < x + bands; z++ ) \
q[z] = v * a[z] + (1.0 - v) * b[z]; \
} \
}
#define fblendn( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( x = 0; x < n; x += bands ) { \
for( z = x; z < x + bands; z++ ) { \
const double v = c[z] / 255.0; \
\
q[z] = v * a[z] + (1.0 - v) * b[z]; \
} \
} \
}
#define cblend1( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( i = 0, x = 0; x < n; i++, x += bands ) { \
const double v = c[i] / 255.0; \
\
for( z = x; z < x + 2 * bands; z++ ) \
q[z] = v * a[z] + (1.0 - v) * b[z]; \
} \
}
#define cblendn( TYPE ) { \
TYPE *a = (TYPE *) ap; \
TYPE *b = (TYPE *) bp; \
TYPE *q = (TYPE *) qp; \
\
for( x = 0; x < n; x += bands ) { \
for( z = x; z < x + bands; z++ ) { \
const double v = c[z] / 255.0; \
\
q[2 * z] = v * a[2 * z] + (1.0 - v) * b[2 * z]; \
q[2 * z + 1] = v * a[2 * z + 1] + \
(1.0 - v) * b[2 * z + 1]; \
} \
} \
}
/* Blend with a 1-band conditional image.
*/
static void
blend1_buffer( PEL *qp, PEL *c, PEL *ap, PEL *bp, int width, IMAGE *im )
{
int i, x, z;
const int bands = im->Bands;
const int n = width * bands;
switch( im->BandFmt ) {
case IM_BANDFMT_UCHAR:
iblend1( unsigned char ); break;
case IM_BANDFMT_CHAR:
iblend1( signed char ); break;
case IM_BANDFMT_USHORT:
iblend1( unsigned short ); break;
case IM_BANDFMT_SHORT:
iblend1( signed short ); break;
case IM_BANDFMT_UINT:
iblend1( unsigned int ); break;
case IM_BANDFMT_INT:
iblend1( signed int ); break;
case IM_BANDFMT_FLOAT:
fblend1( float ); break;
case IM_BANDFMT_DOUBLE:
fblend1( double ); break;
case IM_BANDFMT_COMPLEX:
cblend1( float ); break;
case IM_BANDFMT_DPCOMPLEX:
cblend1( double ); break;
default:
g_assert( 0 );
}
}
/* Blend with a many band conditional image.
*/
static void
blendn_buffer( PEL *qp, PEL *c, PEL *ap, PEL *bp, int width, IMAGE *im )
{
int x, z;
const int bands = im->Bands;
const int n = width * bands;
switch( im->BandFmt ) {
case IM_BANDFMT_UCHAR:
iblendn( unsigned char ); break;
case IM_BANDFMT_CHAR:
iblendn( signed char ); break;
case IM_BANDFMT_USHORT:
iblendn( unsigned short ); break;
case IM_BANDFMT_SHORT:
iblendn( signed short ); break;
case IM_BANDFMT_UINT:
iblendn( unsigned int ); break;
case IM_BANDFMT_INT:
iblendn( signed int ); break;
case IM_BANDFMT_FLOAT:
fblendn( float ); break;
case IM_BANDFMT_DOUBLE:
fblendn( double ); break;
case IM_BANDFMT_COMPLEX:
cblendn( float ); break;
case IM_BANDFMT_DPCOMPLEX:
cblendn( double ); break;
default:
g_assert( 0 );
}
}
static int
blend_gen( REGION *or, void *seq, void *client1, void *client2 )
{
REGION **ir = (REGION **) seq;
Rect *r = &or->valid;
int le = r->left;
int to = r->top;
int bo = IM_RECT_BOTTOM(r);
IMAGE *c = ir[0]->im;
IMAGE *a = ir[1]->im;
int c_elements = r->width * c->Bands;
int x, y;
int all0, all255;
/* Ask for condition pixels.
*/
if( im_prepare( ir[0], r ) )
return( -1 );
/* Is the conditional all zero or all non-zero? We can avoid asking
* for one of the inputs to be calculated.
*/
all0 = *((PEL *) IM_REGION_ADDR( ir[0], le, to )) == 0;
all255 = *((PEL *) IM_REGION_ADDR( ir[0], le, to )) == 255;
for( y = to; y < bo; y++ ) {
PEL *p = (PEL *) IM_REGION_ADDR( ir[0], le, y );
for( x = 0; x < c_elements; x++ ) {
all0 &= p[x] == 0;
all255 &= p[x] == 255;
}
if( !all0 && !all255 )
break;
}
if( all255 ) {
/* All 255. Point or at the then image.
*/
if( im_prepare( ir[1], r ) ||
im_region_region( or, ir[1], r, r->left, r->top ) )
return( -1 );
}
else if( all0 ) {
/* All zero. Point or at the else image.
*/
if( im_prepare( ir[2], r ) ||
im_region_region( or, ir[2], r, r->left, r->top ) )
return( -1 );
}
else {
/* Mix of set and clear ... ask for both then and else parts and
* interleave.
*/
if( im_prepare( ir[1], r ) || im_prepare( ir[2], r ) )
return( -1 );
for( y = to; y < bo; y++ ) {
PEL *cp = (PEL *) IM_REGION_ADDR( ir[0], le, y );
PEL *ap = (PEL *) IM_REGION_ADDR( ir[1], le, y );
PEL *bp = (PEL *) IM_REGION_ADDR( ir[2], le, y );
PEL *q = (PEL *) IM_REGION_ADDR( or, le, y );
if( c->Bands == 1 )
blend1_buffer( q, cp, ap, bp, r->width, a );
else
blendn_buffer( q, cp, ap, bp, r->width, a );
}
}
return( 0 );
}
static int
blend( IMAGE *c, IMAGE *a, IMAGE *b, IMAGE *out )
{
IMAGE **in;
/* Check args.
*/
if( im_check_uncoded( "im_blend", c ) ||
im_check_uncoded( "im_blend", a ) ||
im_check_uncoded( "im_blend", b ) ||
im_check_format( "im_blend", c, IM_BANDFMT_UCHAR ) ||
im_check_format_same( "im_blend", a, b ) ||
im_check_bands_same( "im_blend", a, b ) ||
im_check_bands_1orn( "im_blend", c, a ) ||
im_check_size_same( "im_blend", a, b ) ||
im_check_size_same( "im_blend", a, c ) ||
im_piocheck( c, out ) ||
im_pincheck( a ) ||
im_pincheck( b ) )
return( -1 );
/* Make output image.
*/
if( im_cp_descv( out, a, b, c, NULL ) )
return( -1 );
out->Bands = IM_MAX( c->Bands, a->Bands );
if( im_demand_hint( out, IM_THINSTRIP, a, b, c, NULL ) )
return( -1 );
if( !(in = im_allocate_input_array( out, c, a, b, NULL )) ||
im_generate( out,
im_start_many, blend_gen, im_stop_many, in, NULL ) )
return( -1 );
return( 0 );
}
/**
* im_blend:
* @c: condition #IMAGE
* @a: then #IMAGE
* @b: else #IMAGE
* @out: output #IMAGE
*
* This operation scans the condition image @c
* and uses it to blend pixels from either the then image @a or the else
* image @b. 255 means @a only, 0 means @b only, and intermediate values are a
* mixture.
*
* Any image may have either 1 band or n bands, where n is the same for all
* the non-1-band images. Single band images are then effectively copied to
* make n-band images.
*
* Images @a and @b are cast up to the smallest common format.
*
* If the images differ in size, the smaller images are enlarged to match the
* largest by adding zero pixels along the bottom and right.
*
* See also: im_ifthenelse(), im_equal().
*
* Returns: 0 on success, -1 on error
*/
int
im_blend( IMAGE *c, IMAGE *a, IMAGE *b, IMAGE *out )
{
/* If a and b are both LABPACK, repack agan after the blend.
*/
const int repack = a->Coding == IM_CODING_LABQ &&
b->Coding == IM_CODING_LABQ;
IMAGE *t[12];
if( im_open_local_array( out, t, 12, "im_blend", "p" ) )
return( -1 );
/* Unpack LABPACK as a courtesy.
*/
if( a->Coding == IM_CODING_LABQ ) {
if( im_LabQ2Lab( a, t[0] ) )
return( -1 );
a = t[0];
}
if( b->Coding == IM_CODING_LABQ ) {
if( im_LabQ2Lab( b, t[1] ) )
return( -1 );
b = t[1];
}
/* c must be uchar.
*/
if( c->BandFmt != IM_BANDFMT_UCHAR ) {
if( im_clip2fmt( c, t[2], IM_BANDFMT_UCHAR ) )
return( -1 );
c = t[2];
}
/* Make a and b match in bands and format.
*/
if( im__formatalike( a, b, t[3], t[4] ) ||
im__bandalike( "im_blend", t[3], t[4], t[6], t[7] ) )
return( -1 );
/* Make a, b and c match in size.
*/
t[5] = c;
if( im__sizealike_vec( t + 5, t + 8, 3 ) )
return( -1 );
if( blend( t[8], t[9], t[10], t[11] ) )
return( -1 );
if( repack ) {
if( im_Lab2LabQ( t[11], out ) )
return( -1 );
}
else {
if( im_copy( t[11], out ) )
return( -1 );
}
return( 0 );
}

View File

@ -1,540 +0,0 @@
/* VIPS function dispatch tables for relational.
*
* J. Cupitt, 23/2/95
*/
/*
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 <vips/vips.h>
/**
* SECTION: relational
* @short_description: relational comparisons between pairs of images and
* images and constants
* @see_also: <link linkend="libvips-arithmetic">arithmetic</link>
* @stability: Stable
* @include: vips/vips.h
*
* These operations perform comparison operations, such as equals, on
* every pixel in an image or pair of images.
* All will work with
* images of any type or any mixture of types of any size and of any number
* of bands.
*
* For binary operations, if the number of bands differs, one of the images
* must have one band. In this case, an n-band image is formed from the
* one-band image by joining n copies of the one-band image together and then
* the two n-band images are operated upon.
*
* In the same way, for operations that take an array constant, such as
* im_equal_vec(), you can mix single-element arrays or single-band images
* freely.
*
* The output type is always unsigned char,
* with 255 for every band element for which the condition
* is true, and 0 for every other element.
* For complex images, the operations calculate and compare the modulus.
*
* For binary operations on pairs of images, the images must match in size.
*/
/* Two images in, one out.
*/
static im_arg_desc two_in_one_out[] = {
IM_INPUT_IMAGE( "in1" ),
IM_INPUT_IMAGE( "in2" ),
IM_OUTPUT_IMAGE( "out" )
};
/* One image plus one constant in, one image out.
*/
static im_arg_desc const_in_one_out[] = {
IM_INPUT_IMAGE( "in" ),
IM_OUTPUT_IMAGE( "out" ),
IM_INPUT_DOUBLE( "c" )
};
/* One image plus doublevec in, one image out.
*/
static im_arg_desc vec_in_one_out[] = {
IM_INPUT_IMAGE( "in" ),
IM_OUTPUT_IMAGE( "out" ),
IM_INPUT_DOUBLEVEC( "vec" )
};
/* Call im_equal via arg vector.
*/
static int
equal_vec( im_object *argv )
{
return( im_equal( argv[0], argv[1], argv[2] ) );
}
/* Description of im_equal.
*/
static im_function equal_desc = {
"im_equal", /* Name */
"two images equal in value", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
equal_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_equalconst via arg vector.
*/
static int
equalconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_equalconst( argv[0], argv[1], c ) );
}
/* Description of im_equalconst.
*/
static im_function equalconst_desc = {
"im_equalconst", /* Name */
"image equals const", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
equalconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
};
/* Call im_equal_vec via arg vector.
*/
static int
equal_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_equal_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_equal_vec.
*/
static im_function equal_vec_desc = {
"im_equal_vec", /* Name */
"image equals doublevec", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
equal_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_notequal via arg vector.
*/
static int
notequal_vec( im_object *argv )
{
return( im_notequal( argv[0], argv[1], argv[2] ) );
}
/* Description of im_notequal.
*/
static im_function notequal_desc = {
"im_notequal", /* Name */
"two images not equal in value",/* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
notequal_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_notequalconst via arg vector.
*/
static int
notequalconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_notequalconst( argv[0], argv[1], c ) );
}
/* Description of im_notequalconst.
*/
static im_function notequalconst_desc = {
"im_notequalconst", /* Name */
"image does not equal const", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
notequalconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
};
/* Call im_notequal_vec via arg vector.
*/
static int
notequal_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_notequal_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_notequal_vec.
*/
static im_function notequal_vec_desc = {
"im_notequal_vec", /* Name */
"image does not equal doublevec", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
notequal_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_less via arg vector.
*/
static int
less_vec( im_object *argv )
{
return( im_less( argv[0], argv[1], argv[2] ) );
}
/* Description of im_less.
*/
static im_function less_desc = {
"im_less", /* Name */
"in1 less than in2 in value", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
less_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_lessconst via arg vector.
*/
static int
lessconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_lessconst( argv[0], argv[1], c ) );
}
/* Description of im_lessconst.
*/
static im_function lessconst_desc = {
"im_lessconst", /* Name */
"in less than const", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
lessconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
};
/* Call im_less_vec via arg vector.
*/
static int
less_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_less_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_less_vec.
*/
static im_function less_vec_desc = {
"im_less_vec", /* Name */
"in less than doublevec", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
less_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_more via arg vector.
*/
static int
more_vec( im_object *argv )
{
return( im_more( argv[0], argv[1], argv[2] ) );
}
/* Description of im_more.
*/
static im_function more_desc = {
"im_more", /* Name */
"in1 more than in2 in value", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
more_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_moreconst via arg vector.
*/
static int
moreconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_moreconst( argv[0], argv[1], c ) );
}
/* Description of im_moreconst.
*/
static im_function moreconst_desc = {
"im_moreconst", /* Name */
"in more than const", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
moreconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
};
/* Call im_more_vec via arg vector.
*/
static int
more_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_more_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_more_vec.
*/
static im_function more_vec_desc = {
"im_more_vec", /* Name */
"in more than doublevec", /* Description */
IM_FN_PTOP | IM_FN_PIO, /* Flags */
more_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_moreeq via arg vector.
*/
static int
moreeq_vec( im_object *argv )
{
return( im_moreeq( argv[0], argv[1], argv[2] ) );
}
/* Description of im_moreeq.
*/
static im_function moreeq_desc = {
"im_moreeq", /* Name */
"in1 more than or equal to in2 in value",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
moreeq_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_moreeqconst via arg vector.
*/
static int
moreeqconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_moreeqconst( argv[0], argv[1], c ) );
}
/* Description of im_moreeqconst.
*/
static im_function moreeqconst_desc = {
"im_moreeqconst", /* Name */
"in more than or equal to const",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
moreeqconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
};
/* Call im_moreeq_vec via arg vector.
*/
static int
moreeq_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_moreeq_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_moreeq_vec.
*/
static im_function moreeq_vec_desc = {
"im_moreeq_vec", /* Name */
"in more than or equal to doublevec",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
moreeq_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* Call im_lesseq via arg vector.
*/
static int
lesseq_vec( im_object *argv )
{
return( im_lesseq( argv[0], argv[1], argv[2] ) );
}
/* Description of im_lesseq.
*/
static im_function lesseq_desc = {
"im_lesseq", /* Name */
"in1 less than or equal to in2 in value",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
lesseq_vec, /* Dispatch function */
IM_NUMBER( two_in_one_out ), /* Size of arg list */
two_in_one_out /* Arg list */
};
/* Call im_lesseqconst via arg vector.
*/
static int
lesseqconst_vec( im_object *argv )
{
double c = *((double *) argv[2]);
return( im_lesseqconst( argv[0], argv[1], c ) );
}
/* Description of im_lesseqconst.
*/
static im_function lesseqconst_desc = {
"im_lesseqconst", /* Name */
"in less than or equal to const",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
lesseqconst_vec, /* Dispatch function */
IM_NUMBER( const_in_one_out ), /* Size of arg list */
const_in_one_out /* Arg list */
};
/* Call im_lesseq_vec via arg vector.
*/
static int
lesseq_vec_vec( im_object *argv )
{
im_doublevec_object *rv = (im_doublevec_object *) argv[2];
return( im_lesseq_vec( argv[0], argv[1], rv->n, rv->vec ) );
}
/* Description of im_lesseq_vec.
*/
static im_function lesseq_vec_desc = {
"im_lesseq_vec", /* Name */
"in less than or equal to doublevec",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
lesseq_vec_vec, /* Dispatch function */
IM_NUMBER( vec_in_one_out ), /* Size of arg list */
vec_in_one_out /* Arg list */
};
/* If-then-else args.
*/
static im_arg_desc ifthenelse_args[] = {
IM_INPUT_IMAGE( "cond" ),
IM_INPUT_IMAGE( "in1" ),
IM_INPUT_IMAGE( "in2" ),
IM_OUTPUT_IMAGE( "out" )
};
/* Call im_blend via arg vector.
*/
static int
blend_vec( im_object *argv )
{
return( im_blend( argv[0], argv[1], argv[2], argv[3] ) );
}
/* Description of im_blend.
*/
static im_function blend_desc = {
"im_blend", /* Name */
"use cond image to blend between images in1 and in2",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
blend_vec, /* Dispatch function */
IM_NUMBER( ifthenelse_args ), /* Size of arg list */
ifthenelse_args /* Arg list */
};
/* Call im_ifthenelse via arg vector.
*/
static int
ifthenelse_vec( im_object *argv )
{
return( im_ifthenelse( argv[0], argv[1], argv[2], argv[3] ) );
}
/* Description of im_ifthenelse.
*/
static im_function ifthenelse_desc = {
"im_ifthenelse", /* Name */
"use cond image to choose pels from image in1 or in2",
IM_FN_PTOP | IM_FN_PIO, /* Flags */
ifthenelse_vec, /* Dispatch function */
IM_NUMBER( ifthenelse_args ), /* Size of arg list */
ifthenelse_args /* Arg list */
};
/* Package up all these functions.
*/
static im_function *relational_list[] = {
&blend_desc,
&equal_desc,
&equal_vec_desc,
&equalconst_desc,
&ifthenelse_desc,
&less_desc,
&less_vec_desc,
&lessconst_desc,
&lesseq_desc,
&lesseq_vec_desc,
&lesseqconst_desc,
&more_desc,
&more_vec_desc,
&moreconst_desc,
&moreeq_desc,
&moreeq_vec_desc,
&moreeqconst_desc,
&notequal_desc,
&notequal_vec_desc,
&notequalconst_desc
};
/* Package of functions.
*/
im_package im__relational = {
"relational",
IM_NUMBER( relational_list ),
relational_list
};