Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing 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 8afff388 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Introducing IvusTcRaycaster processor for predicate histogram-based raycasting of IVUS TC data.

parent c9f4bd06
// ================================================================================================
//
// 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.
//
// ================================================================================================
layout(location = 0) out vec4 out_Color; ///< outgoing fragment color
layout(location = 1) out vec4 out_FHP; ///< outgoing fragment first hitpoint
layout(location = 2) out vec4 out_FHN; ///< outgoing fragment first hit normal
#include "tools/colorspace.frag"
#include "tools/gradient.frag"
#include "tools/raycasting.frag"
#include "tools/shading.frag"
#include "tools/texture2d.frag"
#include "tools/texture3d.frag"
#include "tools/transferfunction.frag"
#define NUM_PREDICATE_SETS 3
uniform vec2 _viewportSizeRCP;
uniform float _jitterStepSizeMultiplier;
// ray entry points
uniform sampler2D _entryPoints;
uniform sampler2D _entryPointsDepth;
uniform TextureParameters2D _entryParams;
// ray exit points
uniform sampler2D _exitPoints;
uniform sampler2D _exitPointsDepth;
uniform TextureParameters2D _exitParams;
// volume
uniform sampler3D _volume;
uniform TextureParameters3D _volumeTextureParams;
uniform sampler3D _cm;
uniform TextureParameters3D _cmParams;
uniform sampler3D _tc;
uniform TextureParameters3D _tcParams;
uniform sampler3D _plaque;
uniform TextureParameters3D _plaqueParams;
uniform float _minDepth;
uniform float _maxDepth;
// Transfer function
uniform sampler1D _transferFunction;
uniform TFParameters1D _transferFunctionParams;
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;
uniform float _samplingStepSize;
// TODO: copy+paste from Voreen - eliminate or improve.
const float SAMPLING_BASE_INTERVAL_RCP = 200.0;
uniform vec2 _intensityRange = vec2(0.05, 1.0);
uniform float _intensityImportance = 1.0;
uniform vec2 _gradientMagnitudeRange = vec2(0.03, 1.0);
uniform float _gradientMagnitudeImportance = 2.0;
uniform int _boneBit = 3;
uniform float _boneImportance = 1.2;
uniform int _muscleBit = 1;
uniform float _muscleImportance = 1.75;
uniform int _contextBit = 2;
uniform float _contextImportance = 1.2;
uniform vec3 _scanningDirection = vec3(0.0, 1.0, 0.0);
float hadd(in vec3 v) {
return v.x + v.y + v.z;
}
float hmax(in vec3 v) {
return max(v.x, max(v.y, v.z));
}
/**
* Performs the raycasting and returns the final fragment color.
*/
vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) {
vec4 result = vec4(0.0);
float importance = 0.0;
float firstHitT = -1.0;
// calculate ray parameters
vec3 direction = exitPoint.rgb - entryPoint.rgb;
float t = 0.0;
float tend = length(direction);
direction = normalize(direction);
float depthEntry = texture(_entryPointsDepth, texCoords).z;
float depthExit = texture(_exitPointsDepth, texCoords).z;
jitterEntryPoint(entryPoint, direction, _samplingStepSize * _jitterStepSizeMultiplier);
while (t < tend) {
// compute sample position
vec3 samplePosition = entryPoint.rgb + t * direction;
// lookup intensity and TF
float intensity = texture(_volume, samplePosition).r;
float D = smoothstep(_minDepth, _maxDepth, calculateDepthValue(t/tend, depthEntry, depthExit));
vec3 gradient = computeGradient(_volume, _volumeTextureParams, samplePosition);
// perform compositing
vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity);
if (color.a > 0.0) {
float cm = texture(_cm, samplePosition).r;
vec4 tc = texture(_tc, samplePosition);
float plaque = texture(_plaque, samplePosition).r;
vec3 worldPosition = textureToWorld(_volumeTextureParams, samplePosition).xyz;
vec4 pr = performPredicateBasedShading(intensity, cm, tc, plaque);
float imp = pr.a;
if (imp > 0.0) {
if (pr.z > 0.0)
color = clamp(color + pr.z, 0.0, 1.0);
#ifdef ENABLE_SHADING
// compute gradient (needed for shading and normals)
color.rgb = calculatePhongShading(worldPosition, _lightSource, _cameraPosition, gradient, color.rgb, color.rgb, vec3(1.0, 1.0, 1.0));
#endif
// perform predicate-based shading
color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);
vec3 hsl = rgb2hsv(color.rgb * color.a);
hsl.xy += pr.xy;
hsl.x = mod(hsl.x, 1.0);
color.rgb = hsv2rgb(hsl);
// perform depth-based shading
const float DBS = 0.01;
//color.r += DBS * (0.5 - D);
//color.b += DBS * (D - 0.5);
float vis = 1.0 - exp(importance - imp);
float m = (imp <= importance || (1.0 - result.a) >= vis) ? 1.0 : (1.0 - vis) / result.a;
vec3 cc = m * result.rgb + (1.0 - m * result.a) * color.rgb;
float aa = m * result.a * (1.0 - color.a) + color.a;
result.a = result.a * (1.0 - color.a) + color.a;
result.rgb = (aa == 0.0) ? vec3(0.0) : (result.a * cc) / aa;
importance = max(importance, log(color.a + (1.0 - color.a) * exp(importance - imp)) + imp);
}
}
// save first hit ray parameter for depth value calculation
if (firstHitT < 0.0 && result.a > 0.0) {
firstHitT = t;
out_FHP = vec4(samplePosition, 1.0);
out_FHN = vec4(normalize(computeGradient(_volume, _volumeTextureParams, samplePosition)), 1.0);
}
// advance to the next evaluation point along the ray
t += _samplingStepSize;
}
// calculate depth value from ray parameter
gl_FragDepth = 1.0;
if (firstHitT >= 0.0) {
gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit);
}
return result;
}
/***
* The main method.
***/
void main() {
vec2 p = gl_FragCoord.xy * _viewportSizeRCP;
vec3 frontPos = texture(_entryPoints, p).rgb;
vec3 backPos = texture(_exitPoints, p).rgb;
//determine whether the ray has to be casted
if (frontPos == backPos) {
//background need no raycasting
discard;
} else {
//fragCoords are lying inside the boundingbox
out_Color = performRaycasting(frontPos, backPos, p);
}
}
......@@ -28,10 +28,10 @@
#include "core/datastructures/imagedata.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
#include "core/classification/simpletransferfunction.h"
#include "modules/ivus_tc/processors/ivustcsliceextractor.h"
#include "modules/ivus_tc/processors/ivustcraycaster.h"
namespace campvis {
......@@ -39,9 +39,10 @@ namespace campvis {
: AutoEvaluationPipeline(dc)
, p_sourceDirectory("SoruceDirectory", "Source Directory", "D:/Medical Data/IVUS/H52 LAD1", StringProperty::DIRECTORY)
, p_readImagesButton("ReadImagesButton", "Read Images")
, p_predicateHistogram("PredicateHistogram", "Voxel Predicate Selection")
, _lsp()
, _imageReader(&_canvasSize)
, _ve(&_canvasSize, new IvusTcSliceExtractor(nullptr))
, _ve(&_canvasSize, new IvusTcSliceExtractor(nullptr), new IvusTcRaycaster(nullptr))
{
// Use AbstractPipeline overload to avoid automatic evaluation of _imageReader processor
// AbstractPipeline::addProcessor(&_imageReader);
......@@ -53,6 +54,8 @@ namespace campvis {
addProperty(p_readImagesButton);
addEventListenerToBack(&_ve);
p_predicateHistogram.getPredicateHistogram()->setPredicateFunctionArgumentString("in float ivus, in float cm, in vec4 tc, in float plaque");
}
IvusTcDemo::~IvusTcDemo() {
......@@ -70,14 +73,11 @@ namespace campvis {
_imageReader.p_fileExtension.setValue("bmp");
// initialize predicates with default config
PointPredicateHistogramProperty* php = dynamic_cast<PointPredicateHistogramProperty*>(_ve.getNestedProperty("SliceExtractorProperties::PredicateHistogram"));
PointPredicateHistogramProperty* php = &p_predicateHistogram;
if (php != nullptr) {
PointPredicateHistogram* histogram = php->getPredicateHistogram();
AbstractPointPredicate* vpToAdd = 0;
// vpToAdd = new RangePointPredicate("ivus", "IvusIntensity", "IVUS Intensity Range");
// static_cast<RangePointPredicate*>(vpToAdd)->p_range.setValue(tgt::vec2(0.f, 1.f));
// histogram->addPredicate(vpToAdd);
vpToAdd = new RangePointPredicate("cm", "ConfidenceMap", "Confidence");
static_cast<RangePointPredicate*>(vpToAdd)->p_range.setValue(tgt::vec2(0.25f, 1.f));
......@@ -110,8 +110,16 @@ namespace campvis {
histogram->resetPredicates(false);
addProperty(*php);
php->addSharedProperty(_ve.getNestedProperty("VolumeRendererProperties::RaycasterProps::PredicateHistogram"));
php->addSharedProperty(_ve.getNestedProperty("SliceExtractorProperties::PredicateHistogram"));
}
SimpleTransferFunction* stf = new SimpleTransferFunction(128, tgt::vec2(.1f, 1.f));
stf->setLeftColor(tgt::vec4(0.f));
stf->setRightColor(tgt::vec4(255.f));
static_cast<TransferFunctionProperty*>(_ve.getNestedProperty("VolumeRendererProperties::RaycasterProps::TransferFunction"))->replaceTF(stf);
}
void IvusTcDemo::deinit() {
......
......@@ -33,6 +33,7 @@
#include "modules/io/processors/genericimagereader.h"
#include "modules/ivus_tc/processors/ivusbatchreader.h"
#include "modules/vis/processors/volumeexplorer.h"
#include "modules/advancedusvis/properties/pointpredicatehistogramproperty.h"
namespace campvis {
class IvusTcDemo : public AutoEvaluationPipeline {
......@@ -66,6 +67,7 @@ namespace campvis {
StringProperty p_sourceDirectory;
ButtonProperty p_readImagesButton;
PointPredicateHistogramProperty p_predicateHistogram;
LightSourceProvider _lsp;
IvusBatchReader _imageReader;
......
// ================================================================================================
//
// 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 "ivustcraycaster.h"
#include "tgt/textureunit.h"
#include "core/tools/quadrenderer.h"
#include "core/datastructures/lightsourcedata.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorgradient.h"
namespace campvis {
const std::string IvusTcRaycaster::loggerCat_ = "CAMPVis.modules.vis.IvusTcRaycaster";
IvusTcRaycaster::IvusTcRaycaster(IVec2Property* viewportSizeProp)
: RaycastingProcessor(viewportSizeProp, "modules/ivus_tc/glsl/ivustcraycaster.frag", true, "400")
, p_cmImage("CmImage", "Confidence Map Image", "image.cm", DataNameProperty::READ)
, p_tcImage("TcImage", "Tissue Classification Image", "image.tc", DataNameProperty::READ)
, p_plaqueImage("PlaqueImage", "Plaque Mask Image", "image.plaque", DataNameProperty::READ)
, p_enableShading("EnableShading", "Enable Shading", true)
, p_lightId("LightId", "Input Light Source", "lightsource", DataNameProperty::READ)
, p_predicateHistogram("PredicateHistogram", "Voxel Predicate Selection")
{
addDecorator(new ProcessorDecoratorGradient());
addProperty(p_cmImage);
addProperty(p_tcImage);
addProperty(p_plaqueImage);
addProperty(p_enableShading, INVALID_RESULT | INVALID_PROPERTIES | INVALID_SHADER);
addProperty(p_lightId);
addProperty(p_predicateHistogram);
decoratePropertyCollection(this);
}
IvusTcRaycaster::~IvusTcRaycaster() {
}
void IvusTcRaycaster::init() {
p_predicateHistogram.getPredicateHistogram()->setPredicateFunctionArgumentString("in float ivus, in float cm, in vec4 tc, in float plaque");
RaycastingProcessor::init();
p_predicateHistogram.s_headerChanged.connect(this, &IvusTcRaycaster::onHistogramHeaderChanged);
}
void IvusTcRaycaster::deinit() {
p_predicateHistogram.s_headerChanged.disconnect(this);
RaycastingProcessor::deinit();
}
void IvusTcRaycaster::processImpl(DataContainer& dataContainer, ImageRepresentationGL::ScopedRepresentation& image) {
ImageRepresentationGL::ScopedRepresentation cm(dataContainer, p_cmImage.getValue());
ImageRepresentationGL::ScopedRepresentation tc(dataContainer, p_tcImage.getValue());
ImageRepresentationGL::ScopedRepresentation plaque(dataContainer, p_plaqueImage.getValue());
if (cm && tc && plaque) {
ScopedTypedData<LightSourceData> light(dataContainer, p_lightId.getValue());
if (p_enableShading.getValue() == false || light != nullptr) {
const tgt::Texture* tex = image->getTexture();
if (tex->getFilter() != tgt::Texture::MIPMAP) {
const_cast<tgt::Texture*>(tex)->setFilter(tgt::Texture::MIPMAP);
LGL_ERROR;
glGenerateMipmap(GL_TEXTURE_3D);
LGL_ERROR;
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
LGL_ERROR;
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
LGL_ERROR;
}
tgt::TextureUnit cmUnit, tcUnit, plaqueUnit;
cm->bind(_shader, cmUnit, "_cm", "_cmParams");
tc->bind(_shader, tcUnit, "_tc", "_tcParams");
plaque->bind(_shader, plaqueUnit, "_plaque", "_plaqueParams");
if (p_enableShading.getValue() && light != nullptr) {
light->bind(_shader, "_lightSource");
}
_shader->setIgnoreUniformLocationError(true);
p_predicateHistogram.getPredicateHistogram()->setupRenderShader(_shader);
_shader->setIgnoreUniformLocationError(false);
LGL_ERROR;
FramebufferActivationGuard fag(this);
createAndAttachTexture(GL_RGBA8);
createAndAttachTexture(GL_RGBA32F);
createAndAttachTexture(GL_RGBA32F);
createAndAttachDepthTexture();
static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, buffers);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QuadRdr.renderQuad();
// restore state
glDrawBuffers(1, buffers);
glDisable(GL_DEPTH_TEST);
LGL_ERROR;
dataContainer.addData(p_targetImageID.getValue(), new RenderData(_fbo));
}
else {
LDEBUG("Could not load light source from DataContainer.");
}
}
else {
LERROR("Could not load Voxel Predicate Mask Image.");
}
}
std::string IvusTcRaycaster::generateHeader() const {
std::string toReturn = RaycastingProcessor::generateHeader();
if (p_enableShading.getValue())
toReturn += "#define ENABLE_SHADING\n";
toReturn += p_predicateHistogram.getPredicateHistogram()->getGlslHeader();
return toReturn;
}
void IvusTcRaycaster::onHistogramHeaderChanged() {
invalidate(INVALID_SHADER);
}
void IvusTcRaycaster::updateProperties(DataContainer& dataContainer) {
p_lightId.setVisible(p_enableShading.getValue());
RaycastingProcessor::updateProperties(dataContainer);
validate(INVALID_PROPERTIES);
}
}
// ================================================================================================
//
// 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 IVUSTCRAYCASTER_H__
#define IVUSTCRAYCASTER_H__
#include "core/pipeline/raycastingprocessor.h"
#include "core/properties/floatingpointproperty.h"
#include "core/properties/genericproperty.h"
#include "modules/advancedusvis/properties/pointpredicatehistogramproperty.h"
#include <string>
namespace tgt {
class Shader;
}
namespace campvis {
/**
* Performs a Predicate Histogram-based volume ray casting for IVUS Tissue Classification.
*/
class IvusTcRaycaster : public RaycastingProcessor {
public:
/**
* Constructs a new IvusTcRaycaster Processor
**/
IvusTcRaycaster(IVec2Property* viewportSizeProp);
/**
* Destructor
**/
virtual ~IvusTcRaycaster();
/// \see AbstractProcessor::getName()
virtual const std::string getName() const { return "IvusTcRaycaster"; };
/// \see AbstractProcessor::getDescription()
virtual const std::string getDescription() const { return "Performs a Predicate Histogram-based volume ray casting for IVUS Tissue Classification."; };
/// \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; };
/// \see AbstractProcessor::init
virtual void init();
/// \see AbstractProcessor::deinit
virtual void deinit();
DataNameProperty p_cmImage;
DataNameProperty p_tcImage;
DataNameProperty p_plaqueImage;
BoolProperty p_enableShading; ///< Flag whether to enable shading
DataNameProperty p_lightId; ///< Name/ID for the LightSource to use
PointPredicateHistogramProperty p_predicateHistogram;
protected:
/// \see RaycastingProcessor::processImpl()
virtual void processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image);
/// \see AbstractProcessor::updateProperties()
virtual void updateProperties(DataContainer& dataContainer);
/// \see RaycastingProcessor::generateHeader()
virtual std::string generateHeader() const;
private:
void onHistogramHeaderChanged();
tgt::Shader* _clusterShader;
static const std::string loggerCat_;
};
}
#endif // IVUSTCRAYCASTER_H__
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