* Introducing GlMorphologyFilter processor for fast erosion/dilation filtering.

* Fixed TrackballNavigationEventListener not saving the current scene bounds -> resetting camera too often
parent b863e31c
......@@ -125,6 +125,7 @@ namespace campvis {
}
void TrackballNavigationEventListener::setSceneBounds(const tgt::Bounds& bounds) {
_sceneBounds = bounds;
_trackball->setSceneBounds(bounds);
}
......
// ================================================================================================
//
// 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.
//
// ================================================================================================
in vec3 ex_TexCoord;
out vec4 out_Color;
#define FILTER_3D
#ifdef FILTER_2D
uniform sampler2D _texture;
uniform ivec3 _textureSize;
void main() {
ivec2 texel = ivec2(ex_TexCoord.xy * vec2(_textureSize.xy));
out_Color = texelFetch(_texture, texel, 0);
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec2(1, 0));
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec2(-1, 0));
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec2(0, 1));
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec2(0, -1));
}
#endif
#ifdef FILTER_3D
uniform sampler3D _texture;
uniform ivec3 _textureSize;
uniform int _zTexCoord;
void main() {
ivec3 texel = ivec3(ex_TexCoord.xy * vec2(_textureSize.xy), _zTexCoord);
out_Color = texelFetch(_texture, texel, 0);
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec3(-1, 0, 0)));
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec3( 1, 0, 0)));
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec3( 0, -1, 0)));
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec3( 0, 1, 0)));
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec3( 0, 0, -1)));
out_Color = FILTER_OP(out_Color, texelFetchOffset(_texture, texel, 0, ivec3( 0, 0, 1)));
}
#endif
// ================================================================================================
//
// 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 "morphologyfilterdemo.h"
#include "tgt/event/keyevent.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/renderdata.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
#include "core/tools/glreduction.h"
namespace campvis {
MorphologyDemo::MorphologyDemo(DataContainer* dc)
: AutoEvaluationPipeline(dc)
, _imageReader()
, _morphologyFilter(&_canvasSize)
, _ve(&_canvasSize)
{
addProcessor(&_imageReader);
addProcessor(&_morphologyFilter);
addProcessor(&_ve);
addEventListenerToBack(&_ve);
}
MorphologyDemo::~MorphologyDemo() {
}
void MorphologyDemo::init() {
AutoEvaluationPipeline::init();
_ve.p_outputImage.setValue("result");
_renderTargetID.setValue("result");
_imageReader.p_url.setValue(CAMPVIS_SOURCE_DIR "/modules/vis/sampledata/smallHeart.mhd");
_imageReader.p_targetImageID.setValue("reader.output");
_imageReader.p_targetImageID.addSharedProperty(&_morphologyFilter.p_inputImage);
_morphologyFilter.p_outputImage.setValue("filtered");
_morphologyFilter.p_outputImage.addSharedProperty(&_ve.p_inputVolume);
Geometry1DTransferFunction* dvrTF = new Geometry1DTransferFunction(128, tgt::vec2(0.f, .05f));
dvrTF->addGeometry(TFGeometry1D::createQuad(tgt::vec2(.1f, .125f), tgt::col4(255, 0, 0, 32), tgt::col4(255, 0, 0, 32)));
dvrTF->addGeometry(TFGeometry1D::createQuad(tgt::vec2(.4f, .5f), tgt::col4(0, 255, 0, 128), tgt::col4(0, 255, 0, 128)));
static_cast<TransferFunctionProperty*>(_ve.getProperty("TransferFunction"))->replaceTF(dvrTF);
}
void MorphologyDemo::deinit() {
_canvasSize.s_changed.disconnect(this);
AutoEvaluationPipeline::deinit();
}
}
\ No newline at end of file
// ================================================================================================
//
// 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 MORPHOLOGYFILTERDEMO_H__
#define MORPHOLOGYFILTERDEMO_H__
#include "core/pipeline/autoevaluationpipeline.h"
#include "core/properties/cameraproperty.h"
#include "modules/io/processors/mhdimagereader.h"
#include "modules/preprocessing/processors/glmorphologyfilter.h"
#include "modules/vis/processors/volumeexplorer.h"
#include "core/tools/glreduction.h"
namespace campvis {
class MorphologyDemo : public AutoEvaluationPipeline {
public:
/**
* Creates a AutoEvaluationPipeline.
*/
MorphologyDemo(DataContainer* dc);
/**
* Virtual Destructor
**/
virtual ~MorphologyDemo();
/// \see AutoEvaluationPipeline::init()
virtual void init();
/// \see AutoEvaluationPipeline::deinit()
virtual void deinit();
/// \see AbstractPipeline::getName()
virtual const std::string getName() const { return getId(); };
static const std::string getId() { return "MorphologyDemo"; };
protected:
MhdImageReader _imageReader;
GlMorphologyFilter _morphologyFilter;
VolumeExplorer _ve;
};
}
#endif // MORPHOLOGYFILTERDEMO_H__
// ================================================================================================
//
// 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 "glmorphologyfilter.h"
#include "tgt/logmanager.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorgradient.h"
#include "core/classification/simpletransferfunction.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
#include "core/tools/quadrenderer.h"
#include "core/tools/stringutils.h"
namespace campvis {
const std::string GlMorphologyFilter::loggerCat_ = "CAMPVis.modules.classification.GlMorphologyFilter";
GlMorphologyFilter::GlMorphologyFilter(IVec2Property* viewportSizeProp)
: VisualizationProcessor(viewportSizeProp)
, p_inputImage("InputImage", "Input Image", "", DataNameProperty::READ, AbstractProcessor::INVALID_RESULT)
, p_outputImage("OutputImage", "Output Image", "GlMorphologyFilter.out", DataNameProperty::WRITE)
, p_filterOperation("FilterOperation", "Operations to Apply ([edoc]+)", "ed")
, _erosionFilter(nullptr)
, _dilationFilter(nullptr)
{
addProperty(&p_inputImage);
addProperty(&p_outputImage);
addProperty(&p_filterOperation);
}
GlMorphologyFilter::~GlMorphologyFilter() {
}
void GlMorphologyFilter::init() {
VisualizationProcessor::init();
_erosionFilter = ShdrMgr.load("core/glsl/passthrough.vert", "modules/preprocessing/glsl/GlMorphologyFilter.frag", "#define FILTER_OP min\n");
_erosionFilter->setAttributeLocation(0, "in_Position");
_erosionFilter->setAttributeLocation(1, "in_TexCoord");
_dilationFilter = ShdrMgr.load("core/glsl/passthrough.vert", "modules/preprocessing/glsl/GlMorphologyFilter.frag", "#define FILTER_OP max\n");
_dilationFilter->setAttributeLocation(0, "in_Position");
_dilationFilter->setAttributeLocation(1, "in_TexCoord");
}
void GlMorphologyFilter::deinit() {
ShdrMgr.dispose(_erosionFilter);
ShdrMgr.dispose(_dilationFilter);
VisualizationProcessor::deinit();
}
void GlMorphologyFilter::updateResult(DataContainer& data) {
ImageRepresentationGL::ScopedRepresentation img(data, p_inputImage.getValue());
if (img != 0) {
if (img->getDimensionality() == 3) {
std::string ops = p_filterOperation.getValue();
ops = StringUtils::replaceAll(ops, "o", "ed"); // opening := erosion, dilation
ops = StringUtils::replaceAll(ops, "c", "de"); // closing := dilation, erosion
const tgt::Texture* inputTexture = img->getTexture();
tgt::Texture* outputTexture = nullptr;
for (size_t i = 0; i < ops.length(); ++i) {
if (ops[i] == 'e') {
outputTexture = applyFilter(inputTexture, _erosionFilter);
}
else if (ops[i] == 'd') {
outputTexture = applyFilter(inputTexture, _dilationFilter);
}
else {
continue;
}
if (inputTexture != img->getTexture())
delete inputTexture;
inputTexture = outputTexture;
}
// put resulting image into DataContainer
if (outputTexture != 0) {
ImageData* id = new ImageData(3, img->getSize(), 1);
ImageRepresentationGL::create(id, outputTexture);
id->setMappingInformation(img->getParent()->getMappingInformation());
data.addData(p_outputImage.getValue(), id);
}
else {
data.addDataHandle(p_outputImage.getValue(), img.getDataHandle());
}
tgt::TextureUnit::setZeroUnit();
LGL_ERROR;
}
else {
// yes I was too lazy... But have a look in the shader: Half of the 2D support is already there. :)
LERROR("Sorry, currently only 3D images are supported.");
}
}
else {
LERROR("No suitable input image found.");
}
validate(INVALID_RESULT);
}
tgt::Texture* GlMorphologyFilter::applyFilter(const tgt::Texture* inputTexture, tgt::Shader* filter) const {
tgtAssert(inputTexture != 0, "Input texture must not be 0.");
const tgt::ivec3& size = inputTexture->getDimensions();
tgt::TextureUnit inputUnit;
inputUnit.activate();
// create texture for result
tgt::Texture* resultTexture = new tgt::Texture(0, size, inputTexture->getFormat(), inputTexture->getInternalFormat(), inputTexture->getDataType(), inputTexture->getFilter());
resultTexture->uploadTexture();
// activate shader and bind textures
inputTexture->bind();
filter->activate();
filter->setUniform("_texture", inputUnit.getUnitNumber());
filter->setUniform("_textureSize", size);
// activate FBO and attach texture
_fbo->activate();
glViewport(0, 0, static_cast<GLsizei>(size.x), static_cast<GLsizei>(size.y));
// render quad to compute difference measure by shader
for (int z = 0; z < size.z; ++z) {
filter->setUniform("_zTexCoord", z);
_fbo->attachTexture(resultTexture, GL_COLOR_ATTACHMENT0, 0, z);
QuadRdr.renderQuad();
}
_fbo->detachAll();
_fbo->deactivate();
filter->deactivate();
return resultTexture;
}
}
// ================================================================================================
//
// 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 GLMORPHOLOGYFILTER_H__
#define GLMORPHOLOGYFILTER_H__
#include <string>
#include "core/pipeline/abstractprocessordecorator.h"
#include "core/pipeline/visualizationprocessor.h"
#include "core/properties/datanameproperty.h"
namespace tgt {
class Shader;
}
namespace campvis {
/**
* Creates the gradient volume for the given intensity volume using OpenGL.
*/
class GlMorphologyFilter : public VisualizationProcessor {
public:
/**
* Constructs a new GlMorphologyFilter Processor
**/
GlMorphologyFilter(IVec2Property* viewportSizeProp);
/**
* Destructor
**/
virtual ~GlMorphologyFilter();
/// \see AbstractProcessor::init
virtual void init();
/// \see AbstractProcessor::deinit
virtual void deinit();
/// \see AbstractProcessor::getName()
virtual const std::string getName() const { return "GlMorphologyFilter"; };
/// \see AbstractProcessor::getDescription()
virtual const std::string getDescription() const { return "Creates the gradient volume for the given intensity volume using OpenGL."; };
/// \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; };
DataNameProperty p_inputImage; ///< ID for input volume
DataNameProperty p_outputImage; ///< ID for output gradient volume
StringProperty p_filterOperation; ///< String-encoded filter operation to apply
protected:
/// \see AbstractProcessor::updateResult
virtual void updateResult(DataContainer& dataContainer);
/**
* Applys the morphology filter \a filter to \a inputImage.
* \param inputTexture Input image for the filter
* \param filter Filter to apply (should be _erosionFilter or _dilationFilter or compatible)
* \return An OpenGL texture with the filtered image
*/
tgt::Texture* applyFilter(const tgt::Texture* inputTexture, tgt::Shader* filter) const;
tgt::Shader* _erosionFilter; ///< Shader for performing erosion filter
tgt::Shader* _dilationFilter; ///< Shader for performing dilation filter
static const std::string loggerCat_;
};
}
#endif // GLMORPHOLOGYFILTER_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