Commit ccace339 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Introducing AmiraMeshReader with very limited (not more than currently needed) functionality.

parent b39eeb06
......@@ -54,11 +54,11 @@ namespace campvis {
}
void ImageMappingInformation::updateMatrices() {
_textureToWorldTransformation = cgt::mat4::createTranslation(_offset) * _customTransformation * cgt::mat4::createScale(_voxelSize * _size);
_textureToWorldTransformation = _customTransformation * cgt::mat4::createTranslation(_offset) * cgt::mat4::createScale(_voxelSize * _size);
if (! _textureToWorldTransformation.invert(_worldToTextureTransformation))
cgtAssert(false, "Could not invert texture-to-world matrix. That should not happen!");
_voxelToWorldTransformation = cgt::mat4::createTranslation(_offset) * _customTransformation * cgt::mat4::createScale(_voxelSize);
_voxelToWorldTransformation = _customTransformation * cgt::mat4::createTranslation(_offset) * cgt::mat4::createScale(_voxelSize);
if (! _voxelToWorldTransformation.invert(_worldToVoxelTransformation))
cgtAssert(false, "Could not invert voxel-to-world matrix. That should not happen!");
}
......
......@@ -60,8 +60,8 @@ namespace campvis {
std::ifstream file(_url.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if (file.is_open()) {
size_t fileSize = static_cast<size_t>(file.tellg());
if (fileSize < numBytes) {
LERROR("File is smaller than expected.");
if (fileSize < numBytes + _offset) {
LERROR("File is smaller than expected, " << (numBytes + _offset) - fileSize << " Bytes missing.");
return WeaklyTypedPointer(_type, _parent->getNumChannels(), 0);
}
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "amirameshreader.h"
#include <fstream>
#include "cgt/filesystem.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationdisk.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
#include "core/tools/textfileparser.h"
/*
* ATTENTION: This reader has only a very limited support for AmiraMesh files, if
* your file is not supported properly, you may have to extend this class.
*
* Currently supported:
* - uniform rectlinear grids of basic data types
*
* Some references:
* - http://people.mpi-inf.mpg.de/~weinkauf/notes/amiramesh.html
*/
namespace campvis {
const std::string AmiraMeshReader::loggerCat_ = "CAMPVis.modules.io.AmiraMeshReader";
AmiraMeshReader::AmiraMeshReader()
: AbstractImageReader()
, p_imageOffset("ImageOffset", "Image Offset in mm", cgt::vec3(0.f), cgt::vec3(-10000.f), cgt::vec3(10000.f), cgt::vec3(0.1f))
, p_voxelSize("VoxelSize", "Voxel Size in mm", cgt::vec3(1.f), cgt::vec3(-100.f), cgt::vec3(100.f), cgt::vec3(0.1f))
{
this->_ext.push_back("am");
this->p_targetImageID.setValue("AmiraMeshReader.output");
addProperty(p_url);
addProperty(p_targetImageID);
addProperty(p_imageOffset);
addProperty(p_voxelSize);
}
AmiraMeshReader::~AmiraMeshReader() {
}
namespace {
std::string getTrimmedLine(std::ifstream& file, char delim = '\n') {
std::string toReturn;
std::getline(file, toReturn, delim);
return StringUtils::trim(toReturn);
}
std::string advanceTo(std::ifstream& file, const std::string& startString) {
while (file.good()) {
std::string toReturn = getTrimmedLine(file);
if (toReturn.compare(0, startString.size(), startString) == 0)
return toReturn;
}
return "";
}
}
void AmiraMeshReader::updateResult(DataContainer& data) {
try {
std::ifstream file(p_url.getValue().c_str(), std::ifstream::in | std::ios::binary);
if (!file.is_open() || file.bad())
throw cgt::FileException("Could not open file " + p_url.getValue() + " for reading.", p_url.getValue());
// identify as correct file type
std::string curLine = getTrimmedLine(file);
// cppcheck-suppress stlIfStrFind
if (curLine.find("# AmiraMesh") != 0)
throw cgt::FileException("Could not identify as AmiraMesh file.", p_url.getValue());
if (curLine.find("# AmiraMesh BINARY-LITTLE-ENDIAN") != 0)
throw cgt::FileException("Unsupported format in AmiraMesh file.", p_url.getValue());
// get Lattice (image size)
if ((curLine = advanceTo(file, "define Lattice ")).empty())
throw cgt::FileException("Malformed (or unsupported?) AmiraMesh file.", p_url.getValue());
std::vector<std::string> lattice = StringUtils::parseFloats(curLine.substr(15));
if (lattice.size() != 3)
throw cgt::FileException("Malformed (or unsupported?) AmiraMesh file.", p_url.getValue());
cgt::svec3 size(StringUtils::fromString<size_t>(lattice[0]), StringUtils::fromString<size_t>(lattice[1]), StringUtils::fromString<size_t>(lattice[2]));
cgt::vec3 imageOffset(0.f);
cgt::vec3 voxelSize(1.f);
cgt::mat4 transformationMatrix = cgt::mat4::identity;
size_t numChannels = 1;
WeaklyTypedPointer::BaseType baseType = WeaklyTypedPointer::UINT8;
// get further parameters
if ((curLine = advanceTo(file, "Parameters {")).empty())
throw cgt::FileException("Malformed (or unsupported?) AmiraMesh file.", p_url.getValue());
int nestedLevel = 0;
do {
curLine = getTrimmedLine(file);
if (curLine.substr(curLine.length() - 1, 1) == "{") {
++nestedLevel;
}
else if (curLine == "}") {
--nestedLevel;
}
else if (nestedLevel == 0) {
std::vector<std::string> parts = StringUtils::splitStringsafe(curLine, " \t", '"');
if (parts[0] == "CoordType") {
if (parts[1] != "uniform")
throw cgt::FileException("Unsupported CoordType in file.", p_url.getValue());
}
if (parts[0] == "TransformationMatrix") {
if (parts.size() != 17)
throw cgt::FileException("Unsupported TransformationMatrix structure in file.", p_url.getValue());
for (size_t i = 0; i < 16; ++i)
transformationMatrix.elem[i] = StringUtils::fromString<float>(parts[i+1]);
transformationMatrix = cgt::transpose(transformationMatrix);
}
if (parts[0] == "BoundingBox") {
if (parts.size() != 7)
throw cgt::FileException("Unsupported BoundingBox structure in file.", p_url.getValue());
cgt::vec3 llf, urb;
for (size_t i = 0; i < 3; ++i) {
llf[i] = StringUtils::fromString<float>(parts[i+1]);
urb[i] = StringUtils::fromString<float>(parts[i+4]);
}
imageOffset = llf;
voxelSize = (urb - llf) / cgt::vec3(size);
}
}
} while (file.good() && nestedLevel >= 0);
// get data type
if ((curLine = advanceTo(file, "Lattice { ")).empty())
throw cgt::FileException("Malformed (or unsupported?) AmiraMesh file.", p_url.getValue());
std::vector<std::string> parts = StringUtils::splitStringsafe(curLine, " \t");
std::string dataType = parts[2];
if (dataType == "unsigned") {
dataType = parts[2] + " " + parts[3];
}
if (dataType[dataType.length() - 3] == '[' && dataType[dataType.length() - 1] == ']') {
numChannels = StringUtils::fromString<size_t>(dataType.substr(dataType.length() - 2, 1));
dataType = dataType.substr(0, dataType.length() - 3);
}
if (dataType == "unsigned char")
baseType = WeaklyTypedPointer::UINT8;
else if (dataType == "char")
baseType = WeaklyTypedPointer::INT8;
else if (dataType == "unsigned short")
baseType = WeaklyTypedPointer::UINT16;
else if (dataType == "short")
baseType = WeaklyTypedPointer::INT16;
else if (dataType == "unsigned int")
baseType = WeaklyTypedPointer::UINT32;
else if (dataType == "int")
baseType = WeaklyTypedPointer::INT32;
else if (dataType == "float")
baseType = WeaklyTypedPointer::FLOAT;
// compute offset
if ((curLine = advanceTo(file, "# Data section follows")).empty())
throw cgt::FileException("Malformed (or unsupported?) AmiraMesh file.", p_url.getValue());
getTrimmedLine(file);
size_t offset = file.tellg();
// all parsing done - lets create the image:
ImageData* image = new ImageData(3, size, numChannels);
ImageRepresentationDisk::create(image, p_url.getValue(), baseType, offset, EndianHelper::IS_LITTLE_ENDIAN);
image->setMappingInformation(ImageMappingInformation(size, imageOffset + p_imageOffset.getValue(), voxelSize * p_voxelSize.getValue(), transformationMatrix));
data.addData(p_targetImageID.getValue(), image);
}
catch (cgt::Exception& e) {
LERROR("Error while parsing AmiraMesh header: " << e.what());
return;
}
catch (std::exception& e) {
LERROR("Error while parsing AmiraMesh header: " << e.what());
return;
}
}
}
\ No newline at end of file
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#ifndef AMIRAMESHREADER_H__
#define AMIRAMESHREADER_H__
#include <string>
#include "abstractimagereader.h"
#include "core/pipeline/abstractprocessor.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/floatingpointproperty.h"
#include "modules/modulesapi.h"
namespace campvis {
/**
* Reads an Amira Mesh file (*.am) into the pipeline.
*
* \note ATTENTION: This reader has only a very limited support for Amira Mesh files, if
* your file is not supported properly, you may have to extend this class.
*/
class CAMPVIS_MODULES_API AmiraMeshReader : public AbstractImageReader {
public:
/**
* Constructs a new AmiraMeshReader Processor
**/
AmiraMeshReader();
/**
* Destructor
**/
virtual ~AmiraMeshReader();
/// \see AbstractProcessor::getName()
virtual const std::string getName() const { return "AmiraMeshReader"; };
/// \see AbstractProcessor::getDescription()
virtual const std::string getDescription() const { return "Reads an Amira Mesh file (*.am) into the pipeline."; };
/// \see AbstractProcessor::getAuthor()
virtual const std::string getAuthor() const { return "Christian Schulte zu Berge <christian.szb@in.tum.de>"; };
/// \see AbstractProcessor::getProcessorState()
virtual ProcessorState getProcessorState() const { return AbstractProcessor::EXPERIMENTAL; };
Vec3Property p_imageOffset; ///< Image Offset in mm
Vec3Property p_voxelSize; ///< Voxel Size in mm
protected:
/// \see AbstractProcessor::updateResult
virtual void updateResult(DataContainer& dataContainer);
static const std::string loggerCat_;
};
}
#endif // AMIRAMESHREADER_H__
......@@ -32,6 +32,7 @@
#include "core/datastructures/genericimagerepresentationlocal.h"
#include "core/tools/textfileparser.h"
#include "modules/io/processors/amirameshreader.h"
#include "modules/io/processors/csvdimagereader.h"
#include "modules/io/processors/ltfimagereader.h"
#include "modules/io/processors/mhdimagereader.h"
......@@ -65,6 +66,7 @@ namespace campvis {
addProperty(p_targetImageID);
p_url.s_changed.connect(this, &GenericImageReader::onUrlPropertyChanged);
addReader(new AmiraMeshReader());
addReader(new CsvdImageReader());
addReader(new LtfImageReader());
addReader(new MhdImageReader());
......
......@@ -62,15 +62,15 @@ namespace campvis {
_tcp.p_image.setValue("ImageGroup");
_renderTargetID.setValue("result");
_ctReader.p_url.setValue(ShdrMgr.completePath("D:/Medical Data/K_export/K_CT.nii"));
_ctReader.p_url.setValue(ShdrMgr.completePath("D:/Medical Data/K_export/K_Data/K_CT_CoregT1.am"));
_ctReader.p_targetImageID.setValue("ct.image");
_ctReader.s_validated.connect(this, &NeuroDemo::onReaderValidated);
_t1Reader.p_url.setValue(ShdrMgr.completePath("D:/Medical Data/K_export/K_T1_bet.nii"));
_t1Reader.p_url.setValue(ShdrMgr.completePath("D:/Medical Data/K_export/K_Data/K_T1_bet04.GB306.am"));
_t1Reader.p_targetImageID.setValue("t1_tf.image");
_t1Reader.s_validated.connect(this, &NeuroDemo::onReaderValidated);
_petReader.p_url.setValue(ShdrMgr.completePath("D:/Medical Data/K_export/K_PET.nii"));
_petReader.p_url.setValue(ShdrMgr.completePath("D:/Medical Data/K_export/K_Data/K_PET-CoregNMI_fl.am"));
_petReader.p_targetImageID.setValue("pet.image");
_petReader.s_validated.connect(this, &NeuroDemo::onReaderValidated);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment