load seems to work

This commit is contained in:
John Cupitt 2018-07-02 14:57:24 +01:00
parent 7716fa957b
commit 06e8d1d523

View File

@ -1,7 +1,7 @@
/* load nifti from a file
*
* 29/6/18
* - from niftiload.c
* - from fitsload.c
*/
/*
@ -33,8 +33,13 @@
/*
#define DEBUG
*/
#define VIPS_DEBUG
*/
/* TODO
* - for uncompressed images, we could offer direct mapping of the input
* - could stream the image perhaps?
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -62,6 +67,8 @@ typedef struct _VipsForeignLoadNifti {
*/
char *filename;
nifti_image *nim;
} VipsForeignLoadNifti;
typedef VipsForeignLoadClass VipsForeignLoadNiftiClass;
@ -69,6 +76,17 @@ typedef VipsForeignLoadClass VipsForeignLoadNiftiClass;
G_DEFINE_TYPE( VipsForeignLoadNifti, vips_foreign_load_nifti,
VIPS_TYPE_FOREIGN_LOAD );
static void
vips_foreign_load_nifti_dispose( GObject *gobject )
{
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) gobject;
VIPS_FREEF( nifti_image_free, nifti->nim );
G_OBJECT_CLASS( vips_foreign_load_nifti_parent_class )->
dispose( gobject );
}
/* Map DT_* datatype values to VipsBandFormat.
*/
typedef struct _DT2Vips {
@ -246,7 +264,7 @@ vips_gvalue_read( GValue *value, void *p )
}
static int
vips_foreign_load_nifti_get_header( VipsForeignLoadNifti *nifti,
vips_foreign_load_nifti_set_header( VipsForeignLoadNifti *nifti,
nifti_image *nim, VipsImage *out )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( nifti );
@ -255,6 +273,8 @@ vips_foreign_load_nifti_get_header( VipsForeignLoadNifti *nifti,
guint height;
guint bands;
VipsBandFormat fmt;
double xres;
double yres;
int i;
char txt[256];
@ -265,11 +285,23 @@ vips_foreign_load_nifti_get_header( VipsForeignLoadNifti *nifti,
nim->ndim );
return( 0 );
}
for( i = 1; i < 8; i++ )
for( i = 1; i < 8; i++ ) {
if( nim->dim[i] <= 0 ) {
vips_error( class->nickname,
"%s", _( "invalid dimension" ) );
return( 0 );
}
/* If we have several images in a dimension, the spacing must
* be non-zero, or we'll get a /0 error in resolution
* calculation.
*/
if( nim->dim[i] > 1 &&
nim->pixdim[i] == 0 ) {
vips_error( class->nickname,
"%s", _( "invalid resolution" ) );
return( 0 );
}
}
/* Unfold higher dimensions vertically. bands is updated below for
@ -308,6 +340,31 @@ vips_foreign_load_nifti_get_header( VipsForeignLoadNifti *nifti,
if( nim->datatype == DT_RGBA32 )
bands = 4;
/* We fold y and z together, so they must have the same resolution..
*/
xres = 1.0;
yres = 1.0;
if( nim->nz == 1 ||
nim->dz == nim->dy )
switch( nim->xyz_units ) {
case NIFTI_UNITS_METER:
xres = 1000.0 / nim->dx;
yres = 1000.0 / nim->dy;
break;
case NIFTI_UNITS_MM:
xres = 1.0 / nim->dx;
yres = 1.0 / nim->dy;
break;
case NIFTI_UNITS_MICRON:
xres = 1.0 / (1000.0 * nim->dx);
yres = 1.0 / (1000.0 * nim->dy);
break;
default:
break;
}
#ifdef DEBUG
printf( "get_vips_properties: width = %d\n", width );
printf( "get_vips_properties: height = %d\n", height );
@ -315,12 +372,13 @@ vips_foreign_load_nifti_get_header( VipsForeignLoadNifti *nifti,
printf( "get_vips_properties: fmt = %d\n", fmt );
#endif /*DEBUG*/
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
vips_image_init_fields( out,
width, height, bands, fmt,
VIPS_CODING_NONE,
bands == 1 ?
VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB,
1.0, 1.0 );
xres, yres );
for( i = 0; i < VIPS_NUMBER( other_fields ); i++ ) {
GValue value = { 0 };
@ -333,12 +391,12 @@ vips_foreign_load_nifti_get_header( VipsForeignLoadNifti *nifti,
g_value_unset( &value );
}
vips_strncpy( txt, nim->intent_name, 16 );
txt[16] = '\0';
/* One byte longer than the spec to leave space for any extra
* '\0' termination.
*/
vips_strncpy( txt, nim->intent_name, 17 );
vips_image_set_string( out, "nifti-intent_name", txt );
vips_strncpy( txt, nim->descrip, 80 );
txt[80] = '\0';
vips_strncpy( txt, nim->descrip, 81 );
vips_image_set_string( out, "nifti-descrip", txt );
for( i = 0; i < nim->num_ext; i++ ) {
@ -362,29 +420,86 @@ vips_foreign_load_nifti_header( VipsForeignLoad *load )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) load;
nifti_image *nim;
/* We can't use the (much faster) nifti_read_header() since it just
* reads the 348 bytes iof the analyze struct and does not read any of
* the extension fields.
*/
/* FALSE means don't read data, just the header. Use
* nifti_image_load() later to pull the data in.
*/
if( !(nim = nifti_image_read( nifti->filename, FALSE )) ) {
if( !(nifti->nim = nifti_image_read( nifti->filename, FALSE )) ) {
vips_error( class->nickname,
"%s", _( "unable to read NIFTI file" ) );
"%s", _( "unable to read NIFTI header" ) );
return( 0 );
}
if( vips_foreign_load_nifti_get_header( nifti, nim, load->out ) ) {
nifti_image_free( nim );
if( vips_foreign_load_nifti_set_header( nifti,
nifti->nim, load->out ) ) {
return( -1 );
}
nifti_image_free( nim );
VIPS_SETSTR( load->out->filename, nifti->filename );
return( 0 );
}
static int
vips_foreign_load_nifti_generate( VipsRegion *out,
void *seq, void *a, void *b, gboolean *stop )
{
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) a;
VipsRect *r = &out->valid;
size_t len = VIPS_REGION_SIZEOF_LINE( out );
size_t line_stride = VIPS_IMAGE_SIZEOF_LINE( out->im );
size_t pixel_stride = VIPS_IMAGE_SIZEOF_PEL( out->im );
int y;
VIPS_DEBUG_MSG( "vips_foreign_load_nifti_generate: "
"generating left = %d, top = %d, width = %d, height = %d\n",
r->left, r->top, r->width, r->height );
for( y = r->top; y < VIPS_RECT_BOTTOM( r ); y++ ) {
VipsPel *q = VIPS_REGION_ADDR( out, r->left, y );
VipsPel *p = (VipsPel *) nifti->nim->data +
y * line_stride +
r->left * pixel_stride;
memcpy( q, p, len );
}
return( 0 );
}
static int
vips_foreign_load_nifti_load( VipsForeignLoad *load )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) load;
#ifdef DEBUG
printf( "vips_foreign_load_nifti_load: loading image\n" );
#endif /*DEBUG*/
if( nifti_image_load( nifti->nim ) ) {
vips_error( class->nickname,
"%s", _( "unable to load NIFTI file" ) );
return( -1 );
}
if( vips_foreign_load_nifti_set_header( nifti,
nifti->nim, load->real ) )
return( -1 );
if( vips_image_generate( load->real,
NULL, vips_foreign_load_nifti_generate, NULL, nifti, NULL ) )
return( -1 );
return( 0 );
}
const char *vips__nifti_suffs[] = {
".nii", ".nii.gz",
".hdr", ".hdr.gz",
@ -400,6 +515,7 @@ vips_foreign_load_nifti_class_init( VipsForeignLoadNiftiClass *class )
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->dispose = vips_foreign_load_nifti_dispose;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
@ -414,6 +530,7 @@ vips_foreign_load_nifti_class_init( VipsForeignLoadNiftiClass *class )
load_class->is_a = is_nifti_file;
load_class->header = vips_foreign_load_nifti_header;
load_class->load = vips_foreign_load_nifti_load;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),