VolumeList* ECAT7VolumeReader::read(const std::string &url, int volumeId) throw(tgt::CorruptedFileException, tgt::IOException, std::bad_alloc) { LINFO("Loading dataset " << url << " vid: " << volumeId); VolumeURL origin(url); std::string fileName = origin.getPath(); FILE* fin = fopen(fileName.c_str(), "rb"); if(!fin) { throw tgt::FileNotFoundException("ECAT7: File not found", fileName); } ECAT7VolumeReader::ECAT7Structure s = readStructure(fileName); VolumeList* vc = new VolumeList(); for(size_t i=0; i<s.subVolumes_.size(); i++) { fseek(fin, s.subVolumes_[i].de_.startBlock_ * 512, SEEK_SET); fseek(fin, 512, SEEK_CUR); //skip past header (already read) tgt::svec3 dimensions = s.subVolumes_[i].getDimensions(); //tgt::mat4 m = s.subVolumes_[i].getTransformation(); tgt::vec3 spacing = s.subVolumes_[i].getSpacing(); tgt::vec3 offset = s.subVolumes_[i].getOffset(); if(volumeId != -1) { if(volumeId != s.subVolumes_[i].getId()) continue; } if(s.subVolumes_[i].ih_.num_dimensions != 3) continue; if (getProgressBar()) { getProgressBar()->setTitle("Loading Volume"); getProgressBar()->setProgressMessage("Loading volume: " + fileName); } VolumeRAM* vol; RealWorldMapping denormalize; if(s.h_.file_type == 6) { vol = new VolumeRAM_UInt8(dimensions); denormalize = RealWorldMapping::createDenormalizingMapping<uint8_t>(); } else if(s.h_.file_type == 7) { vol = new VolumeRAM_UInt16(dimensions); denormalize = RealWorldMapping::createDenormalizingMapping<uint16_t>(); } else { LERROR("Unknown file format detected."); return 0; } float scale = s.subVolumes_[i].ih_.scale_factor * s.h_.ecat_calibration_factor; RealWorldMapping rwm(scale, 0.0f, s.h_.data_units); VolumeReader::read(vol, fin); // Assume that the pixel size values given in the ecat header are in cm. Multiply spacing and offset // with 0.1 to convert to mm. Volume* vh = new Volume(vol, spacing * 0.1f, offset * 0.1f); vh->setRealWorldMapping(RealWorldMapping::combine(denormalize, rwm)); if(s.swapEndianness_) VolumeOperatorSwapEndianness::APPLY_OP(vh); // TODO: This must depend on some parameter in the headers, figure out which and how bool mirrorZ = true; if(mirrorZ) { Volume* mirrored = VolumeOperatorMirrorZ::APPLY_OP(vh); delete vh; vh = mirrored; } VolumeURL o("ecat7", fileName); o.addSearchParameter("volumeId", itos(s.subVolumes_[i].de_.id_)); vh->setOrigin(o); s.transformMetaData(vh->getMetaDataContainer(), static_cast<int>(i)); if(length(offset) == 0.f) centerVolume(vh); vc->add(vh); if (getProgressBar()) getProgressBar()->hide(); } fclose(fin); return vc; }
VolumeCollection* AnalyzeVolumeReader::readNifti(const std::string &fileName, bool standalone, int volId) throw (tgt::FileException, std::bad_alloc) { LINFO("Loading nifti file " << fileName); std::ifstream file(fileName.c_str(), std::ios::in | std::ios::binary); if(!file) { throw tgt::FileNotFoundException("Failed to open file: ", fileName); } nifti_1_header header; if (!file.read((char*)&header, sizeof(header))) { throw tgt::CorruptedFileException("Failed to read header!", fileName); } file.close(); bool bigEndian = false; //check if swap is necessary: if((header.dim[0] < 0) || (header.dim[0] > 15)) { bigEndian = true; header.swapEndianess(); } if(header.sizeof_hdr != 348) { throw tgt::CorruptedFileException("Invalid header.sizeof_hdr", fileName); } if(!( (header.magic[0] == 'n') && (header.magic[2] == '1') && (header.magic[3] == 0) )) throw tgt::CorruptedFileException("Not a Nifti header!", fileName); if(header.magic[1] == '+') { if(!standalone) LWARNING("Tried to read standalone Nifti as hdr+img!"); standalone = true; } else if(header.magic[1] == 'i') { if(!standalone) LWARNING("Tried to read hdr+img Nifti as standalone!"); standalone = false; } else throw tgt::CorruptedFileException("Not a Nifti header!", fileName); ivec3 dimensions; dimensions.x = header.dim[1]; dimensions.y = header.dim[2]; dimensions.z = header.dim[3]; LINFO("Resolution: " << dimensions); int numVolumes = header.dim[4]; LINFO("Number of volumes: " << numVolumes); if (hor(lessThanEqual(dimensions, ivec3(0)))) { LERROR("Invalid resolution or resolution not specified: " << dimensions); throw tgt::CorruptedFileException("error while reading data", fileName); } vec3 spacing; spacing.x = header.pixdim[1]; spacing.y = header.pixdim[2]; spacing.z = header.pixdim[3]; LINFO("Spacing: " << spacing); int timeunit = XYZT_TO_TIME(header.xyzt_units); int spaceunit = XYZT_TO_SPACE(header.xyzt_units); LINFO("timeunit: " << timeunit << " spaceunit: " << spaceunit); float dt = header.pixdim[4]; float toffset = header.toffset; switch(timeunit) { case NIFTI_UNITS_SEC: dt *= 1000.0f; toffset *= 1000.0f; break; case NIFTI_UNITS_MSEC: //nothing to do break; case NIFTI_UNITS_USEC: dt /= 1000.0f; toffset /= 1000.0f; break; } switch(spaceunit) { case NIFTI_UNITS_MM: //nothing to do break; case NIFTI_UNITS_METER: spacing *= 1000.0f; LWARNING("Units: meter"); break; case NIFTI_UNITS_MICRON: spacing /= 1000.0f; LWARNING("Units: micron"); break; case NIFTI_UNITS_UNKNOWN: default: LWARNING("Unknown space unit!"); break; } LINFO("Datatype: " << header.datatype); std::string voreenVoxelType = ""; RealWorldMapping denormalize; bool applyRWM = header.scl_slope != 0.0f; switch(header.intent_code) { case IC_INTENT_SYMMATRIX: /* parameter at each voxel is symmetrical matrix */ //TODO: should be relatively easy (=> tensors) case IC_INTENT_DISPVECT: /* parameter at each voxel is displacement vector */ case IC_INTENT_VECTOR: /* parameter at each voxel is vector */ //TODO: should be relatively easy case IC_INTENT_GENMATRIX: /* parameter at each voxel is matrix */ //TODO: should be relatively easy case IC_INTENT_POINTSET: /* value at each voxel is spatial coordinate (vertices/nodes of surface mesh) */ case IC_INTENT_TRIANGLE: /* value at each voxel is spatial coordinate (vertices/nodes of surface mesh) */ case IC_INTENT_QUATERNION: throw tgt::UnsupportedFormatException("Unsupported intent code!"); break; case IC_INTENT_ESTIMATE: /* parameter for estimate in intent_name */ case IC_INTENT_LABEL: /* parameter at each voxel is index to label defined in aux_file */ case IC_INTENT_NEURONAME: /* parameter at each voxel is index to label in NeuroNames label set */ case IC_INTENT_DIMLESS: /* dimensionless value */ case IC_INTENT_NONE: break; default: LWARNING("Unhandled intent code"); break; } //if (header.intent_code == IC_INTENT_SYMMATRIX) { //h.objectModel_ = "TENSOR_FUSION_LOW"; //} if(voreenVoxelType == "") { switch(header.datatype) { case DT_UNSIGNED_CHAR: voreenVoxelType = "uint8"; denormalize = RealWorldMapping::createDenormalizingMapping<uint8_t>(); break; case DT_SIGNED_SHORT: voreenVoxelType = "int16"; denormalize = RealWorldMapping::createDenormalizingMapping<int16_t>(); break; case DT_SIGNED_INT: voreenVoxelType = "int32"; denormalize = RealWorldMapping::createDenormalizingMapping<int32_t>(); break; case DT_FLOAT: voreenVoxelType = "float"; break; case DT_DOUBLE: voreenVoxelType = "double"; break; case DT_RGB: voreenVoxelType = "Vector3(uint8)"; applyRWM = false; break; case DT_RGBA32: /* 4 byte RGBA (32 bits/voxel) */ voreenVoxelType = "Vector4(uint8)"; applyRWM = false; break; case DT_INT8: /* signed char (8 bits) */ voreenVoxelType = "int8"; break; case DT_UINT16: /* unsigned short (16 bits) */ voreenVoxelType = "uint16"; denormalize = RealWorldMapping::createDenormalizingMapping<uint16_t>(); break; case DT_UINT32: /* unsigned int (32 bits) */ voreenVoxelType = "uint32"; denormalize = RealWorldMapping::createDenormalizingMapping<uint32_t>(); break; case DT_INT64: /* long long (64 bits) */ case DT_UINT64: /* unsigned long long (64 bits) */ case DT_FLOAT128: /* long double (128 bits) */ case DT_COMPLEX128: /* double pair (128 bits) */ case DT_COMPLEX256: /* long double pair (256 bits) */ case DT_ALL: case DT_COMPLEX: case 0: //DT_NONE/DT_UNKNOWN case DT_BINARY: default: throw tgt::UnsupportedFormatException("Unsupported datatype!"); } } RealWorldMapping rwm(header.scl_slope, header.scl_inter, ""); int headerskip = static_cast<uint16_t>(header.vox_offset); std::string rawFilename = fileName; if(!standalone) rawFilename = getRelatedImgFileName(fileName); mat4 pToW = mat4::identity; //Calculate transformation: if(header.sform_code > 0) { mat4 vToW(header.srow_x[0], header.srow_x[1], header.srow_x[2], header.srow_x[3], header.srow_y[0], header.srow_y[1], header.srow_y[2], header.srow_y[3], header.srow_z[0], header.srow_z[1], header.srow_z[2], header.srow_z[3], 0.0f, 0.0f, 0.0f, 1.0f); mat4 wToV = mat4::identity; if(!vToW.invert(wToV)) { LERROR("Failed to invert voxel to world matrix!"); } mat4 vToP = mat4::createScale(spacing); //no offset pToW = vToP * wToV; } else if(header.qform_code > 0) { float b = header.quatern_b; float c = header.quatern_c; float d = header.quatern_d; float a = static_cast<float>(sqrt(1.0-(b*b+c*c+d*d))); mat4 rot2(a*a+b*b-c*c-d*d, 2*b*c-2*a*d, 2*b*d+2*a*c, 0.0f, 2*b*c+2*a*d, a*a+c*c-b*b-d*d, 2*c*d-2*a*b, 0.0f, 2*b*d-2*a*c, 2*c*d+2*a*b, a*a+d*d-c*c-b*b, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); float qfac = header.pixdim[0]; if(fabs(qfac) < 0.1f) qfac = 1.0f; mat4 sc = mat4::createScale(vec3(1.0f, 1.0f, qfac)); mat4 os = mat4::createTranslation(vec3(header.qoffset_x, header.qoffset_y, header.qoffset_z)); pToW = os * rot2 * sc; } // Nifti transformations give us the center of the first voxel, we translate to correct: pToW = pToW * mat4::createTranslation(-spacing * 0.5f); VolumeCollection* vc = new VolumeCollection(); size_t volSize = hmul(tgt::svec3(dimensions)) * (header.bitpix / 8); int start = 0; int stop = numVolumes; if(volId != -1) { //we want to load a single volume: start = volId; stop = start + 1; } for(int i=start; i<stop; i++) { VolumeRepresentation* volume = new VolumeDisk(rawFilename, voreenVoxelType, dimensions, headerskip + (i * volSize), bigEndian); Volume* vh = new Volume(volume, spacing, vec3(0.0f)); VolumeURL origin(fileName); origin.addSearchParameter("volumeId", itos(i)); vh->setOrigin(origin); vh->setPhysicalToWorldMatrix(pToW); vh->setMetaDataValue<StringMetaData>("Description", std::string(header.descrip)); //vh->addMetaData("ActualFrameDuration", new IntMetaData(ih_.frame_duration)); //vh->addMetaData("FrameTime", new IntMetaData(ih_.frame_start_time)); vh->setMetaDataValue<IntMetaData>("FrameTime", static_cast<int>(toffset + (i * dt))); if(applyRWM) vh->setRealWorldMapping(RealWorldMapping::combine(denormalize, rwm)); vc->add(vh); } return vc; }