From f873a51b09e89422e785cae996a15dab7295329e Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 6 Jul 2016 14:56:28 +0100 Subject: [PATCH] sort-of working --- libvips/convolution/Makefile.am | 1 + libvips/convolution/convasep.c | 125 +++++++++++++++-------------- libvips/convolution/convi.c | 6 +- libvips/convolution/convolution.c | 4 +- libvips/include/vips/convolution.h | 10 ++- libvips/include/vips/internal.h | 5 +- 6 files changed, 80 insertions(+), 71 deletions(-) diff --git a/libvips/convolution/Makefile.am b/libvips/convolution/Makefile.am index 88bb3e2e..ea97ab10 100644 --- a/libvips/convolution/Makefile.am +++ b/libvips/convolution/Makefile.am @@ -8,6 +8,7 @@ libconvolution_la_SOURCES = \ conv.c \ convf.c \ convi.c \ + convasep.c \ convsep.c \ compass.c \ fastcor.c \ diff --git a/libvips/convolution/convasep.c b/libvips/convolution/convasep.c index b0191203..2a9e92ca 100644 --- a/libvips/convolution/convasep.c +++ b/libvips/convolution/convasep.c @@ -63,6 +63,11 @@ faster? + we could then use orc to write a bit of code to implement this set + of lines + + - need to intize masks? + */ /* Show sample pixels as they are transformed. @@ -88,6 +93,8 @@ #include #include +#include "pconvolution.h" + /* Maximum number of lines we can break the mask into. */ #define MAX_LINES (1000) @@ -106,15 +113,17 @@ gcd( int a, int b ) typedef struct { VipsConvolution parent_instance; - VipsImage *in; - VipsImage *out; - VipsImage *mask; - int layers; int area; int rounding; + /* The "width" of the mask, ie. n for our 1xn or nx1 argument, plus + * an int version of our mask. + */ + int width; + VipsImage *iM; + /* The mask broken into a set of lines. * * Start is the left-most pixel in the line, end is one beyond the @@ -156,7 +165,7 @@ vips_convasep_line_end( VipsConvasep *convasep, int x ) static int vips_convasep_decompose( VipsConvasep *convasep ) { - VipsConvolution *convolution = (VipsConvolution *) object; + VipsConvolution *convolution = (VipsConvolution *) convasep; VipsImage *M = convolution->M; double *coeff = (double *) VIPS_IMAGE_ADDR( M, 0, 0 ); double scale = vips_image_get_scale( M ); @@ -226,23 +235,21 @@ vips_convasep_decompose( VipsConvasep *convasep ) if( (y_positive && coeff[x] >= y_ph) || (!y_positive && coeff[x] <= y_ph) ) { if( !inside ) { - vips_convasep_line_start( convasep, - x, y_positive ? 1 : -1 ); + vips_convasep_line_start( convasep, x, + y_positive ? 1 : -1 ); inside = 1; } } - else { - if( inside ) { - if( vips_convasep_line_end( convasep, x ) ) - return( NULL ); - inside = 0; - } + else if( inside ) { + if( vips_convasep_line_end( convasep, x ) ) + return( -1 ); + inside = 0; } } if( inside && - vips_convasep_line_end( lines, width ) ) - return( NULL ); + vips_convasep_line_end( convasep, width ) ) + return( -1 ); } /* Can we common up any lines? Search for lines with identical @@ -302,7 +309,9 @@ vips_convasep_decompose( VipsConvasep *convasep ) convasep->area = rint( sum * convasep->area / scale ); convasep->rounding = (convasep->area + 1) / 2 + offset * convasep->area; +#ifdef DEBUG /* ASCII-art layer drawing. + */ printf( "lines:\n" ); for( z = 0; z < convasep->n_lines; z++ ) { printf( "%3d - %2d x ", z, convasep->factor[z] ); @@ -318,9 +327,9 @@ vips_convasep_decompose( VipsConvasep *convasep ) } printf( "area = %d\n", convasep->area ); printf( "rounding = %d\n", convasep->rounding ); - */ +#endif /*DEBUG*/ - return( lines ); + return( 0 ); } /* Our sequence value. @@ -491,7 +500,7 @@ G_STMT_START { \ dsum[z] += p[x]; \ sum += convasep->factor[z] * dsum[z]; \ } \ - sum = sum / convasep->area + mask->offset; \ + sum = sum / convasep->area + offset; \ *q = sum; \ q += ostride; \ \ @@ -520,7 +529,8 @@ vips_convasep_generate_horizontal( VipsRegion *or, VipsImage *in = (VipsImage *) a; VipsConvasep *convasep = (VipsConvasep *) b; VipsConvolution *convolution = (VipsConvolution *) convasep; - VipsImage *M = convolution->M; + VipsImage *iM = convasep->iM; + double offset = vips_image_get_offset( M ); VipsRegion *ir = seq->ir; const int n_lines = convasep->n_lines; @@ -540,8 +550,7 @@ vips_convasep_generate_horizontal( VipsRegion *or, * than the section of the output image we are producing. */ s = *r; - s.width += M->Xsize - 1; - s.height += M->Ysize - 1; + s.width += convasep->width - 1; if( vips_region_prepare( ir, &s ) ) return( -1 ); @@ -649,7 +658,7 @@ vips_convasep_generate_horizontal( VipsRegion *or, #define VCONV_FLOAT( TYPE ) { \ for( x = 0; x < sz; x++ ) { \ - double *dsum = seq->sum; \ + double *dsum = seq->dsum; \ \ TYPE *q; \ TYPE *p; \ @@ -665,7 +674,7 @@ vips_convasep_generate_horizontal( VipsRegion *or, dsum[z] += p[y]; \ sum += convasep->factor[z] * dsum[z]; \ } \ - sum = sum / convasep->area + mask->offset; \ + sum = sum / convasep->area + offset; \ *q = sum; \ q += ostride; \ \ @@ -674,13 +683,13 @@ vips_convasep_generate_horizontal( VipsRegion *or, for( z = 0; z < n_lines; z++ ) { \ dsum[z] += p[seq->end[z]]; \ dsum[z] -= p[seq->start[z]]; \ - sum += lines->factor[z] * dsum[z]; \ + sum += convasep->factor[z] * dsum[z]; \ } \ p += istride; \ sum = sum / convasep->area + offset; \ *q = sum; \ q += ostride; \ - } \ + } \ } \ } @@ -695,7 +704,8 @@ vips_convasep_generate_vertical( VipsRegion *or, VipsImage *in = (VipsImage *) a; VipsConvasep *convasep = (VipsConvasep *) b; VipsConvolution *convolution = (VipsConvolution *) convasep; - VipsImage *M = convolution->M; + VipsImage *iM = convasep->iM; + double offset = vips_image_get_offset( M ); VipsRegion *ir = seq->ir; const int n_lines = convasep->n_lines; @@ -715,18 +725,16 @@ vips_convasep_generate_vertical( VipsRegion *or, * than the section of the output image we are producing. */ s = *r; - s.width += mask->xsize - 1; - s.height += mask->ysize - 1; + s.height += convasep->width - 1; if( vips_region_prepare( ir, &s ) ) return( -1 ); /* Stride can be different for the vertical case, keep this here for * ease of direction change. */ - istride = VIPS_REGION_LSKIP( ir ) / - IM_IMAGE_SIZEOF_ELEMENT( convasep->in ); + istride = VIPS_REGION_LSKIP( ir ) / VIPS_IMAGE_SIZEOF_ELEMENT( in ); ostride = VIPS_REGION_LSKIP( or ) / - IM_IMAGE_SIZEOF_ELEMENT( convasep->out ); + VIPS_IMAGE_SIZEOF_ELEMENT( convolution->out ); /* Init offset array. */ @@ -734,8 +742,8 @@ vips_convasep_generate_vertical( VipsRegion *or, seq->last_stride = istride; for( z = 0; z < n_lines; z++ ) { - seq->start[z] = lines->start[z] * istride; - seq->end[z] = lines->end[z] * istride; + seq->start[z] = convasep->start[z] * istride; + seq->end[z] = convasep->end[z] * istride; } } @@ -785,6 +793,9 @@ static int vips_convasep_pass( VipsConvasep *convasep, VipsImage *in, VipsImage **out, VipsDirection direction ) { + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( convasep ); + VipsConvolution *convolution = (VipsConvolution *) convasep; + VipsGenerateFn gen; *out = vips_image_new(); @@ -792,14 +803,12 @@ vips_convasep_pass( VipsConvasep *convasep, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL ) ) return( -1 ); - if( direction == VIPS_DIRECtION_HORIZONTAL ) { - (*out)->Xsize -= M->Xsize - 1; - (*out)->Ysize -= M->Ysize - 1; + if( direction == VIPS_DIRECTION_HORIZONTAL ) { + (*out)->Xsize -= convasep->width - 1; gen = vips_convasep_generate_horizontal; } else { - (*out)->Xsize -= M->Ysize - 1; - (*out)->Ysize -= M->Xsize - 1; + (*out)->Ysize -= convasep->width - 1; gen = vips_convasep_generate_vertical; } @@ -814,15 +823,6 @@ vips_convasep_pass( VipsConvasep *convasep, vips_convasep_start, gen, vips_convasep_stop, in, convasep ) ) return( -1 ); - if( direction == VIPS_DIRECTION_HORIZONTAL ) { - (*out)->Xoffset = -M->Xsize / 2; - (*out)->Yoffset = -M->Ysize / 2; - } - else { - (*out)->Xoffset = -M->Ysize / 2; - (*out)->Yoffset = -M->Xsize / 2; - } - return( 0 ); } @@ -833,11 +833,8 @@ vips_convasep_build( VipsObject *object ) VipsConvasep *convasep = (VipsConvasep *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); + VipsImage *iM; VipsImage *in; - VipsImage *M; - double *coeff; - int ne; - int i; if( VIPS_OBJECT_CLASS( vips_convasep_parent_class )->build( object ) ) return( -1 ); @@ -845,15 +842,21 @@ vips_convasep_build( VipsObject *object ) if( vips_convasep_decompose( convasep ) ) return( -1 ); - M = convolution->M; - coeff = (double *) VIPS_IMAGE_ADDR( M, 0, 0 ); - ne = M->Xsize * M->Ysize; + /* An int version of our mask. + */ + if( vips__image_intize( convolution->M, &t[3] ) ) + return( -1 ); + iM = t[3]; + convasep->width = iM->Xsize * iM->Ysize; + in = convolution->in; - g_object_set( convf, "out", vips_image_new(), NULL ); + g_object_set( convasep, "out", vips_image_new(), NULL ); if( - vips_embed( convolution->in, &t[0], - M->Xsize / 2, M->Ysize / 2, - in->Xsize + M->Xsize - 1, in->Ysize + M->Ysize - 1, + vips_embed( in, &t[0], + convasep->width / 2, + convasep->width / 2, + in->Xsize + convasep->width - 1, + in->Ysize + convasep->width - 1, "extend", VIPS_EXTEND_COPY, NULL ) || vips_convasep_pass( convasep, @@ -863,8 +866,8 @@ vips_convasep_build( VipsObject *object ) vips_image_write( t[2], convolution->out ) ) return( -1 ); - out->Xoffset = 0; - out->Yoffset = 0; + convolution->out->Xoffset = 0; + convolution->out->Yoffset = 0; return( 0 ); } @@ -892,7 +895,7 @@ vips_convasep_class_init( VipsConvasepClass *class ) } static void -vips_convasep_init( VipsConvf *convasep ) +vips_convasep_init( VipsConvasep *convasep ) { convasep->layers = 5; convasep->n_lines = 0; diff --git a/libvips/convolution/convi.c b/libvips/convolution/convi.c index 39ae5952..85817b5e 100644 --- a/libvips/convolution/convi.c +++ b/libvips/convolution/convi.c @@ -753,8 +753,8 @@ vips_convi_generate( VipsRegion *or, * We rint() everything, then adjust the scale try to match the overall * effect. */ -static int -intize( VipsImage *in, VipsImage **out ) +int +vips__image_intize( VipsImage *in, VipsImage **out ) { VipsImage *t; int x, y; @@ -953,7 +953,7 @@ vips_convi_build( VipsObject *object ) if( !convi->n_pass ) { /* Make an int version of our mask. */ - if( intize( M, &t[1] ) ) + if( vips__image_intize( M, &t[1] ) ) return( -1 ); convi->iM = M = t[1]; diff --git a/libvips/convolution/convolution.c b/libvips/convolution/convolution.c index 1e062f15..b699f863 100644 --- a/libvips/convolution/convolution.c +++ b/libvips/convolution/convolution.c @@ -159,8 +159,9 @@ vips_convolution_operation_init( void ) extern int vips_conv_get_type( void ); extern int vips_convf_get_type( void ); extern int vips_convi_get_type( void ); - extern int vips_compass_get_type( void ); extern int vips_convsep_get_type( void ); + extern int vips_convasep_get_type( void ); + extern int vips_compass_get_type( void ); extern int vips_fastcor_get_type( void ); extern int vips_spcor_get_type( void ); extern int vips_sharpen_get_type( void ); @@ -171,6 +172,7 @@ vips_convolution_operation_init( void ) vips_convi_get_type(); vips_compass_get_type(); vips_convsep_get_type(); + vips_convasep_get_type(); vips_fastcor_get_type(); vips_spcor_get_type(); vips_sharpen_get_type(); diff --git a/libvips/include/vips/convolution.h b/libvips/include/vips/convolution.h index 3a114b3a..91f096d9 100644 --- a/libvips/include/vips/convolution.h +++ b/libvips/include/vips/convolution.h @@ -44,21 +44,23 @@ typedef enum { VIPS_COMBINE_LAST } VipsCombine; -int vips_conv( VipsImage *in, VipsImage **out, VipsImage *mask, ... ) - __attribute__((sentinel)); int vips_convf( VipsImage *in, VipsImage **out, VipsImage *mask, ... ) __attribute__((sentinel)); int vips_convi( VipsImage *in, VipsImage **out, VipsImage *mask, ... ) __attribute__((sentinel)); -int vips_compass( VipsImage *in, VipsImage **out, VipsImage *mask, ... ) +int vips_convasep( VipsImage *in, VipsImage **out, VipsImage *mask, ... ) __attribute__((sentinel)); int vips_convsep( VipsImage *in, VipsImage **out, VipsImage *mask, ... ) __attribute__((sentinel)); +int vips_conv( VipsImage *in, VipsImage **out, VipsImage *mask, ... ) + __attribute__((sentinel)); -int vips_sharpen( VipsImage *in, VipsImage **out, ... ) +int vips_compass( VipsImage *in, VipsImage **out, VipsImage *mask, ... ) __attribute__((sentinel)); int vips_gaussblur( VipsImage *in, VipsImage **out, double sigma, ... ) __attribute__((sentinel)); +int vips_sharpen( VipsImage *in, VipsImage **out, ... ) + __attribute__((sentinel)); int vips_spcor( VipsImage *in, VipsImage *ref, VipsImage **out, ... ) __attribute__((sentinel)); diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index bc832d2a..6d32afa2 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -246,11 +246,12 @@ typedef struct _VipsImagePixels { gint64 npels; /* Number of pels calculated so far */ } VipsImagePixels; -int -vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready, +int vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready, VipsSaveable saveable, VipsBandFormat *format, VipsCoding *coding, VipsArrayDouble *background ); +int vips__image_intize( VipsImage *in, VipsImage **out ); + #ifdef __cplusplus } #endif /*__cplusplus*/