Extended GlGaussianFilter to support also 2D images

parent 7be16186
......@@ -25,20 +25,40 @@
in vec3 ex_TexCoord;
out vec4 out_Color;
#include "tools/texture3d.frag"
#ifdef GAUSSIAN_2D
#include "tools/texture2d.frag"
uniform sampler2D _texture;
uniform TextureParameters2D _textureParams;
#endif
#ifdef GAUSSIAN_3D
#include "tools/texture3d.frag"
uniform sampler3D _texture;
uniform TextureParameters3D _textureParams;
#endif
uniform float _zTexCoord;
uniform ivec3 _direction;
uniform int _halfKernelSize;
uniform samplerBuffer _kernel;
void main() {
#ifdef GAUSSIAN_2D
ivec2 texel = ivec2(ex_TexCoord.xy * _textureParams._size);
ivec2 zeroTexel = ivec2(0, 0);
ivec2 lookupTexel;
ivec2 dir = _direction.xy;
#endif
#ifdef GAUSSIAN_3D
ivec3 texel = ivec3(vec3(ex_TexCoord.xy, _zTexCoord) * _textureParams._size);
ivec3 zeroTexel = ivec3(0, 0, 0);
ivec3 lookupTexel;
ivec3 dir = _direction;
#endif
vec4 result = vec4(0.0, 0.0, 0.0, 0.0);
float norm = 0.0;
......@@ -46,14 +66,13 @@ void main() {
// TODO: why the fuck does abs(i) not work here?!?
int absi = (i < 0) ? -i : i;
ivec3 lookupTexel = texel + (_direction * i);
if (all(greaterThanEqual(lookupTexel, ivec3(0, 0, 0))) && all(lessThan(lookupTexel, _textureParams._size))) {
lookupTexel = texel + (dir * i);
if (all(greaterThanEqual(lookupTexel, zeroTexel)) && all(lessThan(lookupTexel, _textureParams._size))) {
vec4 curValue = texelFetch(_texture, lookupTexel, 0);
float mult = texelFetch(_kernel, absi).r;
result += curValue * mult;
norm += mult;
}
}
out_Color = result / norm;
......
......@@ -49,7 +49,8 @@ namespace campvis {
, p_inputImage("InputImage", "Input Image", "", DataNameProperty::READ)
, p_outputImage("OutputImage", "Output Image", "GlGaussianFilter.out", DataNameProperty::WRITE)
, p_sigma("Sigma", "Sigma (relates to kernel size)", 2.5f, 1.f, MAX_SIGMA, .1f, 1)
, _shader(0)
, _shader2D(0)
, _shader3D(0)
, _kernelBuffer(0)
, _kernelBufferTexture(0)
{
......@@ -65,9 +66,13 @@ namespace campvis {
void GlGaussianFilter::init() {
VisualizationProcessor::init();
_shader = ShdrMgr.load("core/glsl/passthrough.vert", "modules/preprocessing/glsl/glgaussianfilter.frag", "");
_shader->setAttributeLocation(0, "in_Position");
_shader->setAttributeLocation(1, "in_TexCoord");
_shader2D = ShdrMgr.load("core/glsl/passthrough.vert", "modules/preprocessing/glsl/glgaussianfilter.frag", "#define GAUSSIAN_2D\n");
_shader2D->setAttributeLocation(0, "in_Position");
_shader2D->setAttributeLocation(1, "in_TexCoord");
_shader3D = ShdrMgr.load("core/glsl/passthrough.vert", "modules/preprocessing/glsl/glgaussianfilter.frag", "#define GAUSSIAN_3D\n");
_shader3D->setAttributeLocation(0, "in_Position");
_shader3D->setAttributeLocation(1, "in_TexCoord");
// create kernel buffer
tgt::TextureUnit inputUnit;
......@@ -79,7 +84,8 @@ namespace campvis {
}
void GlGaussianFilter::deinit() {
ShdrMgr.dispose(_shader);
ShdrMgr.dispose(_shader2D);
ShdrMgr.dispose(_shader3D);
delete _kernelBuffer;
glDeleteTextures(1, &_kernelBufferTexture);
......@@ -89,100 +95,118 @@ namespace campvis {
void GlGaussianFilter::updateResult(DataContainer& data) {
ImageRepresentationGL::ScopedRepresentation img(data, p_inputImage.getValue());
if (img != 0) {
tgt::ivec3 size = img->getSize();
int halfKernelSize = static_cast<int>(2.5 * p_sigma.getValue());
tgtAssert(halfKernelSize < MAX_HALF_KERNEL_SIZE, "halfKernelSize too big -> kernel uniform buffer will be out of bounds!")
if (img != 0) {
if (img->getParent()->getDimensionality() > 1) {
tgt::ivec3 size = img->getSize();
int halfKernelSize = static_cast<int>(2.5 * p_sigma.getValue());
tgtAssert(halfKernelSize < MAX_HALF_KERNEL_SIZE, "halfKernelSize too big -> kernel uniform buffer will be out of bounds!")
tgt::TextureUnit inputUnit, kernelUnit;
inputUnit.activate();
tgt::TextureUnit inputUnit, kernelUnit;
inputUnit.activate();
// create texture for result
tgt::Texture* resultTextures[2];
for (size_t i = 0; i < 2; ++i) {
resultTextures[i] = new tgt::Texture(0, size, img->getTexture()->getFormat(), img->getTexture()->getInternalFormat(), img->getTexture()->getDataType(), tgt::Texture::LINEAR);
resultTextures[i]->uploadTexture();
}
// create texture for result
tgt::Texture* resultTextures[2];
for (size_t i = 0; i < 2; ++i) {
resultTextures[i] = new tgt::Texture(0, size, img->getTexture()->getFormat(), img->getTexture()->getInternalFormat(), img->getTexture()->getDataType(), tgt::Texture::LINEAR);
resultTextures[i]->uploadTexture();
}
// create and upload kernel buffer
GLfloat kernel[MAX_HALF_KERNEL_SIZE];
for (int i = 0; i <= halfKernelSize; ++i) {
kernel[i] = exp(- static_cast<GLfloat>(i*i) / (2.f * p_sigma.getValue() * p_sigma.getValue()));
}
_kernelBuffer->data(kernel, (halfKernelSize + 1) * sizeof(GLfloat), tgt::BufferObject::FLOAT, 1);
// activate shader
_shader->activate();
_shader->setUniform("_halfKernelSize", halfKernelSize);
// bind kernel buffer texture
kernelUnit.activate();
glBindTexture(GL_TEXTURE_BUFFER, _kernelBufferTexture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, _kernelBuffer->getId());
_shader->setUniform("_kernel", kernelUnit.getUnitNumber());
LGL_ERROR;
// activate FBO and attach texture
_fbo->activate();
glViewport(0, 0, static_cast<GLsizei>(size.x), static_cast<GLsizei>(size.y));
// start 3 passes of convolution: in X, Y and Z direction:
{
// X pass
_shader->setUniform("_direction", tgt::ivec3(1, 0, 0));
img->bind(_shader, inputUnit);
// render quad to compute difference measure by shader
for (int z = 0; z < size.z; ++z) {
float zTexCoord = static_cast<float>(z)/static_cast<float>(size.z) + .5f/static_cast<float>(size.z);
_shader->setUniform("_zTexCoord", zTexCoord);
_fbo->attachTexture(resultTextures[0], GL_COLOR_ATTACHMENT0, 0, z);
QuadRdr.renderQuad();
// create and upload kernel buffer
GLfloat kernel[MAX_HALF_KERNEL_SIZE];
for (int i = 0; i <= halfKernelSize; ++i) {
kernel[i] = exp(- static_cast<GLfloat>(i*i) / (2.f * p_sigma.getValue() * p_sigma.getValue()));
}
}
{
// Y pass
_shader->setUniform("_direction", tgt::ivec3(0, 1, 0));
inputUnit.activate();
resultTextures[0]->bind();
// render quad to compute difference measure by shader
for (int z = 0; z < size.z; ++z) {
float zTexCoord = static_cast<float>(z)/static_cast<float>(size.z) + .5f/static_cast<float>(size.z);
_shader->setUniform("_zTexCoord", zTexCoord);
_fbo->attachTexture(resultTextures[1], GL_COLOR_ATTACHMENT0, 0, z);
QuadRdr.renderQuad();
_kernelBuffer->data(kernel, (halfKernelSize + 1) * sizeof(GLfloat), tgt::BufferObject::FLOAT, 1);
// we need to distinguish 2D and 3D case
tgt::Shader* leShader = (size.z == 1) ? _shader2D : _shader3D;
// activate shader
leShader->activate();
leShader->setUniform("_halfKernelSize", halfKernelSize);
// bind kernel buffer texture
kernelUnit.activate();
glBindTexture(GL_TEXTURE_BUFFER, _kernelBufferTexture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, _kernelBuffer->getId());
leShader->setUniform("_kernel", kernelUnit.getUnitNumber());
LGL_ERROR;
// activate FBO and attach texture
_fbo->activate();
glViewport(0, 0, static_cast<GLsizei>(size.x), static_cast<GLsizei>(size.y));
// start 3 passes of convolution: in X, Y and Z direction:
{
// X pass
leShader->setUniform("_direction", tgt::ivec3(1, 0, 0));
img->bind(leShader, inputUnit);
// render quad to compute difference measure by shader
for (int z = 0; z < size.z; ++z) {
float zTexCoord = static_cast<float>(z)/static_cast<float>(size.z) + .5f/static_cast<float>(size.z);
if (size.z > 1)
leShader->setUniform("_zTexCoord", zTexCoord);
_fbo->attachTexture(resultTextures[0], GL_COLOR_ATTACHMENT0, 0, z);
LGL_ERROR;
QuadRdr.renderQuad();
}
}
}
{
// Z pass
_shader->setUniform("_direction", tgt::ivec3(0, 0, 1));
inputUnit.activate();
resultTextures[1]->bind();
// render quad to compute difference measure by shader
for (int z = 0; z < size.z; ++z) {
float zTexCoord = static_cast<float>(z)/static_cast<float>(size.z) + .5f/static_cast<float>(size.z);
_shader->setUniform("_zTexCoord", zTexCoord);
_fbo->attachTexture(resultTextures[0], GL_COLOR_ATTACHMENT0, 0, z);
QuadRdr.renderQuad();
{
// Y pass
leShader->setUniform("_direction", tgt::ivec3(0, 1, 0));
inputUnit.activate();
resultTextures[0]->bind();
// render quad to compute difference measure by shader
for (int z = 0; z < size.z; ++z) {
float zTexCoord = static_cast<float>(z)/static_cast<float>(size.z) + .5f/static_cast<float>(size.z);
if (size.z > 1)
leShader->setUniform("_zTexCoord", zTexCoord);
_fbo->attachTexture(resultTextures[1], GL_COLOR_ATTACHMENT0, 0, z);
LGL_ERROR;
QuadRdr.renderQuad();
}
}
// we need the third pass only in the 3D case
if (size.z > 1) {
// Z pass
leShader->setUniform("_direction", tgt::ivec3(0, 0, 1));
inputUnit.activate();
resultTextures[1]->bind();
// render quad to compute difference measure by shader
for (int z = 0; z < size.z; ++z) {
float zTexCoord = static_cast<float>(z)/static_cast<float>(size.z) + .5f/static_cast<float>(size.z);
leShader->setUniform("_zTexCoord", zTexCoord);
_fbo->attachTexture(resultTextures[0], GL_COLOR_ATTACHMENT0, 0, z);
LGL_ERROR;
QuadRdr.renderQuad();
}
}
else {
// in the 2D case we just swap the result textures, so that we write the correct image out in the lines below.
std::swap(resultTextures[0], resultTextures[1]);
}
}
_fbo->detachAll();
_fbo->deactivate();
_shader->deactivate();
_fbo->detachAll();
_fbo->deactivate();
leShader->deactivate();
// put resulting image into DataContainer
ImageData* id = new ImageData(3, size, img->getParent()->getNumChannels());
ImageRepresentationGL::create(id, resultTextures[0]);
id->setMappingInformation(img->getParent()->getMappingInformation());
data.addData(p_outputImage.getValue(), id);
// put resulting image into DataContainer
ImageData* id = new ImageData(3, size, img->getParent()->getNumChannels());
ImageRepresentationGL::create(id, resultTextures[0]);
id->setMappingInformation(img->getParent()->getMappingInformation());
data.addData(p_outputImage.getValue(), id);
delete resultTextures[1];
delete resultTextures[1];
tgt::TextureUnit::setZeroUnit();
LGL_ERROR;
tgt::TextureUnit::setZeroUnit();
LGL_ERROR;
}
else {
LERROR("Supports only 2D and 3D Gaussian Blur.");
}
}
else {
LERROR("No suitable input image found.");
......
......@@ -76,10 +76,6 @@ namespace campvis {
protected:
/// \see AbstractProcessor::updateResult
virtual void updateResult(DataContainer& dataContainer);
/// \see AbstractProcessor::updateShader
virtual void updateShader();
/// generate the GLSL header
std::string generateGlslHeader() const;
/**
* Applys the morphology filter \a filter to \a inputImage.
......@@ -90,7 +86,8 @@ namespace campvis {
tgt::Texture* applyFilter(const tgt::Texture* inputTexture, tgt::Shader* filter) const;
tgt::Shader* _shader; ///< Shader for performing Gaussian filter
tgt::Shader* _shader2D; ///< Shader for performing 2D Gaussian blur
tgt::Shader* _shader3D; ///< Shader for performing 3D Gaussian blur
tgt::BufferObject* _kernelBuffer; ///< Texture Buffer ID storing the kernel
GLuint _kernelBufferTexture;
......
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