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

Merge remote-tracking branch 'origin/tensor_data_support' into development

parents 60e29112 e27d48a3
......@@ -26,6 +26,7 @@
#define GENERICIMAGEREPRESENTATIONLOCAL_H__
#include "core/datastructures/imagerepresentationlocal.h"
#include "core/datastructures/imagerepresentationdisk.h"
#include "core/tools/typetraits.h"
#include <cstring> // needed for memcpy
......@@ -150,7 +151,7 @@ namespace campvis {
* \param data Pointer to the image data, must not be 0, GenericImageRepresentationLocal takes ownership of this pointer!
* \return A pointer to the newly created ImageRepresentationDisk, you do \b not own this pointer!
*/
static GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* create(ImageData* parent, ElementType* data);
static GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* create(const ImageData* parent, ElementType* data);
/**
* Destructor
......@@ -280,8 +281,8 @@ namespace campvis {
// = Template implementation ======================================================================
template<typename BASETYPE, size_t NUMCHANNELS>
campvis::GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* campvis::GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::create(ImageData* parent, ElementType* data) {
ThisType* toReturn = new ThisType(parent, data);
campvis::GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* campvis::GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::create(const ImageData* parent, ElementType* data) {
ThisType* toReturn = new ThisType(const_cast<ImageData*>(parent), data);
toReturn->addToParent();
return toReturn;
}
......@@ -306,6 +307,12 @@ namespace campvis {
template<typename BASETYPE, size_t NUMCHANNELS>
GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* campvis::GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::tryConvertFrom(const AbstractImageRepresentation* source) {
if (const ImageRepresentationDisk* tester = dynamic_cast<const ImageRepresentationDisk*>(source)) {
if (tester->getBaseType() == TypeTraits<BASETYPE, NUMCHANNELS>::weaklyTypedPointerBaseType && tester->getParent()->getNumChannels() == NUMCHANNELS) {
WeaklyTypedPointer wtp = tester->getImageData();
return create(tester->getParent(), static_cast<ElementType*>(wtp._pointer));
}
}
return 0;
}
......
......@@ -202,6 +202,7 @@ namespace campvis {
else DISPATCH_DISK_TO_GENERIC_LOCAL_CONVERSION(2)
else DISPATCH_DISK_TO_GENERIC_LOCAL_CONVERSION(3)
else DISPATCH_DISK_TO_GENERIC_LOCAL_CONVERSION(4)
else DISPATCH_DISK_TO_GENERIC_LOCAL_CONVERSION(6)
else {
tgtAssert(false, "Should not reach this - wrong number of channel!");
return 0;
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitt Mnchen
// Boltzmannstr. 3, 85748 Garching b. Mnchen, 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 TENSOR_H__
#define TENSOR_H__
#include "tgt/matrix.h"
namespace campvis {
/**
* Second order tensor of base type T
*
* A second order tensor is a symmetric, positive definite 3x3 matrix, though
* can be represented by 6 values. To save memory only these 6 values are stored,
* use according accessor functions to get a Matrix3\<T\> representation.
*
* In this implementation the 6 tensor values are stored in row order as upper
* diagonal matrix, meaning
* Dxx Dxy Dxz
* elem = Dyy Dyz = [Dxx, Dxy, Dxz, Dyy, Dyz, Dzz]
* Dzz
*
* If you have differently organized data use one of the order transforming
* factory methods.
**/
template<class T>
struct Tensor2 {
typedef T ElemType;
enum {
size = 6
};
union {
struct {
T Dxx;
T Dxy;
T Dxz;
T Dyy;
T Dyz;
T Dzz;
};
T elem[size];
};
/// Default constructor
Tensor2() {}
/// Init all elements with the same value
explicit Tensor2(T v) {
for (size_t i = 0; i < size; ++i)
elem[i] = v;
}
/// Init from array with equal size
explicit Tensor2(const T* v) {
for (size_t i = 0; i < size; ++i)
elem[i] = v[i];
}
/// Init componentwisely
Tensor2(T Dxx, T Dxy, T Dxz, T Dyy, T Dyz, T Dzz) {
elem[0] = Dxx;
elem[1] = Dxy;
elem[2] = Dxz;
elem[3] = Dyy;
elem[4] = Dyz;
elem[5] = Dzz;
}
/// Init with another Vector of another type
template<class U>
Tensor2(const Tensor2<U>& v) {
for (size_t i = 0; i < v.size; ++i)
elem[i] = T(v.elem[i]);
}
/// Destructor
~Tensor2() {
}
/// Index operator
const T& operator [] (size_t index) const {
return elem[index];
}
/// Index operator
T& operator [] (size_t index) {
return elem[index];
}
/**
* Returns a 3x3 matrix representation of this rank-2 Tensor
* \return tgt::Matrix3<T>(Dxx, Dxy, Dxz, Dxy, Dyy, Dyz, Dxz, Dyz, Dzz)
*/
tgt::Matrix3<T> getMatrix() const {
return tgt::Matrix3<T>(Dxx, Dxy, Dxz, Dxy, Dyy, Dyz, Dxz, Dyz, Dzz);
}
/**
* Creates a second order tensor from values given in row order as
* lower diagonal matrix, meaning
* Dxx
* elem = Dxy Dyy = [Dxx, Dxy, Dyy, Dxz, Dyz, Dzz]
* Dxz Dyz Dzz
**/
static Tensor2<T> createTensorFromLowerDiagonalMatrix(T Dxx, T Dxy, T Dyy, T Dxz, T Dyz, T Dzz) {
return Tensor2(Dxx, Dxy, Dxz, Dyy, Dyz, Dzz);
}
/**
* Creates a second order tensor from values given in row order as
* lower diagonal matrix, meaning
* Dxx
* elem = Dxy Dyy = [Dxx, Dxy, Dyy, Dxz, Dyz, Dzz]
* Dxz Dyz Dzz
**/
static Tensor2<T> createTensorFromLowerDiagonalMatrix(const T* elem) {
return Tensor2(elem[0], elem[1], elem[3], elem[2], elem[4], elem[5]);
}
/**
* Creates a second order tensor from values given in row order as
* lower diagonal matrix, meaning
* 1 4 5
* elem = 2 6 = [Dxx, Dyy, Dzz, Dxy, Dxz, Dyz]
* 3
**/
static Tensor2<T> createTensorFromDiagonalOrder(T Dxx, T Dyy, T Dzz, T Dxy, T Dxz, T Dyz) {
return Tensor2(Dxx, Dxy, Dxz, Dyy, Dyz, Dzz);
}
/**
* Creates a second order tensor from values given in row order as
* lower diagonal matrix, meaning
* 1 4 5
* elem = 2 6 = [Dxx, Dyy, Dzz, Dxy, Dxz, Dyz]
* 3
**/
static Tensor2<T> createTensorFromDiagonalOrder(const T* elem) {
return Tensor2(elem[0], elem[3], elem[4], elem[1], elem[5], elem[2]);
}
bool operator==(const Tensor2<T>& rhs) {
return ( (Dxx == rhs.Dxx)
&& (Dxy == rhs.Dxy)
&& (Dxz == rhs.Dxz)
&& (Dyy == rhs.Dyy)
&& (Dyz == rhs.Dyz)
&& (Dzz == rhs.Dzz));
}
bool operator!=(const Tensor2<T>& rhs) {
return ( (Dxx != rhs.Dxx)
|| (Dxy != rhs.Dxy)
|| (Dxz != rhs.Dxz)
|| (Dyy != rhs.Dyy)
|| (Dyz != rhs.Dyz)
|| (Dzz != rhs.Dzz));
}
Tensor2<T> operator*(const T& rhs) {
return Tensor2<T>(Dxx*rhs, Dxy*rhs, Dxz*rhs, Dyy*rhs, Dyz*rhs, Dzz*rhs);
}
Tensor2<T> operator/(const T& rhs) {
return Tensor2<T>(Dxx/rhs, Dxy/rhs, Dxz/rhs, Dyy/rhs, Dyz/rhs, Dzz/rhs);
}
Tensor2<T> operator+(const Tensor2<T>& rhs) {
return Tensor2<T>(Dxx+rhs.Dxx, Dxy+rhs.Dxy, Dxz+rhs.Dxz, Dyy+rhs.Dyy, Dyz+rhs.Dyz, Dzz+rhs.Dzz);
}
Tensor2<T> operator-(const Tensor2<T>& rhs) {
return Tensor2<T>(Dxx-rhs.Dxx, Dxy-rhs.Dxy, Dxz-rhs.Dxz, Dyy-rhs.Dyy, Dyz-rhs.Dyz, Dzz-rhs.Dzz);
}
Tensor2<T>& operator+=(const Tensor2<T>& rhs) {
for (size_t i = 0; i < size; ++i)
elem[i] += rhs.elem[i];
return *this;
}
Tensor2<T>& operator-=(const Tensor2<T>& rhs) {
for (size_t i = 0; i < size; ++i)
elem[i] -= rhs.elem[i];
return *this;
}
};
}
#endif // TENSOR_H__
......@@ -27,7 +27,9 @@
#include "tgt/tgt_gl.h"
#include "tgt/tgt_math.h"
#include "tgt/matrix.h"
#include "tgt/vector.h"
#include "core/datastructures/tensor.h"
#include "core/tools/weaklytypedpointer.h"
#include <limits>
......@@ -48,12 +50,12 @@ namespace {
template<>
struct TypeTraitsHelperPerChannel<1> {
static const GLint glFormat = GL_ALPHA;
static const GLint glFormat = GL_RED;
};
template<>
struct TypeTraitsHelperPerChannel<2> {
static const GLint glFormat = GL_LUMINANCE_ALPHA;
static const GLint glFormat = GL_RG;
};
template<>
......@@ -66,6 +68,16 @@ namespace {
static const GLint glFormat = GL_RGBA;
};
template<>
struct TypeTraitsHelperPerChannel<6> {
static const GLint glFormat = GL_RGB;
};
template<>
struct TypeTraitsHelperPerChannel<9> {
static const GLint glFormat = GL_RGB;
};
// ================================================================================================
// ================================================================================================
......@@ -84,37 +96,53 @@ namespace {
static const GLint glInteralFormat = internalFormat; \
}; \
SPCIALIZE_TTIF(uint8_t, 1, GL_ALPHA8)
SPCIALIZE_TTIF(int8_t, 1, GL_ALPHA8)
SPCIALIZE_TTIF(uint16_t,1, GL_ALPHA16)
SPCIALIZE_TTIF(int16_t, 1, GL_ALPHA16)
SPCIALIZE_TTIF(uint32_t,1, GL_ALPHA)
SPCIALIZE_TTIF(int32_t, 1, GL_ALPHA)
SPCIALIZE_TTIF(float, 1, GL_ALPHA32F_ARB)
SPCIALIZE_TTIF(uint8_t, 2, GL_LUMINANCE_ALPHA)
SPCIALIZE_TTIF(int8_t, 2, GL_LUMINANCE_ALPHA)
SPCIALIZE_TTIF(uint16_t,2, GL_LUMINANCE_ALPHA)
SPCIALIZE_TTIF(int16_t, 2, GL_LUMINANCE_ALPHA)
SPCIALIZE_TTIF(uint32_t,2, GL_LUMINANCE_ALPHA)
SPCIALIZE_TTIF(int32_t, 2, GL_LUMINANCE_ALPHA)
SPCIALIZE_TTIF(float, 2, GL_LUMINANCE_ALPHA)
SPCIALIZE_TTIF(uint8_t, 1, GL_R8)
SPCIALIZE_TTIF(int8_t, 1, GL_R8)
SPCIALIZE_TTIF(uint16_t,1, GL_R16)
SPCIALIZE_TTIF(int16_t, 1, GL_R16)
SPCIALIZE_TTIF(uint32_t,1, GL_R32F)
SPCIALIZE_TTIF(int32_t, 1, GL_R32F)
SPCIALIZE_TTIF(float, 1, GL_R32F)
SPCIALIZE_TTIF(uint8_t, 2, GL_RG8)
SPCIALIZE_TTIF(int8_t, 2, GL_RG8)
SPCIALIZE_TTIF(uint16_t,2, GL_RG16)
SPCIALIZE_TTIF(int16_t, 2, GL_RG16)
SPCIALIZE_TTIF(uint32_t,2, GL_RG32F)
SPCIALIZE_TTIF(int32_t, 2, GL_RG32F)
SPCIALIZE_TTIF(float, 2, GL_RG32F)
SPCIALIZE_TTIF(uint8_t, 3, GL_RGB8)
SPCIALIZE_TTIF(int8_t, 3, GL_RGB8)
SPCIALIZE_TTIF(uint16_t,3, GL_RGB16)
SPCIALIZE_TTIF(int16_t, 3, GL_RGB16)
SPCIALIZE_TTIF(uint32_t,3, GL_RGB)
SPCIALIZE_TTIF(int32_t, 3, GL_RGB)
SPCIALIZE_TTIF(float, 3, GL_RGB32F_ARB)
SPCIALIZE_TTIF(uint32_t,3, GL_RGB32F)
SPCIALIZE_TTIF(int32_t, 3, GL_RGB32F)
SPCIALIZE_TTIF(float, 3, GL_RGB32F)
SPCIALIZE_TTIF(uint8_t, 4, GL_RGBA8)
SPCIALIZE_TTIF(int8_t, 4, GL_RGBA8)
SPCIALIZE_TTIF(uint16_t,4, GL_RGBA16)
SPCIALIZE_TTIF(int16_t, 4, GL_RGBA16)
SPCIALIZE_TTIF(uint32_t,4, GL_RGBA)
SPCIALIZE_TTIF(int32_t, 4, GL_RGBA)
SPCIALIZE_TTIF(float, 4, GL_RGBA32F_ARB)
SPCIALIZE_TTIF(uint32_t,4, GL_RGBA32F)
SPCIALIZE_TTIF(int32_t, 4, GL_RGBA32F)
SPCIALIZE_TTIF(float, 4, GL_RGBA32F)
SPCIALIZE_TTIF(uint8_t, 6, GL_RGB8)
SPCIALIZE_TTIF(int8_t, 6, GL_RGB8)
SPCIALIZE_TTIF(uint16_t,6, GL_RGB16)
SPCIALIZE_TTIF(int16_t, 6, GL_RGB16)
SPCIALIZE_TTIF(uint32_t,6, GL_RGB32F)
SPCIALIZE_TTIF(int32_t, 6, GL_RGB32F)
SPCIALIZE_TTIF(float, 6, GL_RGB32F)
SPCIALIZE_TTIF(uint8_t, 9, GL_RGB8)
SPCIALIZE_TTIF(int8_t, 9, GL_RGB8)
SPCIALIZE_TTIF(uint16_t,9, GL_RGB16)
SPCIALIZE_TTIF(int16_t, 9, GL_RGB16)
SPCIALIZE_TTIF(uint32_t,9, GL_RGB32F)
SPCIALIZE_TTIF(int32_t, 9, GL_RGB32F)
SPCIALIZE_TTIF(float, 9, GL_RGB32F)
// ================================================================================================
// ================================================================================================
......@@ -259,6 +287,36 @@ namespace {
}
};
template<typename BASETYPE>
struct TypeTraitsHelperOfBasetypePerChannel<BASETYPE, 6> {
typedef Tensor2< BASETYPE > ElementType;
static inline BASETYPE getChannel(const ElementType& element, size_t channel) {
tgtAssert(channel >= 0 && channel <= 5, "Channel out of bounds!");
return element[channel];
}
static inline void setChannel(ElementType& element, size_t channel, BASETYPE value) {
tgtAssert(channel >= 0 && channel <= 5, "Channel out of bounds!");
element[channel] = value;
}
};
template<typename BASETYPE>
struct TypeTraitsHelperOfBasetypePerChannel<BASETYPE, 9> {
typedef tgt::Matrix3< BASETYPE > ElementType;
static inline BASETYPE getChannel(const ElementType& element, size_t channel) {
tgtAssert(channel >= 0 && channel <= 8, "Channel out of bounds!");
return element.elem[channel];
}
static inline void setChannel(ElementType& element, size_t channel, BASETYPE value) {
tgtAssert(channel >= 0 && channel <= 8, "Channel out of bounds!");
element.elem[channel] = value;
}
};
// ================================================================================================
// ================================================================================================
......
......@@ -32,7 +32,7 @@ namespace campvis {
, _numChannels(numChannels)
, _pointer(ptr)
{
tgtAssert(_numChannels > 0 && _numChannels <= 4, "Number of channels out of bounds!");
tgtAssert(_numChannels > 0, "Number of channels out of bounds!");
};
WeaklyTypedPointer::WeaklyTypedPointer()
......
......@@ -76,8 +76,14 @@ namespace campvis {
// image type
if (tfp.hasKey("ObjectType")) {
if (tfp.getString("ObjectType") != "Image") {
LERROR("Error while parsing MHD header: ObjectType = Image expected");
if (tfp.getString("ObjectType") == "Image") {
numChannels = 1;
}
else if (tfp.getString("ObjectType") == "TensorImage") {
numChannels = 6;
}
else {
LERROR("Error while parsing MHD header: ObjectType = Image or ObjectType = TensorImage expected");
return;
}
}
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, 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 "tensordemo.h"
#include "tgt/event/keyevent.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
namespace campvis {
TensorDemo::TensorDemo(DataContainer* dc)
: AutoEvaluationPipeline(dc)
, _imageReader()
, _ta()
, _sliceExtractor(&_canvasSize)
, _wheelHandler(&_sliceExtractor.p_zSliceNumber)
{
addProcessor(&_imageReader);
addProcessor(&_ta);
addProcessor(&_sliceExtractor);
addEventListenerToBack(&_wheelHandler);
}
TensorDemo::~TensorDemo() {
}
void TensorDemo::init() {
AutoEvaluationPipeline::init();
_imageReader.p_url.setValue(CAMPVIS_SOURCE_DIR "/modules/tensor/sampledata/planar_tensor.mhd");
_imageReader.p_targetImageID.setValue("reader.output");
_imageReader.p_targetImageID.addSharedProperty(&_ta.p_inputImage);
_ta.p_outputProperties[0]->_imageId.addSharedProperty(&_sliceExtractor.p_sourceImageID);
_ta.p_outputProperties[0]->_imageType.selectById("MainEigenvector");
_ta.s_validated.connect(this, &TensorDemo::onProcessorValidated);
_sliceExtractor.p_xSliceNumber.setValue(0);
Geometry1DTransferFunction* tf = new Geometry1DTransferFunction(128, tgt::vec2(0.f, 1.f));
tf->addGeometry(TFGeometry1D::createQuad(tgt::vec2(0.f, 1.f), tgt::col4(0, 0, 0, 0), tgt::col4(255, 255, 255, 255)));
_sliceExtractor.p_transferFunction.replaceTF(tf);
_renderTargetID.setValue("renderTarget");
_renderTargetID.addSharedProperty(&(_sliceExtractor.p_targetImageID));
}
void TensorDemo::onProcessorValidated(AbstractProcessor* processor) {
if (processor == &_imageReader) {
ScopedTypedData<ImageData> img(*_data, _sliceExtractor.p_sourceImageID.getValue());
if (img != 0) {
_sliceExtractor.p_transferFunction.getTF()->setImageHandle(img.getDataHandle());
}
}
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, 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 TENSORDEMO_H__
#define TENSORDEMO_H__
#include "core/eventhandlers/mwheeltonumericpropertyeventlistener.h"
#include "core/pipeline/autoevaluationpipeline.h"
#include "modules/io/processors/mhdimagereader.h"
#include "modules/tensor/processors/tensoranalyzer.h"
#include "modules/vis/processors/sliceextractor.h"
namespace campvis {
class TensorDemo : public AutoEvaluationPipeline {
public:
/**
* Small demo pipeline for tensor data visualization.
*/
TensorDemo(DataContainer* dc);
/**
* Virtual Destructor
**/
virtual ~TensorDemo();
/// \see AutoEvaluationPipeline::init()
virtual void init();
/// \see AbstractPipeline::getName()
virtual const std::string getName() const { return getId(); };
/// \see AbstractPipeline::getId()
static const std::string getId() { return "TensorDemo"; };
protected:
/**
* Slot getting called when one of the observed processors got validated.
* Updates the camera properties, when the input image has changed.
* \param processor The processor that emitted the signal
*/
virtual void onProcessorValidated(AbstractProcessor* processor);
MhdImageReader _imageReader;
TensorAnalyzer _ta;
SliceExtractor _sliceExtractor;
MWheelToNumericPropertyEventListener _wheelHandler;
};
}