diff --git a/Modules/DataTypesExt/include/mitkCompressedImageContainer.h b/Modules/DataTypesExt/include/mitkCompressedImageContainer.h index 71d5d9878e..32ead859c3 100644 --- a/Modules/DataTypesExt/include/mitkCompressedImageContainer.h +++ b/Modules/DataTypesExt/include/mitkCompressedImageContainer.h @@ -1,80 +1,80 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkCompressedImageContainer_h_Included #define mitkCompressedImageContainer_h_Included #include "MitkDataTypesExtExports.h" #include "mitkCommon.h" #include "mitkGeometry3D.h" #include "mitkImage.h" #include "mitkImageDataItem.h" #include #include namespace mitk { /** \brief Holds one (compressed) mitk::Image Uses zlib to compress the data of an mitk::Image. $Author$ */ class MITKDATATYPESEXT_EXPORT CompressedImageContainer : public itk::Object { public: mitkClassMacroItkParent(CompressedImageContainer, itk::Object); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** * \brief Creates a compressed version of the image. * * Will not hold any further SmartPointers to the image. * */ - void SetImage(Image *); + void SetImage(const Image *); /** * \brief Creates a full mitk::Image from its compressed version. * * This Method hold no buffer, so the uncompression algorithm will be * executed every time you call this method. Don't overdo it. * */ - Image::Pointer GetImage(); + Image::Pointer GetImage() const; protected: CompressedImageContainer(); // purposely hidden ~CompressedImageContainer() override; PixelType *m_PixelType; unsigned int m_ImageDimension; std::vector m_ImageDimensions; unsigned long m_OneTimeStepImageSizeInBytes; unsigned int m_NumberOfTimeSteps; /// one for each timestep. first = pointer to compressed data; second = size of buffer in bytes std::vector> m_ByteBuffers; BaseGeometry::Pointer m_ImageGeometry; }; } // namespace #endif diff --git a/Modules/DataTypesExt/src/mitkCompressedImageContainer.cpp b/Modules/DataTypesExt/src/mitkCompressedImageContainer.cpp index bfad62d7ef..7d11a9e9a9 100644 --- a/Modules/DataTypesExt/src/mitkCompressedImageContainer.cpp +++ b/Modules/DataTypesExt/src/mitkCompressedImageContainer.cpp @@ -1,178 +1,178 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkCompressedImageContainer.h" #include "mitkImageReadAccessor.h" #include "itk_zlib.h" #include mitk::CompressedImageContainer::CompressedImageContainer() : m_PixelType(nullptr), m_ImageGeometry(nullptr) { } mitk::CompressedImageContainer::~CompressedImageContainer() { for (auto iter = m_ByteBuffers.begin(); iter != m_ByteBuffers.end(); ++iter) { free(iter->first); } delete m_PixelType; } -void mitk::CompressedImageContainer::SetImage(Image *image) +void mitk::CompressedImageContainer::SetImage(const Image *image) { for (auto iter = m_ByteBuffers.begin(); iter != m_ByteBuffers.end(); ++iter) { free(iter->first); } m_ByteBuffers.clear(); // Compress diff image using zlib (will be restored on demand) // determine memory size occupied by voxel data m_ImageDimension = image->GetDimension(); m_ImageDimensions.clear(); m_PixelType = new mitk::PixelType(image->GetPixelType()); m_OneTimeStepImageSizeInBytes = m_PixelType->GetSize(); // bits per element divided by 8 for (unsigned int i = 0; i < m_ImageDimension; ++i) { unsigned int currentImageDimension = image->GetDimension(i); m_ImageDimensions.push_back(currentImageDimension); if (i < 3) { m_OneTimeStepImageSizeInBytes *= currentImageDimension; // only the 3D memory size } } m_ImageGeometry = image->GetGeometry(); m_NumberOfTimeSteps = 1; if (m_ImageDimension > 3) { m_NumberOfTimeSteps = image->GetDimension(3); } for (unsigned int timestep = 0; timestep < m_NumberOfTimeSteps; ++timestep) { // allocate a buffer as specified by zlib unsigned long bufferSize = m_OneTimeStepImageSizeInBytes + static_cast(m_OneTimeStepImageSizeInBytes * 0.2) + 12; auto *byteBuffer = (unsigned char *)malloc(bufferSize); if (itk::Object::GetDebug()) { // compress image here into a buffer MITK_INFO << "Using ZLib version: '" << zlibVersion() << "'" << std::endl << "Attempting to compress " << m_OneTimeStepImageSizeInBytes << " image bytes into a buffer of size " << bufferSize << std::endl; } ImageReadAccessor imgAcc(image, image->GetVolumeData(timestep)); ::Bytef *dest(byteBuffer); ::uLongf destLen(bufferSize); auto *source((unsigned char *)imgAcc.GetData()); ::uLongf sourceLen(m_OneTimeStepImageSizeInBytes); int zlibRetVal = ::compress(dest, &destLen, source, sourceLen); if (itk::Object::GetDebug()) { if (zlibRetVal == Z_OK) { MITK_INFO << "Success, using " << destLen << " bytes of the buffer (ratio " << ((double)destLen / (double)sourceLen) << ")" << std::endl; } else { switch (zlibRetVal) { case Z_MEM_ERROR: MITK_ERROR << "not enough memory" << std::endl; break; case Z_BUF_ERROR: MITK_ERROR << "output buffer too small" << std::endl; break; default: MITK_ERROR << "other, unspecified error" << std::endl; break; } } } // only use the neccessary amount of memory, realloc the buffer! byteBuffer = (unsigned char *)realloc(byteBuffer, destLen); bufferSize = destLen; // MITK_INFO << "Using " << bufferSize << " bytes to store compressed image (" << destLen << " needed)" << // std::endl; m_ByteBuffers.push_back(std::pair(byteBuffer, bufferSize)); } } -mitk::Image::Pointer mitk::CompressedImageContainer::GetImage() +mitk::Image::Pointer mitk::CompressedImageContainer::GetImage() const { if (m_ByteBuffers.empty()) return nullptr; // uncompress image data, create an Image Image::Pointer image = Image::New(); unsigned int dims[20]; // more than 20 dimensions and bang for (unsigned int dim = 0; dim < m_ImageDimension; ++dim) dims[dim] = m_ImageDimensions[dim]; image->Initialize(*m_PixelType, m_ImageDimension, dims); // this IS needed, right ?? But it does allocate memory -> // does create one big lump of memory (also in windows) unsigned int timeStep(0); for (auto iter = m_ByteBuffers.begin(); iter != m_ByteBuffers.end(); ++iter, ++timeStep) { ImageReadAccessor imgAcc(image, image->GetVolumeData(timeStep)); auto *dest((unsigned char *)imgAcc.GetData()); ::uLongf destLen(m_OneTimeStepImageSizeInBytes); ::Bytef *source(iter->first); ::uLongf sourceLen(iter->second); int zlibRetVal = ::uncompress(dest, &destLen, source, sourceLen); if (itk::Object::GetDebug()) { if (zlibRetVal == Z_OK) { MITK_INFO << "Success, destLen now " << destLen << " bytes" << std::endl; } else { switch (zlibRetVal) { case Z_DATA_ERROR: MITK_ERROR << "compressed data corrupted" << std::endl; break; case Z_MEM_ERROR: MITK_ERROR << "not enough memory" << std::endl; break; case Z_BUF_ERROR: MITK_ERROR << "output buffer too small" << std::endl; break; default: MITK_ERROR << "other, unspecified error" << std::endl; break; } } } } image->SetGeometry(m_ImageGeometry); image->Modified(); return image; } diff --git a/Modules/Segmentation/Algorithms/mitkDiffSliceOperation.cpp b/Modules/Segmentation/Algorithms/mitkDiffSliceOperation.cpp index d5745cc828..c7fbf75857 100644 --- a/Modules/Segmentation/Algorithms/mitkDiffSliceOperation.cpp +++ b/Modules/Segmentation/Algorithms/mitkDiffSliceOperation.cpp @@ -1,100 +1,100 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkDiffSliceOperation.h" #include #include mitk::DiffSliceOperation::DiffSliceOperation() : Operation(1) { m_TimeStep = 0; m_zlibSliceContainer = nullptr; m_Image = nullptr; m_WorldGeometry = nullptr; m_SliceGeometry = nullptr; m_ImageIsValid = false; m_DeleteObserverTag = 0; } -mitk::DiffSliceOperation::DiffSliceOperation(mitk::Image *imageVolume, - Image *slice, - SlicedGeometry3D *sliceGeometry, +mitk::DiffSliceOperation::DiffSliceOperation(Image *imageVolume, + const Image *slice, + const SlicedGeometry3D *sliceGeometry, TimeStepType timestep, - BaseGeometry *currentWorldGeometry) + const BaseGeometry *currentWorldGeometry) : Operation(1) { m_WorldGeometry = currentWorldGeometry->Clone(); /* Quick fix for bug 12338. Guard object - fix this when clone method of PlaneGeometry is cloning the reference geometry (see bug 13392)*/ // xxxx m_GuardReferenceGeometry = mitk::BaseGeometry::New(); - m_GuardReferenceGeometry = dynamic_cast(m_WorldGeometry.GetPointer())->GetReferenceGeometry(); + m_GuardReferenceGeometry = dynamic_cast(m_WorldGeometry.GetPointer())->GetReferenceGeometry(); /*---------------------------------------------------------------------------------------------------*/ m_SliceGeometry = sliceGeometry->Clone(); m_TimeStep = timestep; m_zlibSliceContainer = CompressedImageContainer::New(); m_zlibSliceContainer->SetImage(slice); m_Image = imageVolume; m_DeleteObserverTag = 0; if (m_Image) { /*add an observer to listen to the delete event of the image, this is necessary because the operation is then * invalid*/ itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &DiffSliceOperation::OnImageDeleted); // get the id of the observer, used to remove it later on m_DeleteObserverTag = imageVolume->AddObserver(itk::DeleteEvent(), command); m_ImageIsValid = true; } else m_ImageIsValid = false; } mitk::DiffSliceOperation::~DiffSliceOperation() { m_WorldGeometry = nullptr; m_zlibSliceContainer = nullptr; if (m_ImageIsValid) { // if the image is still there, we have to remove the observer from it m_Image->RemoveObserver(m_DeleteObserverTag); } m_Image = nullptr; } mitk::Image::Pointer mitk::DiffSliceOperation::GetSlice() { Image::Pointer image = m_zlibSliceContainer->GetImage(); return image; } bool mitk::DiffSliceOperation::IsValid() { return m_ImageIsValid && m_zlibSliceContainer.IsNotNull() && (m_WorldGeometry.IsNotNull()); // TODO improve } void mitk::DiffSliceOperation::OnImageDeleted() { // if our imageVolume is removed e.g. from the datastorage the operation is no lnger valid m_ImageIsValid = false; } diff --git a/Modules/Segmentation/Algorithms/mitkDiffSliceOperation.h b/Modules/Segmentation/Algorithms/mitkDiffSliceOperation.h index 0ce05557ba..9647976b40 100644 --- a/Modules/Segmentation/Algorithms/mitkDiffSliceOperation.h +++ b/Modules/Segmentation/Algorithms/mitkDiffSliceOperation.h @@ -1,109 +1,101 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkDiffSliceOperation_h_Included #define mitkDiffSliceOperation_h_Included #include "mitkCompressedImageContainer.h" #include #include #include namespace mitk { class Image; /** \brief An Operation for applying an edited slice to the volume. \sa DiffSliceOperationApplier The information for the operation is specified by properties: imageVolume the volume where the slice was extracted from. slice the slice to be applied. timestep the timestep in an 4D image. currentWorldGeometry specifies the axis where the slice has to be applied in the volume. This Operation can be used to realize undo-redo functionality for e.g. segmentation purposes. */ class MITKSEGMENTATION_EXPORT DiffSliceOperation : public Operation { public: mitkClassMacro(DiffSliceOperation, OperationActor); // itkFactorylessNewMacro(Self) // itkCloneMacro(Self) // mitkNewMacro4Param(DiffSliceOperation,mitk::Image,mitk::Image,unsigned int, mitk::PlaneGeometry); /** \brief Creates an empty instance. Note that it is not valid yet. The properties of the object have to be set. */ DiffSliceOperation(); /** \brief */ DiffSliceOperation(mitk::Image *imageVolume, - mitk::Image *slice, - SlicedGeometry3D *sliceGeometry, - TimeStepType timestep, - BaseGeometry *currentWorldGeometry); + const mitk::Image *slice, + const SlicedGeometry3D *sliceGeometry, + const TimeStepType timestep, + const BaseGeometry *currentWorldGeometry); /** \brief Check if it is a valid operation.*/ bool IsValid(); - /** \brief Set the image volume.*/ - void SetImage(mitk::Image *image) { this->m_Image = image; } /** \brief Get th image volume.*/ mitk::Image *GetImage() { return this->m_Image; } - /** \brief Set thee slice to be applied.*/ - void SetImage(vtkImageData *slice) { this->m_Slice = slice; } + const mitk::Image* GetImage() const { return this->m_Image; } + /** \brief Get the slice that is applied in the operation.*/ Image::Pointer GetSlice(); - /** \brief Get timeStep.*/ - void SetTimeStep(TimeStepType timestep) { this->m_TimeStep = timestep; } /** \brief Set timeStep*/ - TimeStepType GetTimeStep() { return this->m_TimeStep; } - /** \brief Set the axis where the slice has to be applied in the volume.*/ - void SetSliceGeometry(SlicedGeometry3D *sliceGeometry) { this->m_SliceGeometry = sliceGeometry; } + TimeStepType GetTimeStep() const { return this->m_TimeStep; } /** \brief Get the axis where the slice has to be applied in the volume.*/ - SlicedGeometry3D *GetSliceGeometry() { return this->m_SliceGeometry; } - /** \brief Set the axis where the slice has to be applied in the volume.*/ - void SetCurrentWorldGeometry(BaseGeometry *worldGeometry) { this->m_WorldGeometry = worldGeometry; } + const SlicedGeometry3D *GetSliceGeometry() const { return this->m_SliceGeometry; } /** \brief Get the axis where the slice has to be applied in the volume.*/ - BaseGeometry *GetWorldGeometry() { return this->m_WorldGeometry; } + const BaseGeometry *GetWorldGeometry() const { return this->m_WorldGeometry; } protected: ~DiffSliceOperation() override; /** \brief Callback for image observer.*/ void OnImageDeleted(); CompressedImageContainer::Pointer m_zlibSliceContainer; mitk::Image *m_Image; vtkSmartPointer m_Slice; - SlicedGeometry3D::Pointer m_SliceGeometry; + SlicedGeometry3D::ConstPointer m_SliceGeometry; TimeStepType m_TimeStep; - BaseGeometry::Pointer m_WorldGeometry; + BaseGeometry::ConstPointer m_WorldGeometry; bool m_ImageIsValid; unsigned long m_DeleteObserverTag; mitk::BaseGeometry::ConstPointer m_GuardReferenceGeometry; }; } #endif diff --git a/Modules/Segmentation/Algorithms/mitkDiffSliceOperationApplier.cpp b/Modules/Segmentation/Algorithms/mitkDiffSliceOperationApplier.cpp index b34a65bc09..6c666c1b36 100644 --- a/Modules/Segmentation/Algorithms/mitkDiffSliceOperationApplier.cpp +++ b/Modules/Segmentation/Algorithms/mitkDiffSliceOperationApplier.cpp @@ -1,89 +1,89 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkDiffSliceOperationApplier.h" #include "mitkDiffSliceOperation.h" #include "mitkRenderingManager.h" #include "mitkSegTool2D.h" #include #include // VTK #include mitk::DiffSliceOperationApplier::DiffSliceOperationApplier() { } mitk::DiffSliceOperationApplier::~DiffSliceOperationApplier() { } void mitk::DiffSliceOperationApplier::ExecuteOperation(Operation *operation) { auto *imageOperation = dynamic_cast(operation); // as we only support DiffSliceOperation return if operation is not type of DiffSliceOperation if (!imageOperation) return; // chak if the operation is valid if (imageOperation->IsValid()) { // the actual overwrite filter (vtk) vtkSmartPointer reslice = vtkSmartPointer::New(); mitk::Image::Pointer slice = imageOperation->GetSlice(); // Set the slice as 'input' reslice->SetInputSlice(slice->GetVtkImageData()); // set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); // a wrapper for vtkImageOverwrite mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput(imageOperation->GetImage()); extractor->SetTimeStep(imageOperation->GetTimeStep()); - extractor->SetWorldGeometry(dynamic_cast(imageOperation->GetWorldGeometry())); + extractor->SetWorldGeometry(dynamic_cast(imageOperation->GetWorldGeometry())); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry(imageOperation->GetImage()->GetGeometry(imageOperation->GetTimeStep())); extractor->Modified(); extractor->Update(); // make sure the modification is rendered RenderingManager::GetInstance()->RequestUpdateAll(); imageOperation->GetImage()->Modified(); mitk::ExtractSliceFilter::Pointer extractor2 = mitk::ExtractSliceFilter::New(); extractor2->SetInput(imageOperation->GetImage()); extractor2->SetTimeStep(imageOperation->GetTimeStep()); - extractor2->SetWorldGeometry(dynamic_cast(imageOperation->GetWorldGeometry())); + extractor2->SetWorldGeometry(dynamic_cast(imageOperation->GetWorldGeometry())); extractor2->SetResliceTransformByGeometry(imageOperation->GetImage()->GetGeometry(imageOperation->GetTimeStep())); extractor2->Modified(); extractor2->Update(); // TODO Move this code to SurfaceInterpolationController! mitk::Image::Pointer slice2 = extractor2->GetOutput(); - mitk::PlaneGeometry::Pointer plane = dynamic_cast(imageOperation->GetWorldGeometry()); + mitk::PlaneGeometry::ConstPointer plane = dynamic_cast(imageOperation->GetWorldGeometry()); slice2->DisconnectPipeline(); mitk::SegTool2D::UpdateSurfaceInterpolation(slice2, imageOperation->GetImage(), plane, true); } } mitk::DiffSliceOperationApplier *mitk::DiffSliceOperationApplier::GetInstance() { static auto *s_Instance = new DiffSliceOperationApplier(); return s_Instance; }