add "whole_slide" toggle

openslideload now crops to image bounds (if set) ... use @whole_slide to
stop this autocrop
This commit is contained in:
John Cupitt 2014-07-30 12:27:19 +01:00
parent 0bb8a218bb
commit 639c22bf53
5 changed files with 95 additions and 17 deletions

View File

@ -2,6 +2,7 @@
- fix a race in im_maxpos_avg()
- limit n_thr on tiny images
- don't exit() on memleak detected, just warn
- add "whole_slide" option to openslide load
4/7/14 started 7.40.4
- fix vips_rawsave_fd(), thanks aferrero2707

2
TODO
View File

@ -1,7 +1,5 @@
- affine makes black lines with interp window_offset > 1, see nohalo
- get rid of libexif, try exiv2
- experiment with size down to two sizes above in vipsthumbnail
how does this affect speed and sharpness?

View File

@ -41,6 +41,8 @@
* - always output solid (not transparent) pixels
* 25/1/14
* - use openslide_detect_vendor() on >= 3.4.0
* 30/7/14
* - add whole_slide toggle
*/
/*
@ -92,6 +94,12 @@ typedef struct {
char *associated;
/* Normally we crop to image bounds, if set. @whole_slide means, get the
* whole image.
*/
gboolean whole_slide;
VipsRect bounds;
/* Only valid if associated == NULL.
*/
int32_t level;
@ -178,9 +186,39 @@ check_associated_image( openslide_t *osr, const char *name )
return( -1 );
}
static gboolean
get_bounds( openslide_t *osr, VipsRect *rect )
{
static const char *openslide_names[] = {
"openslide.bounds-x",
"openslide.bounds-y",
"openslide.bounds-width",
"openslide.bounds-height"
};
static int vips_offsets[] = {
G_STRUCT_OFFSET( VipsRect, left ),
G_STRUCT_OFFSET( VipsRect, top ),
G_STRUCT_OFFSET( VipsRect, width ),
G_STRUCT_OFFSET( VipsRect, height )
};
const char *value;
int i;
for( i = 0; i < 4; i++ ) {
if( !(value = openslide_get_property_value( osr,
openslide_names[i] )) )
return( FALSE );
G_STRUCT_MEMBER( int, rect, vips_offsets[i] ) =
atoi( value );
}
return( TRUE );
}
static ReadSlide *
readslide_new( const char *filename, VipsImage *out,
int level, const char *associated )
int level, gboolean whole_slide, const char *associated )
{
ReadSlide *rslide;
int64_t w, h;
@ -188,7 +226,8 @@ readslide_new( const char *filename, VipsImage *out,
const char *background;
const char * const *properties;
if( level && associated ) {
if( level &&
associated ) {
vips_error( "openslide2vips",
"%s", _( "specify only one of level or associated "
"image" ) );
@ -201,6 +240,7 @@ readslide_new( const char *filename, VipsImage *out,
rslide );
rslide->level = level;
rslide->whole_slide = whole_slide;
rslide->associated = g_strdup( associated );
/* Non-crazy defaults, override below if we can.
@ -264,6 +304,22 @@ readslide_new( const char *filename, VipsImage *out,
rslide->tile_height = atoi( value );
if( value )
VIPS_DEBUG_MSG( "readslide_new: found tile-size\n" );
/* Some images have a bounds in the header. Try to crop to
* that, unless whole_slide is set.
*/
if( !rslide->whole_slide )
if( !get_bounds( rslide->osr, &rslide->bounds ) )
rslide->whole_slide = TRUE;
if( !rslide->whole_slide ) {
rslide->bounds.left /= rslide->downsample;
rslide->bounds.top /= rslide->downsample;
rslide->bounds.width /= rslide->downsample;
rslide->bounds.height /= rslide->downsample;
w = rslide->bounds.width;
h = rslide->bounds.height;
}
}
rslide->bg = 0xffffff;
@ -271,7 +327,9 @@ readslide_new( const char *filename, VipsImage *out,
OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR )) )
rslide->bg = strtoul( background, NULL, 16 );
if( w < 0 || h < 0 || rslide->downsample < 0 ) {
if( w <= 0 ||
h <= 0 ||
rslide->downsample < 0 ) {
vips_error( "openslide2vips", _( "getting dimensions: %s" ),
openslide_get_error( rslide->osr ) );
return( NULL );
@ -283,6 +341,13 @@ readslide_new( const char *filename, VipsImage *out,
return( NULL );
}
if( rslide->whole_slide ) {
rslide->bounds.left = 0;
rslide->bounds.top = 0;
rslide->bounds.width = w;
rslide->bounds.height = h;
}
vips_image_init_fields( out, w, h, 4, VIPS_FORMAT_UCHAR,
VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 );
@ -301,9 +366,9 @@ readslide_new( const char *filename, VipsImage *out,
int
vips__openslide_read_header( const char *filename, VipsImage *out,
int level, char *associated )
int level, gboolean whole_slide, char *associated )
{
if( !readslide_new( filename, out, level, associated ) )
if( !readslide_new( filename, out, level, whole_slide, associated ) )
return( -1 );
return( 0 );
@ -340,8 +405,8 @@ vips__openslide_generate( VipsRegion *out,
openslide_read_region( rslide->osr,
buf,
r->left * rslide->downsample,
r->top * rslide->downsample,
(r->left + rslide->bounds.left) * rslide->downsample,
(r->top + rslide->bounds.top) * rslide->downsample,
rslide->level,
r->width, r->height );
@ -391,7 +456,8 @@ vips__openslide_generate( VipsRegion *out,
}
int
vips__openslide_read( const char *filename, VipsImage *out, int level )
vips__openslide_read( const char *filename, VipsImage *out,
int level, gboolean whole_slide )
{
ReadSlide *rslide;
VipsImage *raw;
@ -403,7 +469,8 @@ vips__openslide_read( const char *filename, VipsImage *out, int level )
raw = vips_image_new();
vips_object_local( out, raw );
if( !(rslide = readslide_new( filename, raw, level, NULL )) )
if( !(rslide = readslide_new( filename, raw,
level, whole_slide, NULL )) )
return( -1 );
if( vips_image_generate( raw,
@ -446,7 +513,7 @@ vips__openslide_read_associated( const char *filename, VipsImage *out,
raw = vips_image_new_memory();
vips_object_local( out, raw );
if( !(rslide = readslide_new( filename, raw, 0, associated )) ||
if( !(rslide = readslide_new( filename, raw, 0, FALSE, associated )) ||
vips_image_write_prepare( raw ) )
return( -1 );
openslide_read_associated_image( rslide->osr, rslide->associated,

View File

@ -37,9 +37,9 @@ extern "C" {
int vips__openslide_isslide( const char *filename );
int vips__openslide_read_header( const char *filename, VipsImage *out,
int level, char *associated );
int level, gboolean whole_slide, char *associated );
int vips__openslide_read( const char *filename, VipsImage *out,
int level );
int level, gboolean whole_slide );
int vips__openslide_read_associated( const char *filename, VipsImage *out,
const char *associated );

View File

@ -70,6 +70,10 @@ typedef struct _VipsForeignLoadOpenslide {
*/
int level;
/* Don't crop to image bounds.
*/
gboolean whole_slide;
/* Load this associated image.
*/
char *associated;
@ -109,7 +113,8 @@ vips_foreign_load_openslide_header( VipsForeignLoad *load )
VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) load;
if( vips__openslide_read_header( openslide->filename, load->out,
openslide->level, openslide->associated ) )
openslide->level, openslide->whole_slide,
openslide->associated ) )
return( -1 );
VIPS_SETSTR( load->out->filename, openslide->filename );
@ -124,7 +129,7 @@ vips_foreign_load_openslide_load( VipsForeignLoad *load )
if( !openslide->associated ) {
if( vips__openslide_read( openslide->filename, load->real,
openslide->level ) )
openslide->level, openslide->whole_slide ) )
return( -1 );
}
else {
@ -190,7 +195,14 @@ vips_foreign_load_openslide_class_init( VipsForeignLoadOpenslideClass *class )
G_STRUCT_OFFSET( VipsForeignLoadOpenslide, level ),
0, 100000, 0 );
VIPS_ARG_STRING( class, "associated", 11,
VIPS_ARG_BOOL( class, "whole_slide", 11,
_( "Whole slide" ),
_( "Output entire side area" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadOpenslide, whole_slide ),
FALSE );
VIPS_ARG_STRING( class, "associated", 12,
_( "Associated" ),
_( "Load this associated image" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,