static int vips_compass_build( VipsObject *object ) { VipsConvolution *convolution = (VipsConvolution *) object; VipsCompass *compass = (VipsCompass *) object; VipsImage **masks; VipsImage *mask; VipsImage **images; int i; VipsImage **abs; VipsImage **combine; VipsImage *x; g_object_set( compass, "out", vips_image_new(), NULL ); if( VIPS_OBJECT_CLASS( vips_compass_parent_class )->build( object ) ) return( -1 ); masks = (VipsImage **) vips_object_local_array( object, compass->times ); images = (VipsImage **) vips_object_local_array( object, compass->times ); abs = (VipsImage **) vips_object_local_array( object, compass->times ); combine = (VipsImage **) vips_object_local_array( object, compass->times ); mask = convolution->M; for( i = 0; i < compass->times; i++ ) { if( vips_conv( convolution->in, &images[i], mask, "precision", compass->precision, "layers", compass->layers, "cluster", compass->cluster, NULL ) ) return( -1 ); if( vips_rot45( mask, &masks[i], "angle", compass->angle, NULL ) ) return( -1 ); mask = masks[i]; } for( i = 0; i < compass->times; i++ ) if( vips_abs( images[i], &abs[i], NULL ) ) return( -1 ); switch( compass->combine ) { case VIPS_COMBINE_MAX: if( vips_bandrank( abs, &combine[0], compass->times, "index", compass->times - 1, NULL ) ) return( -1 ); x = combine[0]; break; case VIPS_COMBINE_SUM: x = abs[0]; for( i = 1; i < compass->times; i++ ) { if( vips_add( x, abs[i], &combine[i], NULL ) ) return( -1 ); x = combine[i]; } break; default: /* Silence compiler wrning. */ x = NULL; g_assert( 0 ); } if( vips_image_write( x, convolution->out ) ) return( -1 ); return( 0 ); }
static int vips_smartcrop_attention( VipsSmartcrop *smartcrop, VipsImage *in, int *left, int *top ) { /* From smartcrop.js. */ static double skin_vector[] = {-0.78, -0.57, -0.44}; static double ones[] = {1.0, 1.0, 1.0}; VipsImage **t = (VipsImage **) vips_object_local_array( VIPS_OBJECT( smartcrop ), 24 ); double hscale; double vscale; double sigma; double max; int x_pos; int y_pos; /* The size we shrink to gives the precision with which we can place * the crop */ hscale = 32.0 / in->Xsize; vscale = 32.0 / in->Ysize; sigma = VIPS_MAX( sqrt( pow( smartcrop->width * hscale, 2 ) + pow( smartcrop->height * vscale, 2 ) ) / 10, 1.0 ); if ( vips_resize( in, &t[17], hscale, "vscale", vscale, NULL ) ) return( -1 ); /* Simple edge detect. */ if( !(t[21] = vips_image_new_matrixv( 3, 3, 0.0, -1.0, 0.0, -1.0, 4.0, -1.0, 0.0, -1.0, 0.0 )) ) return( -1 ); /* Convert to XYZ and just use the first three bands. */ if( vips_colourspace( t[17], &t[0], VIPS_INTERPRETATION_XYZ, NULL ) || vips_extract_band( t[0], &t[1], 0, "n", 3, NULL ) ) return( -1 ); /* Edge detect on Y. */ if( vips_extract_band( t[1], &t[2], 1, NULL ) || vips_conv( t[2], &t[3], t[21], "precision", VIPS_PRECISION_INTEGER, NULL ) || vips_linear1( t[3], &t[4], 5.0, 0.0, NULL ) || vips_abs( t[4], &t[14], NULL ) ) return( -1 ); /* Look for skin colours. Taken from smartcrop.js. */ if( /* Normalise to magnitude of colour in XYZ. */ pythagoras( smartcrop, t[1], &t[5] ) || vips_divide( t[1], t[5], &t[6], NULL ) || /* Distance from skin point. */ vips_linear( t[6], &t[7], ones, skin_vector, 3, NULL ) || pythagoras( smartcrop, t[7], &t[8] ) || /* Rescale to 100 - 0 score. */ vips_linear1( t[8], &t[9], -100.0, 100.0, NULL ) || /* Ignore dark areas. */ vips_more_const1( t[2], &t[10], 5.0, NULL ) || !(t[11] = vips_image_new_from_image1( t[10], 0.0 )) || vips_ifthenelse( t[10], t[9], t[11], &t[15], NULL ) ) return( -1 ); /* Look for saturated areas. */ if( vips_colourspace( t[1], &t[12], VIPS_INTERPRETATION_LAB, NULL ) || vips_extract_band( t[12], &t[13], 1, NULL ) || vips_ifthenelse( t[10], t[13], t[11], &t[16], NULL ) ) return( -1 ); /* Sum, blur and find maxpos. * * The amount of blur is related to the size of the crop * area: how large an area we want to consider for the scoring * function. */ if( vips_sum( &t[14], &t[18], 3, NULL ) || vips_gaussblur( t[18], &t[19], sigma, NULL ) || vips_max( t[19], &max, "x", &x_pos, "y", &y_pos, NULL ) ) return( -1 ); /* Centre the crop over the max. */ *left = VIPS_CLIP( 0, x_pos / hscale - smartcrop->width / 2, in->Xsize - smartcrop->width ); *top = VIPS_CLIP( 0, y_pos / vscale - smartcrop->height / 2, in->Ysize - smartcrop->height ); return( 0 ); }