The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

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;
};
}
#endif // TENSORDEMO_H__