diff --git a/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/colourimageprocessing/mitkColourImageProcessor.cpp b/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/colourimageprocessing/mitkColourImageProcessor.cpp index fb28276592..c758617786 100644 --- a/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/colourimageprocessing/mitkColourImageProcessor.cpp +++ b/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/colourimageprocessing/mitkColourImageProcessor.cpp @@ -1,1004 +1,995 @@ /*=================================================================== 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 "mitkColourImageProcessor.h" #include #include #include #include namespace mitk { mitkColourImageProcessor::mitkColourImageProcessor() {} mitkColourImageProcessor::~mitkColourImageProcessor() {} template class ScalarToRGBAConverter { const T *dataPtr; unsigned char *tmpPtr; int sizeX; int sizeY; int sizeZ; int sizeXY; int sizeXm1; int sizeYm1; int sizeZm1; mitk::TransferFunction::Pointer tf; public: ScalarToRGBAConverter(const T *_dataPtr, unsigned char *_tmpPtr, int _sizeX, int _sizeY, int _sizeZ, mitk::TransferFunction::Pointer _tf) { dataPtr = _dataPtr; tmpPtr = _tmpPtr; sizeX = _sizeX; sizeY = _sizeY; sizeZ = _sizeZ; sizeXY = sizeX * sizeY; sizeXm1 = sizeX - 1; sizeYm1 = sizeY - 1; sizeZm1 = sizeZ - 1; tf = _tf; } inline float sample(int x, int y, int z) { return float(dataPtr[x + y * sizeX + z * sizeXY]); } inline int clamp(int x) { if (x < 0) x = 0; else if (x > 255) x = 255; return x; } inline void write(int x, int y, int z, float grayValue, float gx, float gy, float gz) { /* gx /= aspect[0]; gy /= aspect[1]; gz /= aspect[2]; */ // Compute the gradient magnitude float t = sqrtf(gx * gx + gy * gy + gz * gz); int doff = x + y * sizeX + z * sizeXY; vtkPiecewiseFunction *opacityTransferFunction = tf->GetScalarOpacityFunction(); vtkPiecewiseFunction *gradientTransferFunction = tf->GetGradientOpacityFunction(); vtkColorTransferFunction *colorTransferFunction = tf->GetColorTransferFunction(); double rgb[3]; colorTransferFunction->GetColor(double(grayValue), rgb); double opacity = opacityTransferFunction->GetValue(double(grayValue)); opacity *= gradientTransferFunction->GetValue(double(0.5f * t)); tmpPtr[doff * 4 + 0] = int(rgb[0] * 255 + 0.5); tmpPtr[doff * 4 + 1] = int(rgb[1] * 255 + 0.5); tmpPtr[doff * 4 + 2] = int(rgb[2] * 255 + 0.5); tmpPtr[doff * 4 + 3] = int(opacity * 255 + 0.5); } inline void compute(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; gx = sample(x + 1, y, z) - sample(x - 1, y, z); gy = sample(x, y + 1, z) - sample(x, y - 1, z); gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void computeClamp(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; if (x == 0) gx = 2.0f * (sample(x + 1, y, z) - grayValue); else if (x == sizeXm1) gx = 2.0f * (grayValue - sample(x - 1, y, z)); else gx = sample(x + 1, y, z) - sample(x - 1, y, z); if (y == 0) gy = 2.0f * (sample(x, y + 1, z) - grayValue); else if (y == sizeYm1) gy = 2.0f * (grayValue - sample(x, y - 1, z)); else gy = sample(x, y + 1, z) - sample(x, y - 1, z); if (z == 0) gz = 2.0f * (sample(x, y, z + 1) - grayValue); else if (z == sizeZm1) gz = 2.0f * (grayValue - sample(x, y, z - 1)); else gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void compute1D(int y, int z) { int x; x = 0; computeClamp(x, y, z); x++; while (x < sizeX - 1) { compute(x, y, z); x++; } if (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp1D(int y, int z) { int x; x = 0; while (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp2D(int z) { int y; y = 0; while (y < sizeY) { computeClamp1D(y, z); y++; } } inline void compute2D(int z) { int y; y = 0; computeClamp1D(y, z); y++; while (y < sizeY - 1) { compute1D(y, z); y++; } if (y < sizeY) { computeClamp1D(y, z); y++; } } inline void fillSlices() { int z; for (z = 0; z < sizeZ; z++) { if (z == 0 || z == sizeZ - 1) computeClamp2D(z); else compute2D(z); } } }; template mitk::Image::Pointer mitkColourImageProcessor::ScalarToRGBA(itk::Image *input, mitk::TransferFunction::Pointer tf) { const TType *inputData = input->GetBufferPointer(); typename itk::Image::SizeType ioSize = input->GetLargestPossibleRegion().GetSize(); MITK_INFO << "size input image: " << ioSize[0] << ", " << ioSize[1] << ", " << ioSize[2]; MITK_INFO << "size voxel: " << ioSize[0] * ioSize[1] * ioSize[2]; int voxel = ioSize[0] * ioSize[1] * ioSize[2]; auto RGBABuffer = new unsigned char[4 * voxel]; // Convert volume { ScalarToRGBAConverter strc(inputData, RGBABuffer, ioSize[0], ioSize[1], ioSize[2], tf); strc.fillSlices(); } // Create MITK Image out of the raw data { mitk::Image::Pointer image = mitk::Image::New(); unsigned int dimensions[3]; dimensions[0] = ioSize[0]; dimensions[1] = ioSize[1]; dimensions[2] = ioSize[2]; mitk::PixelType pixelType(MakePixelType()); image->Initialize(pixelType, 3, dimensions); image->SetImportChannel(RGBABuffer, 0, Image::ManageMemory); return image; } } mitk::Image::Pointer mitkColourImageProcessor::convertToRGBAImage(mitk::Image::Pointer mitkInput, mitk::TransferFunction::Pointer tf) { MITK_INFO << "convertToRGBAImage"; mitk::Image::Pointer mitkResult = mitk::Image::New(); if (mitkInput->GetPixelType().GetComponentType() == itk::ImageIOBase::CHAR) { // cast to itkImage itk::Image::Pointer itkInput; mitk::CastToItkImage(mitkInput, itkInput); mitkResult = ScalarToRGBA(itkInput, tf); } else if (mitkInput->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT) { // cast to itkImage itk::Image::Pointer itkInput; mitk::CastToItkImage(mitkInput, itkInput); mitkResult = ScalarToRGBA(itkInput, tf); } else { MITK_ERROR << "unsupported pixel type"; return nullptr; } mitkResult->SetClonedGeometry(mitkInput->GetGeometry()); return mitkResult; } template class ScalarBinaryToRGBAConverter { const T *dataPtr; const B *data2Ptr; unsigned char *tmpPtr; int sizeX; int sizeY; int sizeZ; int sizeXY; int sizeXm1; int sizeYm1; int sizeZm1; mitk::TransferFunction::Pointer tf; public: ScalarBinaryToRGBAConverter(const T *_dataPtr, const B *_data2Ptr, unsigned char *_tmpPtr, int _sizeX, int _sizeY, int _sizeZ, mitk::TransferFunction::Pointer _tf) { dataPtr = _dataPtr; data2Ptr = _data2Ptr; tmpPtr = _tmpPtr; sizeX = _sizeX; sizeY = _sizeY; sizeZ = _sizeZ; sizeXY = sizeX * sizeY; sizeXm1 = sizeX - 1; sizeYm1 = sizeY - 1; sizeZm1 = sizeZ - 1; tf = _tf; } inline float sample(int x, int y, int z) { return float(dataPtr[x + y * sizeX + z * sizeXY]); } inline bool sampleBinary(int x, int y, int z) { return data2Ptr[x + y * sizeX + z * sizeXY]; } inline int clamp(int x) { if (x < 0) x = 0; else if (x > 255) x = 255; return x; } inline void write(int x, int y, int z, float grayValue, float gx, float gy, float gz) { if (sampleBinary(x, y, z)) { /* gx /= aspect[0]; gy /= aspect[1]; gz /= aspect[2]; */ // Compute the gradient magnitude float t = sqrtf(gx * gx + gy * gy + gz * gz); int doff = x + y * sizeX + z * sizeXY; vtkPiecewiseFunction *opacityTransferFunction = tf->GetScalarOpacityFunction(); vtkPiecewiseFunction *gradientTransferFunction = tf->GetGradientOpacityFunction(); vtkColorTransferFunction *colorTransferFunction = tf->GetColorTransferFunction(); double rgb[3]; colorTransferFunction->GetColor(double(grayValue), rgb); double opacity = opacityTransferFunction->GetValue(double(grayValue)); opacity *= gradientTransferFunction->GetValue(double(0.5f * t)); tmpPtr[doff * 4 + 0] = int(rgb[0] * 255 + 0.5); tmpPtr[doff * 4 + 1] = int(rgb[1] * 255 + 0.5); tmpPtr[doff * 4 + 2] = int(rgb[2] * 255 + 0.5); tmpPtr[doff * 4 + 3] = int(opacity * 255 + 0.5); } else { int doff = x + y * sizeX + z * sizeXY; tmpPtr[doff * 4 + 0] = 0; tmpPtr[doff * 4 + 1] = 0; tmpPtr[doff * 4 + 2] = 0; tmpPtr[doff * 4 + 3] = 0; } } inline void compute(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; gx = sample(x + 1, y, z) - sample(x - 1, y, z); gy = sample(x, y + 1, z) - sample(x, y - 1, z); gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void computeClamp(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; if (x == 0) gx = 2.0f * (sample(x + 1, y, z) - grayValue); else if (x == sizeXm1) gx = 2.0f * (grayValue - sample(x - 1, y, z)); else gx = sample(x + 1, y, z) - sample(x - 1, y, z); if (y == 0) gy = 2.0f * (sample(x, y + 1, z) - grayValue); else if (y == sizeYm1) gy = 2.0f * (grayValue - sample(x, y - 1, z)); else gy = sample(x, y + 1, z) - sample(x, y - 1, z); if (z == 0) gz = 2.0f * (sample(x, y, z + 1) - grayValue); else if (z == sizeZm1) gz = 2.0f * (grayValue - sample(x, y, z - 1)); else gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void compute1D(int y, int z) { int x; x = 0; computeClamp(x, y, z); x++; while (x < sizeX - 1) { compute(x, y, z); x++; } if (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp1D(int y, int z) { int x; x = 0; while (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp2D(int z) { int y; y = 0; while (y < sizeY) { computeClamp1D(y, z); y++; } } inline void compute2D(int z) { int y; y = 0; computeClamp1D(y, z); y++; while (y < sizeY - 1) { compute1D(y, z); y++; } if (y < sizeY) { computeClamp1D(y, z); y++; } } inline void fillSlices() { int z; for (z = 0; z < sizeZ; z++) { if (z == 0 || z == sizeZ - 1) computeClamp2D(z); else compute2D(z); } } }; template mitk::Image::Pointer mitkColourImageProcessor::ScalarAndBinaryToRGBA(itk::Image *input, itk::Image *input2, mitk::TransferFunction::Pointer tf) { const TType *inputData = input->GetBufferPointer(); const BType *input2Data = input2->GetBufferPointer(); typename itk::Image::SizeType ioSize = input->GetLargestPossibleRegion().GetSize(); MITK_INFO << "size input image: " << ioSize[0] << ", " << ioSize[1] << ", " << ioSize[2]; MITK_INFO << "size voxel: " << ioSize[0] * ioSize[1] * ioSize[2]; int voxel = ioSize[0] * ioSize[1] * ioSize[2]; auto RGBABuffer = new unsigned char[4 * voxel]; // for(int i=0;i strc( inputData, input2Data, RGBABuffer, ioSize[0], ioSize[1], ioSize[2], tf); strc.fillSlices(); } // Create MITK Image out of the raw data { mitk::Image::Pointer image = mitk::Image::New(); unsigned int dimensions[3]; dimensions[0] = ioSize[0]; dimensions[1] = ioSize[1]; dimensions[2] = ioSize[2]; mitk::PixelType pixelType(MakePixelType()); image->Initialize(pixelType, 3, dimensions); image->SetImportChannel(RGBABuffer, 0, Image::ManageMemory); return image; } } mitk::Image::Pointer mitkColourImageProcessor::convertWithBinaryToRGBAImage(mitk::Image::Pointer input1, mitk::Image::Pointer input2, mitk::TransferFunction::Pointer tf) { MITK_INFO << "convertWithBinaryToRGBAImage"; itk::Image::Pointer inputCT; itk::Image::Pointer inputBinary; if (input1->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR && input2->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT) { mitk::CastToItkImage(input1, inputBinary); mitk::CastToItkImage(input2, inputCT); } else if (input1->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT && input2->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR) { mitk::CastToItkImage(input1, inputCT); mitk::CastToItkImage(input2, inputBinary); } else { MITK_ERROR << "unsupported pixel type"; return nullptr; } mitk::Image::Pointer resultImage = ScalarAndBinaryToRGBA(inputCT, inputBinary, tf); resultImage->SetClonedGeometry(input1->GetGeometry()); return resultImage; } ////////////////////////////////////////// template class ScalarBinaryColorToRGBAConverter { const T *dataPtr; const B *data2Ptr; unsigned char *tmpPtr; int sizeX; int sizeY; int sizeZ; int sizeXY; int sizeXm1; int sizeYm1; int sizeZm1; mitk::TransferFunction::Pointer tf; int *color; public: ScalarBinaryColorToRGBAConverter(const T *_dataPtr, const B *_data2Ptr, unsigned char *_tmpPtr, int _sizeX, int _sizeY, int _sizeZ, mitk::TransferFunction::Pointer _tf, int *_color) { dataPtr = _dataPtr; data2Ptr = _data2Ptr; tmpPtr = _tmpPtr; sizeX = _sizeX; sizeY = _sizeY; sizeZ = _sizeZ; sizeXY = sizeX * sizeY; sizeXm1 = sizeX - 1; sizeYm1 = sizeY - 1; sizeZm1 = sizeZ - 1; tf = _tf; color = _color; } inline float sample(int x, int y, int z) { return float(dataPtr[x + y * sizeX + z * sizeXY]); } inline bool sampleBinary(int x, int y, int z) { return data2Ptr[x + y * sizeX + z * sizeXY]; } inline int clamp(int x) { if (x < 0) x = 0; else if (x > 255) x = 255; return x; } inline void write(int x, int y, int z, float grayValue, float gx, float gy, float gz) { if (sampleBinary(x, y, z)) { /* gx /= aspect[0]; gy /= aspect[1]; gz /= aspect[2]; */ // Compute the gradient magnitude float t = sqrtf(gx * gx + gy * gy + gz * gz); int doff = x + y * sizeX + z * sizeXY; vtkPiecewiseFunction *opacityTransferFunction = tf->GetScalarOpacityFunction(); vtkPiecewiseFunction *gradientTransferFunction = tf->GetGradientOpacityFunction(); vtkColorTransferFunction *colorTransferFunction = tf->GetColorTransferFunction(); double rgb[3]; colorTransferFunction->GetColor(double(grayValue), rgb); double opacity = opacityTransferFunction->GetValue(double(grayValue)); opacity *= gradientTransferFunction->GetValue(double(0.5f * t)); tmpPtr[doff * 4 + 0] = int(rgb[0] * 255 + 0.5); tmpPtr[doff * 4 + 1] = int(rgb[1] * 255 + 0.5); tmpPtr[doff * 4 + 2] = int(rgb[2] * 255 + 0.5); tmpPtr[doff * 4 + 3] = int(opacity * 255 + 0.5); tmpPtr[doff * 4 + 0] = color[0]; tmpPtr[doff * 4 + 1] = color[1]; tmpPtr[doff * 4 + 2] = color[2]; } else { int doff = x + y * sizeX + z * sizeXY; tmpPtr[doff * 4 + 0] = 0; tmpPtr[doff * 4 + 1] = 0; tmpPtr[doff * 4 + 2] = 0; tmpPtr[doff * 4 + 3] = 0; } } inline void compute(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; gx = sample(x + 1, y, z) - sample(x - 1, y, z); gy = sample(x, y + 1, z) - sample(x, y - 1, z); gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void computeClamp(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; if (x == 0) gx = 2.0f * (sample(x + 1, y, z) - grayValue); else if (x == sizeXm1) gx = 2.0f * (grayValue - sample(x - 1, y, z)); else gx = sample(x + 1, y, z) - sample(x - 1, y, z); if (y == 0) gy = 2.0f * (sample(x, y + 1, z) - grayValue); else if (y == sizeYm1) gy = 2.0f * (grayValue - sample(x, y - 1, z)); else gy = sample(x, y + 1, z) - sample(x, y - 1, z); if (z == 0) gz = 2.0f * (sample(x, y, z + 1) - grayValue); else if (z == sizeZm1) gz = 2.0f * (grayValue - sample(x, y, z - 1)); else gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void compute1D(int y, int z) { int x; x = 0; computeClamp(x, y, z); x++; while (x < sizeX - 1) { compute(x, y, z); x++; } if (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp1D(int y, int z) { int x; x = 0; while (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp2D(int z) { int y; y = 0; while (y < sizeY) { computeClamp1D(y, z); y++; } } inline void compute2D(int z) { int y; y = 0; computeClamp1D(y, z); y++; while (y < sizeY - 1) { compute1D(y, z); y++; } if (y < sizeY) { computeClamp1D(y, z); y++; } } inline void fillSlices() { int z; for (z = 0; z < sizeZ; z++) { if (z == 0 || z == sizeZ - 1) computeClamp2D(z); else compute2D(z); } } }; template mitk::Image::Pointer mitkColourImageProcessor::ScalarAndBinaryAndColorToRGBA(itk::Image *input, itk::Image *input2, mitk::TransferFunction::Pointer tf, int *color) { const TType *inputData = input->GetBufferPointer(); const BType *input2Data = input2->GetBufferPointer(); typename itk::Image::SizeType ioSize = input->GetLargestPossibleRegion().GetSize(); MITK_INFO << "size input image: " << ioSize[0] << ", " << ioSize[1] << ", " << ioSize[2]; MITK_INFO << "size voxel: " << ioSize[0] * ioSize[1] * ioSize[2]; int voxel = ioSize[0] * ioSize[1] * ioSize[2]; auto RGBABuffer = new unsigned char[4 * voxel]; // for(int i=0;i strc( inputData, input2Data, RGBABuffer, ioSize[0], ioSize[1], ioSize[2], tf, color); strc.fillSlices(); } // Create MITK Image out of the raw data { mitk::Image::Pointer image = mitk::Image::New(); unsigned int dimensions[3]; dimensions[0] = ioSize[0]; dimensions[1] = ioSize[1]; dimensions[2] = ioSize[2]; mitk::PixelType pixelType(MakePixelType()); image->Initialize(pixelType, 3, dimensions); image->SetImportChannel(RGBABuffer, 0, Image::ManageMemory); // image->GetGeometry()->SetSpacing(input->GetSpacing()); // image->GetGeometry()->SetOrigin(input->GetOrigin()); return image; } } mitk::Image::Pointer mitkColourImageProcessor::convertWithBinaryAndColorToRGBAImage( mitk::Image::Pointer input1, mitk::Image::Pointer input2, mitk::TransferFunction::Pointer tf, int *color) { MITK_INFO << "convertWithBinaryToRGBAImage"; itk::Image::Pointer inputCT; itk::Image::Pointer inputBinary; if (input1->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR && input2->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT) { mitk::CastToItkImage(input1, inputBinary); mitk::CastToItkImage(input2, inputCT); } else if (input1->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT && input2->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR) { mitk::CastToItkImage(input1, inputCT); mitk::CastToItkImage(input2, inputBinary); } else { MITK_ERROR << "unsupported pixel type"; return nullptr; } mitk::Image::Pointer resultImage = ScalarAndBinaryAndColorToRGBA(inputCT, inputBinary, tf, color); resultImage->SetClonedGeometry(input1->GetGeometry()); return resultImage; } - static inline int clamp(int x) - { - if (x < 0) - x = 0; - else if (x > 255) - x = 255; - return x; - } - mitk::Image::Pointer mitkColourImageProcessor::CombineRGBAImage( const unsigned char *input, const unsigned char *input2, int sizeX, int sizeY, int sizeZ) { int voxel = sizeX * sizeY * sizeZ; auto RGBABuffer = new unsigned char[4 * voxel]; // Convert volume { for (int r = 0; r < voxel; r++) { int rgbaInput1[4]; int rgbaInput2[4]; rgbaInput1[0] = input[r * 4 + 0]; rgbaInput1[1] = input[r * 4 + 1]; rgbaInput1[2] = input[r * 4 + 2]; rgbaInput1[3] = input[r * 4 + 3]; rgbaInput2[0] = input2[r * 4 + 0]; rgbaInput2[1] = input2[r * 4 + 1]; rgbaInput2[2] = input2[r * 4 + 2]; rgbaInput2[3] = input2[r * 4 + 3]; int result[4]; /* float fac1 = rgbaInput1[3]/255.0f; float fac2 = rgbaInput2[3]/255.0f; float sum = fac1+fac2; float cor = 1.0f; if(sum > 1.0f) cor = 1.0f/sum; fac1 *= cor; fac2 *= cor; result[0]= clamp(int(fac1 * rgbaInput1[0] + fac2 * rgbaInput2[0] + 0.5f)); result[1]= clamp(int(fac1 * rgbaInput1[1] + fac2 * rgbaInput2[1] + 0.5f)); result[2]= clamp(int(fac1 * rgbaInput1[2] + fac2 * rgbaInput2[2] + 0.5f)); result[3]= clamp(int(fac1 * rgbaInput1[3] + fac2 * rgbaInput2[3] + 0.5f)); */ if (rgbaInput1[3]) { result[0] = rgbaInput1[0]; result[1] = rgbaInput1[1]; result[2] = rgbaInput1[2]; result[3] = rgbaInput1[3]; } else { result[0] = rgbaInput2[0]; result[1] = rgbaInput2[1]; result[2] = rgbaInput2[2]; result[3] = rgbaInput2[3]; } RGBABuffer[r * 4 + 0] = result[0]; RGBABuffer[r * 4 + 1] = result[1]; RGBABuffer[r * 4 + 2] = result[2]; RGBABuffer[r * 4 + 3] = result[3]; } } // Create MITK Image out of the raw data { mitk::Image::Pointer image = mitk::Image::New(); unsigned int dimensions[3]; dimensions[0] = sizeX; dimensions[1] = sizeY; dimensions[2] = sizeZ; mitk::PixelType pixelType(MakePixelType()); image->Initialize(pixelType, 3, dimensions); image->SetImportChannel(RGBABuffer, 0, Image::ManageMemory); return image; } } mitk::Image::Pointer mitkColourImageProcessor::combineRGBAImage(mitk::Image::Pointer input1, mitk::Image::Pointer input2) { // Order access to a whole Image object try { mitk::ImageReadAccessor img1(input1); const unsigned char *data1 = (const unsigned char *)img1.GetData(); mitk::ImageReadAccessor img2(input2); const unsigned char *data2 = (const unsigned char *)img2.GetData(); unsigned int *dim = input1->GetDimensions(); return CombineRGBAImage(data1, data2, dim[0], dim[1], dim[2]); } catch (mitk::Exception &e) { MITK_ERROR << "mitkColourImageProcessor::combineRGBAImage - No access to image data possible." << e.what(); return nullptr; } } -} // end namespace mitk \ No newline at end of file +} // end namespace mitk diff --git a/Modules/CEST/autoload/IO/mitkCESTIOActivator.h b/Modules/CEST/autoload/IO/mitkCESTIOActivator.h index 494c47439e..4a746242e0 100644 --- a/Modules/CEST/autoload/IO/mitkCESTIOActivator.h +++ b/Modules/CEST/autoload/IO/mitkCESTIOActivator.h @@ -1,45 +1,44 @@ /*=================================================================== 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 MITKCESTIOActivator_H #define MITKCESTIOActivator_H #include #include #include #include namespace mitk { struct IFileReader; class IDICOMTagsOfInterest; class CESTIOActivator : public us::ModuleActivator { public: void Load(us::ModuleContext *context) override; void Unload(us::ModuleContext *context) override; private: std::unique_ptr m_CESTDICOMReader; - us::ModuleContext *mitkContext; std::vector m_MimeTypes; }; } #endif // MITKCESTIOActivator_H diff --git a/Modules/Chart/src/QmitkChartWidget.cpp b/Modules/Chart/src/QmitkChartWidget.cpp index 942a2cac0a..c5841c4f0c 100644 --- a/Modules/Chart/src/QmitkChartWidget.cpp +++ b/Modules/Chart/src/QmitkChartWidget.cpp @@ -1,325 +1,323 @@ /*=================================================================== 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 #include #include "mitkExceptionMacro.h" class QmitkChartWidget::Impl final { public: explicit Impl(QWidget* parent); ~Impl(); Impl(const Impl&) = delete; Impl& operator=(const Impl&) = delete; void AddData1D(const std::vector& data1D); void AddData2D(const std::map& data2D); void ClearData2D(); void SetDataLabels(const std::vector& labels); std::vector GetDataLabels() const; void SetXAxisLabel(const std::string& label); std::string GetXAxisLabel() const; void SetYAxisLabel(const std::string& label); std::string GetYAxisLabel() const; void SetDiagramType(QmitkChartWidget::ChartType diagramType); ChartType GetDiagramType() const; std::string GetDiagramTypeAsString() const; void ClearJavaScriptChart(); void initializeJavaScriptChart(); void callJavaScriptFuntion(const QString& command); QmitkChartData* GetC3Data() const; std::vector* GetC3xyData() const; private: QWebChannel* m_WebChannel; QWebEngineView* m_WebEngineView; - QWidget* m_Parent; QmitkChartData * m_C3Data; std::vector * m_C3xyData; std::map m_DiagramTypeToName; }; QmitkChartWidget::Impl::Impl(QWidget* parent) : m_WebChannel(new QWebChannel(parent)), - m_WebEngineView(new QWebEngineView(parent)), - m_Parent(parent) + m_WebEngineView(new QWebEngineView(parent)) { //disable context menu for QWebEngineView m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu); //Set the webengineview to an initial empty page. The actual chart will be loaded once the data is calculated. m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html"))); m_WebEngineView->page()->setWebChannel(m_WebChannel); connect(m_WebEngineView, SIGNAL(loadFinished(bool)), parent, SLOT(OnLoadFinished(bool))); auto layout = new QGridLayout(parent); layout->setMargin(0); layout->addWidget(m_WebEngineView); parent->setLayout(layout); m_DiagramTypeToName.emplace(ChartType::bar, "bar"); m_DiagramTypeToName.emplace(ChartType::line, "line"); m_DiagramTypeToName.emplace(ChartType::spline, "spline"); m_DiagramTypeToName.emplace(ChartType::pie, "pie"); m_C3Data = new QmitkChartData(); m_C3xyData = new std::vector(); } QmitkChartWidget::Impl::~Impl() { delete m_C3Data; delete m_C3xyData; } void QmitkChartWidget::Impl::SetDataLabels(const std::vector& labels) { QList variantList; for (const auto& label : labels) { variantList.append(QString::fromStdString(label)); } GetC3Data()->SetDataLabels(variantList); } void QmitkChartWidget::Impl::AddData1D(const std::vector& data1D) { QList data1DConverted; for (const auto& aValue : data1D) { data1DConverted.append(aValue); } GetC3xyData()->push_back(new QmitkChartxyData(data1DConverted)); } void QmitkChartWidget::Impl::AddData2D(const std::map& data2D) { QMap data2DConverted; for (const auto& aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } GetC3xyData()->push_back(new QmitkChartxyData(data2DConverted)); } std::vector QmitkChartWidget::Impl::GetDataLabels() const { auto dataLabels = GetC3Data()->GetDataLabels(); std::vector dataLabelsAsStringVector; for (const auto& label : dataLabels) { dataLabelsAsStringVector.push_back(label.toString().toStdString()); } return dataLabelsAsStringVector; } void QmitkChartWidget::Impl::SetXAxisLabel(const std::string& label) { GetC3Data()->SetXAxisLabel(QString::fromStdString(label)); } std::string QmitkChartWidget::Impl::GetXAxisLabel() const { return GetC3Data()->GetXAxisLabel().toString().toStdString(); } void QmitkChartWidget::Impl::SetYAxisLabel(const std::string& label) { GetC3Data()->SetYAxisLabel(QString::fromStdString(label)); } std::string QmitkChartWidget::Impl::GetYAxisLabel() const { return GetC3Data()->GetYAxisLabel().toString().toStdString(); } void QmitkChartWidget::Impl::SetDiagramType(QmitkChartWidget::ChartType diagramType) { const std::string diagramTypeName(m_DiagramTypeToName.at(diagramType)); GetC3Data()->SetDiagramType(QString::fromStdString(diagramTypeName)); } QmitkChartWidget::ChartType QmitkChartWidget::Impl::GetDiagramType() const { for (const auto& aDiagramType : m_DiagramTypeToName) { if (aDiagramType.second == GetDiagramTypeAsString()){ return aDiagramType.first; } } mitkThrow() << "can't find diagram type!"; } std::string QmitkChartWidget::Impl::GetDiagramTypeAsString() const { return GetC3Data()->GetDiagramType().toString().toStdString(); } QmitkChartData* QmitkChartWidget::Impl::GetC3Data() const { return m_C3Data; } std::vector* QmitkChartWidget::Impl::GetC3xyData() const { return m_C3xyData; } void QmitkChartWidget::Impl::ClearData2D() { GetC3xyData()->clear(); } QmitkChartWidget::QmitkChartWidget(ChartType type, QWidget* parent) : QWidget(parent), m_Impl(new Impl(this)) { SetChartType(type); } void QmitkChartWidget::Impl::callJavaScriptFuntion(const QString& command) { m_WebEngineView->page()->runJavaScript(command); } void QmitkChartWidget::Impl::ClearJavaScriptChart() { m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html"))); } void QmitkChartWidget::Impl::initializeJavaScriptChart() { m_WebChannel->registerObject(QStringLiteral("chartData"), m_C3Data); unsigned count = 0; for (auto& xyData : *m_C3xyData) { QString variableName = "xyData" + QString::number(count); m_WebChannel->registerObject(variableName, xyData); count++; } m_WebEngineView->load(QUrl(QStringLiteral("qrc:///C3js/QmitkChartWidget.html"))); } QmitkChartWidget::~QmitkChartWidget() { delete m_Impl; } void QmitkChartWidget::AddData2D(const std::map& data2D) { m_Impl->AddData2D(data2D); } void QmitkChartWidget::AddData1D(const std::vector& data1D) { m_Impl->AddData1D(data1D); } void QmitkChartWidget::SetDataLabels(const std::vector& labels) { m_Impl->SetDataLabels(labels); } std::vector QmitkChartWidget::GetDataLabels() const { return m_Impl->GetDataLabels(); } void QmitkChartWidget::SetXAxisLabel(const std::string & label) { m_Impl->SetXAxisLabel(label); } std::string QmitkChartWidget::GetXAxisLabel() const { return m_Impl->GetXAxisLabel(); } void QmitkChartWidget::SetYAxisLabel(const std::string & label) { m_Impl->SetYAxisLabel(label); } std::string QmitkChartWidget::GetYAxisLabel() const { return m_Impl->GetYAxisLabel(); } void QmitkChartWidget::SetChartType(ChartType type) { m_Impl->SetDiagramType(type); } QmitkChartWidget::ChartType QmitkChartWidget::GetChartType() const { return m_Impl->GetDiagramType(); } void QmitkChartWidget::Show(bool showSubChart) { this->m_Impl->GetC3Data()->SetAppearance(m_Impl->GetC3Data()->GetDiagramType(), showSubChart, m_Impl->GetC3Data()->GetDiagramType()== QVariant("pie")); m_Impl->initializeJavaScriptChart(); } void QmitkChartWidget::Clear() { m_Impl->ClearData2D(); m_Impl->GetC3xyData()->clear(); m_Impl->ClearJavaScriptChart(); } void QmitkChartWidget::OnLoadFinished(bool isLoadSuccessfull) { if(isLoadSuccessfull) { emit PageSuccessfullyLoaded(); } } void QmitkChartWidget::SetChartTypeAndReload(ChartType type) { SetChartType(type); auto diagramTypeName = m_Impl->GetDiagramTypeAsString(); const QString command = QString::fromStdString("transformView('" + diagramTypeName + "')"); m_Impl->callJavaScriptFuntion(command); } void QmitkChartWidget::SetTheme(ChartStyle themeEnabled) { QString command; if (themeEnabled == ChartStyle::darkstyle) { command = QString("changeTheme('dark')"); } else { command = QString("changeTheme('default')"); } m_Impl->callJavaScriptFuntion(command); } void QmitkChartWidget::Reload(bool showSubChart) { QString subChartString; if (showSubChart) { subChartString = "true"; } else { subChartString = "false"; } const QString command = QString("ReloadChart(" + subChartString + ")"); m_Impl->callJavaScriptFuntion(command); } diff --git a/Modules/Classification/DataCollection/Utilities/mitkCollectionStatistic.h b/Modules/Classification/DataCollection/Utilities/mitkCollectionStatistic.h index 780230b91b..e4404805c1 100644 --- a/Modules/Classification/DataCollection/Utilities/mitkCollectionStatistic.h +++ b/Modules/Classification/DataCollection/Utilities/mitkCollectionStatistic.h @@ -1,138 +1,137 @@ #ifndef mitkCollectionStatistic_h #define mitkCollectionStatistic_h #include #include #include namespace mitk { struct MITKDATACOLLECTION_EXPORT StatisticData { unsigned int m_TruePositive; unsigned int m_FalsePositive; unsigned int m_TrueNegative; unsigned int m_FalseNegative; double m_DICE; double m_Jaccard; double m_Sensitivity; double m_Specificity; double m_RMSD; StatisticData() : m_TruePositive(0), m_FalsePositive(0), m_TrueNegative(0), m_FalseNegative(0), m_DICE(0), m_Jaccard(0), m_Sensitivity(0), m_Specificity(0), m_RMSD(-1.0) {} }; class ValueToIndexMapper { public: virtual unsigned char operator() (unsigned char value) const = 0; }; class BinaryValueToIndexMapper : public virtual ValueToIndexMapper { public: unsigned char operator() (unsigned char value) const { return value; } }; class MultiClassValueToIndexMapper : public virtual ValueToIndexMapper { public: unsigned char operator() (unsigned char value) const { if (value == 1 || value == 5) return 0; else return 1; } }; class ProgressionValueToIndexMapper : public virtual ValueToIndexMapper { public: unsigned char operator() (unsigned char value) const { if (value == 1 || value == 0) return 0; else return 1; } }; class MITKDATACOLLECTION_EXPORT CollectionStatistic { public: CollectionStatistic(); ~CollectionStatistic(); typedef std::vector DataVector; typedef std::vector MultiDataVector; void SetCollection(DataCollection::Pointer collection); DataCollection::Pointer GetCollection(); void SetClassCount (size_t count); size_t GetClassCount(); void SetGoldName(std::string name); std::string GetGoldName(); void SetTestName(std::string name); std::string GetTestName(); void SetMaskName(std::string name) {m_MaskName = name; } void SetGroundTruthValueToIndexMapper(const ValueToIndexMapper* mapper); const ValueToIndexMapper* GetGroundTruthValueToIndexMapper(void) const; void SetTestValueToIndexMapper(const ValueToIndexMapper* mapper); const ValueToIndexMapper* GetTestValueToIndexMapper(void) const; void Print(std::ostream& out, std::ostream& sout = std::cout, bool withHeader = false, std::string label = "None"); bool Update(); int IsInSameVirtualClass(unsigned char gold, unsigned char test); /** * @brief mitk::CollectionStatistic::GetStatisticData * @param c The class for which to retrieve the statistic data. * @return */ std::vector GetStatisticData(unsigned char c) const; /** * @brief Computes root-mean-square distance of two binary images. */ void ComputeRMSD(); private: size_t m_ClassCount; std::string m_GroundTruthName; std::string m_TestName; std::string m_MaskName; DataCollection::Pointer m_Collection; std::vector m_ConnectionGold; std::vector m_ConnectionTest; std::vector m_ConnectionClass; - size_t m_VituralClassCount; MultiDataVector m_ImageClassStatistic; std::vector m_ImageNames; DataVector m_ImageStatistic; StatisticData m_MeanCompleteStatistic; StatisticData m_CompleteStatistic; const ValueToIndexMapper* m_GroundTruthValueToIndexMapper; const ValueToIndexMapper* m_TestValueToIndexMapper; }; } #endif // mitkCollectionStatistic_h diff --git a/Modules/OpenIGTLink/mitkIGTLMessageProvider.h b/Modules/OpenIGTLink/mitkIGTLMessageProvider.h index 720513c774..3330413dd9 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageProvider.h +++ b/Modules/OpenIGTLink/mitkIGTLMessageProvider.h @@ -1,228 +1,225 @@ /*=================================================================== 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 IGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ #define IGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ #include "mitkIGTLDevice.h" #include "mitkIGTLDeviceSource.h" //itk #include "itkCommand.h" namespace mitk { /** * \brief Provides information/objects from a MITK-Pipeline to other OpenIGTLink * devices * * This class is intended as the drain of the pipeline. Other OpenIGTLink * devices connect with the IGTLDevice hold by this provider. The other device * asks for a certain data type. The provider checks if there are other * IGTLMessageSources available that provide this data type. If yes the provider * connects with this source and sends the message to the requesting device. * * If a STT message was received the provider looks for fitting messageSources. * Once found it connects with it, starts a timing thread (which updates the * pipeline) and sends the result to the requesting device. * * If a GET message was received the provider just calls an update of the * found source and sends the result without connecting to the source. * * If a STP message was received it stops the thread and disconnects from the * previous source. * * So far the provider can just connect with one source. * * \ingroup OpenIGTLink */ class MITKOPENIGTLINK_EXPORT IGTLMessageProvider : public IGTLDeviceSource { public: mitkClassMacro(IGTLMessageProvider, IGTLDeviceSource); itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef itk::SimpleMemberCommand ProviderCommand; /** * \brief sends the msg to the requesting client * * Note: so far it broadcasts the message to all registered clients */ void Send(mitk::IGTLMessage::Pointer msg); /** * \brief Starts the streaming of the given message source with the given fps. */ void StartStreamingOfSource(mitk::IGTLMessageSource* src, unsigned int fps); /** * \brief Stops the streaming of the given message source. */ void StopStreamingOfSource(mitk::IGTLMessageSource* src); /** * \brief Stops the streaming of all message source. */ void StopStreamingOfAllSources(); /** * \brief Returns the streaming state. */ bool IsStreaming(); /** * \brief Get method for the streaming time */ itkGetMacro(StreamingTime, unsigned int); virtual void Update() override; protected: IGTLMessageProvider(); virtual ~IGTLMessageProvider(); /** * \brief filter execute method * * queries the OpenIGTLink device for new messages and updates its output * igtl::MessageBase objects with it. * \warning Will raise a std::out_of_range exception, if tools were added to * the OpenIGTLink device after it was set as input for this filter */ virtual void GenerateData() override; /** * \brief Create the necessary outputs for the m_IGTLDevice * * This Method is called internally whenever outputs need to be reset. Old * Outputs are deleted when called. **/ void CreateOutputs(); /** * \brief This method is called when the IGTL device hold by this class * receives a new message **/ virtual void OnIncomingMessage() override; /** * \brief This method is called when the IGTL device hold by this class * receives a new command **/ virtual void OnIncomingCommand() override; /** * \brief This method is called when the IGTL device lost the connection to the other side **/ virtual void OnLostConnection() override; /** *\brief Connects the input of this filter to the outputs of the given * IGTLMessageSource * * This method does not support smartpointer. use FilterX.GetPointer() to * retrieve a dumbpointer. */ void ConnectTo( mitk::IGTLMessageSource* UpstreamFilter ); /** *\brief Disconnects this filter from the outputs of the given * IGTLMessageSource * * This method does not support smartpointer. use FilterX.GetPointer() to * retrieve a dumbpointer. */ void DisconnectFrom( mitk::IGTLMessageSource* UpstreamFilter ); /** * \brief Looks for microservices that provide messages with the requested * type. **/ mitk::IGTLMessageSource::Pointer GetFittingSource(const char* requestedType); /** Invokes the start streaming event. This separate method is required, because it * has to be started from the main thread. (It is used as callback function) */ void InvokeStartStreamingEvent(); /** Invokes the stop streaming event. This separate method is required, because it * has to be started from the main thread. (It is used as callback function) */ void InvokeStopStreamingEvent(); private: /** * \brief a command that has to be executed in the main thread */ ProviderCommand::Pointer m_StreamingCommand; ProviderCommand::Pointer m_StopStreamingCommand; ///** // * \brief Timer thread for generating a continuous time signal for the stream // * // * Everyt time the time is passed a time signal is invoked. // * // * \param pInfoStruct pointer to the mitkIGTLMessageProvider object // * \return // */ //static ITK_THREAD_RETURN_TYPE TimerThread(void* pInfoStruct); //int m_ThreadId; ///** \brief timer thread will terminate after the next wakeup if set to true */ //bool m_StopStreamingThread; //itk::SmartPointer m_MultiThreader; /** \brief the time used for streaming */ unsigned int m_StreamingTime; /** \brief mutex for guarding m_Time */ itk::SmartPointer m_StreamingTimeMutex; ///** \brief mutex for guarding m_StopStreamingThread */ //itk::SmartPointer m_StopStreamingThreadMutex; /** \brief flag to indicate if the provider is streaming */ bool m_IsStreaming; - unsigned long m_LostConnectionObserverTag; - - bool m_LogMessages; }; /** * \brief connect to this Event to get notified when a stream is requested * * \note It is necessary to do the following things to have streaming support: 1. listen to this * event. 2. When emitted start a timer with the given interval. 3. In the timeout method of * this timer call IGTLMessageProvider::Update. 4. Also listen to the StreamingStopRequiredEvent * and stop the timer imdediately. * */ itkEventMacro(StreamingStartRequiredEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when a stream shall be stopped * * \note It is necessary to connect to this event and stop the streaming timer when called. * */ itkEventMacro(StreamingStopRequiredEvent, itk::AnyEvent); } // namespace mitk #endif /* MITKIGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ */ diff --git a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp index 4c639f6ebd..36f595df2c 100644 --- a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp +++ b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.cpp @@ -1,226 +1,226 @@ /*=================================================================== 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 "mitkShowSegmentationAsSurface.h" #include "mitkManualSegmentationToSurfaceFilter.h" #include "mitkVtkRepresentationProperty.h" #include #include namespace mitk { - ShowSegmentationAsSurface::ShowSegmentationAsSurface() : m_UIDGeneratorSurfaces("Surface_"), m_AddToTree(false) {} + ShowSegmentationAsSurface::ShowSegmentationAsSurface() : m_UIDGeneratorSurfaces("Surface_") {} ShowSegmentationAsSurface::~ShowSegmentationAsSurface() {} void ShowSegmentationAsSurface::Initialize(const NonBlockingAlgorithm *other) { Superclass::Initialize(other); bool syncVisibility(false); if (other) { other->GetParameter("Sync visibility", syncVisibility); } SetParameter("Sync visibility", syncVisibility); SetParameter("Median kernel size", 3u); SetParameter("Apply median", true); SetParameter("Smooth", true); SetParameter("Gaussian SD", 1.5f); SetParameter("Decimate mesh", true); SetParameter("Decimation rate", 0.8f); SetParameter("Wireframe", false); } bool ShowSegmentationAsSurface::ReadyToRun() { try { Image::Pointer image; GetPointerParameter("Input", image); return image.IsNotNull() && GetGroupNode(); } catch (std::invalid_argument &) { return false; } } bool ShowSegmentationAsSurface::ThreadedUpdateFunction() { Image::Pointer image; GetPointerParameter("Input", image); bool smooth(true); GetParameter("Smooth", smooth); bool applyMedian(true); GetParameter("Apply median", applyMedian); bool decimateMesh(true); GetParameter("Decimate mesh", decimateMesh); unsigned int medianKernelSize(3); GetParameter("Median kernel size", medianKernelSize); float gaussianSD(1.5); GetParameter("Gaussian SD", gaussianSD); float reductionRate(0.8); GetParameter("Decimation rate", reductionRate); MITK_INFO << "Creating polygon model with smoothing " << smooth << " gaussianSD " << gaussianSD << " median " << applyMedian << " median kernel " << medianKernelSize << " mesh reduction " << decimateMesh << " reductionRate " << reductionRate; ManualSegmentationToSurfaceFilter::Pointer surfaceFilter = ManualSegmentationToSurfaceFilter::New(); surfaceFilter->SetInput(image); surfaceFilter->SetThreshold(0.5); // expects binary image with zeros and ones surfaceFilter->SetUseGaussianImageSmooth(smooth); // apply gaussian to thresholded image ? surfaceFilter->SetSmooth(smooth); if (smooth) { surfaceFilter->InterpolationOn(); surfaceFilter->SetGaussianStandardDeviation(gaussianSD); } surfaceFilter->SetMedianFilter3D(applyMedian); // apply median to segmentation before marching cubes ? if (applyMedian) { surfaceFilter->SetMedianKernelSize( medianKernelSize, medianKernelSize, medianKernelSize); // apply median to segmentation before marching cubes } // fix to avoid vtk warnings see bug #5390 if (image->GetDimension() > 3) decimateMesh = false; if (decimateMesh) { surfaceFilter->SetDecimate(ImageToSurfaceFilter::QuadricDecimation); surfaceFilter->SetTargetReduction(reductionRate); } else { surfaceFilter->SetDecimate(ImageToSurfaceFilter::NoDecimation); } surfaceFilter->UpdateLargestPossibleRegion(); // calculate normals for nicer display m_Surface = surfaceFilter->GetOutput(); vtkPolyData *polyData = m_Surface->GetVtkPolyData(); if (!polyData) throw std::logic_error("Could not create polygon model"); polyData->SetVerts(0); polyData->SetLines(0); if (smooth || applyMedian || decimateMesh) { vtkPolyDataNormals *normalsGen = vtkPolyDataNormals::New(); normalsGen->AutoOrientNormalsOn(); normalsGen->FlipNormalsOff(); normalsGen->SetInputData(polyData); normalsGen->Update(); m_Surface->SetVtkPolyData(normalsGen->GetOutput()); normalsGen->Delete(); } else { m_Surface->SetVtkPolyData(polyData); } return true; } void ShowSegmentationAsSurface::ThreadedUpdateSuccessful() { m_Node = DataNode::New(); bool wireframe(false); GetParameter("Wireframe", wireframe); if (wireframe) { VtkRepresentationProperty *np = dynamic_cast(m_Node->GetProperty("material.representation")); if (np) np->SetRepresentationToWireframe(); } m_Node->SetProperty("opacity", FloatProperty::New(0.3)); m_Node->SetProperty("line width", IntProperty::New(1)); m_Node->SetProperty("scalar visibility", BoolProperty::New(false)); std::string groupNodesName("surface"); DataNode *groupNode = GetGroupNode(); if (groupNode) { groupNode->GetName(groupNodesName); // if parameter smooth is set add extension to node name bool smooth(true); GetParameter("Smooth", smooth); if (smooth) groupNodesName.append("_smoothed"); } m_Node->SetProperty("name", StringProperty::New(groupNodesName)); // synchronize this object's color with the parent's color // surfaceNode->SetProperty( "color", parentNode->GetProperty( "color" ) ); // surfaceNode->SetProperty( "visible", parentNode->GetProperty( "visible" ) ); m_Node->SetData(m_Surface); BaseProperty *colorProp = groupNode->GetProperty("color"); if (colorProp) m_Node->ReplaceProperty("color", colorProp->Clone()); else m_Node->SetProperty("color", ColorProperty::New(1.0, 1.0, 0.0)); bool showResult(true); GetParameter("Show result", showResult); bool syncVisibility(false); GetParameter("Sync visibility", syncVisibility); Image::Pointer image; GetPointerParameter("Input", image); BaseProperty *organTypeProp = image->GetProperty("organ type"); if (organTypeProp) m_Surface->SetProperty("organ type", organTypeProp); BaseProperty *visibleProp = groupNode->GetProperty("visible"); if (visibleProp && syncVisibility) m_Node->ReplaceProperty("visible", visibleProp->Clone()); else m_Node->SetProperty("visible", BoolProperty::New(showResult)); InsertBelowGroupNode(m_Node); Superclass::ThreadedUpdateSuccessful(); } } // namespace diff --git a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.h b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.h index 6a0a066f93..e2d9bf6366 100644 --- a/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.h +++ b/Modules/Segmentation/Algorithms/mitkShowSegmentationAsSurface.h @@ -1,54 +1,53 @@ /*=================================================================== 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 MITK_SHOW_SEGMENTATION_AS_SURFACE_H_INCLUDET_WAD #define MITK_SHOW_SEGMENTATION_AS_SURFACE_H_INCLUDET_WAD #include "mitkSegmentationSink.h" #include "mitkSurface.h" #include "mitkUIDGenerator.h" #include namespace mitk { class MITKSEGMENTATION_EXPORT ShowSegmentationAsSurface : public SegmentationSink { public: mitkClassMacro(ShowSegmentationAsSurface, SegmentationSink) mitkAlgorithmNewMacro(ShowSegmentationAsSurface); protected: ShowSegmentationAsSurface(); // use smart pointers virtual ~ShowSegmentationAsSurface(); virtual void Initialize(const NonBlockingAlgorithm *other = nullptr) override; virtual bool ReadyToRun() override; virtual bool ThreadedUpdateFunction() override; // will be called from a thread after calling StartAlgorithm virtual void ThreadedUpdateSuccessful() override; // will be called from a thread after calling StartAlgorithm private: UIDGenerator m_UIDGeneratorSurfaces; Surface::Pointer m_Surface; DataNode::Pointer m_Node; - bool m_AddToTree; }; } // namespace #endif diff --git a/Modules/Segmentation/DataManagement/mitkContourSet.cpp b/Modules/Segmentation/DataManagement/mitkContourSet.cpp index e7668cc8b9..c91ed8ea03 100644 --- a/Modules/Segmentation/DataManagement/mitkContourSet.cpp +++ b/Modules/Segmentation/DataManagement/mitkContourSet.cpp @@ -1,124 +1,124 @@ /*=================================================================== 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 "mitkContourSet.h" #include -mitk::ContourSet::ContourSet() : m_ContourVector(ContourVectorType()), m_NumberOfContours(0) +mitk::ContourSet::ContourSet() : m_ContourVector(ContourVectorType()) { ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(1); SetTimeGeometry(timeGeometry); } mitk::ContourSet::~ContourSet() { } void mitk::ContourSet::AddContour(unsigned int index, mitk::Contour::Pointer contour) { m_ContourVector.insert(std::make_pair(index, contour)); } void mitk::ContourSet::RemoveContour(unsigned long index) { m_ContourVector.erase(index); } void mitk::ContourSet::UpdateOutputInformation() { mitk::ContourSet::ContourVectorType contourVec = GetContours(); auto contoursIterator = contourVec.begin(); auto contoursIteratorEnd = contourVec.end(); // initialize container mitk::BoundingBox::PointsContainer::Pointer pointscontainer = mitk::BoundingBox::PointsContainer::New(); mitk::BoundingBox::PointIdentifier pointid = 0; mitk::Point3D point; mitk::AffineTransform3D *transform = GetGeometry(0)->GetIndexToWorldTransform(); mitk::AffineTransform3D::Pointer inverse = mitk::AffineTransform3D::New(); transform->GetInverse(inverse); // calculate a bounding box that includes all contours // \todo probably we should do this additionally for each time-step while (contoursIterator != contoursIteratorEnd) { const TimeGeometry *geometry = (*contoursIterator).second->GetUpdatedTimeGeometry(); unsigned char i; for (i = 0; i < 8; ++i) { point = inverse->TransformPoint(geometry->GetCornerPointInWorld(i)); if (point[0] * point[0] + point[1] * point[1] + point[2] * point[2] < mitk::large) pointscontainer->InsertElement(pointid++, point); else { itkGenericOutputMacro(<< "Unrealistically distant corner point encountered. Ignored. BoundingObject: " << (*contoursIterator).second); } } ++contoursIterator; } mitk::BoundingBox::Pointer boundingBox = mitk::BoundingBox::New(); boundingBox->SetPoints(pointscontainer); boundingBox->ComputeBoundingBox(); BaseGeometry *geometry3d = GetGeometry(0); geometry3d->SetIndexToWorldTransform(transform); geometry3d->SetBounds(boundingBox->GetBounds()); ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(geometry3d, GetTimeGeometry()->CountTimeSteps()); SetTimeGeometry(timeGeometry); } void mitk::ContourSet::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::ContourSet::RequestedRegionIsOutsideOfTheBufferedRegion() { return true; } bool mitk::ContourSet::VerifyRequestedRegion() { return true; } void mitk::ContourSet::SetRequestedRegion(const itk::DataObject *) { } void mitk::ContourSet::Initialize() { m_ContourVector = ContourVectorType(); ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(1); SetTimeGeometry(timeGeometry); } unsigned int mitk::ContourSet::GetNumberOfContours() { return m_ContourVector.size(); } mitk::ContourSet::ContourVectorType mitk::ContourSet::GetContours() { return m_ContourVector; } diff --git a/Modules/Segmentation/DataManagement/mitkContourSet.h b/Modules/Segmentation/DataManagement/mitkContourSet.h index 12bfb0a5b1..ab87bffc6d 100644 --- a/Modules/Segmentation/DataManagement/mitkContourSet.h +++ b/Modules/Segmentation/DataManagement/mitkContourSet.h @@ -1,110 +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. ===================================================================*/ #ifndef _MITK_CONTOUR_SET_H_ #define _MITK_CONTOUR_SET_H_ #include "mitkBaseData.h" #include "mitkCommon.h" #include "mitkContour.h" #include #include namespace mitk { /** * This class holds stores vertices for drawing a contour * */ class MITKSEGMENTATION_EXPORT ContourSet : public BaseData { public: mitkClassMacro(ContourSet, BaseData); itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef std::map ContourVectorType; typedef ContourVectorType::iterator ContourIterator; typedef itk::BoundingBox BoundingBoxType; /** * clean up the contour data */ void Initialize() override; /** * add a contour */ void AddContour(unsigned int index, mitk::Contour::Pointer contour); /** * add a contour */ void RemoveContour(unsigned long index); /** * returns the number of points stored in the contour */ unsigned int GetNumberOfContours(); /** * returns the container of the contour points */ ContourVectorType GetContours(); /** * intherited from parent */ virtual void UpdateOutputInformation() override; /** * intherited from parent */ virtual void SetRequestedRegionToLargestPossibleRegion() override; /** * intherited from parent */ virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override; /** * intherited from parent */ virtual bool VerifyRequestedRegion() override; /** * intherited from parent */ virtual void SetRequestedRegion(const itk::DataObject *data) override; protected: ContourSet(); virtual ~ContourSet(); private: /** * the bounding box of the contour */ BoundingBoxType::Pointer m_BoundingBox; ContourVectorType m_ContourVector; - unsigned int m_NumberOfContours; }; } // namespace mitk #endif //_MITK_CONTOUR_SET_H_ diff --git a/Modules/Segmentation/Interactions/mitkRegionGrowingTool.cpp b/Modules/Segmentation/Interactions/mitkRegionGrowingTool.cpp index 26715cea7e..9a235f4d73 100644 --- a/Modules/Segmentation/Interactions/mitkRegionGrowingTool.cpp +++ b/Modules/Segmentation/Interactions/mitkRegionGrowingTool.cpp @@ -1,655 +1,654 @@ /*=================================================================== 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 "mitkRegionGrowingTool.h" #include "mitkApplicationCursor.h" #include "mitkBaseRenderer.h" #include "mitkImageDataItem.h" #include "mitkImageToContourModelFilter.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkRegionGrowingTool.xpm" #include "mitkRenderingManager.h" #include "mitkToolManager.h" #include "mitkExtractDirectedPlaneImageFilterNew.h" #include "mitkLabelSetImage.h" #include "mitkOverwriteDirectedPlaneImageFilter.h" // us #include #include #include #include // ITK #include "mitkITKImageImport.h" #include "mitkImageAccessByItk.h" #include #include #include #include #include namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, RegionGrowingTool, "Region growing tool"); } #define ROUND(a) ((a) > 0 ? (int)((a) + 0.5) : -(int)(0.5 - (a))) mitk::RegionGrowingTool::RegionGrowingTool() : FeedbackContourTool("PressMoveRelease"), m_SeedValue(0), m_ScreenYDifference(0), m_ScreenXDifference(0), - m_VisibleWindow(0), m_MouseDistanceScaleFactor(0.5), m_FillFeedbackContour(true), m_ConnectedComponentValue(1) { } mitk::RegionGrowingTool::~RegionGrowingTool() { } void mitk::RegionGrowingTool::ConnectActionsAndFunctions() { CONNECT_FUNCTION("PrimaryButtonPressed", OnMousePressed); CONNECT_FUNCTION("Move", OnMouseMoved); CONNECT_FUNCTION("Release", OnMouseReleased); } const char **mitk::RegionGrowingTool::GetXPM() const { return mitkRegionGrowingTool_xpm; } us::ModuleResource mitk::RegionGrowingTool::GetIconResource() const { us::Module *module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("RegionGrowing_48x48.png"); return resource; } us::ModuleResource mitk::RegionGrowingTool::GetCursorIconResource() const { us::Module *module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("RegionGrowing_Cursor_32x32.png"); return resource; } const char *mitk::RegionGrowingTool::GetName() const { return "Region Growing"; } void mitk::RegionGrowingTool::Activated() { Superclass::Activated(); } void mitk::RegionGrowingTool::Deactivated() { Superclass::Deactivated(); } // Get the average pixel value of square/cube with radius=neighborhood around index template void mitk::RegionGrowingTool::GetNeighborhoodAverage(itk::Image *itkImage, itk::Index index, ScalarType *result, unsigned int neighborhood) { // maybe assert that image dimension is only 2 or 3? int neighborhoodInt = (int)neighborhood; TPixel averageValue(0); unsigned int numberOfPixels = (2 * neighborhood + 1) * (2 * neighborhood + 1); if (imageDimension == 3) { numberOfPixels *= (2 * neighborhood + 1); } MITK_DEBUG << "Getting neighborhood of " << numberOfPixels << " pixels around " << index; itk::Index currentIndex; for (int i = (0 - neighborhoodInt); i <= neighborhoodInt; ++i) { currentIndex[0] = index[0] + i; for (int j = (0 - neighborhoodInt); j <= neighborhoodInt; ++j) { currentIndex[1] = index[1] + j; if (imageDimension == 3) { for (int k = (0 - neighborhoodInt); k <= neighborhoodInt; ++k) { currentIndex[2] = index[2] + k; if (itkImage->GetLargestPossibleRegion().IsInside(currentIndex)) { averageValue += itkImage->GetPixel(currentIndex); } else { numberOfPixels -= 1; } } } else { if (itkImage->GetLargestPossibleRegion().IsInside(currentIndex)) { averageValue += itkImage->GetPixel(currentIndex); } else { numberOfPixels -= 1; } } } } *result = (ScalarType)averageValue; *result /= numberOfPixels; } // Check whether index lies inside a segmentation template void mitk::RegionGrowingTool::IsInsideSegmentation(itk::Image *itkImage, itk::Index index, bool *result) { if (itkImage->GetPixel(index) > 0) { *result = true; } else { *result = false; } } // Do the region growing (i.e. call an ITK filter that does it) template void mitk::RegionGrowingTool::StartRegionGrowing(itk::Image *inputImage, itk::Index seedIndex, std::array thresholds, mitk::Image::Pointer &outputImage) { MITK_DEBUG << "Starting region growing at index " << seedIndex << " with lower threshold " << thresholds[0] << " and upper threshold " << thresholds[1]; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::ConnectedThresholdImageFilter RegionGrowingFilterType; typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New(); // perform region growing in desired segmented region regionGrower->SetInput(inputImage); regionGrower->AddSeed(seedIndex); regionGrower->SetLower(thresholds[0]); regionGrower->SetUpper(thresholds[1]); try { regionGrower->Update(); } catch (...) { return; // Should we do something? } typename OutputImageType::Pointer resultImage = regionGrower->GetOutput(); // Smooth result: Every pixel is replaced by the majority of the neighborhood typedef itk::NeighborhoodIterator NeighborhoodIteratorType; typedef itk::ImageRegionIterator ImageIteratorType; typename NeighborhoodIteratorType::RadiusType radius; radius.Fill(2); // for now, maybe make this something the user can adjust in the preferences? typedef itk::ImageDuplicator< OutputImageType > DuplicatorType; typename DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage(resultImage); duplicator->Update(); typename OutputImageType::Pointer resultDup = duplicator->GetOutput(); NeighborhoodIteratorType neighborhoodIterator(radius, resultDup, resultDup->GetRequestedRegion()); ImageIteratorType imageIterator(resultImage, resultImage->GetRequestedRegion()); for (neighborhoodIterator.GoToBegin(), imageIterator.GoToBegin(); !neighborhoodIterator.IsAtEnd(); ++neighborhoodIterator, ++imageIterator) { DefaultSegmentationDataType voteYes(0); DefaultSegmentationDataType voteNo(0); for (unsigned int i = 0; i < neighborhoodIterator.Size(); ++i) { if (neighborhoodIterator.GetPixel(i) > 0) { voteYes += 1; } else { voteNo += 1; } } if (voteYes > voteNo) { imageIterator.Set(1); } else { imageIterator.Set(0); } } if (resultImage.IsNull()) { MITK_DEBUG << "Region growing result is empty."; } // Can potentially have multiple regions, use connected component image filter to label disjunct regions typedef itk::ConnectedComponentImageFilter ConnectedComponentImageFilterType; typename ConnectedComponentImageFilterType::Pointer connectedComponentFilter = ConnectedComponentImageFilterType::New(); connectedComponentFilter->SetInput(resultImage); connectedComponentFilter->Update(); typename OutputImageType::Pointer resultImageCC = connectedComponentFilter->GetOutput(); m_ConnectedComponentValue = resultImageCC->GetPixel(seedIndex); outputImage = mitk::GrabItkImageMemory(resultImageCC); } void mitk::RegionGrowingTool::OnMousePressed(StateMachineAction *, InteractionEvent *interactionEvent) { mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (!positionEvent) return; MITK_DEBUG << "OnMousePressed"; m_LastEventSender = positionEvent->GetSender(); m_LastEventSlice = m_LastEventSender->GetSlice(); m_LastScreenPosition = positionEvent->GetPointerPositionOnScreen(); // ReferenceSlice is from the underlying image, WorkingSlice from the active segmentation (can be empty) m_ReferenceSlice = FeedbackContourTool::GetAffectedReferenceSlice(positionEvent); m_WorkingSlice = FeedbackContourTool::GetAffectedWorkingSlice(positionEvent); if (m_WorkingSlice.IsNotNull()) // can't do anything without a working slice (i.e. a possibly empty segmentation) { MITK_DEBUG << "OnMousePressed: got working slice"; // 2. Determine if the user clicked inside or outside of the segmentation/working slice (i.e. the whole volume) mitk::BaseGeometry::Pointer workingSliceGeometry; workingSliceGeometry = m_WorkingSlice->GetGeometry(); workingSliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), m_SeedPoint); itk::Index<2> indexInWorkingSlice2D; indexInWorkingSlice2D[0] = m_SeedPoint[0]; indexInWorkingSlice2D[1] = m_SeedPoint[1]; if (workingSliceGeometry->IsIndexInside(m_SeedPoint)) { MITK_DEBUG << "OnMousePressed: point " << positionEvent->GetPositionInWorld() << " (index coordinates " << m_SeedPoint << ") is inside working slice"; // 3. determine the pixel value under the last click to determine what to do bool inside(true); AccessFixedDimensionByItk_2(m_WorkingSlice, IsInsideSegmentation, 2, indexInWorkingSlice2D, &inside); m_PaintingPixelValue = inside ? 0 : 1; if (inside) { MITK_DEBUG << "Clicked inside segmentation"; // For now, we're doing nothing when the user clicks inside the segmentation. Behaviour can be implemented via // OnMousePressedInside() // When you do, be sure to remove the m_PaintingPixelValue check in OnMouseMoved() and OnMouseReleased() return; } else { MITK_DEBUG << "Clicked outside of segmentation"; OnMousePressedOutside(nullptr, interactionEvent); } } } } // Use this to implement a behaviour for when the user clicks inside a segmentation (for example remove something) // Old IpPic code is kept as comment for reference void mitk::RegionGrowingTool::OnMousePressedInside() { // mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent // ); // //const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); // checked in // OnMousePressed // // 3.1.1. Create a skeletonization of the segmentation and try to find a nice cut // // apply the skeletonization-and-cut algorithm // // generate contour to remove // // set m_ReferenceSlice = nullptr so nothing will happen during mouse move // // remember to fill the contour with 0 in mouserelease // mitkIpPicDescriptor* segmentationHistory = ipMITKSegmentationCreateGrowerHistory( workingPicSlice, // m_LastWorkingSeed, nullptr ); // free again // if (segmentationHistory) // { // tCutResult cutContour = ipMITKSegmentationGetCutPoints( workingPicSlice, segmentationHistory, // initialWorkingOffset ); // tCutResult is a ipSegmentation type // mitkIpPicFree( segmentationHistory ); // if (cutContour.cutIt) // { // int timestep = positionEvent->GetSender()->GetTimeStep(); // // 3.1.2 copy point from float* to mitk::Contour // ContourModel::Pointer contourInImageIndexCoordinates = ContourModel::New(); // contourInImageIndexCoordinates->Expand(timestep + 1); // contourInImageIndexCoordinates->SetClosed(true, timestep); // Point3D newPoint; // for (int index = 0; index < cutContour.deleteSize; ++index) // { // newPoint[0] = cutContour.deleteCurve[ 2 * index + 0 ] - 0.5;//correction is needed because the // output of the algorithm is center based // newPoint[1] = cutContour.deleteCurve[ 2 * index + 1 ] - 0.5;//and we want our contour displayed // corner based. // newPoint[2] = 0.0; // contourInImageIndexCoordinates->AddVertex( newPoint, timestep ); // } // free(cutContour.traceline); // free(cutContour.deleteCurve); // perhaps visualize this for fun? // free(cutContour.onGradient); // ContourModel::Pointer contourInWorldCoordinates = FeedbackContourTool::BackProjectContourFrom2DSlice( // m_WorkingSlice->GetGeometry(), contourInImageIndexCoordinates, true ); // true: sub 0.5 for // ipSegmentation correction // FeedbackContourTool::SetFeedbackContour( contourInWorldCoordinates ); // FeedbackContourTool::SetFeedbackContourVisible(true); // mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); // m_FillFeedbackContour = true; // } // else // { // m_FillFeedbackContour = false; // } // } // else // { // m_FillFeedbackContour = false; // } // m_ReferenceSlice = nullptr; // return true; } void mitk::RegionGrowingTool::OnMousePressedOutside(StateMachineAction *, InteractionEvent *interactionEvent) { mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (positionEvent) { // Get geometry and indices mitk::BaseGeometry::Pointer workingSliceGeometry; workingSliceGeometry = m_WorkingSlice->GetGeometry(); itk::Index<2> indexInWorkingSlice2D; indexInWorkingSlice2D[0] = m_SeedPoint[0]; indexInWorkingSlice2D[1] = m_SeedPoint[1]; mitk::BaseGeometry::Pointer referenceSliceGeometry; referenceSliceGeometry = m_ReferenceSlice->GetGeometry(); itk::Index<3> indexInReferenceSlice; itk::Index<2> indexInReferenceSlice2D; referenceSliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), indexInReferenceSlice); indexInReferenceSlice2D[0] = indexInReferenceSlice[0]; indexInReferenceSlice2D[1] = indexInReferenceSlice[1]; // Get seed neighborhood ScalarType averageValue(0); AccessFixedDimensionByItk_3(m_ReferenceSlice, GetNeighborhoodAverage, 2, indexInReferenceSlice2D, &averageValue, 1); m_SeedValue = averageValue; MITK_DEBUG << "Seed value is " << m_SeedValue; // Get level window settings LevelWindow lw(0, 500); // default window 0 to 500, can we do something smarter here? m_ToolManager->GetReferenceData(0)->GetLevelWindow( lw); // will fill lw if levelwindow property is present, otherwise won't touch it. ScalarType currentVisibleWindow = lw.GetWindow(); MITK_DEBUG << "Level window width is " << currentVisibleWindow; m_InitialThresholds[0] = m_SeedValue - currentVisibleWindow / 20.0; // 20 is arbitrary (though works reasonably // well), is there a better alternative (maybe // option in preferences)? m_InitialThresholds[1] = m_SeedValue + currentVisibleWindow / 20.0; m_Thresholds[0] = m_InitialThresholds[0]; m_Thresholds[1] = m_InitialThresholds[1]; // Perform region growing mitk::Image::Pointer resultImage = mitk::Image::New(); AccessFixedDimensionByItk_3( m_ReferenceSlice, StartRegionGrowing, 2, indexInWorkingSlice2D, m_Thresholds, resultImage); resultImage->SetGeometry(workingSliceGeometry); // Extract contour if (resultImage.IsNotNull() && m_ConnectedComponentValue >= 1) { float isoOffset = 0.33; mitk::ImageToContourModelFilter::Pointer contourExtractor = mitk::ImageToContourModelFilter::New(); contourExtractor->SetInput(resultImage); contourExtractor->SetContourValue(m_ConnectedComponentValue - isoOffset); contourExtractor->Update(); ContourModel::Pointer resultContour = ContourModel::New(); resultContour = contourExtractor->GetOutput(); // Show contour if (resultContour.IsNotNull()) { ContourModel::Pointer resultContourWorld = FeedbackContourTool::BackProjectContourFrom2DSlice( workingSliceGeometry, FeedbackContourTool::ProjectContourTo2DSlice(m_WorkingSlice, resultContour)); // this is not a beautiful solution, just one that works, check T22412 for details int timestep = positionEvent->GetSender()->GetTimeStep(); if (0 != timestep) { int size = resultContourWorld->GetNumberOfVertices(0); auto resultContourTimeWorld = mitk::ContourModel::New(); resultContourTimeWorld->Expand(timestep + 1); for (int loop = 0; loop < size; ++loop) { resultContourTimeWorld->AddVertex(resultContourWorld->GetVertexAt(loop, 0), timestep); } FeedbackContourTool::SetFeedbackContour(resultContourTimeWorld); } else { FeedbackContourTool::SetFeedbackContour(resultContourWorld); } FeedbackContourTool::SetFeedbackContourVisible(true); mitk::RenderingManager::GetInstance()->RequestUpdate(m_LastEventSender->GetRenderWindow()); } } } } void mitk::RegionGrowingTool::OnMouseMoved(StateMachineAction *, InteractionEvent *interactionEvent) { // Until OnMousePressedInside() implements a behaviour, we're just returning here whenever m_PaintingPixelValue is 0, // i.e. when the user clicked inside the segmentation if (m_PaintingPixelValue == 0) { return; } mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (m_ReferenceSlice.IsNotNull() && positionEvent) { // Get geometry and indices mitk::BaseGeometry::Pointer workingSliceGeometry; workingSliceGeometry = m_WorkingSlice->GetGeometry(); itk::Index<2> indexInWorkingSlice2D; indexInWorkingSlice2D[0] = m_SeedPoint[0]; indexInWorkingSlice2D[1] = m_SeedPoint[1]; m_ScreenYDifference += positionEvent->GetPointerPositionOnScreen()[1] - m_LastScreenPosition[1]; m_ScreenXDifference += positionEvent->GetPointerPositionOnScreen()[0] - m_LastScreenPosition[0]; m_LastScreenPosition = positionEvent->GetPointerPositionOnScreen(); // Moving the mouse up and down adjusts the width of the threshold window, moving it left and right shifts the // threshold window m_Thresholds[0] = std::min( m_SeedValue, m_InitialThresholds[0] - (m_ScreenYDifference - m_ScreenXDifference) * m_MouseDistanceScaleFactor); m_Thresholds[1] = std::max( m_SeedValue, m_InitialThresholds[1] + (m_ScreenYDifference + m_ScreenXDifference) * m_MouseDistanceScaleFactor); MITK_DEBUG << "Screen difference X: " << m_ScreenXDifference; // Perform region growing again and show the result mitk::Image::Pointer resultImage = mitk::Image::New(); AccessFixedDimensionByItk_3( m_ReferenceSlice, StartRegionGrowing, 2, indexInWorkingSlice2D, m_Thresholds, resultImage); resultImage->SetGeometry(workingSliceGeometry); // Update the contour if (resultImage.IsNotNull() && m_ConnectedComponentValue >= 1) { float isoOffset = 0.33; mitk::ImageToContourModelFilter::Pointer contourExtractor = mitk::ImageToContourModelFilter::New(); contourExtractor->SetInput(resultImage); contourExtractor->SetContourValue(m_ConnectedComponentValue - isoOffset); contourExtractor->Update(); ContourModel::Pointer resultContour = ContourModel::New(); resultContour = contourExtractor->GetOutput(); // Show contour if (resultContour.IsNotNull()) { ContourModel::Pointer resultContourWorld = FeedbackContourTool::BackProjectContourFrom2DSlice( workingSliceGeometry, FeedbackContourTool::ProjectContourTo2DSlice(m_WorkingSlice, resultContour)); // this is not a beautiful solution, just one that works, check T22412 for details int timestep = positionEvent->GetSender()->GetTimeStep(); if (0 != timestep) { int size = resultContourWorld->GetNumberOfVertices(0); auto resultContourTimeWorld = mitk::ContourModel::New(); resultContourTimeWorld->Expand(timestep + 1); for (int loop = 0; loop < size; ++loop) { resultContourTimeWorld->AddVertex(resultContourWorld->GetVertexAt(loop, 0), timestep); } FeedbackContourTool::SetFeedbackContour(resultContourTimeWorld); } else { FeedbackContourTool::SetFeedbackContour(resultContourWorld); } FeedbackContourTool::SetFeedbackContourVisible(true); mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(positionEvent->GetSender()->GetRenderWindow()); } } } } void mitk::RegionGrowingTool::OnMouseReleased(StateMachineAction *, InteractionEvent *interactionEvent) { // Until OnMousePressedInside() implements a behaviour, we're just returning here whenever m_PaintingPixelValue is 0, // i.e. when the user clicked inside the segmentation if (m_PaintingPixelValue == 0) { return; } mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (m_WorkingSlice.IsNotNull() && m_FillFeedbackContour && positionEvent) { // Project contour into working slice ContourModel *feedbackContour(FeedbackContourTool::GetFeedbackContour()); ContourModel::Pointer projectedContour; // this is not a beautiful solution, just one that works, check T22412 for details int timestep = positionEvent->GetSender()->GetTimeStep(); if (0 != timestep) { int size = feedbackContour->GetNumberOfVertices(timestep); auto feedbackContourTime = mitk::ContourModel::New(); feedbackContourTime->Expand(timestep + 1); for (int loop = 0; loop < size; ++loop) { feedbackContourTime->AddVertex(feedbackContour->GetVertexAt(loop, timestep), 0); } projectedContour = FeedbackContourTool::ProjectContourTo2DSlice(m_WorkingSlice, feedbackContourTime, false, false); } else { projectedContour = FeedbackContourTool::ProjectContourTo2DSlice(m_WorkingSlice, feedbackContour, false, false); } // If there is a projected contour, fill it if (projectedContour.IsNotNull()) { // Get working data to pass to following method so we don't overwrite locked labels in a LabelSetImage mitk::DataNode *workingNode(m_ToolManager->GetWorkingData(0)); mitk::LabelSetImage *labelImage = workingNode != nullptr ? dynamic_cast(workingNode->GetData()) : nullptr; MITK_DEBUG << "Filling Segmentation"; if (labelImage != nullptr) { // m_PaintingPixelValue only decides whether to paint or not // For LabelSetImages we want to paint with the active label value auto activeLabel = labelImage->GetActiveLabel(labelImage->GetActiveLayer())->GetValue(); mitk::ContourModelUtils::FillContourInSlice(projectedContour, 0, m_WorkingSlice, labelImage, m_PaintingPixelValue * activeLabel); } else { mitk::ContourModelUtils::FillContourInSlice(projectedContour, 0, m_WorkingSlice, m_WorkingSlice, m_PaintingPixelValue); } this->WriteBackSegmentationResult(positionEvent, m_WorkingSlice); FeedbackContourTool::SetFeedbackContourVisible(false); } m_ScreenYDifference = 0; m_ScreenXDifference = 0; } } diff --git a/Modules/Segmentation/Interactions/mitkRegionGrowingTool.h b/Modules/Segmentation/Interactions/mitkRegionGrowingTool.h index 931c613999..5fcc01adb7 100644 --- a/Modules/Segmentation/Interactions/mitkRegionGrowingTool.h +++ b/Modules/Segmentation/Interactions/mitkRegionGrowingTool.h @@ -1,157 +1,156 @@ /*=================================================================== 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 mitkRegionGrowingTool_h_Included #define mitkRegionGrowingTool_h_Included #include "mitkFeedbackContourTool.h" #include #include namespace us { class ModuleResource; } namespace mitk { /** \brief A slice based region growing tool. \sa FeedbackContourTool \ingroup Interaction \ingroup ToolManagerEtAl When the user presses the mouse button, RegionGrowingTool will use the gray values at that position to initialize a region growing algorithm (in the affected 2D slice). By moving the mouse up and down while the button is still pressed, the user can widen or narrow the threshold window, i.e. select more or less within the desired region. The current result of region growing will always be shown as a contour to the user. After releasing the button, the current result of the region growing algorithm will be written to the working image of this tool's ToolManager. If the first click is inside a segmentation, nothing will happen (other behaviour, for example removal of a region, can be implemented via OnMousePressedInside()). \warning Only to be instantiated by mitk::ToolManager. $Author$ */ class MITKSEGMENTATION_EXPORT RegionGrowingTool : public FeedbackContourTool { public: mitkClassMacro(RegionGrowingTool, FeedbackContourTool); itkFactorylessNewMacro(Self) itkCloneMacro(Self) virtual const char **GetXPM() const override; virtual us::ModuleResource GetCursorIconResource() const override; us::ModuleResource GetIconResource() const override; virtual const char *GetName() const override; protected: RegionGrowingTool(); // purposely hidden virtual ~RegionGrowingTool(); void ConnectActionsAndFunctions() override; virtual void Activated() override; virtual void Deactivated() override; /** * @brief OnMousePressed is called when the user clicks. * Calls either OnMousePressedInside() or OnMousePressedOutside(). */ virtual void OnMousePressed(StateMachineAction *, InteractionEvent *interactionEvent); /** * @brief OnMousePressedInside can be used to implement behaviour when the user clicks inside a segmentation. */ virtual void OnMousePressedInside(); /** * @brief OnMousePressedOutside is called when the user clicks outside of the segmented area. * Grows a region. */ virtual void OnMousePressedOutside(StateMachineAction *, InteractionEvent *interactionEvent); /** * @brief OnMouseMoved is called when the user moves the mouse with the left mouse button pressed. * Adjusts the thresholds. * Up: Increase upper threshold, decrease lower threshold. * Down: Decrease upper threshold, increase lower threshold. * Right: Increase both thresholds. * Left: Decrease both thresholds. */ virtual void OnMouseMoved(StateMachineAction *, InteractionEvent *interactionEvent); /** * @brief OnMouseReleased converts the feedback contour to a segmentation. */ virtual void OnMouseReleased(StateMachineAction *, InteractionEvent *interactionEvent); /** * @brief Template to calculate average pixel value around index using a square/cube with radius neighborhood. * Example: 1 = 3x3 pixels, 2 = 5x5 pixels, etc. */ template void GetNeighborhoodAverage(itk::Image *itkImage, itk::Index index, ScalarType *result, unsigned int neighborhood = 1); /** * @brief Template to check whether index is inside already segmented area. */ template void IsInsideSegmentation(itk::Image *itkImage, itk::Index index, bool *result); /** * @brief Template that calls an ITK filter to do the region growing. */ template void StartRegionGrowing(itk::Image *itkImage, itk::Index seedPoint, std::array thresholds, mitk::Image::Pointer &outputImage); Image::Pointer m_ReferenceSlice; Image::Pointer m_WorkingSlice; ScalarType m_SeedValue; itk::Index<3> m_SeedPoint; std::array m_Thresholds; std::array m_InitialThresholds; Point2I m_LastScreenPosition; int m_ScreenYDifference; int m_ScreenXDifference; private: - ScalarType m_VisibleWindow; ScalarType m_MouseDistanceScaleFactor; int m_PaintingPixelValue; bool m_FillFeedbackContour; int m_ConnectedComponentValue; }; } // namespace #endif diff --git a/Plugins/org.blueberry.core.runtime/src/berrySafeRunner.cpp b/Plugins/org.blueberry.core.runtime/src/berrySafeRunner.cpp index c65061ca80..c34f13112c 100644 --- a/Plugins/org.blueberry.core.runtime/src/berrySafeRunner.cpp +++ b/Plugins/org.blueberry.core.runtime/src/berrySafeRunner.cpp @@ -1,98 +1,98 @@ /*=================================================================== BlueBerry Platform 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 "berrySafeRunner.h" #include "berryOperationCanceledException.h" #include "berryCoreException.h" #include "berryMultiStatus.h" #include "internal/berryIRuntimeConstants.h" #include "internal/berryCTKPluginActivator.h" #include namespace berry { void SafeRunner::Run(ISafeRunnable::Pointer code) { poco_assert(code); try { code->Run(); } catch (const ctkException& e) { HandleException(code, e); } catch (const std::exception& e) { HandleException(code, e); } catch (...) { HandleException(code); } } void SafeRunner::HandleException(ISafeRunnable::Pointer code) { HandleException(code, ctkException("Unknown exception thrown")); } void SafeRunner::HandleException(ISafeRunnable::Pointer code, const std::exception& e) { HandleException(code, ctkException(e.what())); } void SafeRunner::HandleException(ISafeRunnable::Pointer code, const ctkException& e) { try { - dynamic_cast(e); + Q_UNUSED(dynamic_cast(e)) } catch (const std::bad_cast& ) { // try to obtain the correct plug-in id for the bundle providing the safe runnable QString pluginId = CTKPluginActivator::getPluginId(static_cast(code.GetPointer())); if (pluginId.isEmpty()) pluginId = IRuntimeConstants::PI_RUNTIME(); QString message = QString("Problems occurred when invoking code from plug-in: \"%1\".").arg(pluginId); IStatus::Pointer status; try { const CoreException& coreExc = dynamic_cast(e); MultiStatus::Pointer multiStatus(new MultiStatus(pluginId, IRuntimeConstants::PLUGIN_ERROR, message, e, BERRY_STATUS_LOC)); multiStatus->Merge(coreExc.GetStatus()); status = multiStatus; } catch (const std::bad_cast&) { IStatus::Pointer tmpStatus(new Status(IStatus::ERROR_TYPE, pluginId, IRuntimeConstants::PLUGIN_ERROR, message, e, BERRY_STATUS_LOC)); status = tmpStatus; } // Make sure user sees the exception: if the log is empty, log the exceptions on stderr // if (!RuntimeLog.isEmpty()) // RuntimeLog.log(status); // else qWarning() << e.printStackTrace(); } code->HandleException(e); } } diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryQActionContributionItem.h b/Plugins/org.blueberry.ui.qt/src/actions/berryQActionContributionItem.h index b9ce21673d..9cc7c30431 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryQActionContributionItem.h +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryQActionContributionItem.h @@ -1,291 +1,286 @@ /*=================================================================== BlueBerry Platform 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 BERRYQACTIONCONTRIBUTIONITEM_H #define BERRYQACTIONCONTRIBUTIONITEM_H #include "berryContributionItem.h" namespace berry { /** * A contribution item which delegates to a QAction. *

