Skip to content

Commit

Permalink
BUG: Analyze 7.5 fixes/improvements
Browse files Browse the repository at this point in the history
Set better semantics of SetImageIOMetadataFromNIfTI(). It previously
populates the metadata dictionary with data from the ‘nifti_1_header’,
which is literally the first 348 bytes of the file.
This patch populateit from ‘nifti_image’ instead, which is
largely the same, but after some processing by nifti_convert_nhdr2nim().

For example, line 3765 forces the ‘qform_code’ field to 0 for Analyze
7.5 files, since that offset in the header had a different meaning
pre-NIfTI. By using the literal header fields,
SetImageIOMetadataFromNIfTI() is currently providing garbage sform and
qform values for Analyze files.

Which basically uses the data from ‘nifti_image’ instead. A handful of
fields need a little manipulation to get back in the same format.
This basically did what nifti_convert_nim2nhdr() does.

As a bonus, this removes extra file i/o by eliminating the nifti_read_header() call.

There doesn’t seem to be a good way to query if the file read was
Analyze 7.5 or NIfTI. This is needed to distinguish because apps need to provide
warning when Analyze is opened (to ween users off this format). This patch
adds the ‘nifti_type’ field to the metadata to make that info available.

Change-Id: I90c5ce48fcc5b6a4909be4030c0e32e4e9212b9d
  • Loading branch information
seanm authored and hjmjohnson committed Jan 27, 2018
1 parent b58b590 commit f38b1dd
Showing 1 changed file with 125 additions and 129 deletions.
254 changes: 125 additions & 129 deletions Modules/IO/NIFTI/src/itkNiftiImageIO.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -830,170 +830,167 @@ ::CanReadFile(const char *FileNameToRead)
return false;
}

