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* 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 VolumeIOHelper::loadRawVolume(const std::string& filenameStd) { QString filename = QString::fromStdString(filenameStd); if (filename.isEmpty()) return; // query raw parameters via dialog std::string objectModel; std::string format; int numFrames; tgt::ivec3 dim; tgt::vec3 spacing; int headerSkip; bool bigEndian; tgt::mat4 trafoMat = tgt::mat4::identity; RawVolumeWidget* rawVW = new RawVolumeWidget(parent_, tr("Please enter the properties for <br><strong>") + filename + "</strong>", objectModel, format, numFrames, dim, spacing, headerSkip, bigEndian, trafoMat); if (!rawVW->exec() == QDialog::Accepted) return; // derive expected file size from provided properties uint formatBytes = 1;; if (format == "USHORT" || format == "USHORT_12" || format == "SHORT") formatBytes = 2; else if (format == "FLOAT") formatBytes = 4; else if (format == "UINT" || format == "INT") formatBytes = 4; int numChannels = 1; if (objectModel == "RGB") numChannels = 3; else if (objectModel == "RGBA") numChannels = 4; else if (objectModel.find("TENSOR_") == 0) numChannels = 6; uint rawSize = headerSkip + formatBytes * numChannels * (dim.x * dim.y * dim.z) * numFrames; // inform/query user, if file size does not match if (QFile(filename).size() != rawSize) { QMessageBox::StandardButton retButton = QMessageBox::Yes; if(QFile(filename).size() > rawSize) { QString msg = tr("The provided properties result in a size smaller\nthan the actual file size. Do you want to continue?"); retButton = QMessageBox::question(parent_, tr("Size mismatch"), msg, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); } else if (QFile(filename).size() < rawSize) { QString msg = tr("The provided properties result in a size\ngreater than the actual file size."); retButton = QMessageBox::warning(parent_, tr("Size mismatch"), msg, QMessageBox::Cancel); } if (retButton != QMessageBox::Yes && retButton != QMessageBox::Ok) return; } qApp->processEvents(); // load raw volume try { for (int frame=0; frame < numFrames; ++frame) { RawVolumeReader rawReader(progressBar_); rawReader.setReadHints(dim, spacing, objectModel, format, frame, headerSkip, bigEndian); VolumeList* collection = rawReader.read(filename.toStdString()); if (collection && !collection->empty()) { tgtAssert(collection->size() == 1, "More than one raw volume returned"); Volume* volumeHandle = static_cast<Volume*>(collection->first()); oldVolumePosition(volumeHandle); volumeHandle->setPhysicalToWorldMatrix(trafoMat); volumeHandle->setTimestep(static_cast<float>(frame)); emit(volumeLoaded(volumeHandle)); } delete collection; } } catch (const tgt::FileException& e) { LERROR(e.what()); QErrorMessage* errorMessageDialog = new QErrorMessage(VoreenApplicationQt::qtApp()->getMainWindow()); errorMessageDialog->showMessage(e.what()); } catch (std::bad_alloc&) { LERROR("bad allocation while reading file: " << filename.toStdString()); QErrorMessage* errorMessageDialog = new QErrorMessage(VoreenApplicationQt::qtApp()->getMainWindow()); errorMessageDialog->showMessage("Bad allocation while reading file: " + filename); } }
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* 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; }
VolumeList* AmiraMeshReader::readMetaFile(const std::string &fileName, size_t firstSlice, size_t lastSlice, int timeframe) throw (tgt::FileException, std::bad_alloc) { bool error = false; const char* FileName = fileName.c_str(); FILE* fp = fopen(FileName, "rb"); if (!fp) { LERROR("Could not find :" << FileName); error = true; goto K; } char buffer[2048]; fread(buffer, sizeof(char), 2047, fp); buffer[2047] = '\0'; //The following string routines prefer null-terminated strings if (!strstr(buffer, "# AmiraMesh BINARY-LITTLE-ENDIAN 2.1") && !strstr(buffer, "# AmiraMesh 3D BINARY 2.0")) { LERROR("Not a proper AmiraMesh file."); fclose(fp); error = true; goto K; } //Find the Lattice definition, i.e., the dimensions of the uniform grid int xDim(0), yDim(0), zDim(0); sscanf(FindAndJump(buffer, "define Lattice"), "%d %d %d", &xDim, &yDim, &zDim); LDEBUG("Grid Dimensions: " << xDim << " " << yDim << " " << zDim); //Find the BoundingBox float xmin(1.0f), ymin(1.0f), zmin(1.0f); float xmax(-1.0f), ymax(-1.0f), zmax(-1.0f); sscanf(FindAndJump(buffer, "BoundingBox"), "%g %g %g %g %g %g", &xmin, &xmax, &ymin, &ymax, &zmin, &zmax); LDEBUG("BoundingBox in x-Direction: [" << xmin << " " << xmax << "]"); LDEBUG("BoundingBox in x-Direction: [" << ymin << " " << ymax << "]"); LDEBUG("BoundingBox in x-Direction: [" << zmin << " " << zmax << "]"); //Is it a uniform grid? We need this only for the sanity check below. const bool bIsUniform = (strstr(buffer, "CoordType \"uniform\"") != NULL); LDEBUG("GridType: " << bIsUniform ? "uniform" : "UNKNOWN"); //Type of the field: scalar, vector int NumComponents(0); if (strstr(buffer, "Lattice { float Data }")) { //Scalar field NumComponents = 1; } else { //A field with more than one component, i.e., a vector field sscanf(FindAndJump(buffer, "Lattice { float["), "%d", &NumComponents); } LDEBUG("Number of Components: " << NumComponents); //Sanity check if (xDim <= 0 || yDim <= 0 || zDim <= 0 || xmin > xmax || ymin > ymax || zmin > zmax || !bIsUniform || NumComponents <= 0) { printf("Something went wrong\n"); fclose(fp); error = true; goto K; } K : RawVolumeReader::ReadHints h; std::string objectFilename = fileName; h.headerskip_ = strstr(buffer, "# Data section follows") - buffer; //Set the file pointer to the beginning of "# Data section follows" fseek(fp, h.headerskip_, SEEK_SET); //Consume this line, which is "# Data section follows" char buf1[2048]; fgets(buf1, 2047, fp); int l1 = strlen(buf1); //Consume the next line, which is "@1" char buf2[2048]; fgets(buf2, 2047, fp); int l2 = strlen(buf2); vec3 sliceThickness = vec3(1.f, 1.f, 1.f); int numFrames = NumComponents; h.dimensions_.x = xDim; h.dimensions_.y = yDim; h.dimensions_.z = zDim; h.format_ = "FLOAT"; h.objectModel_ = "I"; h.bigEndianByteOrder_ = false; h.headerskip_ += (l1 + l2); LDEBUG("Header size : " << h.headerskip_); if (hor(lessThanEqual(h.dimensions_, ivec3(0)))) { LERROR("Invalid resolution or resolution not specified: " << h.dimensions_); error = true; } h.spacing_ = sliceThickness; h.timeStep_ = 0; if (!error) { RawVolumeReader rawReader(getProgressBar()); // do we have a relative path? if ((objectFilename.substr(0, 1) != "/") && (objectFilename.substr(0, 1) != "\\") && (objectFilename.substr(1, 2) != ":/") && (objectFilename.substr(1, 2) != ":\\")) { size_t p = fileName.find_last_of("\\/"); // construct path relative to dat file objectFilename = fileName.substr(0, p + 1) + objectFilename; } int start = 0; int end = numFrames; if (timeframe != -1) { if (timeframe >= numFrames) throw tgt::FileException("Specified time frame not in volume", fileName); start = timeframe; end = timeframe+1; } VolumeList* toReturn = new VolumeList(); for (int frame = start; frame < end; ++frame) { h.timeframe_ = frame; rawReader.setReadHints(h); VolumeList* volumeList = rawReader.readSlices(objectFilename, firstSlice, lastSlice); if (!volumeList->empty()) { VolumeURL origin(fileName); origin.addSearchParameter("timeframe", itos(frame)); Volume* vh = static_cast<Volume*>(volumeList->first()); vh->setOrigin(origin); vh->setTimestep(static_cast<float>(frame)); oldVolumePosition(vh); if(!h.hash_.empty()) vh->setHash(h.hash_); toReturn->add(volumeList->first()); } delete volumeList; } return toReturn; } else { throw tgt::CorruptedFileException("error while reading data", fileName); } }