* This class may be instantiated; it is not intended to be subclassed. *

* @noextend This class is not intended to be subclassed by clients. */ class BERRY_UI_QT QActionContributionItem : public ContributionItem { public: /** * Creates a new contribution item from the given action and id. * * @param action * the action */ QActionContributionItem(QAction* action, const QString& id); ~QActionContributionItem(); /** * Compares this action contribution item with another object. Two action * contribution items are equal if they refer to the identical QAction. */ bool operator==(const Object* o) const override; uint HashCode() const override; /** * The QActionContributionItem implementation of this * IContributionItem method creates an SWT * Button for the action using the action's style. If the * action's checked property has been set, the button is created and primed * to the value of the checked property. */ void Fill(QStatusBar* parent) override; /** * The ActionContributionItem implementation of this * IContributionItem method creates an SWT * MenuItem for the action using the action's style. If the * action's checked property has been set, a button is created and primed to * the value of the checked property. If the action's menu creator property * has been set, a cascading submenu is created. */ void Fill(QMenu* parent, QAction *before) override; /** * The ActionContributionItem implementation of this , * IContributionItem method creates an SWT * ToolItem for the action using the action's style. If the * action's checked property has been set, a button is created and primed to * the value of the checked property. If the action's menu creator property * has been set, a drop-down tool item is created. */ void Fill(QToolBar* parent, QAction* before) override; using ContributionItem::Fill; /** * Returns the action associated with this contribution item. * * @return the action */ QAction* GetAction() const; /** * Returns the presentation mode, which is the bitwise-or of the * MODE_* constants. The default mode setting is 0, meaning * that for menu items, both text and image are shown (if present), but for * tool items, the text is shown only if there is no image. * * @return the presentation mode settings */ Modes GetMode() const; /** * The action item implementation of this IContributionItem * method returns true for menu items and false * for everything else. */ bool IsDynamic() const override; /* * Method declared on IContributionItem. */ bool IsEnabled() const override; /** * The ActionContributionItem implementation of this * ContributionItem method extends the super implementation * by also checking whether the command corresponding to this action is * active. */ bool IsVisible() const override; /** * Sets the presentation mode, which is the bitwise-or of the * MODE_* constants. * * @param mode * the presentation mode settings */ void SetMode(Modes mode); /** * The action item implementation of this IContributionItem * method calls update(null). */ void Update() override; /** * Synchronizes the UI with the given property. * * @param propertyName * the name of the property, or null meaning all * applicable properties */ void Update(const QString& propertyName) override; protected: /** * Returns true if this item is allowed to enable, * false otherwise. * * @return if this item is allowed to be enabled */ bool IsEnabledAllowed() const; /** * Shorten the given text t so that its length doesn't exceed * the width of the given ToolItem.The default implementation replaces * characters in the center of the original string with an ellipsis ("..."). * Override if you need a different strategy. * * @param textValue * the text to shorten * @param item * the tool item the text belongs to * @return the shortened string * */ //QString ShortenText(const QString& textValue, QToolButton* item); private: /** * Returns the listener for SWT tool item widget events. * * @return a listener for tool item events */ //Listener GetToolItemListener(); /** * Handles a widget dispose event for the widget corresponding to this item. */ //void HandleWidgetDispose(Event e); /** * Handles a widget selection event. */ //void HandleWidgetSelection(Event e, bool selection); /** * Returns whether the given action has any images. * * @param actionToCheck * the action * @return true if the action has any images, * false if not */ //bool HasImages(Action* actionToCheck) const; /** * Returns whether the command corresponding to this action is active. */ bool IsCommandActive() const; /** * Updates the images for this action. * * @param forceImage * true if some form of image is compulsory, and * false if it is acceptable for this item to have * no image * @return true if there are images for this action, * false if not */ //bool UpdateImages(bool forceImage); /** * Dispose any images allocated for this contribution item */ //void DisposeOldImages(); /** * Handle show and hide on the proxy menu for IAction.AS_DROP_DOWN_MENU * actions. * * @return the appropriate listener */ //Listener getMenuCreatorListener(); /** * The proxy menu is being shown, we better get the real menu. * * @param proxy * the proxy menu */ //void HandleShowProxy(QMenu* proxy); /** * Create MenuItems in the proxy menu that can execute the real menu items * if selected. Create proxy menus for any real item submenus. * * @param realMenu * the real menu to copy from * @param proxy * the proxy menu to populate */ //void CopyMenu(QMenu* realMenu, QMenu* proxy); /** * The proxy menu is being hidden, so we need to make it go away. * * @param proxy * the proxy menu */ //void HandleHideProxy(QMenu* proxy); private: /** * This is the easiest way to hold the menu until we can swap it in to the * proxy. */ //QMenu* holdMenu = null; //bool menuCreatorCalled = false; /** a string inserted in the middle of text that has been shortened */ //static const QString ellipsis = "..."; - /** - * Stores the result of the action. False when the action returned failure. - */ - bool result; // = null; - /** * The presentation mode. */ Modes mode; // = 0; /** * The action. */ QAction* action; }; } #endif // BERRYQACTIONCONTRIBUTIONITEM_H diff --git a/Plugins/org.blueberry.ui.qt/src/berrySaveable.cpp b/Plugins/org.blueberry.ui.qt/src/berrySaveable.cpp index f7d33496fa..509656d07b 100644 --- a/Plugins/org.blueberry.ui.qt/src/berrySaveable.cpp +++ b/Plugins/org.blueberry.ui.qt/src/berrySaveable.cpp @@ -1,79 +1,77 @@ /*=================================================================== BlueBerry Platform 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 "berrySaveable.h" #include "berryIWorkbenchPage.h" #include "berryIWorkbenchPart.h" namespace berry { bool Saveable::Show(IWorkbenchPage::Pointer /*page*/) { return false; } /*IJobRunnable*/void Saveable::DoSave(/*IProgressMonitor monitor, IShellProvider shellProvider*/) { - this->DoSave(/*monitor*/); - //return 0; } void Saveable::DisableUI(const QList& /*parts*/, bool /*closing*/) { //TODO Saveable DisableUI // for (int i = 0; i < parts.length; i++) { // IWorkbenchPart workbenchPart = parts[i]; // Composite paneComposite = (Composite) ((PartSite) workbenchPart // .getSite()).getPane().getControl(); // Control[] paneChildren = paneComposite.getChildren(); // Composite toDisable = ((Composite) paneChildren[0]); // toDisable.setEnabled(false); // if (waitCursor == null) { // waitCursor = new Cursor(workbenchPart.getSite().getWorkbenchWindow().getShell().getDisplay(), SWT.CURSOR_WAIT); // } // originalCursor = paneComposite.getCursor(); // paneComposite.setCursor(waitCursor); // } } void Saveable::EnableUI(QList& /*parts*/) { //TODO Saveable EnableUI // for (unsigned int i = 0; i < parts.size(); i++) { // IWorkbenchPart::Pointer workbenchPart = parts[i]; // Composite paneComposite = (Composite) ((PartSite) workbenchPart // .getSite()).getPane().getControl(); // Control[] paneChildren = paneComposite.getChildren(); // Composite toEnable = ((Composite) paneChildren[0]); // paneComposite.setCursor(originalCursor); // if (waitCursor!=null && !waitCursor.isDisposed()) { // waitCursor.dispose(); // waitCursor = null; // } // toEnable.setEnabled(true); // } } Object* Saveable::GetAdapter(const QString& /*adapter*/) const { return nullptr; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryChangeToPerspectiveMenu.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryChangeToPerspectiveMenu.cpp index cbcb341070..bfe0e134cb 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryChangeToPerspectiveMenu.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryChangeToPerspectiveMenu.cpp @@ -1,251 +1,255 @@ /*=================================================================== BlueBerry Platform 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 "berryChangeToPerspectiveMenu.h" #include #include #include #include #include #include #include #include #include #include #include #include "berryCommandContributionItemParameter.h" #include "berryWorkbenchPlugin.h" #include "berryWorkbenchPreferenceConstants.h" #include "berryPreferenceConstants.h" #include namespace berry { const QString ChangeToPerspectiveMenu::NO_TARGETS_MSG = ""; bool PerspectiveComparator(const IPerspectiveDescriptor::Pointer& d1, const IPerspectiveDescriptor::Pointer& d2) { return d1->GetLabel() < d2->GetLabel(); } ChangeToPerspectiveMenu::ChangeToPerspectiveMenu(IWorkbenchWindow* window, const QString& id) : ContributionItem(id) , window(window) , reg(window->GetWorkbench()->GetPerspectiveRegistry()) , showActive(true) , dirty(true) { CommandContributionItemParameter::Pointer showDlgItemParms( new CommandContributionItemParameter( window, QString::null, IWorkbenchCommandConstants::PERSPECTIVES_SHOW_PERSPECTIVE, CommandContributionItem::STYLE_PUSH)); showDlgItemParms->label = "&Other..."; showDlgItem = new CommandContributionItem(showDlgItemParms); // indicate that a open perspectives submenu has been created /* if (WorkbenchWindow* window = dynamic_cast(window)) { window->AddSubmenu(WorkbenchWindow::OPEN_PERSPECTIVE_SUBMENU); } */ } void ChangeToPerspectiveMenu::Fill(QMenu* menu, QAction* before) { if (MenuManager* mm = dynamic_cast(GetParent())) { this->connect(mm, SIGNAL(AboutToShow(IMenuManager*)), SLOT(AboutToShow(IMenuManager*))); } if (!dirty) { return; } MenuManager::Pointer manager(new MenuManager()); FillMenu(manager.GetPointer()); QList items = manager->GetItems(); if (items.isEmpty()) { auto action = new QAction(NO_TARGETS_MSG, menu); action->setEnabled(false); menu->insertAction(before, action); } else { foreach (IContributionItem::Pointer item, items) { item->Fill(menu, before); } } dirty = false; } bool ChangeToPerspectiveMenu::IsDirty() const { return dirty; } bool ChangeToPerspectiveMenu::IsDynamic() const { return true; } void ChangeToPerspectiveMenu::AboutToShow(IMenuManager* manager) { manager->MarkDirty(); dirty = true; } void ChangeToPerspectiveMenu::FillMenu(IMenuManager* manager) { // Clear out the manager so that we have a blank slate. manager->RemoveAll(); // Collect and sort perspective descriptors. QList persps = GetPerspectiveShortcuts(); qSort(persps.begin(), persps.end(), PerspectiveComparator); /* * Convert the perspective descriptors to command parameters, and filter * using the activity/capability mechanism. */ for (IPerspectiveDescriptor::Pointer descriptor : persps) { CommandContributionItemParameter::Pointer ccip = GetItem(descriptor); // if (WorkbenchActivityHelper.filterItem(ccip)) { // continue; // } CommandContributionItem::Pointer item(new CommandContributionItem(ccip)); manager->Add(item); } IPreferences::Pointer prefs = WorkbenchPlugin::GetDefault()->GetPreferences(); bool showOther = true; prefs->GetBool(WorkbenchPreferenceConstants::SHOW_OTHER_IN_PERSPECTIVE_MENU, showOther); if (showOther) { // Add a separator and then "Other..." if (!manager->IsEmpty()) { IContributionItem::Pointer separator(new Separator()); manager->Add(separator); } manager->Add(showDlgItem); } } SmartPointer ChangeToPerspectiveMenu::GetItem(const IPerspectiveDescriptor::Pointer& desc) const { IPreferences::Pointer prefs = WorkbenchPlugin::GetDefault()->GetPreferences(); int mode = prefs->GetInt(PreferenceConstants::OPEN_PERSP_MODE, PreferenceConstants::OPM_ACTIVE_PAGE); IWorkbenchPage::Pointer page = window->GetActivePage(); IPerspectiveDescriptor::Pointer persp; if (page.IsNotNull()) { persp = page->GetPerspective(); } QString perspId = desc->GetId(); class PluginCCIP : public CommandContributionItemParameter, public IPluginContribution { QString localId; QString pluginId; public: - berryObjectMacro(PluginCCIP, CommandContributionItemParameter, IPluginContribution) + typedef PluginCCIP Self; + static const char* GetStaticClassName() { return "PluginCCIP"; } + berryObjectTypeInfo(CommandContributionItemParameter, IPluginContribution) PluginCCIP(const IPerspectiveDescriptor::Pointer& v, IServiceLocator* serviceLocator, const QString& id, const QString& commandId, CommandContributionItem::Style style) : CommandContributionItemParameter(serviceLocator, id, commandId, style) { + + PerspectiveDescriptor::Pointer vd = v.Cast(); localId = vd->GetLocalId(); pluginId = vd->GetPluginId(); } QString GetLocalId() const override { return localId; } QString GetPluginId() const override { return pluginId; } }; CommandContributionItemParameter::Pointer parms(new PluginCCIP(desc, window, perspId, IWorkbenchCommandConstants::PERSPECTIVES_SHOW_PERSPECTIVE, CommandContributionItem::STYLE_PUSH)); parms->label = desc->GetLabel(); parms->icon = desc->GetImageDescriptor(); Object::Pointer strId(new ObjectString(perspId)); parms->parameters.insert(IWorkbenchCommandConstants::PERSPECTIVES_SHOW_PERSPECTIVE_PARM_ID, strId); // Only open a new window if user preference is set and the window // has an active perspective. if (PreferenceConstants::OPM_NEW_WINDOW == mode && persp.IsNotNull()) { Object::Pointer bNewWnd(new ObjectBool(true)); parms->parameters.insert(IWorkbenchCommandConstants::PERSPECTIVES_SHOW_PERSPECTIVE_PARM_NEWWINDOW, bNewWnd); } return parms; } QList > ChangeToPerspectiveMenu::GetPerspectiveShortcuts() const { QList list; IWorkbenchPage::Pointer page = window->GetActivePage(); if (page.IsNull()) { return list; } QList ids = page->GetPerspectiveShortcuts(); for (int i = 0; i < ids.size(); i++) { IPerspectiveDescriptor::Pointer desc = reg->FindPerspectiveWithId(ids[i]); if (desc.IsNotNull() && !list.contains(desc)) { /* if (WorkbenchActivityHelper::FilterItem(desc)) { continue; } */ list.push_back(desc); } } return list; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryShowViewMenu.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryShowViewMenu.cpp index 7b94b5e5b2..f6acd87319 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryShowViewMenu.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryShowViewMenu.cpp @@ -1,277 +1,279 @@ /*=================================================================== BlueBerry Platform 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 "berryShowViewMenu.h" #include #include #include #include #include #include #include #include #include #include "berryCommandContributionItemParameter.h" #include "berryWorkbenchPlugin.h" #include "berryViewDescriptor.h" #include "intro/berryIntroConstants.h" #include #include #include namespace berry { const QString ShowViewMenu::NO_TARGETS_MSG = ""; struct ActionComparator { bool operator()(const CommandContributionItemParameter::Pointer& p1, const CommandContributionItemParameter::Pointer& p2) const { return p1->label < p2->label; } }; ShowViewMenu::ShowViewMenu(IWorkbenchWindow *window, const QString& id) : ContributionItem(id), dirty(true), window(window) { CommandContributionItemParameter::Pointer showDlgItemParms( new CommandContributionItemParameter( window, QString::null, IWorkbenchCommandConstants::VIEWS_SHOW_VIEW, CommandContributionItem::STYLE_PUSH)); showDlgItemParms->label = "&Other..."; showDlgItem = new CommandContributionItem(showDlgItemParms); // window.getWorkbench().getHelpSystem().setHelp(showDlgAction, // IWorkbenchHelpContextIds.SHOW_VIEW_OTHER_ACTION); // // indicate that a show views submenu has been created // if (window instanceof WorkbenchWindow) { // ((WorkbenchWindow) window) // .addSubmenu(WorkbenchWindow.SHOW_VIEW_SUBMENU); // } } bool ShowViewMenu::IsDirty() const { return dirty; } /** * Overridden to always return true and force dynamic menu building. */ bool ShowViewMenu::IsDynamic() const { return true; } void ShowViewMenu::Fill(QMenu* menu, QAction* before) { if (MenuManager* mm = dynamic_cast(GetParent())) { this->connect(mm, SIGNAL(AboutToShow(IMenuManager*)), SLOT(AboutToShow(IMenuManager*))); } if (!dirty) { return; } MenuManager::Pointer manager(new MenuManager()); FillMenu(manager.GetPointer()); QList items = manager->GetItems(); if (items.isEmpty()) { auto action = new QAction(NO_TARGETS_MSG, menu); action->setEnabled(false); menu->insertAction(before, action); } else { foreach (IContributionItem::Pointer item, items) { item->Fill(menu, before); } } dirty = false; } void ShowViewMenu::FillMenu(IMenuManager* innerMgr) { // Remove all. innerMgr->RemoveAll(); // If no page disable all. IWorkbenchPage::Pointer page = window->GetActivePage(); if (page.IsNull()) { return; } // If no active perspective disable all if (page->GetPerspective().IsNull()) { return; } typedef QPair ViewIdPair; // Get visible actions. QSet viewIds = GetShortcuts(page.GetPointer()); // add all open views viewIds = AddOpenedViews(page.GetPointer(), viewIds); QList actions; foreach (ViewIdPair id, viewIds) { if (id.first == IntroConstants::INTRO_VIEW_ID) { continue; } CommandContributionItemParameter::Pointer item = GetItem(id.first, id.second); if (item) { actions.append(item); } } qSort(actions.begin(), actions.end(), ActionComparator()); foreach (CommandContributionItemParameter::Pointer ccip, actions) { // if (WorkbenchActivityHelper.filterItem(ccip)) { // continue; // } CommandContributionItem::Pointer item(new CommandContributionItem(ccip)); innerMgr->Add(item); } // We only want to add the separator if there are show view shortcuts, // otherwise, there will be a separator and then the 'Other...' entry // and that looks weird as the separator is separating nothing if (!innerMgr->IsEmpty()) { IContributionItem::Pointer separator(new Separator()); innerMgr->Add(separator); } // Add Other... innerMgr->Add(showDlgItem); } QSet > ShowViewMenu::GetShortcuts(IWorkbenchPage* page) const { QSet > list; QList shortcuts(page->GetShowViewShortcuts()); for (int i = 0; i < shortcuts.size(); ++i) { list.insert(qMakePair(shortcuts[i], QString())); } return list; } void ShowViewMenu::AboutToShow(IMenuManager* manager) { manager->MarkDirty(); this->dirty = true; } CommandContributionItemParameter::Pointer ShowViewMenu::GetItem(const QString& viewId, const QString& secondaryId) const { IViewRegistry* reg = WorkbenchPlugin::GetDefault()->GetViewRegistry(); IViewDescriptor::Pointer desc = reg->Find(viewId); if (desc.IsNull()) { return CommandContributionItemParameter::Pointer(nullptr); } QString label = desc->GetLabel(); class PluginCCIP : public CommandContributionItemParameter, public IPluginContribution { QString localId; QString pluginId; public: - berryObjectMacro(PluginCCIP, CommandContributionItemParameter, IPluginContribution) + typedef PluginCCIP Self; + static const char* GetStaticClassName() { return "PluginCCIP"; } + berryObjectTypeInfo(CommandContributionItemParameter, IPluginContribution) PluginCCIP(const IViewDescriptor::Pointer& v, IServiceLocator* serviceLocator, const QString& id, const QString& commandId, CommandContributionItem::Style style) : CommandContributionItemParameter(serviceLocator, id, commandId, style) { ViewDescriptor::Pointer vd = v.Cast(); localId = vd->GetLocalId(); pluginId = vd->GetPluginId(); } QString GetLocalId() const override { return localId; } QString GetPluginId() const override { return pluginId; } }; CommandContributionItemParameter::Pointer parms(new PluginCCIP(desc, window, viewId, IWorkbenchCommandConstants::VIEWS_SHOW_VIEW, CommandContributionItem::STYLE_PUSH)); parms->label = label; parms->icon = desc->GetImageDescriptor(); Object::Pointer strViewId(new ObjectString(viewId)); parms->parameters.insert(IWorkbenchCommandConstants::VIEWS_SHOW_VIEW_PARM_ID, strViewId); // if (makeFast) // { // parms.parameters.put( // IWorkbenchCommandConstants.VIEWS_SHOW_VIEW_PARM_FASTVIEW, // "true"); //$NON-NLS-1$ // } if (!secondaryId.isEmpty()) { Object::Pointer strSecondaryId(new ObjectString(secondaryId)); parms->parameters.insert(IWorkbenchCommandConstants::VIEWS_SHOW_VIEW_SECONDARY_ID, strSecondaryId); } return parms; } QSet > ShowViewMenu::AddOpenedViews(IWorkbenchPage* page, QSet >& actions) const { QSet > views = GetParts(page); return views.unite(actions); } QSet > ShowViewMenu::GetParts(IWorkbenchPage* page) const { QSet > parts; QList refs = page->GetViewReferences(); for (int i = 0; i < refs.size(); ++i) { parts.insert(qMakePair(refs[i]->GetId(), refs[i]->GetSecondaryId())); } return parts; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchTestable.h b/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchTestable.h index 987cf6229f..b33378db05 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchTestable.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryWorkbenchTestable.h @@ -1,124 +1,120 @@ /*=================================================================== BlueBerry Platform 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 BERRYWORKBENCHTESTABLE_H_ #define BERRYWORKBENCHTESTABLE_H_ #include "testing/berryTestableObject.h" #include namespace berry { class Display; struct IWorkbench; /** * The Workbench's testable object facade to a test harness. * * @since 3.0 */ class WorkbenchTestable: public TestableObject { private: Display* display; IWorkbench* workbench; - bool oldAutomatedMode; - - bool oldIgnoreErrors; - Poco::Thread thread; class WorkbenchTestRunnable: public Poco::Runnable { public: WorkbenchTestRunnable(TestableObject* testable); void run() override; private: TestableObject* testable; }; WorkbenchTestRunnable testRunnable; public: berryObjectMacro( WorkbenchTestable); /** * Constructs a new workbench testable object. */ WorkbenchTestable(); /** * Initializes the workbench testable with the display and workbench, * and notifies all listeners that the tests can be run. * * @param display the display * @param workbench the workbench */ void Init(Display* display, IWorkbench* workbench); /** * The WorkbenchTestable implementation of this * TestableObject method ensures that the workbench * has been set. */ void TestingStarting() override; /** * The WorkbenchTestable implementation of this * TestableObject method flushes the event queue, * runs the test in a syncExec, then flushes the * event queue again. */ void RunTest(Poco::Runnable* testRunnable) override; /** * The WorkbenchTestable implementation of this * TestableObject method flushes the event queue, * then closes the workbench. */ void TestingFinished() override; private: /** * Waits for the early startup job to complete. */ // void WaitForEarlyStartup() { // try { // Job::GetJobManager()->Join(Workbench::EARLY_STARTUP_FAMILY, 0); // } catch (OperationCanceledException e) { // // ignore // } catch (InterruptedException e) { // // ignore // } // } }; } #endif /* BERRYWORKBENCHTESTABLE_H_ */ diff --git a/Plugins/org.mitk.gui.qt.aicpregistration/src/internal/QmitkAICPRegistrationView.cpp b/Plugins/org.mitk.gui.qt.aicpregistration/src/internal/QmitkAICPRegistrationView.cpp index 69db7b4e85..d31d572eda 100644 --- a/Plugins/org.mitk.gui.qt.aicpregistration/src/internal/QmitkAICPRegistrationView.cpp +++ b/Plugins/org.mitk.gui.qt.aicpregistration/src/internal/QmitkAICPRegistrationView.cpp @@ -1,427 +1,426 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkAICPRegistrationView.h" // Qt #include #include // MITK #include #include #include #include #include #include // vtk #include #include #include const std::string QmitkAICPRegistrationView::VIEW_ID = "org.mitk.views.aicpregistration"; /** * @brief Pimpl holding the datastructures used by the * QmitkAICPRegistrationView. */ class AICPRegistrationViewData { public: QThread* m_RegistrationThread; UIWorker* m_Worker; double m_Threshold; double m_MaxIterations; double m_TrimmFactor; double m_SearchRadius; // anisotropic registration mitk::AnisotropicIterativeClosestPointRegistration::Pointer m_AICP; // covariance matrix calculator mitk::CovarianceMatrixCalculator::Pointer m_MatrixCalculator; vtkSmartPointer m_CleanPolyData; mitk::Surface::Pointer m_MovingSurface; mitk::Surface::Pointer m_FixedSurface; // c tor AICPRegistrationViewData() : m_RegistrationThread(new QThread()), m_Worker(new UIWorker()), m_Threshold(0.00001), m_MaxIterations(1000), m_TrimmFactor(0.0), m_SearchRadius(30.0), m_AICP(mitk::AnisotropicIterativeClosestPointRegistration::New()), m_MatrixCalculator(mitk::CovarianceMatrixCalculator::New()), m_CleanPolyData(vtkSmartPointer::New()), m_MovingSurface(nullptr), m_FixedSurface(nullptr) { } // cleanup ~AICPRegistrationViewData() { if ( m_RegistrationThread ) delete m_RegistrationThread; if ( m_Worker ) delete m_Worker; m_AICP = nullptr; m_MatrixCalculator = nullptr; m_CleanPolyData = nullptr; m_MovingSurface = nullptr; m_FixedSurface = nullptr; } }; QmitkAICPRegistrationView::QmitkAICPRegistrationView() { d = new AICPRegistrationViewData(); } QmitkAICPRegistrationView::~QmitkAICPRegistrationView() { if ( d ) delete d; } void QmitkAICPRegistrationView::SetFocus(){} void QmitkAICPRegistrationView::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); // connect signals and slots connect ( m_Controls.m_EnableTreCalculation,SIGNAL(clicked()),this, SLOT(OnEnableTreCalculation()) ); connect ( m_Controls.m_RegisterSurfaceButton, SIGNAL(clicked()), this, SLOT(OnStartRegistration()) ); connect ( m_Controls.m_EnableTrimming, SIGNAL(clicked()), this, SLOT(OnEnableTrimming()) ); connect ( d->m_Worker, SIGNAL( RegistrationFinished()), this, SLOT( OnRegistrationFinished()) ); connect(d->m_RegistrationThread,SIGNAL(started()), d->m_Worker,SLOT(RegistrationThreadFunc()) ); // move the u worker to the thread d->m_Worker->moveToThread(d->m_RegistrationThread); // setup tooltips m_Controls.m_MovingSurfaceComboBox->setToolTip("Set the moving surface of the A-ICP algorithm"); m_Controls.m_FixedSurfaceComboBox->setToolTip("Set the fixed surface of the A-ICP algorithm"); m_Controls.m_EnableTreCalculation->setToolTip("Enable the trimmed version of the algorithm."); m_Controls.m_TrimmFactorSpinbox->setToolTip("Set the trimmfactor. The algorithm will use a percentage of the Moving pointset for the registration. Valid number are between 0 and 1."); m_Controls.m_ThresholdSpinbox->setToolTip("Set the threshold to wich the algorithm will converge."); m_Controls.m_MaxIterationsSpinbox->setToolTip("The maximum number of iterations used by the algorithm."); m_Controls.m_SearchRadius->setToolTip("Set the search radius in mm for the calculation of the correspondences."); m_Controls.m_RegisterSurfaceButton->setToolTip("Start the registration."); m_Controls.m_EnableTrimming->setToolTip("Enables the trimmed version of the algorithm."); m_Controls.m_TrimmFactorSpinbox->setToolTip("Set teh overlapping part of the surface in %. The valid range is between 0 and 1."); m_Controls.m_MovingTargets->setToolTip("Select the targets for the moving surface."); m_Controls.m_FixedTargets->setToolTip("Select the targets for the fixed surface."); // init combo boxes m_Controls.m_FixedSurfaceComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_FixedSurfaceComboBox->SetPredicate(mitk::NodePredicateDataType::New("Surface")); m_Controls.m_MovingSurfaceComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_MovingSurfaceComboBox->SetPredicate(mitk::NodePredicateDataType::New("Surface")); m_Controls.m_MovingTargets->SetDataStorage(this->GetDataStorage()); m_Controls.m_MovingTargets->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); m_Controls.m_FixedTargets->SetDataStorage(this->GetDataStorage()); m_Controls.m_FixedTargets->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); // disable target selection m_Controls.m_TargetSelectFrame->setEnabled(false); // disable trimming options m_Controls.m_TrimmFactorLabel->setEnabled(false); m_Controls.m_TrimmFactorSpinbox->setEnabled(false); } bool QmitkAICPRegistrationView::CheckInput() { QMessageBox msg; msg.setIcon(QMessageBox::Critical); if ( m_Controls.m_MovingSurfaceComboBox->GetSelectedNode().IsNull() || m_Controls.m_FixedSurfaceComboBox->GetSelectedNode().IsNull() ) { const char* message = "No Surfaces selected."; MITK_ERROR << message; msg.setText(message); msg.exec(); return false; } if ( m_Controls.m_EnableTreCalculation->isChecked() ) { if ( m_Controls.m_FixedTargets->GetSelectedNode().IsNull() || m_Controls.m_MovingTargets->GetSelectedNode().IsNull() ) { const char* message = "TRE calculation is enabled, but no target points are selected."; msg.setText(message); msg.exec(); return false; } } return true; } void QmitkAICPRegistrationView::OnStartRegistration() { d->m_Threshold = m_Controls.m_ThresholdSpinbox->value(); d->m_MaxIterations = m_Controls.m_MaxIterationsSpinbox->value(); d->m_SearchRadius = m_Controls.m_SearchRadius->value(); d->m_TrimmFactor = 0.0; if ( m_Controls.m_EnableTrimming->isChecked() ) { d->m_TrimmFactor = m_Controls.m_TrimmFactorSpinbox->value(); } if (! CheckInput() ) return; d->m_MovingSurface = dynamic_cast( m_Controls.m_MovingSurfaceComboBox->GetSelectedNode()->GetData() ); d->m_FixedSurface = dynamic_cast( m_Controls.m_FixedSurfaceComboBox->GetSelectedNode()->GetData() ); // sanity check if ( d->m_FixedSurface.IsNull() || d->m_MovingSurface.IsNull() ) { const char* message = "Input surfaces are nullptr."; QMessageBox msg; msg.setIcon(QMessageBox::Critical); msg.setText(message); MITK_ERROR << message; return; } // enable trimming if ( m_Controls.m_EnableTrimming->isChecked() ) { d->m_TrimmFactor = m_Controls.m_TrimmFactorSpinbox->value(); } // set data into the UI thread d->m_Worker->SetRegistrationData(d); // start thread d->m_RegistrationThread->start(); // disable registration button m_Controls.m_RegisterSurfaceButton->setEnabled(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkAICPRegistrationView::OnEnableTreCalculation() { if ( m_Controls.m_EnableTreCalculation->isChecked() ) m_Controls.m_TargetSelectFrame->setEnabled(true); else m_Controls.m_TargetSelectFrame->setEnabled(false); } void QmitkAICPRegistrationView::OnEnableTrimming() { if ( m_Controls.m_EnableTrimming->isChecked() ) { // disable trimming options m_Controls.m_TrimmFactorLabel->setEnabled(true); m_Controls.m_TrimmFactorSpinbox->setEnabled(true); } else { // disable trimming options m_Controls.m_TrimmFactorLabel->setEnabled(false); m_Controls.m_TrimmFactorSpinbox->setEnabled(false); } } void QmitkAICPRegistrationView::OnRegistrationFinished() { typedef itk::Matrix Matrix3x3; typedef itk::Vector TranslationVector; double tre = -1.0; Matrix3x3 rotation = d->m_AICP->GetRotation(); TranslationVector translation = d->m_AICP->GetTranslation(); // exit the thread d->m_RegistrationThread->quit(); MITK_INFO << "Rotation: \n" << rotation << "Translation: " << translation; MITK_INFO << "FRE: " << d->m_AICP->GetFRE(); // compute TRE if ( m_Controls.m_EnableTreCalculation->isChecked() ) { mitk::PointSet* movingTargets = dynamic_cast ( m_Controls.m_MovingTargets->GetSelectedNode()->GetData() ); mitk::PointSet* fixedTargets = dynamic_cast ( m_Controls.m_FixedTargets->GetSelectedNode()->GetData() ); // sanity check if ( movingTargets && fixedTargets ) { // swap the moving and the fixed point set, since we use the inverse // transform tre = mitk::AnisotropicRegistrationCommon::ComputeTargetRegistrationError( movingTargets, fixedTargets, rotation, translation ); MITK_INFO << "TRE: " << tre; // transform the fixed point set for ( int i = 0; i < movingTargets->GetSize(); ++i ) { mitk::Point3D p = movingTargets->GetPoint(i); p = rotation * p + translation; movingTargets->SetPoint(i,p); } } } // display result in textbox ( the inverse transform ) QString text(""); std::ostringstream oss; oss << "Iterations: "<< d->m_AICP->GetNumberOfIterations() << "
FRE: " << d->m_AICP->GetFRE() << "
TRE: "; if ( tre != -1.0) oss << tre; else oss << "N/A"; oss << "

Rotation:
"; for ( int i = 0; i < 3; ++i ) { for ( int j = 0; j < 3; ++j ) oss << rotation[i][j] << " "; oss << "
"; } oss << "
Translation:
" << translation << "
"; std::string s(oss.str()); text.append(s.c_str()); m_Controls.m_TextEdit->clear(); m_Controls.m_TextEdit->append(text); mitk::AnisotropicRegistrationCommon::TransformPoints ( d->m_MovingSurface->GetVtkPolyData()->GetPoints(), d->m_MovingSurface->GetVtkPolyData()->GetPoints(), rotation, translation ); // set modified flag to update rendering d->m_MovingSurface->GetVtkPolyData()->Modified(); // reanable registration button m_Controls.m_RegisterSurfaceButton->setEnabled(true); //update view mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void UIWorker::SetRegistrationData(AICPRegistrationViewData *data) { this->d = data; } void UIWorker::RegistrationThreadFunc() { typedef itk::Matrix Matrix3x3; - typedef itk::Vector TranslationVector; typedef std::vector CovarianceMatrixList; // moving surface mitk::Surface::Pointer X = mitk::Surface::New(); // helper vtkPolyData* data_X = vtkPolyData::New(); // fixed surface mitk::Surface::Pointer Y = mitk::Surface::New(); // helper vtkPolyData* data_Y = vtkPolyData::New(); // clean the poly data to prevent manifold edges and duplicated vertices d->m_CleanPolyData->SetInputData(d->m_MovingSurface->GetVtkPolyData()); d->m_CleanPolyData->Update(); // copy the polys data_X->DeepCopy(d->m_CleanPolyData->GetOutput()); X->SetVtkPolyData(data_X); d->m_CleanPolyData->SetInputData(d->m_FixedSurface->GetVtkPolyData()); d->m_CleanPolyData->Update(); data_Y->DeepCopy(d->m_CleanPolyData->GetOutput()); Y->SetVtkPolyData(data_Y); // compute the covariance matrices for the moving surface (X) d->m_MatrixCalculator->SetInputSurface(X); d->m_MatrixCalculator->ComputeCovarianceMatrices(); CovarianceMatrixList sigmas_X = d->m_MatrixCalculator->GetCovarianceMatrices(); const double meanVarX = d->m_MatrixCalculator->GetMeanVariance(); // compute the covariance matrices for the fixed surface (Y) d->m_MatrixCalculator->SetInputSurface(Y); d->m_MatrixCalculator->ComputeCovarianceMatrices(); CovarianceMatrixList sigmas_Y = d->m_MatrixCalculator->GetCovarianceMatrices(); const double meanVarY = d->m_MatrixCalculator->GetMeanVariance(); // the FRE normalization factor const double normalizationFactor = sqrt( meanVarX + meanVarY); // set up parameters d->m_AICP->SetMovingSurface(X); d->m_AICP->SetFixedSurface(Y); d->m_AICP->SetCovarianceMatricesMovingSurface(sigmas_X); d->m_AICP->SetCovarianceMatricesFixedSurface(sigmas_Y); d->m_AICP->SetFRENormalizationFactor(normalizationFactor); d->m_AICP->SetMaxIterations(d->m_MaxIterations); d->m_AICP->SetSearchRadius(d->m_SearchRadius); d->m_AICP->SetThreshold(d->m_Threshold); d->m_AICP->SetTrimmFactor(d->m_TrimmFactor); // run the algorithm d->m_AICP->Update(); data_X->Delete(); data_Y->Delete(); emit RegistrationFinished(); } diff --git a/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationSegmentation.cpp b/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationSegmentation.cpp index f690fc869c..ef2ff1899c 100644 --- a/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationSegmentation.cpp +++ b/Plugins/org.mitk.gui.qt.classificationsegmentation/src/internal/ClassificationSegmentation.cpp @@ -1,984 +1,981 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "ClassificationSegmentation.h" // Qt #include //mitk image #include #include #include #include #include #include #include "mitkVigraRandomForestClassifier.h" #include "mitkCLUtil.h" #include "qboxlayout.h" #include #include "Eigen/Dense" #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include const std::string ClassificationSegmentation::VIEW_ID = "org.mitk.views.classificationsegmentation"; void ClassificationSegmentation::SetFocus() { // m_Controls.buttonPerformImageProcessing->setFocus(); } void ClassificationSegmentation::OnButtonCSFToggle(bool checked) { // m_PointListWidget->SetPointSet(dynamic_cast(m_PointSetList[0]->GetData())); if(checked) m_PointSetDataInteractor->SetDataNode(m_PointSetList[0]); else m_PointSetDataInteractor->SetDataNode(nullptr); } void ClassificationSegmentation::OnButtonLESToggle(bool checked) { // m_PointListWidget->SetPointSet(dynamic_cast(m_PointSetList[1]->GetData())); if(checked) m_PointSetDataInteractor->SetDataNode(m_PointSetList[1]); else m_PointSetDataInteractor->SetDataNode(nullptr); } void ClassificationSegmentation::OnButtonBRAToggle(bool checked) { // m_PointListWidget->SetPointSet(dynamic_cast(m_PointSetList[2]->GetData())); if(checked) m_PointSetDataInteractor->SetDataNode(m_PointSetList[2]); else m_PointSetDataInteractor->SetDataNode(nullptr); } void ClassificationSegmentation::OnButtonNoInteractionToggle(bool checked) { if(checked) m_PointSetDataInteractor->SetDataNode(nullptr); } void ClassificationSegmentation::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); m_CalculateFeatures = true; m_BlockManualSegmentation = false; m_BlockPostProcessing = false; QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); QmitkDataStorageComboBox * cb_maskimage= new QmitkDataStorageComboBox(this->GetDataStorage(),mitk::TNodePredicateDataType::New()); QmitkDataStorageComboBox * cb_classifer= new QmitkDataStorageComboBox(this->GetDataStorage(),mitk::TNodePredicateDataType::New()); m_Controls.m_InputImageLayout->addWidget(cb_inputimage); m_Controls.m_MaskImageLayout->addWidget(cb_maskimage); m_Controls.m_ClassifierLayout->addWidget(cb_classifer); m_Controls.m_ParameterLayout->layout()->addWidget(new QLabel("Gauss Sigma")); m_GaussSlider = new ctkSliderWidget(); m_GaussSlider->setMinimum(0); m_GaussSlider->setMaximum(10); m_GaussSlider->setValue(1); m_Controls.m_ParameterLayout->layout()->addWidget(m_GaussSlider); m_Controls.m_ParameterLayout->layout()->addWidget(new QLabel("Hessian Sigma")); m_HessianSlider = new ctkSliderWidget(); m_HessianSlider->setMinimum(0); m_HessianSlider->setMaximum(10); m_HessianSlider->setValue(3); m_Controls.m_ParameterLayout->layout()->addWidget(m_HessianSlider); m_Controls.m_ParameterLayout->layout()->addWidget(new QLabel("Structure Tensor Inner and Outer Scale")); m_STInnerSlider = new ctkSliderWidget(); m_STInnerSlider->setMinimum(0); m_STInnerSlider->setMaximum(10); m_STInnerSlider->setValue(1.5); m_Controls.m_ParameterLayout->layout()->addWidget(m_STInnerSlider); m_STOuterSlider = new ctkSliderWidget(); m_STOuterSlider->setMinimum(0); m_STOuterSlider->setMaximum(10); m_STOuterSlider->setValue(3); m_Controls.m_ParameterLayout->layout()->addWidget(m_STOuterSlider); m_Controls.m_PostProcessingLayout->layout()->addWidget(new QLabel("Probability map smoothing")); m_GaussCSFSlider = new ctkSliderWidget; m_GaussCSFSlider->setMinimum(0); m_GaussCSFSlider->setMaximum(10); m_GaussCSFSlider->setValue(1.5); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_GaussCSFSlider); m_GaussLESSlider = new ctkSliderWidget; m_GaussLESSlider->setMinimum(0); m_GaussLESSlider->setMaximum(10); m_GaussLESSlider->setValue(3); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_GaussLESSlider); m_GaussBRASlider = new ctkSliderWidget; m_GaussBRASlider->setMinimum(0); m_GaussBRASlider->setMaximum(10); m_GaussBRASlider->setValue(0.5); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_GaussBRASlider); m_Controls.m_PostProcessingLayout->layout()->addWidget(new QLabel("Probability map weighting")); m_WeightCSFSlider = new ctkSliderWidget; m_WeightCSFSlider->setMinimum(0.0); m_WeightCSFSlider->setMaximum(2.0); m_WeightCSFSlider->setValue(1.0); m_WeightCSFSlider->setSingleStep(0.1); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_WeightCSFSlider); m_WeightLESSlider = new ctkSliderWidget; m_WeightLESSlider->setMinimum(0.0); m_WeightLESSlider->setMaximum(2.0); m_WeightLESSlider->setValue(1.0); m_WeightLESSlider->setSingleStep(0.1); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_WeightLESSlider); m_WeightBRASlider = new ctkSliderWidget; m_WeightBRASlider->setMinimum(0.0); m_WeightBRASlider->setMaximum(2.0); m_WeightBRASlider->setValue(1.0); m_WeightBRASlider->setSingleStep(0.1); m_Controls.m_PostProcessingLayout->layout()->addWidget(m_WeightBRASlider); m_PointSetDataInteractor = mitk::PointSetDataInteractor::New(); m_PointSetDataInteractor->LoadStateMachine("PointSet.xml"); m_PointSetDataInteractor->SetEventConfig("PointSetConfig.xml"); connect( cb_inputimage, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnInitializeSession(const mitk::DataNode*))); connect( cb_maskimage, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnInitializeSession(const mitk::DataNode*))); connect( m_Controls.m_SavePointsButton, SIGNAL(clicked(bool)), this, SLOT(DoSavePointsAsMask())); connect( m_Controls.m_ButtonCSFToggle, SIGNAL(toggled(bool)), this, SLOT(OnButtonCSFToggle(bool))); connect( m_Controls.m_ButtonLESToggle, SIGNAL(toggled(bool)), this, SLOT(OnButtonLESToggle(bool))); connect( m_Controls.m_ButtonBRAToggle, SIGNAL(toggled(bool)), this, SLOT(OnButtonBRAToggle(bool))); connect( m_Controls.m_ButtonNoInteraction, SIGNAL(toggled(bool)), this, SLOT(OnButtonNoInteractionToggle(bool))); connect( &m_ManualSegmentationFutureWatcher, SIGNAL(finished()), this, SLOT(ManualSegmentationFinished())); connect( &m_PostProcessingFutureWatcher, SIGNAL(finished()), this, SLOT(PostProcessingFinished())); //connect( m_Controls.m_AddPointSets, SIGNAL(clicked()),this, SLOT(OnAddPointSets()) ); connect( m_GaussSlider, SIGNAL(valueChanged(double)), this, SLOT(OnFeatureSettingsChanged())); connect( m_HessianSlider, SIGNAL(valueChanged(double)), this, SLOT(OnFeatureSettingsChanged())); connect( m_STInnerSlider, SIGNAL(valueChanged(double)), this, SLOT(OnFeatureSettingsChanged())); connect( m_STOuterSlider, SIGNAL(valueChanged(double)), this, SLOT(OnFeatureSettingsChanged())); connect( m_GaussCSFSlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_GaussLESSlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_GaussBRASlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_WeightCSFSlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_WeightLESSlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect( m_WeightBRASlider, SIGNAL(valueChanged(double)), this, SLOT(OnPostProcessingSettingsChanged())); connect(m_Controls.m_DoAutomaticSecmentation, SIGNAL(clicked(bool)), this, SLOT(DoAutomSegmentation())); connect(m_Controls.m_AddForestToDataManager, SIGNAL(clicked(bool)), this, SLOT(OnAddForestToDataManager())); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetName("CSF_Points."); pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024)); pointSetNode->SetColor(0,1.0,0); pointSetNode->SetDataInteractor(m_PointSetDataInteractor.GetPointer()); m_PointSetList.push_back(pointSetNode); GetDataStorage()->Add(pointSetNode); pointSetNode = mitk::DataNode::New(); pointSetNode->SetName("LES_Points."); pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024)); pointSetNode->SetColor(1.0,0,0); pointSetNode->SetDataInteractor(m_PointSetDataInteractor.GetPointer()); m_PointSetList.push_back(pointSetNode); GetDataStorage()->Add(pointSetNode); pointSetNode = mitk::DataNode::New(); pointSetNode->SetName("BRA_Points."); pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024)); pointSetNode->SetColor(0,0,1.0); pointSetNode->SetDataInteractor(m_PointSetDataInteractor.GetPointer()); m_PointSetList.push_back(pointSetNode); GetDataStorage()->Add(pointSetNode); m_Controls.m_PostProcessingLayout->hide(); m_Controls.m_ParameterLayout->hide(); } void ClassificationSegmentation::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes ) { // iterate all selected objects, adjust warning visibility foreach( mitk::DataNode::Pointer node, nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { // m_Controls.labelWarning->setVisible( false ); // m_Controls.buttonPerformImageProcessing->setEnabled( true ); return; } } // m_Controls.labelWarning->setVisible( true ); // m_Controls.buttonPerformImageProcessing->setEnabled( false ); } void ClassificationSegmentation::OnAddForestToDataManager() { AddAsDataNode(m_TempClassifier.GetPointer(),"ManualSegmentation_Classifier"); } void ClassificationSegmentation::OnInitializeSession(const mitk::DataNode *) { MITK_WARN << "Data selection changed! New session initialized."; m_PointSetDataInteractor->SetDataNode(nullptr); /// CSF POINTSET mitk::PointSet::Pointer pntset = mitk::PointSet::New(); m_PointSetList[0]->SetData(pntset); itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &ClassificationSegmentation::ManualSegmentationTrigger); pntset->AddObserver( mitk::PointSetAddEvent(), command ); pntset->AddObserver( mitk::PointSetRemoveEvent(), command ); pntset->AddObserver( mitk::PointSetMoveEvent(), command ); /// LES POINTSET pntset = mitk::PointSet::New(); m_PointSetList[1]->SetData(pntset); command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &ClassificationSegmentation::ManualSegmentationTrigger); pntset->AddObserver( mitk::PointSetAddEvent(), command ); pntset->AddObserver( mitk::PointSetRemoveEvent(), command ); pntset->AddObserver( mitk::PointSetMoveEvent(), command ); /// BRA POINTSET pntset = mitk::PointSet::New(); m_PointSetList[2]->SetData(pntset); command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &ClassificationSegmentation::ManualSegmentationTrigger); pntset->AddObserver( mitk::PointSetAddEvent(), command ); pntset->AddObserver( mitk::PointSetRemoveEvent(), command ); pntset->AddObserver( mitk::PointSetMoveEvent(), command ); } void ClassificationSegmentation::DoSavePointsAsMask() { mitk::Image::Pointer sampled_image = nullptr; QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); mitk::Image::Pointer raw_image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); int label = 1; for( auto datanode : m_PointSetList) { mitk::PointSet::Pointer point_set = dynamic_cast(datanode->GetData()); mitk::Image::Pointer temp_img; SampleClassMaskByPointSet(raw_image, point_set,temp_img); mitk::CLUtil::InsertLabel(temp_img,sampled_image,label++); QmitkIOUtil::Save(datanode->GetData(),QString("PointSet.mps")); } QmitkIOUtil::Save(sampled_image,QString("PointSetMask.nrrd")); } void ClassificationSegmentation::ProcessFeatureImages(const mitk::Image::Pointer & raw_image, const mitk::Image::Pointer & brain_mask) { typedef itk::Image DoubleImageType; typedef itk::Image ShortImageType; typedef itk::ConstNeighborhoodIterator NeighborhoodType; // Neighborhood iterator to access image typedef itk::Functor::NeighborhoodFirstOrderStatistics FunctorType; typedef itk::NeighborhoodFunctorImageFilter FOSFilerType; - typedef FOSFilerType::MaskImageType MaskImageType; m_FeatureImageVector.clear(); // RAW m_FeatureImageVector.push_back(raw_image); // GAUSS mitk::Image::Pointer smoothed; mitk::CLUtil::GaussianFilter(raw_image,smoothed,m_GaussSlider->value()); m_FeatureImageVector.push_back(smoothed); // Calculate Probability maps (parameters used from literatur) // CSF mitk::Image::Pointer csf_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,13.9, 8.3,csf_prob); m_FeatureImageVector.push_back(csf_prob); // Lesion mitk::Image::Pointer les_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,59, 11.6,les_prob); m_FeatureImageVector.push_back(les_prob); // Barin (GM/WM) mitk::Image::Pointer brain_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,32, 5.6,brain_prob); m_FeatureImageVector.push_back(brain_prob); std::vector FOS_sizes; FOS_sizes.push_back(1); DoubleImageType::Pointer input; ShortImageType::Pointer mask; mitk::CastToItkImage(smoothed, input); mitk::CastToItkImage(brain_mask, mask); for(unsigned int i = 0 ; i < FOS_sizes.size(); i++) { FOSFilerType::Pointer filter = FOSFilerType::New(); filter->SetNeighborhoodSize(FOS_sizes[i]); filter->SetInput(input); filter->SetMask(mask); filter->Update(); FOSFilerType::DataObjectPointerArray array = filter->GetOutputs(); for( unsigned int i = 0; i < FunctorType::OutputCount; i++) { mitk::Image::Pointer featureimage; mitk::CastToMitkImage(dynamic_cast(array[i].GetPointer()),featureimage); m_FeatureImageVector.push_back(featureimage); // AddImageAsDataNode(featureimage,FunctorType::GetFeatureName(i))->SetVisibility(show_nodes); } } { itk::HessianMatrixEigenvalueImageFilter< DoubleImageType >::Pointer filter = itk::HessianMatrixEigenvalueImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->SetSigma(m_HessianSlider->value()); filter->Update(); mitk::Image::Pointer o1,o2,o3; mitk::CastToMitkImage(filter->GetOutput(0),o1); mitk::CastToMitkImage(filter->GetOutput(1),o2); mitk::CastToMitkImage(filter->GetOutput(2),o3); m_FeatureImageVector.push_back(o1); m_FeatureImageVector.push_back(o2); m_FeatureImageVector.push_back(o3); // AddImageAsDataNode(o1,"HE_1")->SetVisibility(show_nodes); // AddImageAsDataNode(o2,"HE_2")->SetVisibility(show_nodes); // AddImageAsDataNode(o3,"HE_3")->SetVisibility(show_nodes); } { itk::StructureTensorEigenvalueImageFilter< DoubleImageType >::Pointer filter = itk::StructureTensorEigenvalueImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->SetInnerScale(m_STInnerSlider->value()); filter->SetOuterScale(m_STOuterSlider->value()); filter->Update(); mitk::Image::Pointer o1,o2,o3; mitk::CastToMitkImage(filter->GetOutput(0),o1); mitk::CastToMitkImage(filter->GetOutput(1),o2); mitk::CastToMitkImage(filter->GetOutput(2),o3); m_FeatureImageVector.push_back(o1); m_FeatureImageVector.push_back(o2); m_FeatureImageVector.push_back(o3); // AddImageAsDataNode(o1,"ST_1")->SetVisibility(show_nodes); // AddImageAsDataNode(o2,"ST_2")->SetVisibility(show_nodes); // AddImageAsDataNode(o3,"ST_3")->SetVisibility(show_nodes); } { itk::LineHistogramBasedMassImageFilter< DoubleImageType >::Pointer filter = itk::LineHistogramBasedMassImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->Update(); mitk::Image::Pointer o1; mitk::CastToMitkImage(filter->GetOutput(0),o1); m_FeatureImageVector.push_back(o1); } } void ClassificationSegmentation::OnFeatureSettingsChanged() { MITK_INFO << "FeatureSettingsChanged"; m_CalculateFeatures = true; ManualSegmentationTrigger(); } void ClassificationSegmentation::OnPostProcessingSettingsChanged() { MITK_INFO << "PostProcessingSettigsChanged"; PostProcessingTrigger(); } void ClassificationSegmentation::DoAutomSegmentation() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); mitk::Image::Pointer raw_image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls.m_MaskImageLayout->itemAt(1)->widget()); QmitkDataStorageComboBox * cb_rf = dynamic_cast(m_Controls.m_ClassifierLayout->itemAt(1)->widget()); mitk::Image::Pointer mask_image = dynamic_cast(cb_maskimage->GetSelectedNode()->GetData()); mitk::VigraRandomForestClassifier::Pointer classifier = dynamic_cast(cb_rf->GetSelectedNode()->GetData()); if(m_CalculateFeatures) { ProcessFeatureImages(raw_image,mask_image); m_CalculateFeatures = false; } Eigen::MatrixXd X_test; unsigned int count_test = 0; mitk::CLUtil::CountVoxel(mask_image, count_test); X_test = Eigen::MatrixXd(count_test, m_FeatureImageVector.size()); unsigned int index = 0; for( const auto & image : m_FeatureImageVector) { X_test.col(index) = mitk::CLUtil::Transform(image,mask_image); ++index; } Eigen::MatrixXi Y_test = classifier->Predict(X_test); mitk::Image::Pointer result_mask = mitk::CLUtil::Transform(Y_test,mask_image); auto node = AddAsDataNode(result_mask.GetPointer(),"Autom-ResultMask"); auto lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::PET_20); auto * lut_prop = dynamic_cast(node->GetProperty("LookupTable")); lut_prop->SetLookupTable(lut); mitk::LevelWindow lw(1,3); node->SetLevelWindow(lw); node->SetOpacity(0.3); std::map perlabelvoxelcount; mitk::CLUtil::CountVoxel(result_mask, perlabelvoxelcount); double voxel_volume = result_mask->GetGeometry()->GetSpacing().GetVnlVector().inf_norm(); QString newtext; newtext += "Name\tVolume\tUnit\n"; for(const auto & pair: perlabelvoxelcount) { newtext += "Label" + QString::number(pair.first) + "\t" + QString::number(pair.second*voxel_volume* 0.001) + "\tml\n"; } m_Controls.m_ResultTextEdit->setText(newtext); } std::vector ClassificationSegmentation::ManualSegmentationCallback() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls.m_MaskImageLayout->itemAt(1)->widget()); mitk::Image::Pointer raw_image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); mitk::Image::Pointer mask_image = dynamic_cast(cb_maskimage->GetSelectedNode()->GetData()); if(raw_image.IsNull() || mask_image.IsNull()) { MITK_WARN << "Please provide input iamge and mask image"; //return nullptr; } if(m_CalculateFeatures) { ProcessFeatureImages(raw_image,mask_image); m_CalculateFeatures = false; } mitk::Image::Pointer sampled_image = nullptr; int label = 1; for( auto datanode : m_PointSetList) { mitk::PointSet::Pointer point_set = dynamic_cast(datanode->GetData()); mitk::Image::Pointer temp_img; SampleClassMaskByPointSet(raw_image, point_set,temp_img); mitk::CLUtil::InsertLabel(temp_img,sampled_image,label++); } m_TempClassifier = mitk::VigraRandomForestClassifier::New(); m_TempClassifier->SetTreeCount(50); m_TempClassifier->SetSamplesPerTree(0.66); Eigen::MatrixXd X_train; Eigen::MatrixXd X_test; unsigned int count_train = 0; unsigned int count_test = 0; mitk::CLUtil::CountVoxel(sampled_image, count_train); mitk::CLUtil::CountVoxel(mask_image, count_test); X_train = Eigen::MatrixXd(count_train, m_FeatureImageVector.size() ); X_test = Eigen::MatrixXd(count_test, m_FeatureImageVector.size()); unsigned int index = 0; for( const auto & image : m_FeatureImageVector) { X_train.col(index) = mitk::CLUtil::Transform(image,sampled_image); X_test.col(index) = mitk::CLUtil::Transform(image,mask_image); ++index; } Eigen::MatrixXi Y = mitk::CLUtil::Transform(sampled_image,sampled_image); m_TempClassifier->Train(X_train,Y); Eigen::MatrixXi Y_test = m_TempClassifier->Predict(X_test); Eigen::MatrixXd Yp_test = m_TempClassifier->GetPointWiseProbabilities(); // mitk::Image::Pointer result_mask = mitk::CLUtil::Transform(Y_test,mask_image); std::vector resultvector; resultvector.push_back( mitk::CLUtil::Transform(Y_test,mask_image) ); resultvector.push_back( mitk::CLUtil::Transform(Yp_test.col(0),mask_image) ); resultvector.push_back( mitk::CLUtil::Transform(Yp_test.col(1),mask_image) ); resultvector.push_back( mitk::CLUtil::Transform(Yp_test.col(2),mask_image) ); return resultvector; } void ClassificationSegmentation::ManualSegmentationFinished() { // Receive Future result m_ResultImageVector = m_ManualSegmentationFutureWatcher.result(); // Add result to Datastorage mitk::DataNode::Pointer node = AddAsDataNode(m_ResultImageVector[0].GetPointer(),"Manual-ResultMask"); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::PET_20); mitk::LookupTableProperty * lut_prop = dynamic_cast(node->GetProperty("LookupTable")); lut_prop->SetLookupTable(lut); mitk::LevelWindow lw(1,3); node->SetLevelWindow(lw); node->SetOpacity(0.3); m_BlockManualSegmentation = false; this->PostProcessingTrigger(); // Update Volume data std::map perlabelvoxelcount; mitk::CLUtil::CountVoxel(m_ResultImageVector[0], perlabelvoxelcount); double voxel_volume = m_ResultImageVector[0]->GetGeometry()->GetSpacing().GetVnlVector().inf_norm(); QString newtext; newtext += "Name\tVolume\tUnit\n"; for(const auto & pair: perlabelvoxelcount) newtext += "Label" + QString::number(pair.first) + "\t" + QString::number(pair.second*voxel_volume* 0.001) + "\tml\n"; m_Controls.m_ResultTextEdit->setText(newtext); } void ClassificationSegmentation::ManualSegmentationTrigger() { unsigned int samplecounter = 0; for( auto datanode : m_PointSetList) { mitk::PointSet::Pointer point_set = dynamic_cast(datanode->GetData()); samplecounter += point_set->GetSize(); } if(samplecounter < 10) return; if(!m_BlockManualSegmentation){ // Start GUI Thread m_ManualSegmentationFutureWatcher.setFuture( QtConcurrent::run(this, &ClassificationSegmentation::ManualSegmentationCallback)); // on finish call OnManualSegmentationFinished(); m_BlockManualSegmentation = true; } } void ClassificationSegmentation::SampleClassMaskByPointSet(const mitk::Image::Pointer & ref_img, mitk::PointSet::Pointer & pointset, mitk::Image::Pointer & outimage) { outimage = ref_img->Clone(); itk::Image::Pointer itk_out; mitk::CastToItkImage(outimage,itk_out); itk_out->FillBuffer(0); typedef itk::ImageRegionIteratorWithIndex > IteratorType; IteratorType oit(itk_out, itk_out->GetLargestPossibleRegion()); for(int i = 0 ; i < pointset->GetSize(); ++i) { IteratorType::IndexType index; ref_img->GetGeometry()->WorldToIndex(pointset->GetPoint(i), index); oit.SetIndex(index); oit.Set(1); } mitk::CastToMitkImage(itk_out,outimage); } // old version //void ClassificationSegmentation::DoImageProcessing() //{ // QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls.m_InputImageLayout->itemAt(1)->widget()); // QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls.m_MaskImageLayout->itemAt(1)->widget()); // QmitkDataStorageComboBox * cb_classifier = dynamic_cast(m_Controls.m_RandomForestLayout->itemAt(1)->widget()); // if (cb_image == nullptr || cb_classifier == nullptr || cb_maskimage == nullptr) // { // QMessageBox::information( nullptr, "Template", "Please load and select an image before starting image processing."); // return; // } // mitk::VigraRandomForestClassifier::Pointer rf = dynamic_cast(cb_classifier->GetSelectedNode()->GetData()); // mitk::Image::Pointer image = dynamic_cast(cb_image->GetSelectedNode()->GetData()); // mitk::Image::Pointer mask = dynamic_cast(cb_maskimage->GetSelectedNode()->GetData()); // unsigned int n_samples = 0; // mitk::CLUtil::CountVoxel(mask, n_samples); // unsigned int n_features = 13; // InputImage, PROBA_CSF, PROBA_LES, PROBA_BRA, FOS_MEAN,FOS_VARIANCE,FOS_SKEWNESS, FOS_KURTOSIS, FOS_MIN, FOS_MAX, HE_1, HE_2, HE_3 // Eigen::MatrixXd feature_matrix = Eigen::MatrixXd(n_samples, n_features); // MITK_INFO << "Remove voxels outside the mask"; // // mitk::CLUtil::LogicalAndImages(image,brain_mask,image); // feature_matrix.block(0,0,n_samples,1) = mitk::CLUtil::Transform(image,mask); // AddImageAsDataNode(image, "UI_InputImage"); // mitk::Image::Pointer csf_prob = mitk::Image::New(); // mitk::CLUtil::ProbabilityMap(image,13.9, 8.3,csf_prob); // feature_matrix.block(0,1,n_samples,1) = mitk::CLUtil::Transform(csf_prob,mask); // AddImageAsDataNode(csf_prob, "UI_CSFProb"); // mitk::Image::Pointer les_prob = mitk::Image::New(); // mitk::CLUtil::ProbabilityMap(image,59, 11.6,les_prob); // feature_matrix.block(0,2,n_samples,1) = mitk::CLUtil::Transform(les_prob,mask); // AddImageAsDataNode(les_prob, "UI_LESProb"); // mitk::Image::Pointer brain_prob = mitk::Image::New(); // mitk::CLUtil::ProbabilityMap(image,32, 5.6,brain_prob); // feature_matrix.block(0,3,n_samples,1) = mitk::CLUtil::Transform(brain_prob,mask); // AddImageAsDataNode(brain_prob, "UI_BRAProb"); // int n = 0; // std::vector res; // DoFirstOrderFeatureCalculation(image, mask, 1, res); // for( const auto & img: res) // { // feature_matrix.block(0,3+(++n),n_samples,1) = mitk::CLUtil::Transform(img,mask); // std::string name; // img->GetPropertyList()->GetStringProperty("name", name); // AddImageAsDataNode(img.GetPointer(), name ); // } // res.clear(); // DoHessianEigenvaluesFeatureCalculation(image, mask, 3.0, res); // for( const auto & img: res) // { // feature_matrix.block(0,3+(++n),n_samples,1) = mitk::CLUtil::Transform(img,mask); // std::string name; // img->GetPropertyList()->GetStringProperty("name", name); // AddImageAsDataNode(img.GetPointer(), name ); // } // MITK_INFO << "Start Prediction"; // rf->Predict(feature_matrix); // MITK_INFO << "End Prediction"; // mitk::Image::Pointer result_image = mitk::CLUtil::Transform(rf->GetLabels(),mask); // mitk::Image::Pointer proba1_image = mitk::CLUtil::Transform(rf->GetPointWiseProbabilities().col(0),mask); // mitk::Image::Pointer proba2_image = mitk::CLUtil::Transform(rf->GetPointWiseProbabilities().col(1),mask); // mitk::Image::Pointer proba3_image = mitk::CLUtil::Transform(rf->GetPointWiseProbabilities().col(2),mask); // AddImageAsDataNode(result_image, "ClassificationResult"); // AddImageAsDataNode(proba1_image, "CSF_Proba_CL"); // AddImageAsDataNode(proba2_image, "LES_Proba_CL"); // AddImageAsDataNode(proba3_image, "BRA_Proba_CL"); // PostProcessing(rf,mask); //} mitk::DataNode::Pointer ClassificationSegmentation::AddAsDataNode(const mitk::BaseData::Pointer & data_, const std::string & name ) { mitk::DataNode::Pointer node = nullptr; node = this->GetDataStorage()->GetNamedNode(name); if(node.IsNull()) { node = mitk::DataNode::New(); node->SetData(data_); node->SetName(name); this->GetDataStorage()->Add(node); }else{ if(dynamic_cast(node->GetData()) && dynamic_cast(data_.GetPointer())) { mitk::Image::Pointer target_image = dynamic_cast(node->GetData()); mitk::Image::Pointer source_image = dynamic_cast(data_.GetPointer()); mitk::ImageReadAccessor ra(source_image); target_image->SetImportVolume(const_cast(ra.GetData())); this->RequestRenderWindowUpdate(); } if(dynamic_cast(node->GetData()) && dynamic_cast(data_.GetPointer())) { node->SetData(data_); node->Modified(); } } return node; } void ClassificationSegmentation::PostProcessingTrigger() { if(m_ResultImageVector.empty() || m_ResultImageVector.size() < 4) { MITK_ERROR("PostProcessingCallback") << "Result image vector not initialized!"; return; } if(!m_BlockPostProcessing){ m_PostProcessingFutureWatcher.setFuture( QtConcurrent::run(this, &ClassificationSegmentation::PostProcessingCallback)); // on finish call OnManualSegmentationFinished(); m_BlockPostProcessing = true; } } void ClassificationSegmentation::PostProcessingFinished() { // Receive Future result m_PostProcessingImageVector = m_PostProcessingFutureWatcher.result(); // Add result to Datastorage mitk::DataNode::Pointer node = AddAsDataNode(m_PostProcessingImageVector[0].GetPointer(),"Manual-ResultMask-PostProcessing"); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::PET_20); mitk::LookupTableProperty * lut_prop = dynamic_cast(node->GetProperty("LookupTable")); lut_prop->SetLookupTable(lut); mitk::LevelWindow lw(1,3); node->SetLevelWindow(lw); node->SetOpacity(0.3); m_BlockPostProcessing = false; } std::vector ClassificationSegmentation::PostProcessingCallback() { std::vector resultvector; mitk::Image::Pointer CSF_PMap = m_ResultImageVector[1]->Clone(); mitk::Image::Pointer LES_PMap = m_ResultImageVector[2]->Clone(); mitk::Image::Pointer BRA_PMap = m_ResultImageVector[3]->Clone(); mitk::Image::Pointer mask = m_ResultImageVector[0]->Clone(); - typedef itk::Image TImageType; - MITK_INFO("PostProcessingCallback") << "ProbabilityMap merg strat ..."; { mitk::Image::Pointer resultmask = mask->Clone(); mitk::CLUtil::GaussianFilter(CSF_PMap, CSF_PMap, m_GaussCSFSlider->value()); mitk::CLUtil::GaussianFilter(LES_PMap, LES_PMap, m_GaussLESSlider->value()); mitk::CLUtil::GaussianFilter(BRA_PMap, BRA_PMap, m_GaussBRASlider->value()); itk::Image::Pointer itk_csf, itk_les, itk_bra; itk::Image::Pointer itk_result; mitk::CastToItkImage(CSF_PMap, itk_csf); mitk::CastToItkImage(LES_PMap, itk_les); mitk::CastToItkImage(BRA_PMap, itk_bra); mitk::CastToItkImage(resultmask, itk_result); itk::ImageRegionIterator > it_csf(itk_csf,itk_csf->GetLargestPossibleRegion()); itk::ImageRegionIterator > it_les(itk_les,itk_les->GetLargestPossibleRegion()); itk::ImageRegionIterator > it_bra(itk_bra,itk_bra->GetLargestPossibleRegion()); itk::ImageRegionIterator > it_res(itk_result,itk_result->GetLargestPossibleRegion()); while (!it_csf.IsAtEnd()) { double csf = it_csf.Value() * m_WeightCSFSlider->value(); double les = it_les.Value() * m_WeightLESSlider->value(); double bra = it_bra.Value() * m_WeightBRASlider->value(); if(csf > les && csf > bra) it_res.Set(1); if(les > csf && les > bra) it_res.Set(2); if(bra > les && bra > csf) it_res.Set(3); ++it_csf; ++it_les; ++it_bra; ++it_res; } mitk::CastToMitkImage(itk_result, resultmask); { std::map mergeinstruction ; mergeinstruction[1] = 1; mergeinstruction[2] = 1; mergeinstruction[3] = 1; mergeinstruction[4] = 1; mergeinstruction[5] = 1; mergeinstruction[6] = 1; // {{1,1},{2,1},{3,1},{4,1},{5,1},{6,1}}; mitk::Image::Pointer brain_mask = mask->Clone(); mitk::CLUtil::MergeLabels(brain_mask, mergeinstruction); mitk::CLUtil::ClosingBinary(brain_mask,brain_mask,2,mitk::CLUtil::All); mitk::CLUtil::LogicalAndImages(resultmask, brain_mask, resultmask); } MITK_INFO("PostProcessingCallback") << "ProbabilityMap merg end!"; resultvector.push_back(resultmask); } return resultvector; // { // MITK_INFO << "Morphological processing strat ..."; // mitk::Image::Pointer resultmask = mask->Clone(); // mitk::Image::Pointer csf_mask; // mitk::CLUtil::GrabLabel(resultmask, csf_mask, 1); // mitk::CLUtil::ClosingBinary(csf_mask,csf_mask,1,mitk::CLUtil::Axial); // mitk::CLUtil::ErodeBinary(csf_mask, csf_mask, 2, mitk::CLUtil::Axial); // mitk::CLUtil::DilateBinary(csf_mask, csf_mask, 1, mitk::CLUtil::Axial); // std::map merge_instruction = {{0,0},{1,3},{2,2},{3,3}}; // mitk::CLUtil::MergeLabels(resultmask, merge_instruction); // mitk::CLUtil::InsertLabel(resultmask, csf_mask, 1/*as csf mask*/); // add morpological manipulated csf_mask // // ------------ // mitk::Image::Pointer les_mask; // mitk::CLUtil::GrabLabel(resultmask, les_mask, 2); // mitk::CLUtil::ClosingBinary(les_mask,les_mask,1,mitk::CLUtil::Axial); // mitk::Image::Pointer les_cc_mask; unsigned int num = 0; // mitk::CLUtil::ConnectedComponentsImage(les_mask, mask, les_cc_mask, num); // std::map map; // mitk::CLUtil::CountVoxel(les_cc_mask,map); // unsigned int counter = 0; // while(map.size() > 2) // { // mitk::CLUtil::ErodeBinary(les_mask, les_mask, 1, mitk::CLUtil::Axial); // mitk::CLUtil::LogicalAndImages(les_cc_mask,les_mask,les_cc_mask); // map.clear(); // mitk::CLUtil::CountVoxel(les_cc_mask,map); // MITK_INFO("PostProcessing") << map.size(); // counter++; // } // while(counter != 0) // { // mitk::CLUtil::DilateBinary(les_mask, les_mask, 1, mitk::CLUtil::Axial); // counter--; // } // merge_instruction = {{0,0},{1,1},{2,3},{3,3}}; // mitk::CLUtil::MergeLabels(resultmask, merge_instruction); // mitk::CLUtil::InsertLabel(resultmask, les_mask, 2/*as les mask*/); // MITK_INFO << "Morphological processing end"; // // ------------ // mitk::CLUtil::LogicalAndImages(resultmask,mask,resultmask); // AddImageAsDataNode(resultmask,"SmoothedMaskMorphed"); // } } // mitk::Image::Pointer r= mitk::Image::New(),g= mitk::Image::New(),b = mitk::Image::New(); // unsigned int* m_ImageDimensions; // m_ImageDimensions = new unsigned int[3]; // m_ImageDimensions[0] = raw_image->GetDimensions()[0]; // m_ImageDimensions[1] = raw_image->GetDimensions()[1]; // m_ImageDimensions[2] = 1; // r->Initialize( mitk::MakePixelType() ,3,m_ImageDimensions); // g->Initialize( mitk::MakePixelType() ,3,m_ImageDimensions); // b->Initialize( mitk::MakePixelType() ,3,m_ImageDimensions); // mitk::ImageReadAccessor inputAccForRGB(raw_image, raw_image->GetSliceData(0,0,0)); // unsigned char* rbgSlice = (unsigned char*)inputAccForRGB.GetData(); // mitk::ImageReadAccessor inputAcc(r, r->GetSliceData(0,0,0)); // unsigned char* rData = (unsigned char*)inputAcc.GetData(); // mitk::ImageReadAccessor inputAcc2(g, g->GetSliceData(0,0,0)); // unsigned char* gData = (unsigned char*)inputAcc2.GetData(); // mitk::ImageReadAccessor inputAcc3(b, b->GetSliceData(0,0,0)); // unsigned char* // bData = (unsigned char*)inputAcc3.GetData(); // for(int i = 0; i < m_ImageDimensions[0] * m_ImageDimensions[1]*3; i+=3) // { // rData[i/3] = rbgSlice[i]; // gData[i/3] = rbgSlice[i+1]; // bData[i/3] = rbgSlice[i+2]; // } // m_FeatureImageVector.push_back(r); // m_FeatureImageVector.push_back(g); // m_FeatureImageVector.push_back(b); // AddImageAsDataNode(r,"r"); // AddImageAsDataNode(g,"g"); // AddImageAsDataNode(b,"b");