surfaceExtractionGUIExample.cpp source

An example of a GUI for performing surface extraction from a volume in real-time.

main.cpp:

#include "SimpleGUI.hpp"

using namespace fast;

int main() {

    auto window = SimpleGUI::create();
#ifdef FAST_CONTINUOUS_INTEGRATION
    // This will automatically close the window after 5 seconds, used for CI testing
    window->setTimeout(5*1000);
#endif
    window->run();

    return 0;
}

SimpleGUI.hpp:

#pragma once

#include "FAST/Visualization/Window.hpp"
#include "FAST/Algorithms/SurfaceExtraction/SurfaceExtraction.hpp"
#include <FAST/Algorithms/GaussianSmoothing/GaussianSmoothing.hpp>
#include <QLabel>

namespace fast {

class SimpleGUI : public Window {
    FAST_OBJECT_V4(SimpleGUI)
    public:
        FAST_CONSTRUCTOR(SimpleGUI)
        void updateThreshold(int value);
        void updateSmoothingParameter(int value);
    private:

        SurfaceExtraction::pointer mSurfaceExtraction;
        GaussianSmoothing::pointer mSmoothing;
        QLabel* mSmoothingLabel;
        QLabel* mThresholdLabel;
};

} // end namespace fast

SimpleGUI.cpp:

#include "SimpleGUI.hpp"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QSlider>
#include <FAST/Importers/ImageFileImporter.hpp>
#include <FAST/Visualization/TriangleRenderer/TriangleRenderer.hpp>
#include <functional>


namespace fast {

SimpleGUI::SimpleGUI() {

    // Create a 3D view
    View* view = createView();
    view->set3DMode();

    setWidth(std::min(1920, getScreenWidth()));
    setHeight(std::min(1080, getScreenHeight()));
    enableMaximized();

    // Import image
    ImageFileImporter::pointer importer = ImageFileImporter::New();
    importer->setFilename(Config::getTestDataPath() + "CT/CT-Abdomen.mhd");

    // Smooth image
    mSmoothing = GaussianSmoothing::create(1.0f)
            ->connect(importer);

    // Set up surface extraction
    mSurfaceExtraction = SurfaceExtraction::create(100)
            ->connect(mSmoothing);

    // Set up rendering
    auto renderer = TriangleRenderer::create()
            ->connect(mSurfaceExtraction);
    view->addRenderer(renderer);

    // Create and add GUI elements

    // First create the menu layout
    auto menuLayout = new QVBoxLayout;

    // Menu items should be aligned to the top
    menuLayout->setAlignment(Qt::AlignTop);

    // Title label
    auto title = new QLabel;
    title->setText("Simple GUI<br>Example");
    QFont font;
    font.setPointSize((int)round(18*getScalingFactor()));
    title->setFont(font);
    menuLayout->addWidget(title);

    // Quit button
    const int width = getScreenWidth()/6.0f;
    auto quitButton = new QPushButton;
    quitButton->setText("Quit");
    quitButton->setFixedWidth(width);
    menuLayout->addWidget(quitButton);

    // Connect the clicked signal of the quit button to the stop method for the window
    QObject::connect(quitButton, &QPushButton::clicked, std::bind(&Window::stop, this));

    // Smoothing parameter label
    mSmoothingLabel = new QLabel;
    mSmoothingLabel->setText("Smoothing: 1.5 mm");
    menuLayout->addWidget(mSmoothingLabel);

    // Smoothing parameter slider
    auto slider = new QSlider(Qt::Horizontal);
    slider->setMinimum(0);
    slider->setMaximum(3);
    slider->setValue(1);
    slider->setFixedWidth(width);
    menuLayout->addWidget(slider);

    // Connect the value changed signal of the slider to the updateSmoothingParameter method
    QObject::connect(slider, &QSlider::valueChanged, std::bind(&SimpleGUI::updateSmoothingParameter, this, std::placeholders::_1));

    // Threshold label
    mThresholdLabel = new QLabel;
    mThresholdLabel->setText("Threshold: 100 HU");
    menuLayout->addWidget(mThresholdLabel);

    // Threshold slider
    auto slider2 = new QSlider(Qt::Horizontal);
    slider2->setMinimum(-100);
    slider2->setMaximum(300);
    slider2->setValue(100);
    slider2->setFixedWidth(width);
    menuLayout->addWidget(slider2);

    // Connect the value changed signal of the slider to the updateThreshold method
    QObject::connect(slider2, &QSlider::valueChanged, std::bind(&SimpleGUI::updateThreshold, this, std::placeholders::_1));

    // Add menu and view to main layout
    auto layout = new QHBoxLayout;
    layout->addLayout(menuLayout);
    layout->addWidget(view);

    mWidget->setLayout(layout);
}

void SimpleGUI::updateThreshold(int value) {
    mSurfaceExtraction->setThreshold(value);

    // Update label
    std::string text = "Threshold: " + std::to_string(value) + " HU";
    mThresholdLabel->setText(text.c_str());
}

void SimpleGUI::updateSmoothingParameter(int value) {
    // The slider can only use int values, must convert to float manually
    float standardDeviation = 1 + value*0.5;
    mSmoothing->setStandardDeviation(standardDeviation);

    // Update label
    std::string text = "Smoothing: " + std::to_string(standardDeviation) + " mm";
    mSmoothingLabel->setText(text.c_str());
}

}