Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Open sidebar
CAMP
campvis-public
Commits
79819c19
Commit
79819c19
authored
Jan 05, 2017
by
Jakob Weiss
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MedianFilter demonstrates use of compute shaders
parent
9f3fff0d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
373 additions
and
0 deletions
+373
-0
modules/preprocessing/glsl/medianfilter.comp
modules/preprocessing/glsl/medianfilter.comp
+120
-0
modules/preprocessing/preprocessing.cmake
modules/preprocessing/preprocessing.cmake
+1
-0
modules/preprocessing/preprocessing.cpp
modules/preprocessing/preprocessing.cpp
+2
-0
modules/preprocessing/processors/medianfilter.cpp
modules/preprocessing/processors/medianfilter.cpp
+153
-0
modules/preprocessing/processors/medianfilter.h
modules/preprocessing/processors/medianfilter.h
+97
-0
No files found.
modules/preprocessing/glsl/medianfilter.comp
0 → 100644
View file @
79819c19
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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.
//
// ================================================================================================
// ==================== Shader for median filtering. ====================
// Expects the following dynamic defines:
//
// #define OUTPUT_TEXTURE_FORMAT
// The texture format of the output texture. Preferrably specified through Texture::calcMatchingWriteFormat()
//
// #define MEDIAN_WINDOW_X
// #define MEDIAN_WINDOW_Y
// #define MEDIAN_WINDOW_Z
// Size of the Median filter kernel in every dimension. All values to 1 performs results in a 3x3x3 filter window
// The work group size can be overridden by dynamic defines
#ifndef WORK_GROUP_SIZE_X
#define WORK_GROUP_SIZE_X 1
#endif
#ifndef WORK_GROUP_SIZE_Y
#define WORK_GROUP_SIZE_Y 1
#endif
#ifndef WORK_GROUP_SIZE_Z
#define WORK_GROUP_SIZE_Z 1
#endif
#include "tools/texture3d.frag"
uniform sampler3D _texture;
uniform TextureParameters3D _textureParams;
layout(OUTPUT_TEXTURE_FORMAT, binding = 0) uniform image3D _outputImage;
layout(local_size_x = WORK_GROUP_SIZE_X, local_size_y = WORK_GROUP_SIZE_Y, local_size_z = WORK_GROUP_SIZE_Z) in;
#define KERNEL_X (MEDIAN_WINDOW_X*2 + 1)
#define KERNEL_Y (MEDIAN_WINDOW_Y*2 + 1)
#define KERNEL_Z (MEDIAN_WINDOW_Z*2 + 1)
#define KERNEL_S KERNEL_X*KERNEL_Y*KERNEL_Z
float sorted[KERNEL_S];
int end = 0;
void sorted_insert2(float val) {
for(int i=0; i < end; i++) {
if(sorted[i].x < val.x) {
float tmp = val;
val = sorted[i];
sorted[i] = tmp;
}
}
sorted[end] = val;
end++;
}
void sorted_insert(float val) {
int i=end-1;
while( i >= 0) {
if(sorted[i].x < val.x) {
sorted[i+1] = sorted[i];
}
else {
break;
}
--i;
}
sorted[i+1] = val;
end++;
}
void sorted_insert3(float val) {
sorted[end] = val;
end++;
}
void main() {
// get index in global work group i.e x,y position
ivec3 pixel_coords = ivec3(gl_GlobalInvocationID.xyz);
//vec4 pixel = texelFetch(_texture, pixel_coords, 0);
vec4 pixel = vec4(0);
const ivec3 wnd = ivec3(MEDIAN_WINDOW_X, MEDIAN_WINDOW_Y, MEDIAN_WINDOW_Z);
ivec3 lo = max(pixel_coords - wnd, ivec3(0));
ivec3 hi = min(pixel_coords + wnd, ivec3(_textureParams._size) - ivec3(1));
for(int x = lo.x; x <= hi.x; x++) {
for(int y = lo.y; y <= hi.y; y++) {
for(int z = lo.z; z <= hi.z; z++) {
sorted_insert(texelFetch(_texture, ivec3(x,y,z), 0).r);
}
}
}
float result = sorted[end/2];
// output to a specific pixel in the image
imageStore(_outputImage, pixel_coords, vec4(result));
}
\ No newline at end of file
modules/preprocessing/preprocessing.cmake
View file @
79819c19
...
...
@@ -12,6 +12,7 @@ IF(${ModuleEnabled})
# Header files
FILE
(
GLOB ThisModHeaders RELATIVE
${
ModulesDir
}
modules/preprocessing/glsl/*.frag
modules/preprocessing/glsl/*.comp
modules/preprocessing/pipelines/*.h
modules/preprocessing/processors/*.h
modules/preprocessing/tools/*.h
...
...
modules/preprocessing/preprocessing.cpp
View file @
79819c19
...
...
@@ -39,6 +39,7 @@
#include "modules/preprocessing/processors/glstructuralsimilarity.h"
#include "modules/preprocessing/processors/glvesselnessfilter.h"
#include "modules/preprocessing/processors/gradientvolumegenerator.h"
#include "modules/preprocessing/processors/medianfilter.h"
namespace
campvis
{
...
...
@@ -60,5 +61,6 @@ namespace campvis {
template
class
SmartProcessorRegistrar
<
GlStructuralSimilarity
>;
template
class
SmartProcessorRegistrar
<
GlVesselnessFilter
>;
template
class
SmartProcessorRegistrar
<
GradientVolumeGenerator
>;
template
class
SmartProcessorRegistrar
<
MedianFilter
>;
}
\ No newline at end of file
modules/preprocessing/processors/medianfilter.cpp
0 → 100644
View file @
79819c19
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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 "medianfilter.h"
#include "cgt/buffer.h"
#include "cgt/imageunit.h"
#include "cgt/logmanager.h"
#include "cgt/shadermanager.h"
#include "cgt/textureunit.h"
#include "cgt/texture.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/renderdata.h"
#include "core/tools/quadrenderer.h"
#include "core/tools/stringutils.h"
namespace
campvis
{
const
std
::
string
MedianFilter
::
loggerCat_
=
"CAMPVis.modules.preprocessing.MedianFilter"
;
MedianFilter
::
MedianFilter
()
:
AbstractProcessor
()
,
p_inputImage
(
"InputImage"
,
"Input Image"
,
""
,
DataNameProperty
::
READ
)
,
p_outputImage
(
"OutputImage"
,
"Output Image"
,
"GlGaussianFilter.out"
,
DataNameProperty
::
WRITE
)
,
p_windowSize
(
"WindowSize"
,
"Window Size"
,
cgt
::
ivec3
(
1
,
1
,
0
),
cgt
::
ivec3
(
0
),
cgt
::
ivec3
(
30
))
,
p_workgroupSize
(
"WorkgroupSize"
,
"Workgroup Size"
,
cgt
::
ivec3
(
4
),
cgt
::
ivec3
(
1
),
cgt
::
ivec3
(
16
))
,
_shader
(
0
)
{
addProperty
(
p_inputImage
);
addProperty
(
p_outputImage
);
addProperty
(
p_windowSize
);
addProperty
(
p_workgroupSize
);
}
MedianFilter
::~
MedianFilter
()
{
}
void
MedianFilter
::
init
()
{
AbstractProcessor
::
init
();
LGL_ERROR
;
}
void
MedianFilter
::
deinit
()
{
ShdrMgr
.
dispose
(
_shader
);
AbstractProcessor
::
deinit
();
}
void
MedianFilter
::
updateResult
(
DataContainer
&
data
)
{
ImageRepresentationGL
::
ScopedRepresentation
img
(
data
,
p_inputImage
.
getValue
());
if
(
img
!=
0
)
{
if
(
img
->
getParent
()
->
getDimensionality
()
>
1
)
{
generateShader
(
img
);
if
(
_shader
)
{
cgt
::
ivec3
size
=
img
->
getSize
();
cgt
::
ivec3
wgSize
=
p_workgroupSize
.
getValue
();
cgt
::
vec3
groups
=
cgt
::
ceil
(
cgt
::
vec3
(
size
)
/
cgt
::
vec3
(
wgSize
));
cgt
::
TextureUnit
inputUnit
;
inputUnit
.
activate
();
cgt
::
ImageUnit
outputUnit
;
_shader
->
activate
();
// create texture for result
std
::
unique_ptr
<
cgt
::
Texture
>
resultTexture
(
new
cgt
::
Texture
(
img
->
getTexture
()
->
getType
(),
size
,
img
->
getTexture
()
->
getInternalFormat
(),
cgt
::
Texture
::
LINEAR
));
img
->
bind
(
_shader
,
inputUnit
);
LGL_ERROR
;
resultTexture
->
bindImage
(
outputUnit
,
GL_WRITE_ONLY
);
LGL_ERROR
;
_shader
->
setUniform
(
"_outputImage"
,
outputUnit
.
getUnitNumber
());
LGL_ERROR
;
LGL_ERROR
;
glDispatchCompute
(
groups
.
x
,
groups
.
y
,
groups
.
z
);
LGL_ERROR
;
_shader
->
deactivate
();
glFinish
();
// put resulting image into DataContainer
std
::
unique_ptr
<
ImageData
>
id
(
new
ImageData
(
img
->
getParent
()
->
getDimensionality
(),
size
,
img
->
getParent
()
->
getNumChannels
()));
ImageRepresentationGL
::
create
(
id
.
get
(),
resultTexture
.
release
());
id
->
setMappingInformation
(
img
->
getParent
()
->
getMappingInformation
());
data
.
addData
(
p_outputImage
.
getValue
(),
id
.
release
());
cgt
::
TextureUnit
::
setZeroUnit
();
LGL_ERROR
;
}
}
else
{
LERROR
(
"Supports only 2D and 3D Median Filtering."
);
}
}
else
{
LDEBUG
(
"No suitable input image found."
);
}
}
void
MedianFilter
::
generateShader
(
const
ImageRepresentationGL
::
ScopedRepresentation
&
img
)
{
auto
wnd
=
p_windowSize
.
getValue
();
auto
wg
=
p_workgroupSize
.
getValue
();
std
::
stringstream
ss
;
ss
<<
"#define MEDIAN_WINDOW_X "
<<
wnd
.
x
<<
std
::
endl
;
ss
<<
"#define MEDIAN_WINDOW_Y "
<<
wnd
.
y
<<
std
::
endl
;
ss
<<
"#define MEDIAN_WINDOW_Z "
<<
wnd
.
z
<<
std
::
endl
;
ss
<<
"#define WORK_GROUP_SIZE_X "
<<
wg
.
x
<<
std
::
endl
;
ss
<<
"#define WORK_GROUP_SIZE_Y "
<<
wg
.
y
<<
std
::
endl
;
ss
<<
"#define WORK_GROUP_SIZE_Z "
<<
wg
.
z
<<
std
::
endl
;
ss
<<
"#define OUTPUT_TEXTURE_FORMAT "
<<
cgt
::
Texture
::
calcMatchingWriteFormat
(
img
->
getTexture
()
->
getInternalFormat
())
<<
std
::
endl
;
// very simple caching to eliminate the glsl compiler as a bottleneck
static
std
::
string
headers
;
if
(
!
_shader
||
headers
!=
ss
.
str
())
{
headers
=
ss
.
str
();
_shader
=
ShdrMgr
.
loadCompute
(
"modules/preprocessing/glsl/medianfilter.comp"
,
headers
);
}
}
}
modules/preprocessing/processors/medianfilter.h
0 → 100644
View file @
79819c19
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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 MEDIANFILTER_H__
#define MEDIANFILTER_H__
#include <string>
#include "core/datastructures/imagerepresentationgl.h"
#include "core/pipeline/abstractprocessordecorator.h"
#include "core/pipeline/visualizationprocessor.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/floatingpointproperty.h"
#include "core/properties/optionproperty.h"
#include "modules/modulesapi.h"
namespace
cgt
{
class
BufferObject
;
class
Shader
;
}
namespace
campvis
{
/**
* Performs a median filtering on the input image using OpenGL Compute Shaders.
*/
class
CAMPVIS_MODULES_API
MedianFilter
:
public
AbstractProcessor
{
public:
/**
* Constructs a new GlGaussianFilter Processor
**/
MedianFilter
();
/**
* Destructor
**/
virtual
~
MedianFilter
();
/// \see AbstractProcessor::init
virtual
void
init
();
/// \see AbstractProcessor::deinit
virtual
void
deinit
();
/**
* To be used in ProcessorFactory static methods
*/
static
const
std
::
string
getId
()
{
return
"MedianFilter"
;
};
/// \see AbstractProcessor::getName()
virtual
const
std
::
string
getName
()
const
{
return
getId
();
};
/// \see AbstractProcessor::getDescription()
virtual
const
std
::
string
getDescription
()
const
{
return
"Performs a median filtering on the input image using OpenGL Compute Shaders."
;
};
/// \see AbstractProcessor::getAuthor()
virtual
const
std
::
string
getAuthor
()
const
{
return
"Jakob Weiss <jakob.weiss@tum.de>"
;
};
/// \see AbstractProcessor::getProcessorState()
virtual
ProcessorState
getProcessorState
()
const
{
return
AbstractProcessor
::
TESTING
;
};
DataNameProperty
p_inputImage
;
///< ID for input volume
DataNameProperty
p_outputImage
;
///< ID for output gradient volume
IVec3Property
p_windowSize
;
///< Size for specifying filtering window
IVec3Property
p_workgroupSize
;
///< Size of the workgroup
protected:
/// \see AbstractProcessor::updateResult
virtual
void
updateResult
(
DataContainer
&
dataContainer
)
override
;
void
generateShader
(
const
ImageRepresentationGL
::
ScopedRepresentation
&
img
);
cgt
::
Shader
*
_shader
;
///< Shader for performing median filtering
static
const
std
::
string
loggerCat_
;
};
}
#endif // MEDIANFILTER_H__
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment