2.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 1ce3187c authored by Declara Denis's avatar Declara Denis Committed by Christian Schulte zu Berge
Browse files

Added automatic CG iteration count handling

* Now it is possible to set a time budget for the CudaConfidenceMapsDemo
  pipeline and the number of CG iterations that can be carried out is
  automatically determined.
* Code still needs some cleanup.
parent 40e26d0b
......@@ -24,6 +24,8 @@
#include "cudaconfidencemapsdemo.h"
#include <tbb/tick_count.h>
#include "core/datastructures/imagedata.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
......@@ -39,7 +41,7 @@ namespace campvis {
, _usFusion(&_canvasSize)
, _usFanRenderer(&_canvasSize)
, p_iterations("Iterations", "Number of CG Iterations", 150, 1, 500)
, p_autoIterationCount("AutoIterationCount", "Estimate iteration count based on time slot", false)
, p_autoIterationCount("AutoIterationCount", "Estimate iteration count based on time slot", true)
, p_timeSlot("TimeSlot", "Milliseconds per frame", 32.0f, 10.0f, 250.0f)
, p_connectToIGTLinkServer("ConnectToIGTLink", "Connect/Disconnect to IGTLink")
, p_gaussianFilterSize("GaussianSigma", "Blur amount", 2.5f, 1.0f, 10.0f)
......@@ -133,6 +135,63 @@ namespace campvis {
AutoEvaluationPipeline::deinit();
}
void CudaConfidenceMapsDemo::executePipeline() {
static float iterationsPerMsAverage = 1.0f;
static unsigned char frame = 0;
if (p_autoIterationCount.getValue() == false) {
AutoEvaluationPipeline::executePipeline();
}
else {
// Only launch the pipeline if the IgtlReader has recieved new data
if (!_usIgtlReader.isValid()) {
auto startTime = tbb::tick_count::now();
// Make sure that the whole pipeline gets invalidated
_usBlurFilter.invalidate(AbstractProcessor::INVALID_RESULT);
_usBlurFilter.invalidate(AbstractProcessor::INVALID_RESULT);
_usResampler.invalidate(AbstractProcessor::INVALID_RESULT);
_usMapsSolver.invalidate(AbstractProcessor::INVALID_RESULT);
_usFusion.invalidate(AbstractProcessor::INVALID_RESULT);
executeProcessorAndCheckOpenGLState(&_usIgtlReader);
executeProcessorAndCheckOpenGLState(&_usBlurFilter);
executeProcessorAndCheckOpenGLState(&_usResampler);
auto solverStartTime = tbb::tick_count::now();
executeProcessorAndCheckOpenGLState(&_usMapsSolver);
executeProcessorAndCheckOpenGLState(&_usFusion);
executeProcessorAndCheckOpenGLState(&_usFanRenderer);
if (frame % 16 == 0) {
tbb::tick_count endTime = tbb::tick_count::now();
auto ms = (endTime - startTime).seconds() * 1000.0f;
std::stringstream string;
string << "Execution time: " << static_cast<int>(ms) << "ms" << std::endl;
string << "CG Iterations: " << _usMapsSolver.getActualConjugentGradientIterations() << std::endl;
string << "Error: " << _usMapsSolver.getResidualNorm() << std::endl;
_usFanRenderer.p_text.setValue(string.str());
}
frame++;
// Get the total end time (including fanRenderer) and calculate the number of
// cg iterations that can be afforded
auto endTime = tbb::tick_count::now();
auto ms = (endTime - startTime).seconds() * 1000.0f;
auto iterationsPerMs = _usMapsSolver.getActualConjugentGradientIterations() / ms;
float mixRatio = 0.85f;
iterationsPerMsAverage = iterationsPerMsAverage * mixRatio + iterationsPerMs * (1.0f - mixRatio);
// Factor out the time needed for preprocessing the image from the time slot
float timeSlot = (p_timeSlot.getValue() - (solverStartTime - startTime).seconds() / 1000.0f);
int iterations = std::round(p_timeSlot.getValue() * iterationsPerMsAverage);
p_iterations.setValue(iterations);
}
}
}
void CudaConfidenceMapsDemo::onRenderTargetSizeChanged(const AbstractProperty *prop) {
}
}
\ No newline at end of file
......@@ -57,6 +57,9 @@ namespace campvis {
/// \see AutoEvaluationPipeline::deinit()
virtual void deinit();
/// \see AbstractPipeline::executePipeline()
virtual void executePipeline();
/// \see AbstractPipeline::getName()
virtual const std::string getName() const { return getId(); };
static const std::string getId() { return "CudaConfidenceMapsDemo"; };
......
......@@ -123,6 +123,16 @@ namespace campvis {
void CudaConfidenceMapsSolver::updateProperties(DataContainer& dataContainer) { }
int CudaConfidenceMapsSolver::getActualConjugentGradientIterations() const
{
return _solver.getSolutionIterationCount();
}
float CudaConfidenceMapsSolver::getResidualNorm() const
{
return _solver.getSolutionResidualNorm();
}
void CudaConfidenceMapsSolver::resetSolutionVector() {
// Create a linear gradient image of the same size as the input image
_solver.resetSolution();
......
......@@ -80,6 +80,9 @@ namespace campvis {
/// \see AbstractProcessor::updateProperties
virtual void updateProperties(DataContainer& dataContainer);
int getActualConjugentGradientIterations() const;
float getResidualNorm() const;
DataNameProperty p_inputImage; ///< ID for input volume
DataNameProperty p_outputConfidenceMap; ///< ID for output gradient volume
......
......@@ -44,6 +44,9 @@ namespace campvis {
, p_renderTargetID("RenderTargetID", "Render Target ID", "us.output", DataNameProperty::WRITE)
, p_halfAngle("HalfAngle", "Fan Half Angle", 45.0f, 1.0f, 90.0f)
, p_innerRadius("InnerRadius", "Fan Inner Radius", 0.2f, 0.0f, 0.99f)
, p_text("Text", "Text", "Ultrasound Title")
, p_fontFileName("FontFileName", "Path to the Font File to Use", "", StringProperty::OPEN_FILENAME)
, p_fontSize("FontSize", "Font Size", 20, 4, 100)
, _shader(0)
, _grid(nullptr)
{
......@@ -51,6 +54,12 @@ namespace campvis {
addProperty(p_renderTargetID);
addProperty(p_halfAngle);
addProperty(p_innerRadius);
addProperty(p_text);
addProperty(p_fontFileName);
addProperty(p_fontSize);
p_fontFileName.setValue(ShdrMgr.completePath("/modules/fontrendering/fonts/FreeSans.ttf"));
}
UsFanRenderer::~UsFanRenderer() {
......@@ -63,12 +72,16 @@ namespace campvis {
_grid = GeometryDataFactory::createGrid(cgt::vec3(-0.5f, 1.0f, 0.0f), cgt::vec3(0.5f, 0.0f, 0.0f),
cgt::vec3(0.0f, 1.0f, 0.0f), cgt::vec3(1.0f, 0.0f, 0.0f),
16, 4);
// Initialize font rendering
updateFontAtlas();
}
void UsFanRenderer::deinit() {
ShdrMgr.dispose(_shader);
_shader = nullptr;
_grid = nullptr;
_atlas = nullptr;
VisualizationProcessor::deinit();
}
......@@ -128,9 +141,27 @@ namespace campvis {
_grid->render(GL_TRIANGLE_STRIP);
_shader->deactivate();
// Render text (if any)
if (_atlas != nullptr) {
const cgt::mat4 transformation = cgt::mat4::createTranslation(cgt::vec3(-1.f, -1.f, 0.f))
* cgt::mat4::createScale(cgt::vec3(2.f / _viewportSizeProperty->getValue().x, 2.f / _viewportSizeProperty->getValue().y, 1.f));
cgt::vec2 pos(32.0f, static_cast<float>(_viewportSizeProperty->getValue().y - 32.0f));
_atlas->renderText(p_text.getValue(), pos, cgt::vec4(1.0f), transformation);
}
LGL_ERROR;
data.addData(p_renderTargetID.getValue(), new RenderData(_fbo));
}
}
void UsFanRenderer::updateFontAtlas() {
_atlas = nullptr;
try {
_atlas = std::unique_ptr<fontrendering::FontAtlas>(new fontrendering::FontAtlas(p_fontFileName.getValue(), p_fontSize.getValue()));
}
catch (...) {
LERROR("Could not create FontAtlas, UsFanRenderer will not display any text.");
}
}
}
......@@ -33,6 +33,8 @@
#include "core/properties/allproperties.h"
#include "core/datastructures/multiindexedgeometry.h"
#include "modules/fontrendering/tools/fontatlas.h"
namespace cgt {
class Shader;
}
......@@ -69,17 +71,24 @@ namespace campvis {
DataNameProperty p_inputImage;
DataNameProperty p_renderTargetID;
FloatProperty p_halfAngle;
FloatProperty p_halfAngle; ///< Half of the fan's opening angle in degrees
FloatProperty p_innerRadius;
StringProperty p_text; ///< Text to render
StringProperty p_fontFileName; ///< Path to the font file to use
IntProperty p_fontSize; ///< Font size to use
protected:
/// \see AbstractProcessor::updateResult
virtual void updateResult(DataContainer& dataContainer);
void updateFontAtlas();
cgt::Shader* _shader;
std::unique_ptr<MultiIndexedGeometry> _grid;
std::unique_ptr<fontrendering::FontAtlas> _atlas;
private:
static const std::string loggerCat_;
};
......
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