diff --git a/Modules/PhotoacousticArtifacts/include/mitkPhotoacousticArtifact.h b/Modules/PhotoacousticArtifacts/include/mitkPhotoacousticArtifact.h index c767e24b88..74b798ce47 100644 --- a/Modules/PhotoacousticArtifacts/include/mitkPhotoacousticArtifact.h +++ b/Modules/PhotoacousticArtifacts/include/mitkPhotoacousticArtifact.h @@ -1,41 +1,56 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkPhotoacousticArtifact_h #define mitkPhotoacousticArtifact_h #include #include #include #include +#include namespace mitk { - - class MITKPHOTOACOUSTICARTIFACTS_EXPORT PhotoacousticArtifact + class MITKPHOTOACOUSTICARTIFACTS_EXPORT PhotoacousticArtifact final : public mitk::ImageToImageFilter { public: - PhotoacousticArtifact(); - virtual ~PhotoacousticArtifact(); + // All classes that derive from an ITK-based MITK class need at least the + // following two macros. Make sure you don't declare the constructor public + // to force clients of your class to follow the ITK convention for + // instantiating classes via the static New() method. + mitkClassMacro(PhotoacousticArtifact, mitk::ImageToImageFilter) + itkFactorylessNewMacro(Self) + + itkSetMacro(UpperThreshold, int) + itkGetMacro(UpperThreshold, int) + itkSetMacro(LowerThreshold, int) + itkGetMacro(LowerThreshold, int) protected: - + private: + PhotoacousticArtifact(); + virtual ~PhotoacousticArtifact(); + + void GenerateData() override; + int m_UpperThreshold; + int m_LowerThreshold; }; } #endif mitkPhotoacousticArtifact_h diff --git a/Modules/PhotoacousticArtifacts/src/Algorithms/mitkPhotoacousticArtifact.cpp b/Modules/PhotoacousticArtifacts/src/Algorithms/mitkPhotoacousticArtifact.cpp index 96748ec3b7..bc78576cbb 100644 --- a/Modules/PhotoacousticArtifacts/src/Algorithms/mitkPhotoacousticArtifact.cpp +++ b/Modules/PhotoacousticArtifacts/src/Algorithms/mitkPhotoacousticArtifact.cpp @@ -1,28 +1,102 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include +#include +#include + +#include + +// See definition of AwesomeImageFilter::GenerateData() further below for +// a rationale behind this function template. +template +static void AddThresholdFilter(const itk::Image* inputImage, + int upperThreshold, int lowerThreshold, mitk::Image::Pointer outputImage) +{ + typedef itk::Image ImageType; + typedef itk::ShiftScaleImageFilter FilterType; + + auto filter = FilterType::New(); + filter->SetInput(inputImage); + filter->SetShift(upperThreshold); //add lower + + filter->Update(); + + // This is the tricky part that is done wrong very often. As the image data + // of ITK images and MITK images are binary compatible, we don't need to + // cast or copy the ITK output image. Instead, we just want to reference + // the image data and tell ITK that we took the ownership. + mitk::GrabItkImageMemory(filter->GetOutput(), outputImage); +} + mitk::PhotoacousticArtifact::PhotoacousticArtifact() + : m_UpperThreshold(20), m_LowerThreshold(0) { - MITK_INFO << "Hallo!"; - MITK_INFO << "Test12345"; + MITK_INFO << "Hallo!"; + this->SetNumberOfRequiredInputs(1); + this->SetNumberOfRequiredOutputs(1); } mitk::PhotoacousticArtifact::~PhotoacousticArtifact() { +} + +void mitk::PhotoacousticArtifact::GenerateData() +{ + mitk::Image::Pointer inputImage = this->GetInput(0); + + if (m_UpperThreshold == 0) // upper>lower, =! + { + // Nothing to calculate in this case, just copy the input image. + this->SetPrimaryOutput(inputImage->Clone().GetPointer()); + } + else + { + mitk::Image::Pointer outputImage = this->GetOutput(); -} \ No newline at end of file + try + { + // We want to apply an ITK filter to the MITK input image. While MITK + // images are not templated, ITK images are templated by both pixel type + // and image dimension. The actual image data is binary compatible, though. + // MITK provides ITK access macros that enable you to directly operate + // on MITK images without any superfluous copying. + // To allow ITK filters to work with different image types at runtime you + // would be required to instantiate your function templates for each and + // every expected combination of pixel type and image dimension. Luckily, + // MITK provides a whole bunch of multiplexer macros to save you doing this + // manually (see mitkImageAccessByItk.h). + // These macros range from being completely generic to partly constrained + // variants. For example, you may want to constrain the image dimension or + // the pixel type. As your function template is compiled for each allowed + // combination, compile time and code size may increase dramatically. + // As a rule of thumb, use a suitable multiplexer macro that is as + // constrained as possible and yet as generic as necessary. + // To prevent a combinatorial explosion, image dimension is restricted to + // 2 and 3 even for the dimension-variable multiplexer macros. + // Thus, the following multiplexer macro allows for 2-dimensional and + // 3-dimensional images with an integer pixel type, for example, + // (un)signed char, short, and int, resulting in a total of 12 distinct + // combinations. + AccessIntegralPixelTypeByItk_n(inputImage, AddThresholdFilter, (m_UpperThreshold, m_LowerThreshold, outputImage)); + } + catch (const mitk::AccessByItkException& e) + { + MITK_ERROR << "Unsupported pixel type or image dimension: " << e.what(); + } + } +} diff --git a/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifact.cpp b/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifact.cpp index dd7bd6ad49..0979857f20 100644 --- a/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifact.cpp +++ b/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifact.cpp @@ -1,180 +1,180 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "PhotoacousticArtifact.h" +// QT includes (GUI) +#include + +// Berry includes (selection service) #include #include +// MITK includes (general) #include - -#include #include - #include -//#include -//#include - -// Helper function to create a fully set up instance of our -// AwesomeImageInteractor, based on the state machine specified in Paint.xml -// as well as its configuration in PaintConfig.xml. Both files are compiled -// into our MyAwesomeLib module as resources. -//static AwesomeImageInteractor::Pointer CreateAwesomeImageInteractor() -//{ -// auto myAwesomeLib = us::ModuleRegistry::GetModule("MyAwesomeLib"); -// -// auto interactor = AwesomeImageInteractor::New(); -// interactor->LoadStateMachine("Paint.xml", myAwesomeLib); -// interactor->SetEventConfig("PaintConfig.xml", myAwesomeLib); -// -// return interactor; -//} +// Includes for image casting between ITK and MITK +#include +#include + +// ITK includes (general) +//#include + +// Threshold +#include // Don't forget to initialize the VIEW_ID. const std::string PhotoacousticArtifact::VIEW_ID = "photoacousticproject.views.photoacoustic.artifacts"; void PhotoacousticArtifact::CreateQtPartControl(QWidget* parent) { // Setting up the UI is a true pleasure when using .ui files, isn't it? m_Controls.setupUi(parent); // Wire up the UI widgets with our functionality. connect(m_Controls.applyFilterPushButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedImage())); } void PhotoacousticArtifact::SetFocus() { - //m_Controls.processImageButton->setFocus(); + m_Controls.applyFilterPushButton->setFocus(); } void PhotoacousticArtifact::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& dataNodes) { for (const auto& dataNode : dataNodes) { // Write robust code. Always check pointers before using them. If the // data node pointer is null, the second half of our condition isn't // even evaluated and we're safe (C++ short-circuit evaluation). if (dataNode.IsNotNull() && dynamic_cast(dataNode->GetData()) != nullptr) { m_Controls.selectImageLabel->setVisible(false); return; } } - //m_Controls.horizontalLayout->activate(); j // Nothing is selected or the selection doesn't contain an image. - //m_Controls.selectImageLabel->setVisible(true); + m_Controls.selectImageLabel->setVisible(true); } void PhotoacousticArtifact::ProcessSelectedImage() { // Before we even think about processing something, we need to make sure // that we have valid input. Don't be sloppy, this is a main reason // for application crashes if neglected. - mitk::PhotoacousticArtifact* filter = new mitk::PhotoacousticArtifact(); + //mitk::PhotoacousticArtifact* filter = new mitk::PhotoacousticArtifact(); auto selectedDataNodes = this->GetDataManagerSelection(); if (selectedDataNodes.empty()) return; auto firstSelectedDataNode = selectedDataNodes.front(); if (firstSelectedDataNode.IsNull()) { QMessageBox::information(nullptr, "Photoacoustic Artifact", "Please load and select an image before starting image processing."); return; } auto data = firstSelectedDataNode->GetData(); // Something is selected, but does it contain data? if (data != nullptr) { // We don't use the auto keyword here, which would evaluate to a native // image pointer. Instead, we want a smart pointer in order to ensure that // the image isn't deleted somewhere else while we're using it. mitk::Image::Pointer image = dynamic_cast(data); // Something is selected and it contains data, but is it an image? if (image.IsNotNull()) { auto imageName = firstSelectedDataNode->GetName(); - auto offset = m_Controls.chooseThresholdSpinBox->value(); + auto threshold = m_Controls.chooseThresholdSpinBox->value(); MITK_INFO << "Process image \"" << imageName << "\" ..."; - // We're finally using the AwesomeImageFilter from our AwesomeLib module. - //auto filter = AwesomeImageFilter::New(); - //filter->SetInput(image); - //filter->SetOffset(offset); + // == From QmitkBasicImageProcessingView: == + // ThresholdFilterType::Pointer thFilter = ThresholdFilterType::New(); + // thFilter->SetLowerThreshold(param1 < param2 ? param1 : param2); + // thFilter->SetUpperThreshold(param2 > param1 ? param2 : param1); + // thFilter->SetInsideValue(1); + // thFilter->SetOutsideValue(0); + // thFilter->SetInput(itkImage); + // thFilter->UpdateLargestPossibleRegion(); + // newImage = mitk::ImportItkImage(thFilter->GetOutput())->Clone(); + // nameAddition << "_Threshold"; + // std::cout << "Thresholding successful." << std::endl; + + // We're finally using the AwesomeImageFilter from our AwesomeLib module. - //filter->Update(); + //typedef itk::Image ImageType; + //auto filter = itk::ThresholdImageFilter::New(); + auto filter = mitk::PhotoacousticArtifact::New(); + filter->SetInput(image); + filter->SetUpperThreshold(17); //upperThreshold - //mitk::Image::Pointer processedImage = filter->GetOutput(); + filter->Update(); - //if (processedImage.IsNull() || !processedImage->IsInitialized()) - //return; + mitk::Image::Pointer processedImage = filter->GetOutput(); + + if (processedImage.IsNull() || !processedImage->IsInitialized()) + return; MITK_INFO << " done"; // Stuff the resulting image into a data node, set some properties, // and add it to the data storage, which will eventually display the // image in the application. auto processedImageDataNode = mitk::DataNode::New(); //processedImageDataNode->SetData(processedImage); //QString name = QString("%1 (Offset: %2)").arg(imageName.c_str()).arg(offset); //processedImageDataNode->SetName(name.toStdString()); // We don't really need to copy the level window, but if we wouldn't // do it, the new level window would be initialized to display the image // with optimal contrast in order to capture the whole range of pixel // values. This is also true for the input image as long as one didn't // modify its level window manually. Thus, the images would appear // identical unless you compare the level window widget for both images. mitk::LevelWindow levelWindow; if (firstSelectedDataNode->GetLevelWindow(levelWindow)) processedImageDataNode->SetLevelWindow(levelWindow); - // We also attach our AwesomeImageInteractor, which allows us to paint - // on the resulting images by using the mouse as long as the CTRL key - // is pressed. - //auto interactor = CreateAwesomeImageInteractor(); - - //if (interactor.IsNotNull()) - // interactor->SetDataNode(processedImageDataNode); - this->GetDataStorage()->Add(processedImageDataNode); } } // Now it's your turn. This class/method has lots of room for improvements, // for example: // // - What happens when multiple items are selected but the first one isn't // an image? - There isn't any feedback for the user at all. // - What's the front item of a selection? Does it depend on the order // of selection or the position in the Data Manager? - Isn't it // better to process all selected images? Don't forget to adjust the // titles of the UI widgets. // - In addition to the the displayed label, it's probably a good idea to // enable or disable the button depending on the selection. } diff --git a/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifact.h b/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifact.h index f369e1707a..71fd0ffc6f 100644 --- a/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifact.h +++ b/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifact.h @@ -1,69 +1,70 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef PhotoacousticArtifact_h #define PhotoacousticArtifact_h #include #include +#include // There's an item "PhotoacousticArtifactViewControls.ui" in the UI_FILES list in // files.cmake. The Qt UI Compiler will parse this file and generate a // header file prefixed with "ui_", which is located in the build directory. // Use Qt Creator to view and edit .ui files. The generated header file // provides a class that contains all of the UI widgets. #include // All views in MITK derive from QmitkAbstractView. You have to override // at least the two methods CreateQtPartControl() and SetFocus(). class PhotoacousticArtifact : public QmitkAbstractView { // As QmitkAbstractView derives from QObject and we want to use the Qt // signal and slot mechanism, we must not forget the Q_OBJECT macro. // This header file also has to be listed in MOC_H_FILES in files.cmake, // in order that the Qt Meta-Object Compiler can find and process this // class declaration. Q_OBJECT public: // This is a tricky one and will give you some headache later on in // your debug sessions if it has been forgotten. Also, don't forget // to initialize it in the implementation file. static const std::string VIEW_ID; // In this method we initialize the GUI components and connect the // associated signals and slots. void CreateQtPartControl(QWidget* parent) override; private slots: void ProcessSelectedImage(); private: // Typically a one-liner. Set the focus to the default widget. void SetFocus() override; // This method is conveniently called whenever the selection of Data Manager // items changes. void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, const QList& dataNodes) override; // Generated from the associated UI file, it encapsulates all the widgets // of our view. Ui::PhotoacousticArtifactViewControls m_Controls; }; #endif diff --git a/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifactActivator.cpp b/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifactActivator.cpp index b60f9ac123..9d8a9682a1 100644 --- a/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifactActivator.cpp +++ b/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifactActivator.cpp @@ -1,27 +1,28 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "PhotoacousticArtifactActivator.h" #include "PhotoacousticArtifact.h" void PhotoacousticArtifactActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(PhotoacousticArtifact, context) } -void PhotoacousticArtifactActivator::stop(ctkPluginContext*) +void PhotoacousticArtifactActivator::stop(ctkPluginContext* context) { + Q_UNUSED(context) }