Beispiel #1
0
static int
vips_resize_build( VipsObject *object )
{
	VipsResample *resample = VIPS_RESAMPLE( object );
	VipsResize *resize = (VipsResize *) object;

	VipsImage **t = (VipsImage **) 
		vips_object_local_array( object, 7 );

	VipsImage *in;
	int window_size;
	int int_shrink;
	int int_shrink_width;
	double residual;
	double sigma;

	if( VIPS_OBJECT_CLASS( vips_resize_parent_class )->build( object ) )
		return( -1 );

	if( !vips_object_argument_isset( object, "interpolate" ) ) {
		VipsInterpolate *interpolate;
		char *nick;

		if( vips_type_find( "VipsInterpolate", "bicubic" ) )
			nick = "bicubic";
		else
			nick = "bilinear";
		interpolate = vips_interpolate_new( nick );
		g_object_set( object, "interpolate", interpolate, NULL ); 
		VIPS_UNREF( interpolate ); 
	}

	in = resample->in;

	window_size = resize->interpolate ? 
		vips_interpolate_get_window_size( resize->interpolate ) : 2;

	/* If the factor is > 1.0, we need to zoom rather than shrink.
	 * Just set the int part to 1 in this case.
	 */
	int_shrink = resize->scale > 1.0 ? 1 : floor( 1.0 / resize->scale );

	/* We want to shrink by less for interpolators with larger windows.
	 */
	int_shrink = VIPS_MAX( 1,
		int_shrink / VIPS_MAX( 1, window_size / 2 ) );

	/* Size after int shrink.
	 */
	int_shrink_width = in->Xsize / int_shrink;

	/* Therefore residual scale factor is.
	 */
	residual = (in->Xsize * resize->scale) / int_shrink_width;

	/* A copy for enlarge resize.
	 */
	if( vips_shrink( in, &t[0], int_shrink, int_shrink, NULL ) )
		return( -1 );
	in = t[0];

	/* We want to make sure we read the image sequentially.
	 * However, the convolution we may be doing later will force us 
	 * into SMALLTILE or maybe FATSTRIP mode and that will break
	 * sequentiality.
	 *
	 * So ... read into a cache where tiles are scanlines, and make sure
	 * we keep enough scanlines to be able to serve a line of tiles.
	 *
	 * We use a threaded tilecache to avoid a deadlock: suppose thread1,
	 * evaluating the top block of the output, is delayed, and thread2, 
	 * evaluating the second block, gets here first (this can happen on 
	 * a heavily-loaded system). 
	 *
	 * With an unthreaded tilecache (as we had before), thread2 will get
	 * the cache lock and start evaling the second block of the shrink. 
	 * When it reaches the png reader it will stall until the first block 
	 * has been used ... but it never will, since thread1 will block on 
	 * this cache lock. 
	 */
	if( int_shrink > 1 ) { 
		int tile_width;
		int tile_height;
		int nlines;

		vips_get_tile_size( in, 
			&tile_width, &tile_height, &nlines );
		if( vips_tilecache( in, &t[6], 
			"tile_width", in->Xsize,
			"tile_height", 10,
			"max_tiles", 1 + (nlines * 2) / 10,
			"access", VIPS_ACCESS_SEQUENTIAL,
			"threaded", TRUE, 
			NULL ) )
			return( -1 );
		in = t[6];
	}

	/* If the final affine will be doing a large downsample, we can get 
	 * nasty aliasing on hard edges. Blur before affine to smooth this out.
	 *
	 * Don't blur for very small shrinks, blur with radius 1 for x1.5
	 * shrinks, blur radius 2 for x2.5 shrinks and above, etc.
	 */
	sigma = ((1.0 / residual) - 0.5) / 1.5;
	if( residual < 1.0 &&
		sigma > 0.1 ) { 
		if( vips_gaussblur( in, &t[2], sigma, NULL ) )
			return( -1 );
		in = t[2];
	}

	if( vips_affine( in, &t[3], residual, 0, 0, residual, 
		"interpolate", resize->interpolate,
		"idx", resize->idx,
		"idy", resize->idy,
		NULL ) )  
		return( -1 );
	in = t[3];

	/* If we are upsampling, don't sharpen.
	 */
	if( int_shrink > 1 ) { 
		t[5] = vips_image_new_matrixv( 3, 3,
			-1.0, -1.0, -1.0,
			-1.0, 32.0, -1.0,
			-1.0, -1.0, -1.0 );
		vips_image_set_double( t[5], "scale", 24 );

		if( vips_conv( in, &t[4], t[5], NULL ) ) 
			return( -1 );
		in = t[4];
	}

	if( vips_image_write( in, resample->out ) )
		return( -1 ); 

	return( 0 );
}
Beispiel #2
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 ); 
}