polish, add test for find_trim

This commit is contained in:
John Cupitt 2017-07-26 10:43:28 +01:00
parent effc1d53d0
commit 6359c92c01
3 changed files with 48 additions and 38 deletions

View File

@ -51,46 +51,29 @@ typedef struct _VipsFindTrim {
VipsImage *in; VipsImage *in;
double threshold; double threshold;
VipsArrayDouble *background;
int left; int left;
int top; int top;
int width; int width;
int height; int height;
double *ones;
double *background;
int n;
} VipsFindTrim; } VipsFindTrim;
typedef VipsOperationClass VipsFindTrimClass; typedef VipsOperationClass VipsFindTrimClass;
G_DEFINE_TYPE( VipsFindTrim, vips_find_trim, VIPS_TYPE_OPERATION ); G_DEFINE_TYPE( VipsFindTrim, vips_find_trim, VIPS_TYPE_OPERATION );
static void
vips_find_trim_finalize( GObject *gobject )
{
VipsFindTrim *find_trim = (VipsFindTrim *) gobject;
#ifdef DEBUG
printf( "vips_find_trim_finalize: " );
vips_object_print_name( VIPS_OBJECT( gobject ) );
printf( "\n" );
#endif /*DEBUG*/
VIPS_FREE( find_trim->background );
VIPS_FREE( find_trim->ones );
G_OBJECT_CLASS( vips_find_trim_parent_class )->finalize( gobject );
}
static int static int
vips_find_trim_build( VipsObject *object ) vips_find_trim_build( VipsObject *object )
{ {
VipsFindTrim *find_trim = (VipsFindTrim *) object; VipsFindTrim *find_trim = (VipsFindTrim *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 20 ); VipsImage **t = (VipsImage **) vips_object_local_array( object, 20 );
int i; double *background;
int n;
double *neg_bg;
double *ones; double *ones;
int i;
double left; double left;
double top; double top;
double right; double right;
@ -102,27 +85,21 @@ vips_find_trim_build( VipsObject *object )
if( vips_image_decode( find_trim->in, &t[0] ) ) if( vips_image_decode( find_trim->in, &t[0] ) )
return( -1 ); return( -1 );
/* Fetch pixel (0, 0) as the background value.
*/
if( vips_getpoint( t[0],
&find_trim->background, &find_trim->n,
0, 0, NULL ) )
return( -1 );
/* We want to subtract the bg. /* We want to subtract the bg.
*/ */
if( !(ones = VIPS_ARRAY( find_trim, find_trim->n, double )) ) background = vips_array_double_get( find_trim->background, &n );
if( !(neg_bg = VIPS_ARRAY( find_trim, n, double )) ||
!(ones = VIPS_ARRAY( find_trim, n, double )) )
return( -1 ); return( -1 );
for( i = 0; i < find_trim->n; i++ ) { for( i = 0; i < n; i++ ) {
neg_bg[i] = -1 * background[i];
ones[i] = 1.0; ones[i] = 1.0;
find_trim->background[i] *= -1;
} }
/* Smooth, find difference from bg, abs, threshold. /* Smooth, find difference from bg, abs, threshold.
*/ */
if( vips_median( t[0], &t[1], 3, NULL ) || if( vips_median( t[0], &t[1], 3, NULL ) ||
vips_linear( t[1], &t[2], vips_linear( t[1], &t[2], ones, neg_bg, n, NULL ) ||
ones, find_trim->background, find_trim->n, NULL ) ||
vips_abs( t[2], &t[3], NULL ) || vips_abs( t[2], &t[3], NULL ) ||
vips_more_const1( t[3], &t[4], find_trim->threshold, NULL ) ) vips_more_const1( t[3], &t[4], find_trim->threshold, NULL ) )
return( -1 ); return( -1 );
@ -167,9 +144,7 @@ vips_find_trim_class_init( VipsFindTrimClass *class )
{ {
GObjectClass *gobject_class = (GObjectClass *) class; GObjectClass *gobject_class = (GObjectClass *) class;
VipsObjectClass *object_class = (VipsObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
gobject_class->finalize = vips_find_trim_finalize;
gobject_class->set_property = vips_object_set_property; gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property; gobject_class->get_property = vips_object_get_property;
@ -192,6 +167,13 @@ vips_find_trim_class_init( VipsFindTrimClass *class )
G_STRUCT_OFFSET( VipsFindTrim, threshold ), G_STRUCT_OFFSET( VipsFindTrim, threshold ),
0, INFINITY, 10.0 ); 0, INFINITY, 10.0 );
VIPS_ARG_BOXED( class, "background", 3,
_( "Background" ),
_( "Color for background pixels" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsFindTrim, background ),
VIPS_TYPE_ARRAY_DOUBLE );
VIPS_ARG_INT( class, "left", 5, VIPS_ARG_INT( class, "left", 5,
_( "Left" ), _( "Left" ),
_( "Left edge of image" ), _( "Left edge of image" ),
@ -226,6 +208,7 @@ static void
vips_find_trim_init( VipsFindTrim *find_trim ) vips_find_trim_init( VipsFindTrim *find_trim )
{ {
find_trim->threshold = 10; find_trim->threshold = 10;
find_trim->background = vips_array_double_newv( 1, 255.0 );
} }
/** /**
@ -239,9 +222,20 @@ vips_find_trim_init( VipsFindTrim *find_trim )
* *
* Optional arguments: * Optional arguments:
* *
* * @threshold: background / object threshold * * @threshold: %gdouble, background / object threshold
* * @background: #VipsArrayDouble, background colour, default 255
* *
* See also: vips_extract_area(), vips_smartcrop(). * Search @in for the bounding box of the non-background area.
*
* @in is median-filtered, then all the row and column sums of the absolute
* difference from @background are calculated in a
* single pass through the image, then the first row or column in each of the
* four directions is found where the sum is greater than @threshold.
*
* @background defaults to 255. Set another value, or use vips_getpoint() to
* pick a value from an edge. @threshold defaults to 10.
*
* See also: vips_getpoint(), vips_extract_area(), vips_smartcrop().
* *
* Returns: 0 on success, -1 on error * Returns: 0 on success, -1 on error
*/ */

View File

@ -607,6 +607,7 @@ vips_embed_class_init( VipsEmbedClass *class )
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsEmbed, background ), G_STRUCT_OFFSET( VipsEmbed, background ),
VIPS_TYPE_ARRAY_DOUBLE ); VIPS_TYPE_ARRAY_DOUBLE );
} }
static void static void

View File

@ -641,6 +641,21 @@ class TestArithmetic(unittest.TestCase):
self.assertAlmostEqual(p1, 0) self.assertAlmostEqual(p1, 0)
self.assertAlmostEqual(p2, 10) self.assertAlmostEqual(p2, 10)
def test_find_trim(self):
im = Vips.Image.black(50, 60) + 100
test = im.embed(10, 20, 200, 300, extend = "white")
test.write_to_file("x.v")
for x in unsigned_formats + float_formats:
a = test.cast(x)
left, top, width, height = a.find_trim()
self.assertEqual(left, 10)
self.assertEqual(top, 20)
self.assertEqual(width, 50)
self.assertEqual(height, 60)
def test_profile(self): def test_profile(self):
test = Vips.Image.black(100, 100).draw_rect(100, 40, 50, 1, 1) test = Vips.Image.black(100, 100).draw_rect(100, 40, 50, 1, 1)