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__
Supports Markdown
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