diff --git a/Core/Code/DataManagement/mitkImagePixelReadAccessor.h b/Core/Code/DataManagement/mitkImagePixelReadAccessor.h index 5e83cb7e43..252131513b 100644 --- a/Core/Code/DataManagement/mitkImagePixelReadAccessor.h +++ b/Core/Code/DataManagement/mitkImagePixelReadAccessor.h @@ -1,168 +1,171 @@ /*=================================================================== 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 MITKIMAGEPIXELREADACCESSOR_H #define MITKIMAGEPIXELREADACCESSOR_H #include #include #include #include #include "mitkImageDataItem.h" #include "mitkPixelType.h" #include "mitkImage.h" #include "mitkImageReadAccessor.h" #include "mitkImagePixelAccessor.h" namespace mitk { class Image; typedef itk::SmartPointer ImagePointer; //##Documentation //## @brief Gives locked and index-based read access for a particular image part. //## The class provides several set- and get-methods, which allow an easy pixel access. //## It needs to know about pixel type and dimension of its image at compile time. //## @tparam TPixel defines the PixelType //## @tparam VDimension defines the dimension for accessing data //## @ingroup Data template class ImagePixelReadAccessor : public ImagePixelAccessor { friend class Image; public: typedef ImagePixelAccessor ImagePixelAccessorType; /** \brief Instantiates a mitk::ImageReadAccessor (see its doxygen page for more details) * \param Image::Pointer specifies the associated Image * \param ImageDataItem* specifies the allocated image part * \param OptionFlags properties from mitk::ImageAccessorBase::Options can be chosen and assembled with bitwise unification. * \throws mitk::Exception if the Constructor was created inappropriately * \throws mitk::MemoryIsLockedException if requested image area is exclusively locked and mitk::ImageAccessorBase::ExceptionIfLocked is set in OptionFlags * * Includes a check if typeid of PixelType coincides with templated TPixel * and a check if VDimension equals to the Dimension of the Image.*/ ImagePixelReadAccessor( ImagePointer iP, ImageDataItem* iDI = NULL, int OptionFlags = ImageAccessorBase::DefaultBehavior ) : ImagePixelAccessor(iP,iDI), m_ReadAccessor(iP, iDI, OptionFlags) { // Check if Dimensions are correct if(ImagePixelAccessor::m_ImageDataItem == NULL) { if(m_ReadAccessor.m_Image->GetDimension() != VDimension) mitkThrow() << "Invalid ImageAccessor: The Dimensions of ImageAccessor and Image are not equal. They have to be equal if an entire image is requested"; } else { if(ImagePixelAccessor::m_ImageDataItem->GetDimension() != VDimension) mitkThrow() << "Invalid ImageAccessor: The Dimensions of ImageAccessor and ImageDataItem are not equal."; } // Check if PixelType is correct if(!(m_ReadAccessor.m_Image->GetPixelType() == mitk::MakePixelType< itk::Image >()) ) { mitkThrow() << "Invalid ImageAccessor: PixelTypes of Image and ImageAccessor are not equal"; } } /** Destructor informs Image to unlock memory. */ virtual ~ImagePixelReadAccessor() { } /** Returns a const reference to the pixel at given index. */ const TPixel & GetPixelByIndex(const itk::Index& idx) const { unsigned int offset = ImagePixelAccessorType::GetOffset(idx); return *(((TPixel*)m_ReadAccessor.m_AddressBegin) + offset); } /** Extends GetPixel by integrating index validation to prevent overflow. * \throws mitk::Exception in case of overflow */ const TPixel & GetPixelByIndexSafe(const itk::Index& idx) const { unsigned int offset = ImagePixelAccessorType::GetOffset(idx); TPixel* targetAddress = ((TPixel*)m_ReadAccessor.m_AddressBegin) + offset; if(!(targetAddress >= m_ReadAccessor.m_AddressBegin && targetAddress < m_ReadAccessor.m_AddressEnd)) { mitkThrow() << "ImageAccessor Overflow: image access exceeds the requested image area at " << idx << "."; } return *targetAddress; } /** Returns a const reference to the pixel at given world coordinate - works only with three-dimensional ImageAccessor */ const TPixel & GetPixelByWorldCoordinates(mitk::Point3D position) { Index3D itkIndex; m_ReadAccessor.m_Image->GetGeometry()->WorldToIndex(position, itkIndex); return GetPixelByIndex( itkIndex); } /** Returns a const reference to the pixel at given world coordinate - works only with four-dimensional ImageAccessor */ const TPixel & GetPixelByWorldCoordinates(mitk::Point3D position, unsigned int timestep) { Index3D itkIndex; m_ReadAccessor.m_Image->GetGeometry()->WorldToIndex(position, itkIndex); if (m_ReadAccessor.m_Image->GetTimeSteps() < timestep) { timestep = m_ReadAccessor.m_Image->GetTimeSteps(); } itk::Index<4> itk4Index; for(int i=0; i<3; ++i) itk4Index[i] = itkIndex[i]; itk4Index[3] = timestep; return GetPixelByIndex( itk4Index ); } /** \brief Gives const access to the data. */ virtual inline const TPixel * GetConstData() { return (TPixel*) m_ReadAccessor.m_AddressBegin; } protected: // protected members private: ImageReadAccessor m_ReadAccessor; + ImagePixelReadAccessor& operator=(const ImagePixelReadAccessor&); // Not implemented on purpose. + ImagePixelReadAccessor(const ImagePixelReadAccessor&); + }; } #endif // MITKIMAGEPIXELREADACCESSOR_H diff --git a/Core/Code/DataManagement/mitkImagePixelWriteAccessor.h b/Core/Code/DataManagement/mitkImagePixelWriteAccessor.h index 887eeba1a3..ccc2c58002 100644 --- a/Core/Code/DataManagement/mitkImagePixelWriteAccessor.h +++ b/Core/Code/DataManagement/mitkImagePixelWriteAccessor.h @@ -1,168 +1,171 @@ /*=================================================================== 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 MITKIMAGEPIXELWRITEACCESSOR_H #define MITKIMAGEPIXELWRITEACCESSOR_H #include "mitkImagePixelAccessor.h" #include "mitkImageWriteAccessor.h" namespace mitk { //##Documentation //## @brief Gives locked and index-based write access for a particular image part. //## The class provides several set- and get-methods, which allow an easy pixel access. //## It needs to know about pixel type and dimension of its image at compile time. //## @tparam TPixel defines the PixelType //## @tparam VDimension defines the dimension for accessing data //## @ingroup Data template class ImagePixelWriteAccessor : public ImagePixelAccessor { friend class Image; public: typedef ImagePixelAccessor ImagePixelAccessorType; /** \brief Instantiates a mitk::ImageWriteAccessor (see its doxygen page for more details) * \param Image::Pointer specifies the associated Image * \param ImageDataItem* specifies the allocated image part * \param OptionFlags properties from mitk::ImageAccessorBase::Options can be chosen and assembled with bitwise unification. * \throws mitk::Exception if the Constructor was created inappropriately * \throws mitk::MemoryIsLockedException if requested image area is exclusively locked and mitk::ImageAccessorBase::ExceptionIfLocked is set in OptionFlags * * Includes a check if typeid of PixelType coincides with templated TPixel * and a check if VDimension equals to the Dimension of the Image.*/ ImagePixelWriteAccessor( ImagePointer iP, ImageDataItem* iDI = NULL, int OptionFlags = ImageAccessorBase::DefaultBehavior ) : ImagePixelAccessor(iP,iDI), m_WriteAccessor(iP , iDI, OptionFlags) { // Check if Dimensions are correct if(ImagePixelAccessor::m_ImageDataItem == NULL) { if(m_WriteAccessor.m_Image->GetDimension() != VDimension) mitkThrow() << "Invalid ImageAccessor: The Dimensions of ImageAccessor and Image are not equal. They have to be equal if an entire image is requested"; } else { if(ImagePixelAccessor::m_ImageDataItem->GetDimension() != VDimension) mitkThrow() << "Invalid ImageAccessor: The Dimensions of ImageAccessor and ImageDataItem are not equal."; } // Check if PixelType is correct if(!(m_WriteAccessor.m_Image->GetPixelType() == mitk::MakePixelType< itk::Image >()) ) { mitkThrow() << "Invalid ImageAccessor: PixelTypes of Image and ImageAccessor are not equal"; } } /** \brief Gives full data access. */ virtual inline TPixel * GetData() { return (TPixel*) m_WriteAccessor.m_AddressBegin; } /// Sets a pixel value at given index. void SetPixelByIndex(const itk::Index& idx, const TPixel & value) { unsigned int offset = ImagePixelAccessor::GetOffset(idx); *(((TPixel*)m_WriteAccessor.m_AddressBegin) + offset) = value; } /** Extends SetPixel by integrating index validation to prevent overflow. */ void SetPixelByIndexSafe(const itk::Index& idx, const TPixel & value) { unsigned int offset = ImagePixelAccessorType::GetOffset(idx); TPixel* targetAddress = ((TPixel*)m_WriteAccessor.m_AddressBegin) + offset; if(targetAddress >= m_WriteAccessor.m_AddressBegin && targetAddress < m_WriteAccessor.m_AddressEnd) { *targetAddress = value; } else { //printf("image dimensions = %d, %d, %d\n", imageDims[0], imageDims[1], imageDims[2]); //printf("m_AddressBegin: %p, m_AddressEnd: %p, offset: %u\n", m_WriteAccessor.m_AddressBegin, m_WriteAccessor.m_AddressEnd, offset); mitkThrow() << "ImageAccessor Overflow: image access exceeds the requested image area at " << idx << "."; } } /** Returns a const reference to the pixel at given index. */ const TPixel & GetPixelByIndex(const itk::Index& idx) const { unsigned int offset = ImagePixelAccessorType::GetOffset(idx); return *(((TPixel*)m_WriteAccessor.m_AddressBegin) + offset); } /** Extends GetPixel by integrating index validation to prevent overflow. * \throws mitk::Exception in case of overflow */ const TPixel & GetPixelByIndexSafe(const itk::Index& idx) const { unsigned int offset = ImagePixelAccessorType::GetOffset(idx); TPixel* targetAddress = ((TPixel*)m_WriteAccessor.m_AddressBegin) + offset; if(!(targetAddress >= m_WriteAccessor.m_AddressBegin && targetAddress < m_WriteAccessor.m_AddressEnd)) { mitkThrow() << "ImageAccessor Overflow: image access exceeds the requested image area at " << idx << "."; } return *targetAddress; } /** Returns a const reference to the pixel at given world coordinate - works only with three-dimensional ImageAccessor */ const TPixel & GetPixelByWorldCoordinates(mitk::Point3D position) { Index3D itkIndex; m_WriteAccessor.m_Image->GetGeometry()->WorldToIndex(position, itkIndex); return GetPixelByIndex( itkIndex); } /** Returns a reference to the pixel at given world coordinate */ void SetPixelByWorldCoordinates(const mitk::Point3D&, const TPixel & value, unsigned int timestep = 0); virtual ~ImagePixelWriteAccessor() { } private: ImageWriteAccessor m_WriteAccessor; + ImagePixelWriteAccessor& operator=(const ImagePixelWriteAccessor&); // Not implemented on purpose. + ImagePixelWriteAccessor(const ImagePixelWriteAccessor &); + }; } #endif // MITKIMAGEWRITEACCESSOR_H diff --git a/Core/Code/DataManagement/mitkImageReadAccessor.h b/Core/Code/DataManagement/mitkImageReadAccessor.h index 44f6079f08..2aafe90371 100644 --- a/Core/Code/DataManagement/mitkImageReadAccessor.h +++ b/Core/Code/DataManagement/mitkImageReadAccessor.h @@ -1,165 +1,168 @@ /*=================================================================== 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 MITKIMAGEREADACCESSOR_H #define MITKIMAGEREADACCESSOR_H #include #include #include #include #include "mitkImageAccessorBase.h" #include "mitkImageDataItem.h" #include "mitkPixelType.h" #include "mitkImage.h" namespace mitk { class Image; typedef itk::SmartPointer ImagePointer; //##Documentation //## @brief ImageReadAccessor class to get locked read access for a particular image part //## @ingroup Data class ImageReadAccessor : public ImageAccessorBase { friend class Image; public: /** \brief Orders read access for a slice, volume or 4D-Image * \param Image::Pointer specifies the associated Image * \param ImageDataItem* specifies the allocated image part * \param OptionFlags properties from mitk::ImageAccessorBase::Options can be chosen and assembled with bitwise unification. * \throws mitk::Exception if the Constructor was created inappropriately * \throws mitk::MemoryIsLockedException if requested image area is exclusively locked and mitk::ImageAccessorBase::ExceptionIfLocked is set in OptionFlags */ ImageReadAccessor( ImagePointer iP, ImageDataItem* iDI = NULL, int OptionFlags = ImageAccessorBase::DefaultBehavior ) : ImageAccessorBase(iP,iDI,OptionFlags) { if(!(OptionFlags & ImageAccessorBase::IgnoreLock)) { OrganizeReadAccess(); } } /** \brief Gives const access to the data. */ inline const void * GetData() { return m_AddressBegin; } /** Destructor informs Image to unlock memory. */ virtual ~ImageReadAccessor() { if(!(m_Options & ImageAccessorBase::IgnoreLock)) { // Future work: In case of non-coherent memory, copied area needs to be deleted m_Image->m_ReadWriteLock.Lock(); // delete self from list of ImageReadAccessors in Image std::vector::iterator it = std::find(m_Image->m_Readers.begin(),m_Image->m_Readers.end(),this); m_Image->m_Readers.erase(it); // delete lock, if there are no waiting ImageAccessors if(m_WaitLock->m_WaiterCount <= 0) { m_WaitLock->m_Mutex.Unlock(); delete m_WaitLock; } else { m_WaitLock->m_Mutex.Unlock(); } m_Image->m_ReadWriteLock.Unlock(); } } protected: // protected members private: /** \brief manages a consistent read access and locks the ordered image part */ void OrganizeReadAccess() { m_Image->m_ReadWriteLock.Lock(); // Check, if there is any Write-Access going on if(m_Image->m_Writers.size() > 0) { // Check for every WriteAccessors, if the Region of this ImageAccessors overlaps // make sure this iterator is not used, when m_ReadWriteLock is Unlocked! std::vector::iterator it = m_Image->m_Writers.begin(); for(; it!=m_Image->m_Writers.end(); ++it) { ImageAccessorBase* w = *it; if( Overlap(w) ) { // An Overlap was detected. There are two possibilities to deal with this situation: // Throw an exception or wait for the WriteAccessor w until it is released and start again with the request afterwards. if(!(m_Options & ExceptionIfLocked)) { PreventRecursiveMutexLock(w); // WAIT w->Increment(); m_Image->m_ReadWriteLock.Unlock(); ImageAccessorBase::WaitForReleaseOf(w->m_WaitLock); //after waiting for the WriteAccessor w, start this method again OrganizeReadAccess(); return; } else { // THROW EXCEPTION m_Image->m_ReadWriteLock.Unlock(); mitkThrowException(mitk::MemoryIsLockedException) << "The image part being ordered by the ImageAccessor is already in use and locked"; return; } } // if } // for } // if // Now, we know, that there is no conflict with a Write-Access // Lock the Mutex in ImageAccessorBase, to make sure that every other ImageAccessor has to wait if it locks the mutex m_WaitLock->m_Mutex.Lock(); // insert self into readers list in Image m_Image->m_Readers.push_back(this); //printf("ReadAccess %d %d\n",(int) m_Image->m_Readers.size(),(int) m_Image->m_Writers.size()); //fflush(0); m_Image->m_ReadWriteLock.Unlock(); } + ImageReadAccessor& operator=(const ImageReadAccessor&); // Not implemented on purpose. + ImageReadAccessor(const ImageReadAccessor&); + }; } #endif // MITKIMAGEACCESSOR_H diff --git a/Core/Code/DataManagement/mitkImageWriteAccessor.h b/Core/Code/DataManagement/mitkImageWriteAccessor.h index 4b24a63f70..80c9ecf534 100644 --- a/Core/Code/DataManagement/mitkImageWriteAccessor.h +++ b/Core/Code/DataManagement/mitkImageWriteAccessor.h @@ -1,186 +1,189 @@ /*=================================================================== 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 MITKIMAGEWRITEACCESSOR_H #define MITKIMAGEWRITEACCESSOR_H #include "mitkImageAccessorBase.h" #include "mitkImage.h" namespace mitk { //##Documentation //## @brief ImageWriteAccessor class to get locked write-access for a particular image part. //## @ingroup Data class ImageWriteAccessor : public ImageAccessorBase { public: /** \brief Orders write access for a slice, volume or 4D-Image * \param Image::Pointer specifies the associated Image * \param ImageDataItem* specifies the allocated image part * \param OptionFlags properties from mitk::ImageAccessorBase::Options can be chosen and assembled with bitwise unification. * \throws mitk::Exception if the Constructor was created inappropriately * \throws mitk::MemoryIsLockedException if requested image area is exclusively locked and mitk::ImageAccessorBase::ExceptionIfLocked is set in OptionFlags */ ImageWriteAccessor( ImagePointer iP, ImageDataItem* iDI = NULL, int OptionFlags = ImageAccessorBase::DefaultBehavior ) : ImageAccessorBase(iP , iDI, OptionFlags) { OrganizeWriteAccess(); } /** \brief Gives full data access. */ virtual inline void * GetData() { return m_AddressBegin; } /** \brief informs Image to unlock the represented image part */ virtual ~ImageWriteAccessor() { // In case of non-coherent memory, copied area needs to be written back // TODO m_Image->m_ReadWriteLock.Lock(); // delete self from list of ImageReadAccessors in Image std::vector::iterator it = std::find(m_Image->m_Writers.begin(),m_Image->m_Writers.end(),this); m_Image->m_Writers.erase(it); // delete lock, if there are no waiting ImageAccessors if(m_WaitLock->m_WaiterCount <= 0) { m_WaitLock->m_Mutex.Unlock(); delete m_WaitLock; } else { m_WaitLock->m_Mutex.Unlock(); } m_Image->m_ReadWriteLock.Unlock(); } private: /** \brief manages a consistent write access and locks the ordered image part */ void OrganizeWriteAccess() { m_Image->m_ReadWriteLock.Lock(); bool readOverlap = false; bool writeOverlap = false; ImageAccessorWaitLock* overlapLock = 0; // Check, if there is any Read-Access going on if(m_Image->m_Readers.size() > 0) { // Check for every ReadAccessor, if the Region of this ImageAccessors overlaps // make sure this iterator is not used, when m_ReadWriteLock is Unlocked! std::vector::iterator it = m_Image->m_Readers.begin(); for(; it!=m_Image->m_Readers.end(); ++it) { ImageAccessorBase* r = *it; if(Overlap(r)) { // An Overlap was detected. PreventRecursiveMutexLock(r); readOverlap = true; overlapLock = r->m_WaitLock; break; } // if } // for } // if // Check, if there is any Write-Access going on if(m_Image->m_Writers.size() > 0) { // Check for every WriteAccessor, if the Region of this ImageAccessors overlaps // make sure this iterator is not used, when m_ReadWriteLock is Unlocked! std::vector::iterator it = m_Image->m_Writers.begin(); for(; it!=m_Image->m_Writers.end(); ++it) { ImageAccessorBase* w = *it; if(Overlap(w)) { // An Overlap was detected. PreventRecursiveMutexLock(w); // save overlapping Waitlock writeOverlap = true; overlapLock = w->m_WaitLock; break; } // if } // for } // if if(readOverlap || writeOverlap) { // Throw an exception or wait for the WriteAccessor w until it is released and start again with the request afterwards. if(!(m_Options & ExceptionIfLocked)) { // WAIT overlapLock->m_WaiterCount += 1; m_Image->m_ReadWriteLock.Unlock(); ImageAccessorBase::WaitForReleaseOf(overlapLock); //after waiting for the ImageAccessor, start this method again OrganizeWriteAccess(); return; } else { // THROW EXCEPTION m_Image->m_ReadWriteLock.Unlock(); mitkThrowException(mitk::MemoryIsLockedException) << "The image part being ordered by the ImageAccessor is already in use and locked"; //MITK_ERROR("Speicherbereich belegt"); return; } } // Now, we know, that there is no conflict with a Read- or Write-Access // Lock the Mutex in ImageAccessorBase, to make sure that every other ImageAccessor has to wait m_WaitLock->m_Mutex.Lock(); // insert self into Writers list in Image m_Image->m_Writers.push_back(this); //printf("WriteAccess %d %d\n",(int) m_Image->m_Readers.size(),(int) m_Image->m_Writers.size()); //fflush(0); m_Image->m_ReadWriteLock.Unlock(); } + ImageWriteAccessor& operator=(const ImageWriteAccessor&); // Not implemented on purpose. + ImageWriteAccessor(const ImageWriteAccessor&); + }; } #endif // MITKIMAGEWRITEACCESSOR_H