// This method adds the available header information to the
// metadata dictionary.
// This method adds information to the metadata dictionary.
void NiftiImageIO::SetImageIOMetadataFromNIfTI()
{
int swap = 0;
nifti_1_header *header = nifti_read_header(this->GetFileName(), &swap, true);
auto & nim = this->m_NiftiImage;

if ( header )
{
// Encapsulate as many header information as possible.
MetaDataDictionary & thisDic = this->GetMetaDataDictionary();
// Necessary to clear dict if ImageIO object is re-used
thisDic.Clear();
// Encapsulate as much information as possible.
MetaDataDictionary & thisDic = this->GetMetaDataDictionary();
// Necessary to clear dict if ImageIO object is re-used
thisDic.Clear();

std::ostringstream dim_info;
dim_info << header->dim_info;
EncapsulateMetaData< std::string >( thisDic, "dim_info", dim_info.str() );
std::ostringstream nifti_type;
nifti_type << nim->nifti_type;
EncapsulateMetaData< std::string >( thisDic, "nifti_type", nifti_type.str() );

for ( int idx = 0; idx < 8; idx++ )
{
std::ostringstream dim;
dim << header->dim[idx];
std::ostringstream dimKey;
dimKey << "dim[" << idx << "]";
EncapsulateMetaData< std::string >( thisDic, dimKey.str(), dim.str() );
}
std::ostringstream dim_info;
dim_info << FPS_INTO_DIM_INFO( nim->freq_dim, nim->phase_dim, nim->slice_dim );
EncapsulateMetaData< std::string >( thisDic, "dim_info", dim_info.str() );

std::ostringstream intent_p1;
intent_p1 << header->intent_p1;
EncapsulateMetaData< std::string >( thisDic, "intent_p1", intent_p1.str() );

std::ostringstream intent_p2;
intent_p2 << header->intent_p2;
EncapsulateMetaData< std::string >( thisDic, "intent_p2", intent_p2.str() );
for ( int idx = 0; idx < 8; idx++ )
{
std::ostringstream dim;
dim << nim->dim[idx];
std::ostringstream dimKey;
dimKey << "dim[" << idx << "]";
EncapsulateMetaData< std::string >( thisDic, dimKey.str(), dim.str() );
}

std::ostringstream intent_p3;
intent_p3 << header->intent_p3;
EncapsulateMetaData< std::string >( thisDic, "intent_p3", intent_p3.str() );
std::ostringstream intent_p1;
intent_p1 << nim->intent_p1;
EncapsulateMetaData< std::string >( thisDic, "intent_p1", intent_p1.str() );

std::ostringstream intent_code;
intent_code << header->intent_code;
EncapsulateMetaData< std::string >( thisDic, "intent_code", intent_code.str() );
std::ostringstream intent_p2;
intent_p2 << nim->intent_p2;
EncapsulateMetaData< std::string >( thisDic, "intent_p2", intent_p2.str() );

std::ostringstream datatype;
datatype << header->datatype;
EncapsulateMetaData< std::string >( thisDic, "datatype", datatype.str() );
std::ostringstream intent_p3;
intent_p3 << nim->intent_p3;
EncapsulateMetaData< std::string >( thisDic, "intent_p3", intent_p3.str() );

std::ostringstream bitpix;
bitpix << header->bitpix;
EncapsulateMetaData< std::string >( thisDic, "bitpix", bitpix.str() );
std::ostringstream intent_code;
intent_code << nim->intent_code;
EncapsulateMetaData< std::string >( thisDic, "intent_code", intent_code.str() );

std::ostringstream slice_start;
slice_start << header->slice_start;
EncapsulateMetaData< std::string >( thisDic, "slice_start", slice_start.str() );
std::ostringstream datatype;
datatype << nim->datatype;
EncapsulateMetaData< std::string >( thisDic, "datatype", datatype.str() );

for ( int idx = 0; idx < 8; idx++ )
{
std::ostringstream pixdim;
pixdim << header->pixdim[idx];
std::ostringstream pixdimKey;
pixdimKey << "pixdim[" << idx << "]";
EncapsulateMetaData< std::string >( thisDic, pixdimKey.str(), pixdim.str() );
}
std::ostringstream bitpix;
bitpix << (8 * nim->nbyper);
EncapsulateMetaData< std::string >( thisDic, "bitpix", bitpix.str() );

std::ostringstream vox_offset;
vox_offset << header->vox_offset;
EncapsulateMetaData< std::string >( thisDic, "vox_offset", vox_offset.str() );
std::ostringstream slice_start;
slice_start << nim->slice_start;
EncapsulateMetaData< std::string >( thisDic, "slice_start", slice_start.str() );

std::ostringstream scl_slope;
scl_slope << header->scl_slope;
EncapsulateMetaData< std::string >( thisDic, "scl_slope", scl_slope.str() );
for ( int idx = 0; idx < 8; idx++ )
{
std::ostringstream pixdim;
pixdim << nim->pixdim[idx];
std::ostringstream pixdimKey;
pixdimKey << "pixdim[" << idx << "]";
EncapsulateMetaData< std::string >( thisDic, pixdimKey.str(), pixdim.str() );
}

std::ostringstream scl_inter;
scl_inter << header->scl_inter;
EncapsulateMetaData< std::string >( thisDic, "scl_inter", scl_inter.str() );
std::ostringstream vox_offset;
vox_offset << nim->iname_offset;
EncapsulateMetaData< std::string >( thisDic, "vox_offset", vox_offset.str() );

std::ostringstream slice_end;
slice_end << header->slice_end;
EncapsulateMetaData< std::string >( thisDic, "slice_end", slice_end.str() );
std::ostringstream scl_slope;
scl_slope << nim->scl_slope;
EncapsulateMetaData< std::string >( thisDic, "scl_slope", scl_slope.str() );

std::ostringstream slice_code;
slice_code << header->slice_code;
EncapsulateMetaData< std::string >( thisDic, "slice_code", slice_code.str() );
std::ostringstream scl_inter;
scl_inter << nim->scl_inter;
EncapsulateMetaData< std::string >( thisDic, "scl_inter", scl_inter.str() );

std::ostringstream xyzt_units;
xyzt_units << header->xyzt_units;
EncapsulateMetaData< std::string >( thisDic, "xyzt_units", xyzt_units.str() );
std::ostringstream slice_end;
slice_end << nim->slice_end;
EncapsulateMetaData< std::string >( thisDic, "slice_end", slice_end.str() );

std::ostringstream cal_max;
cal_max << header->cal_max;
EncapsulateMetaData< std::string >( thisDic, "cal_max", cal_max.str() );
std::ostringstream slice_code;
slice_code << nim->slice_code;
EncapsulateMetaData< std::string >( thisDic, "slice_code", slice_code.str() );

std::ostringstream cal_min;
cal_min << header->cal_min;
EncapsulateMetaData< std::string >( thisDic, "cal_min", cal_min.str() );
std::ostringstream xyzt_units;
xyzt_units << SPACE_TIME_TO_XYZT( nim->xyz_units, nim->time_units );
EncapsulateMetaData< std::string >( thisDic, "xyzt_units", xyzt_units.str() );

std::ostringstream slice_duration;
slice_duration << header->slice_duration;
EncapsulateMetaData< std::string >( thisDic, "slice_duration", slice_duration.str() );
std::ostringstream cal_max;
cal_max << nim->cal_max;
EncapsulateMetaData< std::string >( thisDic, "cal_max", cal_max.str() );

std::ostringstream toffset;
toffset << header->toffset;
EncapsulateMetaData< std::string >( thisDic, "toffset", toffset.str() );
std::ostringstream cal_min;
cal_min << nim->cal_min;
EncapsulateMetaData< std::string >( thisDic, "cal_min", cal_min.str() );

std::ostringstream descrip;
descrip << header->descrip;
EncapsulateMetaData< std::string >( thisDic, "descrip", descrip.str() );
std::ostringstream slice_duration;
slice_duration << nim->slice_duration;
EncapsulateMetaData< std::string >( thisDic, "slice_duration", slice_duration.str() );

std::ostringstream aux_file;
aux_file << header->aux_file;
EncapsulateMetaData< std::string >( thisDic, "aux_file", aux_file.str() );
std::ostringstream toffset;
toffset << nim->toffset;
EncapsulateMetaData< std::string >( thisDic, "toffset", toffset.str() );

std::ostringstream qform_code;
qform_code << header->qform_code;
EncapsulateMetaData< std::string >( thisDic, "qform_code", qform_code.str() );
EncapsulateMetaData< std::string >( thisDic, "qform_code_name", std::string( str_xform( header->qform_code ) ) );
std::ostringstream descrip;
descrip << nim->descrip;
EncapsulateMetaData< std::string >( thisDic, "descrip", descrip.str() );

std::ostringstream sform_code;
sform_code << header->sform_code;
EncapsulateMetaData< std::string >( thisDic, "sform_code", sform_code.str() );
EncapsulateMetaData< std::string >( thisDic, "sform_code_name", std::string( str_xform( header->sform_code ) ) );
std::ostringstream aux_file;
aux_file << nim->aux_file;
EncapsulateMetaData< std::string >( thisDic, "aux_file", aux_file.str() );

std::ostringstream quatern_b;
quatern_b << header->quatern_b;
EncapsulateMetaData< std::string >( thisDic, "quatern_b", quatern_b.str() );
std::ostringstream qform_code;
qform_code << nim->qform_code;
EncapsulateMetaData< std::string >( thisDic, "qform_code", qform_code.str() );
EncapsulateMetaData< std::string >( thisDic, "qform_code_name", std::string( str_xform( nim->qform_code ) ) );

std::ostringstream quatern_c;
quatern_c << header->quatern_c;
EncapsulateMetaData< std::string >( thisDic, "quatern_c", quatern_c.str() );
std::ostringstream sform_code;
sform_code << nim->sform_code;
EncapsulateMetaData< std::string >( thisDic, "sform_code", sform_code.str() );
EncapsulateMetaData< std::string >( thisDic, "sform_code_name", std::string( str_xform( nim->sform_code ) ) );

std::ostringstream quatern_d;
quatern_d << header->quatern_d;
EncapsulateMetaData< std::string >( thisDic, "quatern_d", quatern_d.str() );
std::ostringstream quatern_b;
quatern_b << nim->quatern_b;
EncapsulateMetaData< std::string >( thisDic, "quatern_b", quatern_b.str() );

std::ostringstream qoffset_x;
qoffset_x << header->qoffset_x;
EncapsulateMetaData< std::string >( thisDic, "qoffset_x", qoffset_x.str() );
std::ostringstream quatern_c;
quatern_c << nim->quatern_c;
EncapsulateMetaData< std::string >( thisDic, "quatern_c", quatern_c.str() );

std::ostringstream qoffset_y;
qoffset_y << header->qoffset_y;
EncapsulateMetaData< std::string >( thisDic, "qoffset_y", qoffset_y.str() );
std::ostringstream quatern_d;
quatern_d << nim->quatern_d;
EncapsulateMetaData< std::string >( thisDic, "quatern_d", quatern_d.str() );

std::ostringstream qoffset_z;
qoffset_z << header->qoffset_z;
EncapsulateMetaData< std::string >( thisDic, "qoffset_z", qoffset_z.str() );
std::ostringstream qoffset_x;
qoffset_x << nim->qoffset_x;
EncapsulateMetaData< std::string >( thisDic, "qoffset_x", qoffset_x.str() );

std::ostringstream srow_x;
srow_x << header->srow_x[0] << " " << header->srow_x[1] << " " << header->srow_x[2] << " " << header->srow_x[3];
EncapsulateMetaData< std::string >( thisDic, "srow_x", srow_x.str() );
std::ostringstream qoffset_y;
qoffset_y << nim->qoffset_y;
EncapsulateMetaData< std::string >( thisDic, "qoffset_y", qoffset_y.str() );

std::ostringstream srow_y;
srow_y << header->srow_y[0] << " " << header->srow_y[1] << " " << header->srow_y[2] << " " << header->srow_y[3];
EncapsulateMetaData< std::string >( thisDic, "srow_y", srow_y.str() );
std::ostringstream qoffset_z;
qoffset_z << nim->qoffset_z;
EncapsulateMetaData< std::string >( thisDic, "qoffset_z", qoffset_z.str() );

std::ostringstream srow_z;
srow_z << header->srow_z[0] << " " << header->srow_z[1] << " " << header->srow_z[2] << " " << header->srow_z[3];
EncapsulateMetaData< std::string >( thisDic, "srow_z", srow_z.str() );
std::ostringstream srow_x;
srow_x << nim->sto_xyz.m[0][0] << " " << nim->sto_xyz.m[0][1] << " " << nim->sto_xyz.m[0][2]<< " " << nim->sto_xyz.m[0][3];
EncapsulateMetaData< std::string >( thisDic, "srow_x", srow_x.str() );

std::ostringstream intent_name;
intent_name << header->intent_name;
EncapsulateMetaData< std::string >( thisDic, "intent_name", intent_name.str() );
std::ostringstream srow_y;
srow_y << nim->sto_xyz.m[1][0] << " " << nim->sto_xyz.m[1][1] << " " << nim->sto_xyz.m[1][2] << " " << nim->sto_xyz.m[1][3];
EncapsulateMetaData< std::string >( thisDic, "srow_y", srow_y.str() );

free(header);
}
std::ostringstream srow_z;
srow_z << nim->sto_xyz.m[2][0] << " " << nim->sto_xyz.m[2][1] << " " << nim->sto_xyz.m[2][2] << " " << nim->sto_xyz.m[2][3];
EncapsulateMetaData< std::string >( thisDic, "srow_z", srow_z.str() );

std::ostringstream intent_name;
intent_name << nim->intent_name;
EncapsulateMetaData< std::string >( thisDic, "intent_name", intent_name.str() );
}

void
Expand Down Expand Up @@ -1739,8 +1736,7 @@ NiftiImageIO::SetImageIOOrientationFromNIfTI(unsigned short int dims)

//
// in the case of an Analyze75 file, use old analyze orient method.
if ( this->m_NiftiImage->qform_code == 0
&& this->m_NiftiImage->sform_code == 0 )
if ( this->m_NiftiImage->nifti_type == NIFTI_FTYPE_ANALYZE )
{
SpatialOrientationAdapter::DirectionType dir;
SpatialOrientationAdapter::OrientationType orient;
Expand Down

0 comments on commit f38b1dd

Please sign in to comment.