diff --git a/Modules/PhotoacousticArtifacts/include/mitkPhotoacousticArtifact.h b/Modules/PhotoacousticArtifacts/include/mitkPhotoacousticArtifact.h index 74b798ce47..5879a0f75c 100644 --- a/Modules/PhotoacousticArtifacts/include/mitkPhotoacousticArtifact.h +++ b/Modules/PhotoacousticArtifacts/include/mitkPhotoacousticArtifact.h @@ -1,56 +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 final : public mitk::ImageToImageFilter { public: // 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(); + ~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 bc78576cbb..2f951a2956 100644 --- a/Modules/PhotoacousticArtifacts/src/Algorithms/mitkPhotoacousticArtifact.cpp +++ b/Modules/PhotoacousticArtifacts/src/Algorithms/mitkPhotoacousticArtifact.cpp @@ -1,102 +1,109 @@ /*=================================================================== 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 +#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) + int lowerThreshold, int upperThreshold, mitk::Image::Pointer outputImage) { - typedef itk::Image ImageType; - typedef itk::ShiftScaleImageFilter FilterType; + typedef typename itk::Image ImageType; + typedef typename itk::ThresholdImageFilter FilterType; auto filter = FilterType::New(); filter->SetInput(inputImage); - filter->SetShift(upperThreshold); //add lower + filter->SetLower(lowerThreshold); + filter->SetUpper(upperThreshold); + filter->ThresholdOutside(lowerThreshold, upperThreshold); + filter->SetOutsideValue(0); 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) { + // TODO output + this->SetPrimaryOutput(mitk::Image::New()); 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, =! + if (m_LowerThreshold > m_UpperThreshold) { - // Nothing to calculate in this case, just copy the input image. - this->SetPrimaryOutput(inputImage->Clone().GetPointer()); + // Error Handling + MITK_WARN << "Could not do that"; //beschreiben, could not bcs lower > upper + return; } else { mitk::Image::Pointer outputImage = this->GetOutput(); 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)); + AccessIntegralPixelTypeByItk_n(inputImage, AddThresholdFilter, (m_LowerThreshold, m_UpperThreshold, 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 0979857f20..7fe2bd0141 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,166 @@ /*=================================================================== 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 // 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.applyFilterPushButton->setFocus(); } -void PhotoacousticArtifact::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& dataNodes) +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); } 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(); - 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."); + 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 threshold = m_Controls.chooseThresholdSpinBox->value(); + auto lowerThreshold = m_Controls.lowerThresholdSpinBox->value(); + auto upperThreshold = m_Controls.upperThresholdSpinBox->value(); MITK_INFO << "Process image \"" << imageName << "\" ..."; - // == 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. - - //typedef itk::Image ImageType; - //auto filter = itk::ThresholdImageFilter::New(); auto filter = mitk::PhotoacousticArtifact::New(); filter->SetInput(image); - filter->SetUpperThreshold(17); //upperThreshold + filter->SetLowerThreshold(lowerThreshold); + filter->SetUpperThreshold(upperThreshold); filter->Update(); 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); + processedImageDataNode->SetData(processedImage); - //QString name = QString("%1 (Offset: %2)").arg(imageName.c_str()).arg(offset); - //processedImageDataNode->SetName(name.toStdString()); + QString name = QString("%1 (Threshold: %2 - %3)").arg(imageName.c_str()). + arg(lowerThreshold).arg(upperThreshold); + 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); 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/PhotoacousticArtifactViewControls.ui b/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifactViewControls.ui index 81ffd320fc..ae90b9dbc1 100644 --- a/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifactViewControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacousticartifacts/src/internal/PhotoacousticArtifactViewControls.ui @@ -1,82 +1,92 @@ PhotoacousticArtifactViewControls 0 0 220 160 Photoacoustic Artifacts QLabel { color: rgb(255, 0, 0) } Please select an image. - - + + - 101 + 202 16777215 - - Choose threshold: - - - + + - 202 + 101 16777215 + + Lower threshold: + + + + + + + Upper threshold: + + + + Apply Filter Qt::Vertical QSizePolicy::Expanding 20 220