voreen::VolumeCollection* VolumeCollection::selectOrigin(const VolumeOrigin& origin) const { VolumeCollection* collection = new VolumeCollection(); for (size_t i=0; i<volumeHandles_.size(); ++i) { if (volumeHandles_[i]->getOrigin() == origin) collection->add(volumeHandles_[i]); } return collection; }
VolumeCollection* VolumeCollection::subCollection(const std::vector<size_t>& indices) const { VolumeCollection* subCollection = new VolumeCollection(); for (size_t i=0; i<indices.size(); i++) { tgtAssert(indices.at(i) < volumeHandles_.size(), "invalid index"); subCollection->add(volumeHandles_.at(indices.at(i))); } return subCollection; }
VolumeCollection* VolumeCollection::selectModality(const Modality& modality) const { VolumeCollection* collection = new VolumeCollection(); for (size_t i=0; i<volumeHandles_.size(); ++i) { if (volumeHandles_[i]->getModality() == modality) collection->add(volumeHandles_[i]); } return collection; }
voreen::VolumeCollection* VolumeCollection::selectOrigin(const VolumeURL& origin) const { VolumeCollection* collection = new VolumeCollection(); for (size_t i=0; i<volumeHandles_.size(); ++i) { Volume* vh = dynamic_cast<Volume*>(volumeHandles_[i]); if (vh && vh->getOrigin() == origin) collection->add(volumeHandles_[i]); } return collection; }
VolumeCollection* VolumeCollection::subCollection(size_t start, size_t end) const { VolumeCollection* subCollection = new VolumeCollection(); tgtAssert(start <= end, "invalid indices"); tgtAssert(start < volumeHandles_.size(), "invalid start index"); tgtAssert(end < volumeHandles_.size(), "invalid end index"); for (size_t index = start; index <= end; index++) subCollection->add(volumeHandles_.at(index)); return subCollection; }
VolumeCollection* VolumeCollection::selectTimestep(float timestep) const { VolumeCollection* collection = new VolumeCollection(); for (size_t i=0; i<volumeHandles_.size(); ++i) { if (volumeHandles_[i]->getTimestep() == timestep) collection->add(volumeHandles_[i]); } return collection; }
voreen::VolumeCollection* VolumeCollection::selectOriginTimestep(const VolumeOrigin& origin, float timestep) const { VolumeCollection* collection = new VolumeCollection(); for (size_t i=0; i<volumeHandles_.size(); ++i) { VolumeHandle* vh = dynamic_cast<VolumeHandle*>(volumeHandles_[i]); if (vh && vh->getOrigin() == origin && vh->getTimestep() == timestep) collection->add(volumeHandles_[i]); } return collection; }
VolumeCollection* RawVoxVolumeReader::read(const std::string &url) throw (tgt::CorruptedFileException, tgt::IOException, std::bad_alloc) { VolumeURL origin(url); std::string fileName = origin.getPath(); LINFO("Reading file " << fileName); std::fstream fin(fileName.c_str(), std::ios::in | std::ios::binary); if (!fin.good()) throw tgt::IOException(); RawVoxHeader header; fin.read(reinterpret_cast<char*>(&header), sizeof(header)); svec3 dimensions = svec3(header.sizeX_, header.sizeY_, header.sizeZ_); if(header.magic_ != 1381388120) { throw tgt::CorruptedFileException("Wrong magic number."); } VolumeRAM* dataset; switch(header.bitsPerVoxel_) { case 8: LINFO("Reading 8 bit dataset"); dataset = new VolumeRAM_UInt8(dimensions); break; case 16: LINFO("Reading 16 bit dataset"); dataset = new VolumeRAM_UInt16(dimensions); break; case 32: LINFO("Reading 32 bit (float) dataset"); dataset = new VolumeRAM_Float(dimensions); break; default: LERROR("Unknown bpp!"); throw tgt::UnsupportedFormatException("Unexpected bpp."); } fin.read(reinterpret_cast<char*>(dataset->getData()), dataset->getNumBytes()); if ( fin.eof() ) { delete dataset; throw tgt::CorruptedFileException(); } fin.close(); VolumeCollection* volumeCollection = new VolumeCollection(); Volume* volumeHandle = new Volume(dataset, vec3(1.0f), vec3(0.0f)); oldVolumePosition(volumeHandle); volumeHandle->setOrigin(fileName); volumeCollection->add(volumeHandle); return volumeCollection; }
VolumeCollection* VvdVolumeReader::read(const std::string &url) throw (tgt::FileException, std::bad_alloc) { VolumeURL origin(url); std::string fileName = origin.getPath(); // open file for reading std::fstream fileStream(fileName.c_str(), std::ios_base::in); if (fileStream.fail()) { throw tgt::FileException("Failed to open file '" + tgt::FileSystem::absolutePath(fileName) + "' for reading."); } // read data stream into deserializer XmlDeserializer d(fileName); d.setUseAttributes(true); try { d.read(fileStream); } catch (SerializationException& e) { throw tgt::FileException("SerializationException: Failed to read serialization data stream from file '" + fileName + "': " + e.what()); } catch (...) { throw tgt::FileException("Failed to read serialization data stream from file '" + fileName + "' (unknown exception)."); } std::vector<VvdObject> vec; // deserialize from data stream try { d.deserialize("Volumes", vec, "Volume"); } catch (std::exception& e) { throw tgt::FileException("Deserialization from file '" + fileName + "' failed: " + e.what()); } catch (...) { throw tgt::FileException("Deserialization from file '" + fileName + "' failed (unknown exception)."); } if (vec.empty()) throw tgt::FileException("Deserialization from file '" + fileName + "' failed: no volume found"); VolumeCollection* vc = new VolumeCollection(); for(size_t i=0; i<vec.size(); i++) { Volume* vh = vec[i].createVolume(tgt::FileSystem::dirName(fileName)); vh->setOrigin(origin); vc->add(vh); } return vc; }
VolumeCollection* TransFuncListProperty::getVolumes(bool selectedOnly /*= true*/) const { VolumeCollection* collection = new VolumeCollection(); std::vector<std::string> urls = get(); for (size_t i=0; i<urls.size(); i++) { std::string url = urls.at(i); if (handleMap_.find(url) != handleMap_.end()) { if (!selectedOnly || (selectionMap_.find(url) != selectionMap_.end() && selectionMap_.find(url)->second == true) ) { VolumeBase* handle = handleMap_.find(url)->second; tgtAssert(handle, "handleMap_ contains null pointer"); collection->add(handle); } } } return collection; }
VolumeBase* AnalyzeVolumeReader::read(const VolumeURL& origin) throw (tgt::FileException, std::bad_alloc) { VolumeBase* result = 0; int volumeId = -1; std::string tmp = origin.getSearchParameter("volumeId"); if (! tmp.empty()) volumeId = stoi(tmp); VolumeCollection* collection = read(origin.getPath(), volumeId); if (collection && collection->size() == 1) { result = collection->first(); } else if (collection && collection->size() > 1) { while(!collection->empty()) { VolumeBase* vh = collection->first(); collection->remove(vh); delete vh; } delete collection; throw tgt::FileException("Only one volume expected", origin.getPath()); } delete collection; return result; }
VolumeCollection* MultiVolumeReader::read(const std::string& url) throw (tgt::FileException, std::bad_alloc) { LINFO("Loading multi volume file " << url); VolumeURL urlOrigin(url); std::vector<VolumeURL> origins = listVolumes(url); if (origins.empty()) throw tgt::FileException("No volumes listed in multi-volume file", url); VolumeCollection* volumeCollection = new VolumeCollection(); std::string refFile = urlOrigin.getSearchParameter("file"); if (refFile == "") { // no particular file specified in URL => load all listed ones for (size_t i=0; i<origins.size(); i++) { VolumeBase* handle = read(origins.at(i)); if (handle) volumeCollection->add(handle); } } else { // load specified file for (size_t i=0; i<origins.size(); i++) { if (origins.at(i).getSearchParameter("file") == refFile) { VolumeBase* handle = read(origins.at(i)); if (handle) { volumeCollection->add(handle); break; } } } if (volumeCollection->empty()) { delete volumeCollection; throw tgt::FileException("File '" + refFile + "' not listed in multi-volume file", urlOrigin.getPath()); } } return volumeCollection; }
void VolumeCollectionModalityFilter::adjustFilteredCollection() { VolumeCollection* collection = inport_.getData(); if ((collection == 0) || (collection->empty() == true)) { filteredCollection_.clear(); outport_.setData(0); return; } if (currentModality_.getName() != modalityProp_.get()) { currentModality_ = *(modalityProp_.getValue()); filteredCollection_.clear(); if (currentModality_ != Modality::MODALITY_ANY) { for (size_t i = 0; i < collection->size(); ++i) { if (collection->at(i)->getModality() == currentModality_) filteredCollection_.add(collection->at(i)); } outport_.setData(&filteredCollection_); } else outport_.setData(inport_.getData()); } }
VolumeCollection* MRCVolumeReader::read(const std::string &url) throw (tgt::FileException, tgt::IOException, std::bad_alloc) { VolumeCollection* volumeCollection = new VolumeCollection(); VolumeURL origin(url); std::string fileName = origin.getPath(); LINFO(fileName); std::ifstream mrc; mrc.open(fileName.c_str(), std::ios::binary); if (!mrc.is_open()) { LWARNING("Can't open stream"); } else { int dim[3]; // grid dimensions i.e. numbers of voxels for each dimension mrc.read((char*)(&dim), sizeof(dim)); std::cout << "X: " << dim[0] << std::endl; // number of columns (fastest changing in map) std::cout << "Y: " << dim[1] << std::endl; // number of rows std::cout << "Z: " << dim[2] << std::endl; // number of sections (slowest changing in map) int numVoxels = dim[0] * dim[1] * dim[2]; // total number of voxels in volume std::cout << "numVoxels: " << numVoxels << std::endl; int dataType; // see below mrc.read((char*)(&dataType), sizeof(dataType)); std::cout << "dataType: " << dataType << std::endl; int dataSize = 0; // i.e. 8-bit, 16-bit or 32-bit if (dataType == 0) dataSize = 1; // signed 8-bit bytes range -128 to 127 else if (dataType == 1) dataSize = 2; // 16-bit halfwords else if (dataType == 2) dataSize = 4; // 32-bit reals else if (dataType == 6) dataSize = 2; // unsigned 16-bit range 0 to 65535 tgtAssert(dataSize, "Datasize is 0 at MRCVolumeReader::read()"); int totalDataSize = dataSize * numVoxels; int start[3]; // numbers of first columns i.e. offset of the volume origin in voxel coordinates mrc.read((char*)(&start), sizeof(start)); std::cout << "startX: " << start[0] << std::endl; // number of columns (fastest changing in map) std::cout << "startY: " << start[1] << std::endl; // number of rows std::cout << "startZ: " << start[2] << std::endl; // number of sections (slowest changing in map) int gridSize[3]; mrc.read((char*)(&gridSize), sizeof(gridSize)); std::cout << "gridSizeX: " << gridSize[0] << std::endl; std::cout << "gridSizeY: " << gridSize[1] << std::endl; std::cout << "gridSizeZ: " << gridSize[2] << std::endl; float cellDimensions[3]; // cell dimensions in angstroms mrc.read((char*)(&cellDimensions), sizeof(cellDimensions)); std::cout << "cellX: " << cellDimensions[0] << std::endl; std::cout << "cellY: " << cellDimensions[1] << std::endl; std::cout << "cellZ: " << cellDimensions[2] << std::endl; float scale[3]; // pixelSpacing i.e. scale from voxel to real-word coordinates scale[0] = cellDimensions[0] / gridSize[0]; scale[1] = cellDimensions[1] / gridSize[1]; scale[2] = cellDimensions[2] / gridSize[2]; std::cout << "pixelSpacingX: " << scale[0] << std::endl; std::cout << "pixelSpacingY: " << scale[1] << std::endl; std::cout << "pixelSpacingZ: " << scale[2] << std::endl; float angles[3]; // cell angles in degrees mrc.read((char*)(&angles), sizeof(angles)); std::cout << "cellAngleX: " << angles[0] << std::endl; std::cout << "cellAngleY: " << angles[1] << std::endl; std::cout << "cellAngleZ: " << angles[2] << std::endl; int axes[3]; // Which axis corresponds to columns, rows and sections (1,2,3 for X,Y,Z) mrc.read((char*)(&axes), sizeof(axes)); std::cout << "axesX: " << axes[0] << std::endl; std::cout << "axesY: " << axes[1] << std::endl; std::cout << "axesZ: " << axes[2] << std::endl; float origin[3]; mrc.seekg(4*49, std::ios::beg); mrc.read((char*)(&origin), sizeof(origin)); std::cout << "originX: " << origin[0] << std::endl; std::cout << "originY: " << origin[1] << std::endl; std::cout << "originZ: " << origin[2] << std::endl; void* data = malloc(totalDataSize); mrc.seekg(1024, std::ios::beg); mrc.read((char*)data, totalDataSize); mrc.close(); VolumeRAM* targetDataset; int a = axes[0]-1; int b = axes[1]-1; int c = axes[2]-1; /**/ if (dataType == 0) { targetDataset = new VolumeAtomic<int8_t>(ivec3(dim[a], dim[b], dim[c])); fillVolume<int8_t>(targetDataset, data, dim, axes); } else if (dataType == 1) { targetDataset = new VolumeAtomic<int16_t>(ivec3(dim[a], dim[b], dim[c])); fillVolume<int16_t>(targetDataset, data, dim, axes); } else if (dataType == 2) { targetDataset = new VolumeAtomic<float>(ivec3(dim[a], dim[b], dim[c])); fillVolume<float>(targetDataset, data, dim, axes); } else if (dataType == 6) { targetDataset = new VolumeAtomic<uint16_t>(ivec3(dim[a], dim[b], dim[c])); fillVolume<uint16_t>(targetDataset, data, dim, axes); } else LERROR("Unsupported data type at MRCVolumeReader::read()"); free(data); angles[0] *= (PI / 180.); angles[1] *= (PI / 180.); angles[2] *= (PI / 180.); float row[3][3]; // X row[0][0] = 1; row[0][1] = 0; row[0][2] = 0; // Y row[1][0] = cos(angles[2]); // cos(gamma) row[1][1] = sin(angles[2]); // sin(gamma) row[1][2] = 0; // Z row[2][0] = cos(angles[1]); // cos(beta) row[2][1] = (cos(angles[0]) - row[2][0] * row[1][0]) / row[1][1]; // [cos(alpha) - cos(beta)*cos(gamma)] / sin(gamma) row[2][2] = sqrt(1 - row[2][0] * row[2][0] - row[2][1] * row[2][1]); // squared length is 1 tgt::Matrix4<float> transform ( row[0][0], row[1][0], row[2][0], 0, row[0][1], row[1][1], row[2][1], 0, row[0][2], row[1][2], row[2][2], 0, 0.0f, 0.0f, 0.0f, 1.0f ); Volume* volumeHandle = new MoleculeVolume( targetDataset, // data vec3(scale[a], scale[b], scale[c]), // scale vec3(start[a]*scale[a], start[b]*scale[b], start[c]*scale[c]), // offset transform // transform ); volumeCollection->add(volumeHandle); } if (!volumeCollection->empty()) volumeCollection->first()->setOrigin(VolumeURL(fileName)); return volumeCollection; }
VolumeCollection* FlowReader::read(const std::string& url) throw(tgt::FileException, std::bad_alloc) { VolumeOrigin origin(url); std::string fileName = origin.getPath(); LINFO("reading flow file '" << fileName << "'..."); // try to open the file // std::fstream ifs(fileName.c_str(), std::ios_base::in | std::ios_base::binary); if (ifs.good() == false) throw tgt::IOException("Unable to open flow file for reading", fileName); // read the magic number (string "VOREENFLOW") // char magicNumber[11] = {0}; ifs.read(magicNumber, 11); std::string temp(magicNumber); if (temp != "VOREENFLOW") throw tgt::IOException("Missing magic number in flow file", fileName); // read file version (must currently be 1 or 2) // unsigned int fileVersion = 0; ifs.read(reinterpret_cast<char*>(&fileVersion), sizeof(unsigned int)); LINFO("file version: " << fileVersion); if ((fileVersion < 1) || (fileVersion > 2)) throw tgt::IOException("Unsupported file version of flow file", fileName); // read flow dimension (usually 3 for 3D flows) // unsigned int flowDimension = 0; ifs.read(reinterpret_cast<char*>(&flowDimension), sizeof(unsigned int)); LINFO("flow dimension: " << flowDimension << "D"); if (flowDimension != 3) throw tgt::IOException("Unsupported flow dimension in flow file", fileName); unsigned char dataOrientation = 0; unsigned char reverseSlicesMask = 0; ifs.read(reinterpret_cast<char*>(&dataOrientation), sizeof(unsigned char)); if (fileVersion > 1) { ifs.read(reinterpret_cast<char*>(&reverseSlicesMask), sizeof(unsigned char)); } // read the dimension of the volume data containing the flow // tgt::ivec3 dimensions; ifs.read(reinterpret_cast<char*>(&dimensions), sizeof(tgt::ivec3)); LINFO("volume dimensions: " << dimensions); unsigned int byteSize = 0; ifs.read(reinterpret_cast<char*>(&byteSize), sizeof(unsigned int)); LINFO("expected size of vector field: " << byteSize << " byte"); VolumeFlow3D* volume = readConvert(dimensions, dataOrientation, ifs); ifs.close(); if (volume == 0) { LERROR("an error occured during reading flow data! Proceeding impossible."); return 0; } if (reverseSlicesMask != 0) reverseSlices(volume, reverseSlicesMask); // TODO: volume container merge /*VolumeSet* volumeSet = new VolumeSet(fileName); VolumeSeries* volumeSeries = new VolumeSeries(Modality::MODALITY_FLOW.getName(), Modality::MODALITY_FLOW); volumeSet->addSeries(volumeSeries); VolumeHandle* volumeHandle = new VolumeHandle(volume, 0.0f); volumeSeries->addVolumeHandle(volumeHandle); */ VolumeCollection* collection = new VolumeCollection(); VolumeHandle* volumeHandle = new VolumeHandle(volume, tgt::vec3(1.0f), tgt::vec3(0.0f));//FIXME: spacing? oldVolumePosition(volumeHandle); volumeHandle->setModality(Modality::MODALITY_FLOW); collection->add(volumeHandle); // TODO: origin does not save series and timestamp anymore //volumeHandle->setOrigin(fileName, Modality::MODALITY_FLOW.getName(), 0.0f); volumeHandle->setOrigin(fileName); return collection; }
void VolumeCollectionTester::Test ( Tcl_Interp* iInterp ) { stringstream ssError; try { string fnMRI = "test_data/bertT1.mgz"; VolumeCollection* vol = new VolumeCollection(); vol->SetFileName( fnMRI ); MRI* mri = const_cast<MRI*>(vol->GetMRI()); Assert( (vol->GetTypeDescription() == "Volume"), "GetTypeDescription didn't return Volume" ); DataManager dataMgr = DataManager::GetManager(); MRILoader mriLoader = dataMgr.GetMRILoader(); Assert( 1 == mriLoader.CountLoaded(), "CountLoaded didn't return 1" ); Assert( 1 == mriLoader.CountReferences(mri), "CountReferences didn't return 1" ); char* fnMRIC = strdup( fnMRI.c_str() ); MRI* mriComp = MRIread( fnMRIC ); Assert( (MRImatch( mriComp, mri )), "MRImatch failed for load" ); MRIfree( &mriComp ); // Save it in /tmp, load it, and match it again. string fnSave( "/tmp/test.mgz" ); vol->Save( fnSave ); VolumeCollection* testVol = new VolumeCollection(); testVol->SetFileName( fnSave ); MRI* testMri = const_cast<MRI*>(testVol->GetMRI()); Assert( (MRImatch( testMri, mri )), "MRImatch failed for load after save"); // Make an ROI and make sure it's a volume ROI. try { int roiID = vol->NewROI(); ScubaROIVolume* roi = dynamic_cast<ScubaROIVolume*>(&ScubaROI::FindByID( roiID )); roi = NULL; } catch (...) { throw( runtime_error("typecast failed for NewROI") ); } // Try our conversions. Point3<float> world; Point3<float> data; Point3<int> index; world.Set( -50, 0, -80 ); vol->RASToMRIIndex( world.xyz(), index.xyz() ); { stringstream ssError; ssError << "RASToMRIIndex failed. world " << world << " index " << index; Assert( (index.x() == 178 && index.y() == 208 && index.z() == 128), ssError.str() ); } // Set a transform that scales the volume up by 2x in the world. ScubaTransform dataTransform; dataTransform.SetMainTransform( 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1 ); vol->SetDataToWorldTransform( dataTransform.GetID() ); world.Set( -50, 0, -80 ); vol->RASToDataRAS( world.xyz(), data.xyz() ); { stringstream ssError; ssError << "RASToDataRAS failed. world " << world << " data " << data; Assert( ((FEQUAL(data.x(),-25)) && (FEQUAL(data.y(),0)) && (FEQUAL(data.z(),-40))), ssError.str() ); } vol->RASToMRIIndex( world.xyz(), index.xyz() ); if ( index.x() != 153 || index.y() != 168 || index.z() != 128 ) { cerr << "RASToMRIIndex with data transform failed. world " << world << " index " << index << endl; throw( runtime_error( "failed" ) ); } world.Set( -50, 0, -80 ); VolumeLocation loc( vol->MakeVolumeLocationFromRAS( world.xyz() ) ); if ( !vol->IsInBounds( loc ) ) { stringstream ssError; ssError << "IsInBounds failed. world " << world; throw( runtime_error( ssError.str() ) ); } world.Set( -1000, 0, 0 ); VolumeLocation loc2( vol->MakeVolumeLocationFromRAS( world.xyz() ) ); if ( vol->IsInBounds( loc2 ) ) { stringstream ssError; ssError << "IsInBounds failed. world " << world; throw( runtime_error( ssError.str() ) ); } dataTransform.SetMainTransform( 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1 ); vol->SetDataToWorldTransform( dataTransform.GetID() ); world.Set( 0, -1000, -254 ); VolumeLocation loc3( vol->MakeVolumeLocationFromRAS( world.xyz() ) ); if ( vol->IsInBounds( loc3 ) ) { stringstream ssError; vol->RASToMRIIndex( world.xyz(), index.xyz() ); ssError << "IsRASInMRIBounds failed. world " << world << " index " << index; throw( runtime_error( ssError.str() ) ); } { // Create a new one from template. VolumeCollection* vol2 = new VolumeCollection(); vol2->MakeUsingTemplate( vol->GetID(), -1 ); Assert( (vol->mVoxelSize[0] == vol2->mVoxelSize[0] && vol->mVoxelSize[1] == vol2->mVoxelSize[1] && vol->mVoxelSize[2] == vol2->mVoxelSize[2]), "NewUsingTemplate failed, vol2 didn't match vol's voxelsize" ); Assert( (vol->GetDataType() == vol2->GetDataType()), "NewUsingTemplate(-1) failed, vol2 didn't match vol's data type" ); delete vol2; } { VolumeCollection* vol2 = new VolumeCollection(); vol2->MakeUsingTemplate( vol->GetID(), MRI_FLOAT ); Assert( (vol->mVoxelSize[0] == vol2->mVoxelSize[0] && vol->mVoxelSize[1] == vol2->mVoxelSize[1] && vol->mVoxelSize[2] == vol2->mVoxelSize[2]), "NewUsingTemplate failed, vol2 didn't match vol's voxelsize" ); Assert( (MRI_FLOAT == vol2->GetDataType()), "NewUsingTemplate(float) failed, vol2 wasn't a float" ); int idx[3] = { 0, 0, 0 }; VolumeLocation loc( vol2->MakeVolumeLocationFromIndex( idx ) ); vol2->SetMRIValue( loc, 0.6789 ); float value = vol2->GetMRINearestValue(loc); stringstream ssError; ssError << "NewUsingTemplate(float) failed value comparison, " << "was expecting 0.6789 but got " << value; Assert( (fabs(0.6789 - value) < 0.00001), ssError.str() ); delete vol2; } { VolumeCollection* vol2 = NULL; try { vol2 = new VolumeCollection(); vol2->MakeUsingTemplate( vol->GetID(), 10000 ); throw runtime_error( "MakeUsingTemplate(10000) didn't throw an error"); } catch(...) {} delete vol2; } dataTransform.SetMainTransform( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); vol->SetDataToWorldTransform( dataTransform.GetID() ); // FindRASPointsInSquare { Point3<float> sqRAS[4], cRAS; sqRAS[0].Set( 0, -3, 71 ); sqRAS[1].Set( 0, 1, 71 ); sqRAS[2].Set( 0, 1, 67 ); sqRAS[3].Set( 0, -3, 67 ); cRAS.Set( 0, -1, 69 ); list<Point3<float> > points; vol->FindRASPointsInSquare( cRAS.xyz(), sqRAS[0].xyz(), sqRAS[1].xyz(), sqRAS[2].xyz(), sqRAS[3].xyz(), 0, points ); list<Point3<float> >::iterator tPoint; for ( tPoint = points.begin(); tPoint != points.end(); ++tPoint ) { Point3<float> pRAS = *tPoint; stringstream ssMsg; ssMsg << "Failed: " << pRAS << " outside of square"; Assert( ( pRAS[0] == 0 && (pRAS[1] >= -3 && pRAS[1] <= 1) && (pRAS[2] >= 67 && pRAS[2] <= 71) ), ssMsg.str() ); } } // VoxelIntersectsSegment { Point3<int> idx; Point3<float> segIdxA, segIdxB; Point3<float> intIdx; idx.Set( 5, 5, 5 ); float aSegments[6][3] = { {3, 5.5, 5.5}, {6, 5.5, 5.5}, {5.5, 3, 5.5}, {5.5, 6, 5.5}, {5.5, 5.5, 3}, {5.5, 5.5, 6} }; for ( int nSegment = 0; nSegment < 6; nSegment += 2 ) { segIdxA.Set( aSegments[nSegment] ); segIdxB.Set( aSegments[nSegment+1] ); VectorOps::IntersectionResult rInt = vol->VoxelIntersectsSegment( idx, segIdxA, segIdxB, intIdx ); if ( VectorOps::intersect != rInt ) { cerr << "Failed VoxelIntersectsSegment test: idx " << idx << ", seg " << segIdxA << ", " << segIdxB << endl << "\tDidn't intersect" << endl; throw runtime_error("failed"); } } segIdxA.Set( 0, 5.5, 5.5 ); segIdxB.Set( 4, 5.5, 5.5 ); VectorOps::IntersectionResult rInt = vol->VoxelIntersectsSegment( idx, segIdxA, segIdxB, intIdx ); if ( VectorOps::dontIntersect != rInt ) { cerr << "Failed VoxelIntersectsSegment test: idx " << idx << ", seg " << segIdxA << ", " << segIdxB << endl << "\tIntersected" << endl; throw runtime_error("failed"); } } // FindRASPointsOnSegment { } // GetVoxelsWithValue { // This is a 5cubed volume whose values are set to the x // coordinate. So for x=3,y=0..4,z=0..4, value = 3. string fnVol = "test_data/testVolumeCollection-GetVoxelsWithValue.mgh"; ifstream fVol( fnMRI.c_str(), ios::in ); if ( !fVol ) { throw runtime_error("Couldn't find necessary test data."); } fVol.close(); VolumeCollection* vol = new VolumeCollection(); vol->SetFileName( fnVol ); vol->LoadVolume(); // Get the values 0-4 and make sure we got the right voxels. for ( int nStructure = 0; nStructure < 5; nStructure++ ) { list<VolumeLocation> lLocations; vol->GetVoxelsWithValue( nStructure, lLocations ); Volume3<bool> bGot( 5, 5, 5, false ); list<VolumeLocation>::iterator tLocation; for ( tLocation = lLocations.begin(); tLocation != lLocations.end(); ++tLocation ) { VolumeLocation loc = *(tLocation); bGot.Set( loc.Index()[0], loc.Index()[1], loc.Index()[2], true ); } for ( int nZ = 0; nZ < 5; nZ++ ) { for ( int nY = 0; nY < 5; nY++ ) { for ( int nX = 0; nX < 5; nX++ ) { if ( nX == nStructure && !bGot.Get( nX, nY, nZ ) ) { stringstream ssErr; ssErr << "Failed GetVoxelsWithValue test: " << " nStructure = " << nStructure << " index " << Point3<int>(nX,nY,nZ) << " - was supposed to get voxel but didn't"; throw runtime_error(ssErr.str()); } if ( nX != nStructure && bGot.Get( nX, nY, nZ ) ) { stringstream ssErr; ssErr << "Failed GetVoxelsWithValue test: " << " nStructure = " << nStructure << " index " << Point3<int>(nX,nY,nZ) << " - wasn't supposed to get voxel but did"; throw runtime_error(ssErr.str()); } } } } } delete vol; } // GetAverageValue { // We'll use the same volume as with GetVoxelsWithValue. string fnVol = "test_data/testVolumeCollection-GetVoxelsWithValue.mgh"; ifstream fVol( fnMRI.c_str(), ios::in ); if ( !fVol ) { throw runtime_error("Couldn't find necessary test data."); } fVol.close(); VolumeCollection* vol = new VolumeCollection(); vol->SetFileName( fnVol ); vol->LoadVolume(); // Get values of all voxels in plane x=3 and make sure it's 3. list<VolumeLocation> lVoxels; for ( int nZ = 0; nZ < 5; nZ++ ) { for ( int nY = 0; nY < 5; nY++ ) { int index[3] = { 3, nY, nZ }; VolumeLocation loc( vol->MakeVolumeLocationFromIndex( index ) ); lVoxels.push_back( loc ); } } float average = vol->GetAverageValue( lVoxels ); if ( average != 3.0 ) { stringstream ssErr; ssErr << "Failed GetAverageValue: Getting all voxels in x=3, " << "average should have been 3, but was " << average; throw runtime_error( ssErr.str() ); } // Get values of 5 voxels, one from each x plane // (val=0,1,2,3,4), and make sure it's 2. lVoxels.clear(); for ( int nX = 0; nX < 5; nX++ ) { int index[3] = { nX, 3, 3 }; VolumeLocation loc( vol->MakeVolumeLocationFromIndex( index ) ); lVoxels.push_back( loc ); } average = vol->GetAverageValue( lVoxels ); if ( average != 2.0 ) { stringstream ssErr; ssErr << "Failed GetAverageValue: Getting voxels in different planes, " << "average should have been 2, but was " << average; throw runtime_error( ssErr.str() ); } // Make sure we get an error for no voxels. lVoxels.clear(); bool bDidntThrow = false; try { average = vol->GetAverageValue( lVoxels ); bDidntThrow = true; } catch ( exception& e ) {} if ( bDidntThrow ) { stringstream ssErr; ssErr << "Failed GetAverageValue: Didn't throw with empty list"; throw runtime_error( ssErr.str() ); } delete vol; } // Check the tcl commands. char sCommand[1024]; int rTcl; int id = vol->GetID(); string fnTest = "test-name"; sprintf( sCommand, "SetVolumeCollectionFileName %d test-name", id ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); Assert( (vol->mfnMRI == fnTest), "Setting file name via tcl didn't work" ); vol->SetDataToWorldTransform( 0 ); delete vol; delete testVol; } catch ( exception& e ) { cerr << "failed with exception: " << e.what() << endl; exit( 1 ); } catch (...) { cerr << "failed." << endl; exit( 1 ); } }
void SegmentationVolumeReportTester::Test ( Tcl_Interp* iInterp ) { try { // Load our seg volume. string fnSegVolume = "test_data/testSegmentationVolumeReportData-Seg.mgz"; VolumeCollection seg; seg.SetFileName( fnSegVolume ); seg.LoadVolume(); seg.SetLabel( "Seg" ); // Load our intensity volume. string fnIntVolume = "test_data/testSegmentationVolumeReportData-Int.mgz"; VolumeCollection vol; vol.SetFileName( fnIntVolume ); vol.LoadVolume(); vol.SetLabel( "Int" ); // Load our LUT. string fnLUT = "test_data/TestLUT.txt"; ScubaColorLUT lut; lut.UseFile( fnLUT ); // Set up the report. SegmentationVolumeReport& report = SegmentationVolumeReport::GetReport(); report.SetSegmentation( seg ); if ( NULL == report.mSegVol ) { stringstream ssError; ssError << "Error on SetSegmentation, mSegVol was NULL"; throw runtime_error( ssError.str() ); } if ( report.mSegVol->GetID() != seg.GetID() ) { stringstream ssError; ssError << "Error on SetSegmentation, mSegVol was the wrong volume (should be ID " << seg.GetID() << " but was " << report.mSegVol->GetID(); throw runtime_error( ssError.str() ); } report.DontUseROI(); if ( report.mbUseROI ) { stringstream ssError; ssError << "Error on DontUseROI, mbUseROI was true"; throw runtime_error( ssError.str() ); } report.SetColorLUT( lut ); if ( NULL == report.mLUT ) { stringstream ssError; ssError << "Error on SetColorLUT, mROI was NULL"; throw runtime_error( ssError.str() ); } if ( report.mLUT->GetID() != lut.GetID() ) { stringstream ssError; ssError << "Error on SetColorLUT, id didn't match"; throw runtime_error( ssError.str() ); } // Add 1-5 but not 3. report.AddSegmentationStructure( 1 ); report.AddSegmentationStructure( 2 ); report.AddSegmentationStructure( 4 ); report.AddSegmentationStructure( 5 ); map<int,bool> structureMap; list<int>::iterator tStructure; for ( tStructure = report.mlStructures.begin(); tStructure != report.mlStructures.end(); ++tStructure ) { int nStructure = *tStructure; if ( nStructure != 1 && nStructure != 2 && nStructure != 4 && nStructure != 5 ) { stringstream ssError; ssError << "Error on AddSegmentationStructure, added an unknown structure " << nStructure; throw runtime_error( ssError.str() ); } structureMap[nStructure] = true; } if ( !(structureMap[1] && structureMap[2] && structureMap[4] && structureMap[5]) ) { stringstream ssError; ssError << "Error in AddSegmentationStructure, didn't add all structures"; throw runtime_error( ssError.str() ); } // Test handling of undefined structures. report.AddSegmentationStructure( 200 ); // Add the intensity volume. Also add the seg vol as an additional // intensity volume. report.AddIntensityVolume( vol ); report.AddIntensityVolume( seg ); map<int,bool> volsLoadedMap; list<VolumeCollection*>::iterator tVolume; for ( tVolume = report.mlIntVols.begin(); tVolume != report.mlIntVols.end(); ++tVolume ) { VolumeCollection* testVol = *tVolume; int volID = testVol->GetID(); if ( volID != vol.GetID() && volID != seg.GetID() ) { stringstream ssError; ssError << "Error in AddIntensityVolume, added a volume with an unknown id " << volID; throw runtime_error( ssError.str() ); } volsLoadedMap[volID] = true; } if ( !(volsLoadedMap[vol.GetID()] && volsLoadedMap[seg.GetID()]) ) { stringstream ssError; ssError << "Error in AddIntensityVolume, didn't add both volumes"; throw runtime_error( ssError.str() ); } report.MakeVolumeReport(); for ( int nStructure = 1; nStructure <= 5; nStructure++ ) { // Check the number of voxels we got. float expectedSize; if ( nStructure == 3 ) { expectedSize = 0; } else { expectedSize = 25 * 25; } if ( report.mStructureToVolumeMap[nStructure] != expectedSize ) { stringstream ssError; ssError << "Error on report for seg " << nStructure << ": expectedSize was " << expectedSize << ", but got " << report.mStructureToVolumeMap[nStructure]; throw runtime_error( ssError.str() ); } // Check the intensity values (for the vol, should be 2x the // segmentation index, and for the seg, should be ==). float expectedIntensityAverage; if ( nStructure == 3 ) { expectedIntensityAverage = 0; } else { expectedIntensityAverage = nStructure * 2.0; } if ( report.mVolumeToIntensityAverageMap[&vol][nStructure] != expectedIntensityAverage ) { stringstream ssError; ssError << "Error on report for seg " << nStructure << ": expectedIntensityAverage for intensity vol " << &vol << " was " << expectedIntensityAverage << ", but got " << report.mVolumeToIntensityAverageMap[&vol][nStructure]; throw runtime_error( ssError.str() ); } if ( nStructure == 3 ) { expectedIntensityAverage = 0; } else { expectedIntensityAverage = nStructure; } if ( report.mVolumeToIntensityAverageMap[&seg][nStructure] != expectedIntensityAverage ) { stringstream ssError; ssError << "Error on report for seg " << nStructure << ": expectedIntensityAverage for seg vol " << &seg << " was " << expectedIntensityAverage << ", but got " << report.mVolumeToIntensityAverageMap[&seg][nStructure]; throw runtime_error( ssError.str() ); } } // Make the report. report.MakeVolumeReport( "/tmp/testReport.txt" ); // Compare it with the correct one. int rDiff = system( "diff /tmp/testReport.txt testSegmentationVolumeReport-correct.txt" ); if ( rDiff != 0 ) { throw runtime_error( "diff failed on testReport" ); } // Make the report. report.MakeIntensityReport( "/tmp/testIntReport.txt" ); // Compare it with the correct one. rDiff = system( "diff /tmp/testIntReport.txt testSegmentationVolumeReportIntReport-correct.txt" ); if ( rDiff != 0 ) { throw runtime_error( "diff failed on testIntReport" ); } // Test the tcl functions now. Just call them all and check the // results. Need to clear the report first. report.Clear(); if ( NULL != report.mSegVol || report.mlIntVols.size() != 0 || report.mbUseROI || NULL != report.mROIVol || NULL != report.mROI || NULL != report.mLUT || report.mlStructures.size() != 0 || !report.mbReportDirty || report.mVolumeToIntensityAverageMap.size() != 0 || report.mStructureToVolumeVoxelListMap.size() != 0 ) { stringstream ssError; ssError << "Error on Clear: not cleared"; throw runtime_error( ssError.str() ); } char sCommand[1024]; int rTcl; sprintf( sCommand, "SetSegVolReportSegmentation %d", seg.GetID() ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); if ( NULL == report.mSegVol ) { stringstream ssError; ssError << "Error on Tcl SetSegVolReportSegmentation, mSegVol was NULL"; throw runtime_error( ssError.str() ); } if ( report.mSegVol->GetID() != seg.GetID() ) { stringstream ssError; ssError << "Error on Tcl SetSegVolReportSegmentation, mSegVol was the wrong volume (should be ID " << seg.GetID() << " but was " << report.mSegVol->GetID(); throw runtime_error( ssError.str() ); } sprintf( sCommand, "AddSegVolReportIntensityVolume %d", vol.GetID() ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); sprintf( sCommand, "AddSegVolReportIntensityVolume %d", seg.GetID() ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); volsLoadedMap.clear(); for ( tVolume = report.mlIntVols.begin(); tVolume != report.mlIntVols.end(); ++tVolume ) { VolumeCollection* testVol = *tVolume; int volID = testVol->GetID(); if ( volID != vol.GetID() && volID != seg.GetID() ) { stringstream ssError; ssError << "Error in Tcl AddSegVolReportIntensityVolume, added a volume with an unknown id " << volID; throw runtime_error( ssError.str() ); } volsLoadedMap[volID] = true; } if ( !(volsLoadedMap[vol.GetID()] && volsLoadedMap[seg.GetID()]) ) { stringstream ssError; ssError << "Error in Tcl AddSegVolReportIntensityVolume, didn't add both volumes"; throw runtime_error( ssError.str() ); } sprintf( sCommand, "AddSegmentationToSegVolReport 1" ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); sprintf( sCommand, "AddSegmentationToSegVolReport 2" ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); sprintf( sCommand, "AddSegmentationToSegVolReport 4" ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); sprintf( sCommand, "AddSegmentationToSegVolReport 5" ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); structureMap.clear(); for ( tStructure = report.mlStructures.begin(); tStructure != report.mlStructures.end(); ++tStructure ) { int nStructure = *tStructure; if ( nStructure != 1 && nStructure != 2 && nStructure != 4 && nStructure != 5 ) { stringstream ssError; ssError << "Error on Tcl AddSegmentationToSegVolReport, added an unknown structure " << nStructure; throw runtime_error( ssError.str() ); } structureMap[nStructure] = true; } if ( !(structureMap[1] && structureMap[2] && structureMap[4] && structureMap[5]) ) { stringstream ssError; ssError << "Error in Tcl AddSegmentationToSegVolReport, didn't add all structures"; throw runtime_error( ssError.str() ); } report.AddSegmentationStructure( 200 ); sprintf( sCommand, "SetSegVolReportLUT %d", lut.GetID() ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); if ( NULL == report.mLUT ) { stringstream ssError; ssError << "Error on Tcl SetSegVolReportLUT, mLUT was NULL"; throw runtime_error( ssError.str() ); } if ( report.mLUT->GetID() != lut.GetID() ) { stringstream ssError; ssError << "Error on Tcl SetSegVolReportLUT, id didn't match"; throw runtime_error( ssError.str() ); } sprintf( sCommand, "MakeSegVolReport /tmp/testReport2.txt" ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); rDiff = system( "diff /tmp/testReport2.txt testSegmentationVolumeReport-correct.txt" ); if ( rDiff != 0 ) { throw runtime_error( "diff failed on testReport in Tcl MakeSegVolReport" ); } sprintf( sCommand, "MakeSegVolIntensityReport /tmp/testIntReport2.txt" ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); rDiff = system( "diff /tmp/testIntReport2.txt testSegmentationVolumeReportIntReport-correct.txt" ); if ( rDiff != 0 ) { throw runtime_error( "diff failed on testIntReport in Tcl MakeSegVolIntensityReport" ); } sprintf( sCommand, "ClearSegVolReport" ); rTcl = Tcl_Eval( iInterp, sCommand ); AssertTclOK( rTcl ); if ( NULL != report.mSegVol || report.mlIntVols.size() != 0 || report.mbUseROI || NULL != report.mROIVol || NULL != report.mROI || NULL != report.mLUT || report.mlStructures.size() != 0 || !report.mbReportDirty || report.mVolumeToIntensityAverageMap.size() != 0 || report.mStructureToVolumeVoxelListMap.size() != 0 ) { stringstream ssError; ssError << "Error on Tcl ClearSegVolReport: not cleared"; throw runtime_error( ssError.str() ); } } catch ( exception& e ) { cerr << "failed with exception: " << e.what() << endl; exit( 1 ); } catch (...) { cerr << "failed." << endl; exit( 1 ); } }
VolumeCollection* AnalyzeVolumeReader::readAnalyze(const std::string &fileName, int volId) throw (tgt::FileException, std::bad_alloc) { LINFO("Loading analyze file " << fileName); LINFO("Related img file: " << getRelatedImgFileName(fileName)); std::ifstream file(fileName.c_str(), std::ios::in | std::ios::binary); if(!file) { throw tgt::FileNotFoundException("Failed to open file: ", fileName); } file.seekg(0, std::ios::end); std::streamoff fileSize = file.tellg(); file.seekg(0, std::ios::beg); if(fileSize != 348) LWARNING("Filesize != 348"); header_key header; if (!file.read((char*)&header, sizeof(header))) { throw tgt::CorruptedFileException("Failed to read header!", fileName); } image_dimension dimension; if (!file.read((char*)&dimension, sizeof(dimension))) { throw tgt::CorruptedFileException("Failed to read dimensions!", fileName); } data_history history; if (!file.read((char*)&history, sizeof(history))) { throw tgt::CorruptedFileException("Failed to read history!", fileName); } bool bigEndian = false; //check if swap is necessary: if((dimension.dim[0] < 0) || (dimension.dim[0] > 15)) { bigEndian = true; header.swapEndianess(); dimension.swapEndianess(); history.swapEndianess(); } ivec3 dimensions; dimensions.x = dimension.dim[1]; dimensions.y = dimension.dim[2]; dimensions.z = dimension.dim[3]; LINFO("Resolution: " << dimensions); int numVolumes = dimension.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 = dimension.pixdim[1]; spacing.y = dimension.pixdim[2]; spacing.z = dimension.pixdim[3]; LINFO("Spacing: " << spacing); LINFO("Datatype: " << dimension.datatype); std::string voreenVoxelType; switch(dimension.datatype) { case DT_UNSIGNED_CHAR: voreenVoxelType = "uint8"; break; case DT_SIGNED_SHORT: voreenVoxelType = "int16"; break; case DT_SIGNED_INT: voreenVoxelType = "int32"; break; case DT_FLOAT: voreenVoxelType = "float"; break; case DT_DOUBLE: voreenVoxelType = "double"; break; case DT_RGB: voreenVoxelType = "Vector3(uint8)"; break; case DT_ALL: case DT_COMPLEX: case 0: //DT_NONE/DT_UNKNOWN case DT_BINARY: default: throw tgt::UnsupportedFormatException("Unsupported datatype!"); } std::string objectType; std::string gridType; int start = 0; int stop = numVolumes; if(volId != -1) { //we want to load a single volume: start = volId; stop = start + 1; } // Nifti transformations give us the center of the first voxel, we translate to correct: mat4 pToW = mat4::createTranslation(-spacing * 0.5f); VolumeCollection* vc = new VolumeCollection(); size_t volSize = hmul(tgt::svec3(dimensions)) * (dimension.bitpix / 8); for(int i=start; i<stop; i++) { VolumeRepresentation* volume = new VolumeDisk(getRelatedImgFileName(fileName), voreenVoxelType, dimensions, i * volSize, bigEndian); Volume* vh = new Volume(volume, spacing, vec3(0.0f)); vh->setOrigin(VolumeURL(fileName)); vh->setPhysicalToWorldMatrix(pToW); VolumeURL origin(fileName); origin.addSearchParameter("volumeId", itos(i)); vh->setOrigin(origin); vc->add(vh); } 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; }
int main( int argc, char **argv ) { try { QApplication a( argc, argv ); string fnMRI = "/Users/kteich/work/subjects/bert/mri/orig"; char* sSubjectsDir = getenv("SUBJECTS_DIR"); if ( NULL != sSubjectsDir ) { fnMRI = string(sSubjectsDir) + "/bert/mri/orig"; } if ( argc == 2 ) { fnMRI = argv[1]; } VolumeCollection vol; vol.SetFileName( fnMRI ); MRI* mri = vol.GetMRI(); if ( NULL == mri ) exit( 1 ); QtVolumeHistogram* histogram; histogram = new QtVolumeHistogram( 0, (const char*) "QtVolumeHistogram" ); histogram->SetVolumeSource( &vol ); histogram->SetNumberOfBins( 255 ); histogram->SetMinIgnore( 0 ); histogram->SetMaxIgnore( 20 ); histogram->SetNumberOfMarkers( 4 ); histogram->SetMarkerColor( 0, Qt::red ); histogram->SetMarkerValue( 0, 10 ); histogram->SetMarkerColor( 1, Qt::green ); histogram->SetMarkerValue( 1, 30 ); histogram->SetMarkerColor( 2, Qt::blue ); histogram->SetMarkerValue( 2, 50 ); histogram->SetMarkerColor( 3, Qt::yellow ); histogram->SetMarkerValue( 3, 70 ); histogram->resize( 600, 200 ); a.setMainWidget( histogram ); histogram->show(); QApplication::setGlobalMouseTracking( true ); return a.exec(); } catch ( runtime_error& e ) { cerr << "failed with exception: " << e.what() << endl; exit( 1 ); } catch ( exception& e ) { cerr << "failed with exception: " << e.what() << endl; exit( 1 ); } catch (...) { cerr << "failed" << endl; exit( 1 ); } exit( 0 ); }
VolumeCollection* ITKVolumeReader::read(const std::string &url) throw (tgt::CorruptedFileException, tgt::IOException, std::bad_alloc) { VolumeURL origin(url); std::string fileName = origin.getPath(); LINFO("Reading file " << fileName); //Get OutputInformation of an arbitrary reader to find out pixel type etc: typedef itk::Image<char,3> TestImageType; // pixel type doesn't matter for current purpose typedef itk::ImageFileReader<TestImageType> TestFileReaderType; // reader for testing a file TestFileReaderType::Pointer onefileReader = TestFileReaderType::New(); onefileReader->SetFileName(fileName.c_str()); try { onefileReader->GenerateOutputInformation(); } catch(itk::ExceptionObject& excp) { throw tgt::CorruptedFileException("Failed to read OutputInformation! " + std::string(excp.GetDescription()), fileName); } // grab the ImageIO instance for the reader itk::ImageIOBase *imageIO = onefileReader->GetImageIO(); unsigned int NumberOfDimensions = imageIO->GetNumberOfDimensions(); LINFO("Number of Dimensions: " << NumberOfDimensions); if(NumberOfDimensions != 3) { throw tgt::UnsupportedFormatException("Unsupported number of dimensions!"); } // PixelType is SCALAR, RGB, RGBA, VECTOR, COVARIANTVECTOR, POINT, INDEX itk::ImageIOBase::IOPixelType pixelType = imageIO->GetPixelType(); LINFO("PixelType: " << imageIO->GetPixelTypeAsString(pixelType)); // IOComponentType is UCHAR, CHAR, USHORT, SHORT, UINT, INT, ULONG, LONG, FLOAT, DOUBLE itk::ImageIOBase::IOComponentType componentType = imageIO->GetComponentType(); LINFO("ComponentType: " << imageIO->GetComponentTypeAsString(componentType)); // NumberOfComponents is usually one, but for non-scalar pixel types, it can be anything unsigned int NumberOfComponents = imageIO->GetNumberOfComponents(); LINFO("Number of Components: " << NumberOfComponents); if(NumberOfComponents != 1) { throw tgt::UnsupportedFormatException("Unsupported number of components!"); } //-------Info we don't need here:--------------- //unsigned dims[32]; // almost always no more than 4 dims, but ... //unsigned origin[32]; double spacing[32]; //std::vector<double> directions[32]; for(unsigned i = 0; i < NumberOfDimensions && i < 32; i++) { //dims[i] = imageIO->GetDimensions(i); //origin[i] = imageIO->GetOrigin(i); spacing[i] = imageIO->GetSpacing(i); //directions[i] = imageIO->GetDirection(i); } Volume* dataset; switch(pixelType) { case itk::ImageIOBase::SCALAR: switch(componentType) { case itk::ImageIOBase::UCHAR: dataset = readScalarVolume<uint8_t>(fileName); break; case itk::ImageIOBase::CHAR: dataset = readScalarVolume<int8_t>(fileName); break; case itk::ImageIOBase::USHORT: dataset = readScalarVolume<uint16_t>(fileName); break; case itk::ImageIOBase::SHORT: dataset = readScalarVolume<int16_t>(fileName); break; case itk::ImageIOBase::UINT: dataset = readScalarVolume<uint32_t>(fileName); break; case itk::ImageIOBase::INT: dataset = readScalarVolume<int32_t>(fileName); break; #ifndef WIN32 case itk::ImageIOBase::ULONG: dataset = readScalarVolume<uint64_t>(fileName); break; case itk::ImageIOBase::LONG: dataset = readScalarVolume<int64_t>(fileName); break; #endif case itk::ImageIOBase::FLOAT: dataset = readScalarVolume<float>(fileName); break; case itk::ImageIOBase::DOUBLE: dataset = readScalarVolume<double>(fileName); break; default: throw tgt::UnsupportedFormatException("Unsupported component type!"); } break; case itk::ImageIOBase::RGB: case itk::ImageIOBase::RGBA: case itk::ImageIOBase::VECTOR: case itk::ImageIOBase::COVARIANTVECTOR: case itk::ImageIOBase::POINT: default: throw tgt::UnsupportedFormatException("Unsupported pixel type!"); return 0; } VolumeCollection* volumeCollection = new VolumeCollection(); dataset->setOrigin(fileName); volumeCollection->add(dataset); return volumeCollection; }
VolumeCollection* AnalyzeVolumeReader::readNifti(const std::string &fileName, bool standalone) 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); } //file.seekg(0, std::ios::end); //int fileSize = file.tellg(); //file.seekg(0, std::ios::beg); 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 hdr+img Nifti as standalone!"); standalone = false; } else throw tgt::CorruptedFileException("Not a Nifti header!", fileName); RawVolumeReader::ReadHints h; h.dimensions_.x = header.dim[1]; h.dimensions_.y = header.dim[2]; h.dimensions_.z = header.dim[3]; LINFO("Resolution: " << h.dimensions_); if (hor(lessThanEqual(h.dimensions_, ivec3(0)))) { LERROR("Invalid resolution or resolution not specified: " << h.dimensions_); throw tgt::CorruptedFileException("error while reading data", fileName); } h.spacing_.x = header.pixdim[1]; h.spacing_.y = header.pixdim[2]; h.spacing_.z = header.pixdim[3]; LINFO("Spacing: " << h.spacing_); LINFO("Datatype: " << header.datatype); //TODO: support more datatypes if(header.datatype > 128) { header.datatype -= 128; h.objectModel_ = "RGB"; } else h.objectModel_ = "I"; switch(header.datatype) { case DT_UNSIGNED_CHAR: h.format_ = "UCHAR"; h.objectModel_ = "I"; break; case DT_SIGNED_SHORT: h.format_ = "SHORT"; h.objectModel_ = "I"; break; case DT_SIGNED_INT: h.format_ = "INT"; h.objectModel_ = "I"; break; case DT_FLOAT: h.format_ = "FLOAT"; h.objectModel_ = "I"; break; case DT_DOUBLE: h.format_ = "DOUBLE"; h.objectModel_ = "I"; break; case DT_RGB: h.format_ = "UCHAR"; h.objectModel_ = "RGB"; break; case DT_RGBA32: /* 4 byte RGBA (32 bits/voxel) */ h.format_ = "UCHAR"; h.objectModel_ = "RGBA"; break; case DT_INT8: /* signed char (8 bits) */ h.format_ = "CHAR"; h.objectModel_ = "I"; break; case DT_UINT16: /* unsigned short (16 bits) */ h.format_ = "USHORT"; h.objectModel_ = "I"; break; case DT_UINT32: /* unsigned int (32 bits) */ h.format_ = "UINT"; h.objectModel_ = "I"; 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!"); } if (header.intent_code == IC_INTENT_SYMMATRIX) { h.objectModel_ = "TENSOR_FUSION_LOW"; } h.bigEndianByteOrder_ = bigEndian; //std::string objectType; //std::string gridType; //} else if (type == "ObjectType:") { //args >> objectType; //LDEBUG(type << " " << objectType); //} else if (type == "GridType:") { //args >> gridType; //LDEBUG(type << " " << gridType); //} else if (type == "BitsStored:") { //args >> h.bitsStored_; //LDEBUG(type << " " << h.bitsStored_); //} else if (type == "Unit:") { //args >> h.unit_; //LDEBUG(type << " " << h.unit_); if (standalone) h.headerskip_ = static_cast<uint16_t>(header.vox_offset); RawVolumeReader rawReader(getProgressBar()); rawReader.setReadHints(h); VolumeCollection* volumeCollection = 0; if(standalone) volumeCollection = rawReader.read(fileName); else volumeCollection = rawReader.read(getRelatedImgFileName(fileName)); if (!volumeCollection->empty()) { static_cast<VolumeHandle*>(volumeCollection->first())->setOrigin(VolumeOrigin(fileName)); oldVolumePosition(static_cast<VolumeHandle*>(volumeCollection->first())); } return volumeCollection; }
VolumeCollection* AnalyzeVolumeReader::readAnalyze(const std::string &fileName) throw (tgt::FileException, std::bad_alloc) { LWARNING("Loading analyze file " << fileName); LWARNING("Related img file: " << getRelatedImgFileName(fileName)); std::ifstream file(fileName.c_str(), std::ios::in | std::ios::binary); if(!file) { throw tgt::FileNotFoundException("Failed to open file: ", fileName); } file.seekg(0, std::ios::end); std::streamoff fileSize = file.tellg(); file.seekg(0, std::ios::beg); if(fileSize != 348) LWARNING("Filesize != 348"); header_key header; if (!file.read((char*)&header, sizeof(header))) { throw tgt::CorruptedFileException("Failed to read header!", fileName); } image_dimension dimension; if (!file.read((char*)&dimension, sizeof(dimension))) { throw tgt::CorruptedFileException("Failed to read dimensions!", fileName); } data_history history; if (!file.read((char*)&history, sizeof(history))) { throw tgt::CorruptedFileException("Failed to read history!", fileName); } bool bigEndian = false; //check if swap is necessary: if((dimension.dim[0] < 0) || (dimension.dim[0] > 15)) { bigEndian = true; header.swapEndianess(); dimension.swapEndianess(); history.swapEndianess(); } RawVolumeReader::ReadHints h; h.dimensions_.x = dimension.dim[1]; h.dimensions_.y = dimension.dim[2]; h.dimensions_.z = dimension.dim[3]; LINFO("Resolution: " << h.dimensions_); if (hor(lessThanEqual(h.dimensions_, ivec3(0)))) { LERROR("Invalid resolution or resolution not specified: " << h.dimensions_); throw tgt::CorruptedFileException("error while reading data", fileName); } h.spacing_.x = dimension.pixdim[1]; h.spacing_.y = dimension.pixdim[2]; h.spacing_.z = dimension.pixdim[3]; LINFO("Spacing: " << h.spacing_); LINFO("Datatype: " << dimension.datatype); switch(dimension.datatype) { case DT_UNSIGNED_CHAR: h.format_ = "UCHAR"; h.objectModel_ = "I"; break; case DT_SIGNED_SHORT: h.format_ = "SHORT"; h.objectModel_ = "I"; break; case DT_SIGNED_INT: h.format_ = "INT"; h.objectModel_ = "I"; break; case DT_FLOAT: h.format_ = "FLOAT"; h.objectModel_ = "I"; break; case DT_DOUBLE: h.format_ = "DOUBLE"; h.objectModel_ = "I"; break; case DT_RGB: h.format_ = "UCHAR"; h.objectModel_ = "RGB"; break; case DT_ALL: case DT_COMPLEX: case 0: //DT_NONE/DT_UNKNOWN case DT_BINARY: default: throw tgt::UnsupportedFormatException("Unsupported datatype!"); } h.bigEndianByteOrder_ = bigEndian; std::string objectType; std::string gridType; RawVolumeReader rawReader(getProgressBar()); rawReader.setReadHints(h); VolumeCollection* volumeCollection = rawReader.read(getRelatedImgFileName(fileName)); if (!volumeCollection->empty()) { static_cast<VolumeHandle*>(volumeCollection->first())->setOrigin(VolumeOrigin(fileName)); oldVolumePosition(static_cast<VolumeHandle*>(volumeCollection->first())); } return volumeCollection; }
VolumeCollection* PVMVolumeReader::read(const std::string &url) throw (tgt::FileException, tgt::IOException, std::bad_alloc) { VolumeOrigin origin(url); std::string fileName = origin.getPath(); uint8_t* data; uint8_t* tmpData; unsigned int width, height, depth, components; float scalex, scaley, scalez; unsigned char *description; unsigned char *courtesy; unsigned char *parameter; unsigned char *comment; LINFO("Reading PVM volume " << fileName); /* TODO This subroutine returns an array created with malloc but it should be created with 'new[]' because this chunk of data will be deleted with 'delete[]'. This can cause hard to find errors. As a temporary workaround the data are copied over into a new array and the c-array is deleted with 'free'. Because of some c-pointer vodoo done in ddsbase.cpp free must be invoked after the use of all other returned pointers. (roland) */ tmpData = readPVMvolume(const_cast<char*>(fileName.c_str()), getProgressBar(), &width, &height, &depth, &components, &scalex, &scaley, &scalez, &description, &courtesy, ¶meter, &comment); if (!tmpData) { LERROR("PVM Reading failed"); return 0; } data = new uint8_t[width * height * depth * components]; memcpy(data, tmpData, width * height * depth * components); Volume* dataset = 0; if (!data) { throw tgt::IOException(); } else { LINFO("Size: " << width << " x " << height << " x " << depth); LINFO("Spacing: " << scalex << " x " << scaley << " x " << scalez); LINFO("Components: " << components); if (description) LINFO("Description: " << description); if (courtesy) LINFO("Courtesy: " << courtesy); if (parameter) LINFO("Parameter: " << parameter); if (comment) LINFO("Comment: " << comment); if (components == 1) { LINFO("Create 8 bit data set."); dataset = new VolumeUInt8(data, tgt::ivec3(width, height, depth), tgt::vec3(scalex, scaley, scalez)); } else if (components == 2) { // the endianness conversion in ddsbase.cpp seem to be broken, // so we perform it here instead uint16_t* data16 = reinterpret_cast<uint16_t*>(data); int numElements = width * height * depth; uint16_t maxValue = 0; for (int i=0; i < numElements; i++) { endian_swap(data16[i]); if (data16[i] > maxValue) maxValue = data16[i]; } int bits; if (maxValue < 4096) { LINFO("Create 12 bit data set."); bits = 12; } else { LINFO("Create 16 bit data set."); bits = 16; } dataset = new VolumeUInt16((uint16_t*)data, tgt::ivec3(width, height, depth), tgt::vec3(scalex, scaley, scalez), tgt::mat4::identity, bits); } else LERROR("Bit depth not supported."); } // TODO now it is safe to free free(tmpData); VolumeCollection* volumeCollection = new VolumeCollection(); if (dataset) { VolumeHandle* volumeHandle = new VolumeHandle(dataset, 0.0f); volumeHandle->setOrigin(VolumeOrigin(fileName)); volumeCollection->add(volumeHandle); } return volumeCollection; }