void getNiftiImageOrientation(nifti_1_header hdr, char *orientation) { orientation[0]='\0'; if(hdr.qform_code == 0 && hdr.sform_code == 0) { printf("\nWarning: Could not determine image orientation ...\n"); printf("\nWarning: \"NIFTI\" header does not contain orientation information.\n"); return; } if(hdr.qform_code > 0 ) { mat44 R; R = nifti_quatern_to_mat44(hdr.quatern_b, hdr.quatern_c, hdr.quatern_d, hdr.qoffset_x, hdr.qoffset_y, hdr.qoffset_z, hdr.pixdim[1], hdr.pixdim[2], hdr.pixdim[3], hdr.pixdim[0]); orientation[0] = directionCode(R.m[0][0],R.m[1][0],R.m[2][0]); orientation[1] = directionCode(R.m[0][1],R.m[1][1],R.m[2][1]); orientation[2] = directionCode(R.m[0][2],R.m[1][2],R.m[2][2]); orientation[3] = '\0'; } else { orientation[0] = directionCode(hdr.srow_x[0],hdr.srow_y[0],hdr.srow_z[0]); orientation[1] = directionCode(hdr.srow_x[1],hdr.srow_y[1],hdr.srow_z[1]); orientation[2] = directionCode(hdr.srow_x[2],hdr.srow_y[2],hdr.srow_z[2]); orientation[3] = '\0'; } return; }
unsigned char * nii_setOrtho(unsigned char* img, struct nifti_1_header *h) { if ((h->dim[1] < 1) || (h->dim[2] < 1) || (h->dim[3] < 1)) return img; if ((h->sform_code == NIFTI_XFORM_UNKNOWN) && (h->qform_code != NIFTI_XFORM_UNKNOWN)) { //only q-form provided mat44 q = nifti_quatern_to_mat44(h->quatern_b, h->quatern_c, h->quatern_d, h->qoffset_x, h->qoffset_y, h->qoffset_z, h->pixdim[1], h->pixdim[2], h->pixdim[3],h->pixdim[0]); mat2sForm(h,q); //convert q-form to s-form h->sform_code = h->qform_code; } if (h->sform_code == NIFTI_XFORM_UNKNOWN) { #ifdef MY_DEBUG printf("No Q or S spatial transforms - assuming canonical orientation"); #endif return img; } mat44 s = sFormMat(h); if (isMat44Canonical( s)) { #ifdef MY_DEBUG printf("Image in perfect alignment: no need to reorient"); #endif return img; } vec3i flipV; vec3 minMM = minCornerFlip(h, &flipV); mat33 orient = getBestOrient(s, flipV); vec3i orientVec = setOrientVec(orient); if ((orientVec.v[0]==1) && (orientVec.v[1]==2) && (orientVec.v[2]==3) ) { #ifdef MY_DEBUG printf("Image already near best orthogonal alignment: no need to reorient\n"); #endif return img; } bool is24 = false; if (h->bitpix == 24 ) { //RGB stored as planar data. treat as 3 8-bit slices return img; is24 = true; h->bitpix = 8; h->dim[3] = h->dim[3] * 3; } img = reOrient(img, h,orientVec, orient, minMM); if (is24 ) { h->bitpix = 24; h->dim[3] = h->dim[3] / 3; } #ifdef MY_DEBUG printf("NewRotation= %d %d %d\n", orientVec.v[0],orientVec.v[1],orientVec.v[2]); printf("MinCorner= %.2f %.2f %.2f\n", minMM.v[0],minMM.v[1],minMM.v[2]); reportMat44o("input",s); s = sFormMat(h); reportMat44o("output",s); #endif return img; }
/* *************************************************************** */ nifti_image *reg_io_nrdd2nifti(Nrrd *nrrdImage) { // Check if the file can be converted if(nrrdImage->dim>7){ fprintf(stderr, "[NiftyReg ERROR] reg_io_nrdd2nifti - The Nifti format only support 7 dimensions\n"); exit(1); } // Need first to extract the input image dimension int dim[8]={1,1,1,1,1,1,1,1}; dim[0]=nrrdImage->dim; int vectorIncrement=0; if(nrrdImage->axis[0].kind==nrrdKindVector) vectorIncrement=1; for(int i=0;i<(dim[0]<7?dim[0]:7);++i) dim[i+1]=(int)nrrdImage->axis[i+vectorIncrement].size; if(vectorIncrement==1){ dim[0]=5; dim[4]=1; dim[5]=nrrdImage->axis[0].size; } // The nifti_image pointer is created nifti_image *niiImage=NULL; // The nifti image is generated based on the nrrd image datatype switch(nrrdImage->type){ case nrrdTypeUChar: niiImage=nifti_make_new_nim(dim,NIFTI_TYPE_UINT8,true); break; case nrrdTypeChar: niiImage=nifti_make_new_nim(dim,NIFTI_TYPE_INT8,true); break; case nrrdTypeUShort: niiImage=nifti_make_new_nim(dim,NIFTI_TYPE_UINT16,true); break; case nrrdTypeShort: niiImage=nifti_make_new_nim(dim,NIFTI_TYPE_INT16,true); break; case nrrdTypeUInt: niiImage=nifti_make_new_nim(dim,NIFTI_TYPE_UINT32,true); break; case nrrdTypeInt: niiImage=nifti_make_new_nim(dim,NIFTI_TYPE_INT32,true); break; case nrrdTypeFloat: niiImage=nifti_make_new_nim(dim,NIFTI_TYPE_FLOAT32,true); break; case nrrdTypeDouble: niiImage=nifti_make_new_nim(dim,NIFTI_TYPE_FLOAT64,true); break; default: fprintf(stderr, "[NiftyReg ERROR] reg_io_nrdd2nifti - The data type is not supported\n"); exit(1); } // The data are copied over from the nrrd to the nifti structure memcpy(niiImage->data, nrrdImage->data, niiImage->nvox*niiImage->nbyper); // We set the spacing information for every axis double spaceDir[NRRD_SPACE_DIM_MAX], spacing; for(int i=0;i<7;++i){ nrrdSpacingCalculate(nrrdImage,i+vectorIncrement,&spacing,spaceDir); if(spacing==spacing) niiImage->pixdim[i+1]=(float)spacing; else niiImage->pixdim[i+1]=1.0f; } niiImage->dx=niiImage->pixdim[1]; niiImage->dy=niiImage->pixdim[2]; niiImage->dz=niiImage->pixdim[3]; niiImage->dt=niiImage->pixdim[4]; niiImage->du=niiImage->pixdim[5]; niiImage->dv=niiImage->pixdim[6]; niiImage->dw=niiImage->pixdim[7]; // Set the slope and intersection niiImage->scl_inter=0; niiImage->scl_slope=1; // Set the min and max intensities niiImage->cal_min=reg_tools_getMinValue(niiImage); niiImage->cal_max=reg_tools_getMaxValue(niiImage); // The space orientation is extracted and converted into a matrix mat44 qform_orientation_matrix; reg_mat44_eye(&qform_orientation_matrix); if(nrrdImage->space==nrrdSpaceRightAnteriorSuperior || nrrdImage->space==nrrdSpaceRightAnteriorSuperiorTime || nrrdImage->space==nrrdSpace3DRightHanded || nrrdImage->space==nrrdSpace3DRightHandedTime ){ qform_orientation_matrix.m[0][0]=1.f; // NIFTI_L2R qform_orientation_matrix.m[1][1]=1.f; // NIFTI_P2A qform_orientation_matrix.m[2][2]=1.f; // NIFTI_I2S niiImage->qform_code=1; } else if(nrrdImage->space==nrrdSpaceLeftAnteriorSuperior || nrrdImage->space==nrrdSpaceLeftAnteriorSuperiorTime || nrrdImage->space==nrrdSpace3DLeftHanded || nrrdImage->space==nrrdSpace3DLeftHandedTime ){ qform_orientation_matrix.m[0][0]=-1.f; //NIFTI_R2L qform_orientation_matrix.m[1][1]=1.f; // NIFTI_P2A qform_orientation_matrix.m[2][2]=1.f; // NIFTI_I2S niiImage->qform_code=1; } else if(nrrdImage->space!=nrrdSpaceScannerXYZ && nrrdImage->space!=nrrdSpaceScannerXYZTime ){ niiImage->qform_code=0; fprintf(stderr, "[NiftyReg WARNING] reg_io_nrdd2nifti - nrrd space value unrecognised: the Nifti qform is set to identity\n"); } if(niiImage->qform_code>0){ // The origin is set // Note that x and y origin are negated to fit with ITK conversion if(niiImage->ndim>=1) qform_orientation_matrix.m[0][3]=niiImage->qoffset_x=-nrrdImage->spaceOrigin[0]; if(niiImage->ndim>=2) qform_orientation_matrix.m[1][3]=niiImage->qoffset_y=-nrrdImage->spaceOrigin[1]; if(niiImage->ndim>=3) qform_orientation_matrix.m[2][3]=niiImage->qoffset_z=nrrdImage->spaceOrigin[2]; // Flipp the orientation to fit ITK's filters qform_orientation_matrix.m[0][0] *= -1.0f; qform_orientation_matrix.m[1][1] *= -1.0f; // Extract the quaternions and qfac values nifti_mat44_to_quatern(qform_orientation_matrix, &niiImage->quatern_b, &niiImage->quatern_c, &niiImage->quatern_d, &niiImage->qoffset_x, &niiImage->qoffset_y, &niiImage->qoffset_z, &niiImage->dx, &niiImage->dy, &niiImage->dz, &niiImage->qfac); // Set the qform matrices niiImage->qto_xyz=nifti_quatern_to_mat44(niiImage->quatern_b, niiImage->quatern_c, niiImage->quatern_d, niiImage->qoffset_x, niiImage->qoffset_y, niiImage->qoffset_z, niiImage->dx, niiImage->dy, niiImage->dz, niiImage->qfac); } else{ // diagonal matrix is assumed niiImage->qto_xyz=qform_orientation_matrix; niiImage->qto_xyz.m[0][0]=niiImage->dx; niiImage->qto_xyz.m[1][1]=niiImage->dy; if(niiImage->ndim>2) niiImage->qto_xyz.m[2][2]=niiImage->dz; } niiImage->qto_ijk=nifti_mat44_inverse(niiImage->qto_xyz); // The sform has to be set if required // Check if the spaceDirection array is set // The check is performed in the dim in case you are dealing with a vector if(nrrdImage->axis[1].spaceDirection[0]!=std::numeric_limits<double>::quiet_NaN()){ niiImage->sform_code=1; reg_mat44_eye(&niiImage->sto_xyz); for(int i=0;i<(niiImage->ndim<3?niiImage->ndim:3);++i){ for(int j=0;j<(niiImage->ndim<3?niiImage->ndim:3);++j){ niiImage->sto_xyz.m[i][j]=(float)nrrdImage->axis[i+vectorIncrement].spaceDirection[j]; } niiImage->sto_xyz.m[i][3]=(float)nrrdImage->spaceOrigin[i]; } // The matrix is flipped to go from nrrd to nifti // and follow the ITK style for(unsigned int i=0;i<2;++i) for(unsigned int j=0;j<4;++j) niiImage->sto_xyz.m[i][j]*=-1.0f; niiImage->sto_ijk=nifti_mat44_inverse(niiImage->sto_xyz); } // Set the space unit if it is defined if(nrrdImage->spaceUnits[1]!=NULL){ if(strcmp(nrrdImage->spaceUnits[1],"m")==0) niiImage->xyz_units=NIFTI_UNITS_METER; else if(strcmp(nrrdImage->spaceUnits[1],"mm")==0) niiImage->xyz_units=NIFTI_UNITS_MM; else if(strcmp(nrrdImage->spaceUnits[1],"um")==0) niiImage->xyz_units=NIFTI_UNITS_MICRON; } // Set the time unit if it is defined if(nrrdImage->axis[3].size>1){ if(nrrdImage->spaceUnits[4]!=NULL){ if(strcmp(nrrdImage->spaceUnits[4],"sec")) niiImage->time_units=NIFTI_UNITS_SEC; else if(strcmp(nrrdImage->spaceUnits[4],"msec")) niiImage->time_units=NIFTI_UNITS_MSEC; } } // Check if the nrrd image was a NiftyReg velocity field parametrisation if(vectorIncrement == 1){ // The intensity array has to be reoriented switch(niiImage->datatype){ case NIFTI_TYPE_FLOAT32: reg_convertVectorField_nrrd_to_nifti<float>(nrrdImage,niiImage); break; case NIFTI_TYPE_FLOAT64: reg_convertVectorField_nrrd_to_nifti<double>(nrrdImage,niiImage); break; default: fprintf(stderr, "[NiftyReg ERROR] - reg_convertVectorField_nrrd_to_nifti - unsupported datatype\n"); exit(1); } // The orientation flag are re-organised niiImage->ndim=5; niiImage->dim[4]=niiImage->nt=1; niiImage->dim[5]=niiImage->nu=nrrdImage->axis[0].size; niiImage->intent_code=NIFTI_INTENT_VECTOR; // Check if the image is a stationary field from NiftyReg if(nrrdImage->axis[0].label!=NULL){ std::string str=nrrdImage->axis[0].label; size_t it; if((it=str.find("NREG_VEL_STEP "))!=std::string::npos){ str=str.substr(it+13); memset(niiImage->intent_name, 0, 16); strcpy(niiImage->intent_name,"NREG_VEL_STEP"); niiImage->intent_p1=atof(str.c_str()); } if(str.find("NREG_CPP_FILE")!=std::string::npos){ memset(niiImage->intent_name, 0, 16); strcpy(niiImage->intent_name,"NREG_CPP_FILE"); } } } // returns the new nii image return niiImage; }
void getNiftiImageOrientation(const char *filename, char *orientation) { FILE *fp; nifti_1_header hdr; int swapflg=0; orientation[0]='\0'; // ensure that the specified image has either a .hdr or a .nii extension if( !checkNiftiFileExtension(filename) ) { errorMessage("The image filename must have a `.hdr' or `.nii' extension."); } fp = fopen(filename,"r"); if(fp==NULL) { file_open_error(filename); } if( fread(&hdr, sizeof(nifti_1_header), 1, fp) != 1 ) { errorMessage("I have trouble reading the specified image file."); } fclose(fp); // looks like ANALYZE 7.5, cannot determine orientation if( hdr.magic[0]!='n' || (hdr.magic[1]!='+' && hdr.magic[1]!='i') || hdr.magic[2]!='1') { printf("\nWarning: Could not determine %s image orientation ...\n",filename); return; } // if dim[0] is outside range 1..7, then the header information // needs to be byte swapped appropriately if(hdr.dim[0]<1 || hdr.dim[0]>7) { swapflg=1; } // Here I am only byte swapping the header fields relevant for determining the image orientation if(swapflg) { swapByteOrder( (char *)&(hdr.qform_code), sizeof(short)); swapByteOrder( (char *)&(hdr.sform_code), sizeof(short)); swapByteOrder( (char *)&(hdr.quatern_b), sizeof(float)); swapByteOrder( (char *)&(hdr.quatern_c), sizeof(float)); swapByteOrder( (char *)&(hdr.quatern_d), sizeof(float)); swapByteOrder( (char *)&(hdr.qoffset_x), sizeof(float)); swapByteOrder( (char *)&(hdr.qoffset_y), sizeof(float)); swapByteOrder( (char *)&(hdr.qoffset_z), sizeof(float)); for(int i=0; i<4; i++) { swapByteOrder( (char *)&(hdr.srow_x[i]), sizeof(float)); swapByteOrder( (char *)&(hdr.srow_y[i]), sizeof(float)); swapByteOrder( (char *)&(hdr.srow_z[i]), sizeof(float)); } } if(hdr.qform_code == 0 && hdr.sform_code == 0) { printf("\nWarning: Could not determine %s image orientation ...\n",filename); printf("\nWarning: The header of this \"NIFTI\" file does not contain orientation information.\n"); return; } if(hdr.qform_code > 0 ) { mat44 R; R = nifti_quatern_to_mat44(hdr.quatern_b, hdr.quatern_c, hdr.quatern_d, hdr.qoffset_x, hdr.qoffset_y, hdr.qoffset_z, hdr.pixdim[1], hdr.pixdim[2], hdr.pixdim[3], hdr.pixdim[0]); orientation[0] = directionCode(R.m[0][0],R.m[1][0],R.m[2][0]); orientation[1] = directionCode(R.m[0][1],R.m[1][1],R.m[2][1]); orientation[2] = directionCode(R.m[0][2],R.m[1][2],R.m[2][2]); orientation[3] = '\0'; } else { orientation[0] = directionCode(hdr.srow_x[0],hdr.srow_y[0],hdr.srow_z[0]); orientation[1] = directionCode(hdr.srow_x[1],hdr.srow_y[1],hdr.srow_z[1]); orientation[2] = directionCode(hdr.srow_x[2],hdr.srow_y[2],hdr.srow_z[2]); orientation[3] = '\0'; } return; }
// returns the orientations vectors xvec, yvec, and zvec in NIFTI's RAS system void readOrientationVectorsFromFile(const char *filename, float *xvec, float *yvec, float *zvec) { FILE *fp; nifti_1_header hdr; int swapflg=0; // ensure that the specified image has either a .hdr or a .nii extension if( !checkNiftiFileExtension(filename) ) { errorMessage("Error: The image filename must have a `.hdr' or `.nii' extension."); } fp = fopen(filename,"r"); if(fp==NULL) { errorMessage("Error: I have trouble opening the specified image file."); } if( fread(&hdr, sizeof(nifti_1_header), 1, fp) != 1 ) { errorMessage("Error: I have trouble reading the specified image file."); } fclose(fp); // looks like ANALYZE 7.5, cannot determine orientation if( hdr.magic[0]!='n' || (hdr.magic[1]!='+' && hdr.magic[1]!='i') || hdr.magic[2]!='1') { return; } // if dim[0] is outside range 1..7, then the header information // needs to be byte swapped appropriately if(hdr.dim[0]<1 || hdr.dim[0]>7) { swapflg=1; } // Here I am only byte swapping the header fields relevant for determining the image orientation if(swapflg) { swapByteOrder( (char *)&(hdr.qform_code), sizeof(short)); swapByteOrder( (char *)&(hdr.sform_code), sizeof(short)); swapByteOrder( (char *)&(hdr.quatern_b), sizeof(float)); swapByteOrder( (char *)&(hdr.quatern_c), sizeof(float)); swapByteOrder( (char *)&(hdr.quatern_d), sizeof(float)); swapByteOrder( (char *)&(hdr.qoffset_x), sizeof(float)); swapByteOrder( (char *)&(hdr.qoffset_y), sizeof(float)); swapByteOrder( (char *)&(hdr.qoffset_z), sizeof(float)); for(int i=0; i<4; i++) { swapByteOrder( (char *)&(hdr.srow_x[i]), sizeof(float)); swapByteOrder( (char *)&(hdr.srow_y[i]), sizeof(float)); swapByteOrder( (char *)&(hdr.srow_z[i]), sizeof(float)); } } if(hdr.qform_code == 0 && hdr.sform_code == 0) { printf("\nThe header of this so called \"NIFTI\" file does not contain orientation information.\n"); return; } if(hdr.qform_code > 0 ) { mat44 R; R = nifti_quatern_to_mat44(hdr.quatern_b, hdr.quatern_c, hdr.quatern_d, hdr.qoffset_x, hdr.qoffset_y, hdr.qoffset_z, hdr.pixdim[1], hdr.pixdim[2], hdr.pixdim[3], hdr.pixdim[0]); xvec[0] = R.m[0][0]; xvec[1] = R.m[1][0]; xvec[2] = R.m[2][0]; yvec[0] = R.m[0][1]; yvec[1] = R.m[1][1]; yvec[2] = R.m[2][1]; zvec[0] = R.m[0][2]; zvec[1] = R.m[1][2]; zvec[2] = R.m[2][2]; } else { xvec[0] = hdr.srow_x[0]; xvec[1] = hdr.srow_y[0]; xvec[2] = hdr.srow_z[0]; yvec[0] = hdr.srow_x[1]; yvec[1] = hdr.srow_y[1]; yvec[2] = hdr.srow_z[1]; zvec[0] = hdr.srow_x[2]; zvec[1] = hdr.srow_y[2]; zvec[2] = hdr.srow_z[2]; } normalizeVector(xvec, 3); normalizeVector(yvec, 3); normalizeVector(zvec, 3); return; }