vips_conv() should work
This commit is contained in:
parent
45a9e417f4
commit
feb72b2a5a
@ -66,12 +66,59 @@ typedef struct {
|
||||
VipsConvolution parent_instance;
|
||||
|
||||
VipsPrecision precision;
|
||||
int layers;
|
||||
int cluster;
|
||||
} VipsConv;
|
||||
|
||||
typedef VipsConvolutionClass VipsConvClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsConv, vips_conv, VIPS_TYPE_CONVOLUTION );
|
||||
|
||||
static int
|
||||
vips_conv_build( VipsObject *object )
|
||||
{
|
||||
VipsConvolution *convolution = (VipsConvolution *) object;
|
||||
VipsConv *conv = (VipsConv *) object;
|
||||
|
||||
INTMASK *imsk;
|
||||
DOUBLEMASK *dmsk;
|
||||
|
||||
g_object_set( conv, "out", vips_image_new(), NULL );
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_conv_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
|
||||
switch( conv->precision ) {
|
||||
case VIPS_PRECISION_INTEGER:
|
||||
if( !(imsk = im_vips2imask( convolution->M, "im_stats" )) ||
|
||||
!im_local_imask( convolution->out, imsk ) ||
|
||||
im_conv( convolution->in, convolution->out, imsk ) )
|
||||
return( -1 );
|
||||
break;
|
||||
|
||||
case VIPS_PRECISION_FLOAT:
|
||||
if( !(dmsk = im_vips2mask( convolution->M, "im_stats" )) ||
|
||||
!im_local_dmask( convolution->out, dmsk ) ||
|
||||
im_conv_f( convolution->in, convolution->out, dmsk ) )
|
||||
return( -1 );
|
||||
break;
|
||||
|
||||
case VIPS_PRECISION_APPROXIMATE:
|
||||
if( !(dmsk = im_vips2mask( convolution->M, "im_stats" )) ||
|
||||
!im_local_dmask( convolution->out, dmsk ) ||
|
||||
im_aconv( convolution->in, convolution->out, dmsk,
|
||||
conv->layers, conv->cluster ) )
|
||||
return( -1 );
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_conv_class_init( VipsConvClass *class )
|
||||
{
|
||||
@ -83,6 +130,7 @@ vips_conv_class_init( VipsConvClass *class )
|
||||
|
||||
object_class->nickname = "conv";
|
||||
object_class->description = _( "convolution operation" );
|
||||
object_class->build = vips_conv_build;
|
||||
|
||||
VIPS_ARG_ENUM( class, "precision", 103,
|
||||
_( "Precision" ),
|
||||
@ -91,11 +139,28 @@ vips_conv_class_init( VipsConvClass *class )
|
||||
G_STRUCT_OFFSET( VipsConv, precision ),
|
||||
VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER );
|
||||
|
||||
VIPS_ARG_INT( class, "layers", 103,
|
||||
_( "Layers" ),
|
||||
_( "Use this many layers in approximation" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsConv, layers ),
|
||||
1, 1000, 5 );
|
||||
|
||||
VIPS_ARG_INT( class, "cluster", 103,
|
||||
_( "Cluster" ),
|
||||
_( "Cluster lines closer than this in approximation" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsConv, cluster ),
|
||||
1, 100, 1 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_conv_init( VipsConv *conv )
|
||||
{
|
||||
conv->precision = VIPS_PRECISION_INTEGER;
|
||||
conv->layers = 5;
|
||||
conv->cluster = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,9 +170,27 @@ vips_conv_init( VipsConv *conv )
|
||||
* @mask: convolve with this mask
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
* @precision: calculation accuracy
|
||||
* @layers: number of layers for approximation
|
||||
* @cluster: cluster lines closer than this distance
|
||||
*
|
||||
* Convolution.
|
||||
*
|
||||
* See also: vips_hist_norm().
|
||||
* Perform a convolution of @in with @mask.
|
||||
*
|
||||
* The output image
|
||||
* always has the same #VipsBandFmt as the input image.
|
||||
*
|
||||
* Larger values for @n_layers give more accurate
|
||||
* results, but are slower. As @n_layers approaches the mask radius, the
|
||||
* accuracy will become close to exact convolution and the speed will drop to
|
||||
* match. For many large masks, such as Gaussian, @n_layers need be only 10% of
|
||||
* this value and accuracy will still be good.
|
||||
*
|
||||
* Smaller values of @cluster will give more accurate results, but be slower
|
||||
* and use more memory. 10% of the mask radius is a good rule of thumb.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
|
@ -131,6 +131,81 @@ im_vips2mask( IMAGE *in, const char *filename )
|
||||
memcpy( out->coeff, in->data,
|
||||
width * height * sizeof( double ) );
|
||||
|
||||
out->scale = vips_image_get_scale( in );
|
||||
out->offset = vips_image_get_offset( in );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
INTMASK *
|
||||
im_vips2imask( IMAGE *in, const char *filename )
|
||||
{
|
||||
int width, height;
|
||||
INTMASK *out;
|
||||
|
||||
double *data;
|
||||
int x, y;
|
||||
|
||||
/* double* only: cast if necessary.
|
||||
*/
|
||||
if( in->BandFmt != IM_BANDFMT_DOUBLE ) {
|
||||
IMAGE *t;
|
||||
|
||||
if( !(t = im_open( "im_vips2imask", "p" )) )
|
||||
return( NULL );
|
||||
if( im_clip2fmt( in, t, IM_BANDFMT_DOUBLE ) ||
|
||||
!(out = im_vips2imask( t, filename )) ) {
|
||||
im_close( t );
|
||||
return( NULL );
|
||||
}
|
||||
im_close( t );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
/* Check the image.
|
||||
*/
|
||||
if( im_incheck( in ) ||
|
||||
im_check_uncoded( "im_vips2imask", in ) )
|
||||
return( NULL );
|
||||
|
||||
if( in->Bands == 1 ) {
|
||||
width = in->Xsize;
|
||||
height = in->Ysize;
|
||||
}
|
||||
else if( in->Xsize == 1 ) {
|
||||
width = in->Bands;
|
||||
height = in->Ysize;
|
||||
}
|
||||
else if( in->Ysize == 1 ) {
|
||||
width = in->Xsize;
|
||||
height = in->Bands;
|
||||
}
|
||||
else {
|
||||
im_error( "im_vips2imask",
|
||||
"%s", _( "one band, nx1, or 1xn images only" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
data = (double *) in->data;
|
||||
if( !(out = im_create_imask( filename, width, height )) )
|
||||
return( NULL );
|
||||
|
||||
for( y = 0; y < height; y++ )
|
||||
for( x = 0; x < width; x++ )
|
||||
if( in->Bands > 1 && in->Ysize == 1 )
|
||||
/* Need to transpose: the image is RGBRGBRGB,
|
||||
* we need RRRGGGBBB.
|
||||
*/
|
||||
out->coeff[x + y * width] =
|
||||
VIPS_RINT( data[x * height + y] );
|
||||
else
|
||||
out->coeff[x + y * width] =
|
||||
VIPS_RINT( data[x + y * width] );
|
||||
|
||||
out->scale = vips_image_get_scale( in );
|
||||
out->offset = vips_image_get_offset( in );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
|
@ -766,6 +766,7 @@ 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 );
|
||||
INTMASK *im_vips2imask( IMAGE *in, const char *filename );
|
||||
int im_mask2vips( DOUBLEMASK *in, VipsImage *out );
|
||||
|
||||
int im_bandmean( VipsImage *in, VipsImage *out );
|
||||
|
Loading…
Reference in New Issue
Block a user