vips_conv() should work
This commit is contained in:
parent
45a9e417f4
commit
feb72b2a5a
@ -66,12 +66,59 @@ typedef struct {
|
|||||||
VipsConvolution parent_instance;
|
VipsConvolution parent_instance;
|
||||||
|
|
||||||
VipsPrecision precision;
|
VipsPrecision precision;
|
||||||
|
int layers;
|
||||||
|
int cluster;
|
||||||
} VipsConv;
|
} VipsConv;
|
||||||
|
|
||||||
typedef VipsConvolutionClass VipsConvClass;
|
typedef VipsConvolutionClass VipsConvClass;
|
||||||
|
|
||||||
G_DEFINE_TYPE( VipsConv, vips_conv, VIPS_TYPE_CONVOLUTION );
|
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
|
static void
|
||||||
vips_conv_class_init( VipsConvClass *class )
|
vips_conv_class_init( VipsConvClass *class )
|
||||||
{
|
{
|
||||||
@ -83,6 +130,7 @@ vips_conv_class_init( VipsConvClass *class )
|
|||||||
|
|
||||||
object_class->nickname = "conv";
|
object_class->nickname = "conv";
|
||||||
object_class->description = _( "convolution operation" );
|
object_class->description = _( "convolution operation" );
|
||||||
|
object_class->build = vips_conv_build;
|
||||||
|
|
||||||
VIPS_ARG_ENUM( class, "precision", 103,
|
VIPS_ARG_ENUM( class, "precision", 103,
|
||||||
_( "Precision" ),
|
_( "Precision" ),
|
||||||
@ -91,11 +139,28 @@ vips_conv_class_init( VipsConvClass *class )
|
|||||||
G_STRUCT_OFFSET( VipsConv, precision ),
|
G_STRUCT_OFFSET( VipsConv, precision ),
|
||||||
VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER );
|
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
|
static void
|
||||||
vips_conv_init( VipsConv *conv )
|
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
|
* @mask: convolve with this mask
|
||||||
* @...: %NULL-terminated list of optional named arguments
|
* @...: %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.
|
* 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
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
|
@ -131,6 +131,81 @@ im_vips2mask( IMAGE *in, const char *filename )
|
|||||||
memcpy( out->coeff, in->data,
|
memcpy( out->coeff, in->data,
|
||||||
width * height * sizeof( double ) );
|
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 );
|
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 );
|
int im_blend( VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out );
|
||||||
|
|
||||||
DOUBLEMASK *im_vips2mask( VipsImage *in, const char *filename );
|
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_mask2vips( DOUBLEMASK *in, VipsImage *out );
|
||||||
|
|
||||||
int im_bandmean( VipsImage *in, VipsImage *out );
|
int im_bandmean( VipsImage *in, VipsImage *out );
|
||||||
|
Loading…
Reference in New Issue
Block a user