diff --git a/Core/Code/DataManagement/mitkImagePixelReadAccessor.h b/Core/Code/DataManagement/mitkImagePixelReadAccessor.h index 6b44abd154..43cf6ed8b3 100644 --- a/Core/Code/DataManagement/mitkImagePixelReadAccessor.h +++ b/Core/Code/DataManagement/mitkImagePixelReadAccessor.h @@ -1,166 +1,166 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #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: /** \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 >()) ) + 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 IndexType & idx) const { - unsigned int offset = PixelAccessorType::GetOffset(idx); + 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 IndexType& idx) const { - unsigned int offset = PixelAccessorType::GetOffset(idx); + 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; }; } #endif // MITKIMAGEPIXELREADACCESSOR_H diff --git a/Core/Code/Testing/mitkImageAccessorTest.cpp b/Core/Code/Testing/mitkImageAccessorTest.cpp index 2e1ad2bab6..a4dc90dd6c 100644 --- a/Core/Code/Testing/mitkImageAccessorTest.cpp +++ b/Core/Code/Testing/mitkImageAccessorTest.cpp @@ -1,190 +1,244 @@ /*=================================================================== 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 "mitkImage.h" #include "mitkImageReadAccessor.h" +#include "mitkImagePixelReadAccessor.h" +#include "mitkImagePixelWriteAccessor.h" #include "mitkImageWriteAccessor.h" #include "mitkDataNodeFactory.h" #include "mitkImageTimeSelector.h" #include #include "itkBarrier.h" #include #include #include #include +#include struct ThreadData - { - itk::Barrier::Pointer m_Barrier; // holds a pointer to the used barrier - mitk::Image::Pointer data; // some random data - int m_NoOfThreads; // holds the number of generated threads - }; +{ + itk::Barrier::Pointer m_Barrier; // holds a pointer to the used barrier + mitk::Image::Pointer data; // some random data + int m_NoOfThreads; // holds the number of generated threads + bool m_Successful; // to check if everything worked +}; ITK_THREAD_RETURN_TYPE ThreadMethod(void* data) { - /* extract data pointer from Thread Info structure */ - struct itk::MultiThreader::ThreadInfoStruct * pInfo = - (struct itk::MultiThreader::ThreadInfoStruct*)data; - - // some data validity checking - if (pInfo == NULL) - { - return ITK_THREAD_RETURN_VALUE; - } - if (pInfo->UserData == NULL) - { - return ITK_THREAD_RETURN_VALUE; - } - - // obtain user data for processing - ThreadData* threadData = (ThreadData*) pInfo->UserData; - - srand( pInfo->ThreadID ); - - mitk::Image::Pointer im = threadData->data; - - //int xlength = im->GetDimension(0); - //int ylength = im->GetDimension(1); - int nrSlices = im->GetDimension(2); - - // Create randomly a PixelRead- or PixelWriteAccessor for a slice and access all pixels in it. - { - if(rand() % 2) { - mitk::ImageDataItem* iDi = im->GetSliceData(rand() % nrSlices); - while(!iDi->IsComplete()); - mitk::ImageReadAccessor* iRA = new mitk::ImageReadAccessor(im,iDi); - /*itk::Index<2> idx; - - for(int i=0; iGetPixelByIndexSafe(idx); - value = 0; - } - }*/ - - delete iRA; - } - else - { - try { - mitk::ImageDataItem* iDi = im->GetSliceData(rand() % nrSlices); - while(!iDi->IsComplete()); - mitk::ImageWriteAccessor iB(im,iDi); - void* pointer = iB.GetData(); - *((char*) pointer) = 0; - - /*for(int i=0; i idx = {{ i, j }}; - iB.SetPixelByIndexSafe(idx, rand() % 16000); - } - }*/ + /* extract data pointer from Thread Info structure */ + struct itk::MultiThreader::ThreadInfoStruct * pInfo = + (struct itk::MultiThreader::ThreadInfoStruct*)data; + + // some data validity checking + if (pInfo == NULL) + { + return ITK_THREAD_RETURN_VALUE; + } + if (pInfo->UserData == NULL) + { + return ITK_THREAD_RETURN_VALUE; + } + + // obtain user data for processing + ThreadData* threadData = (ThreadData*) pInfo->UserData; + + srand( pInfo->ThreadID ); + + mitk::Image::Pointer im = threadData->data; + + + int nrSlices = im->GetDimension(2); + + // Create randomly a PixelRead- or PixelWriteAccessor for a slice and access all pixels in it. + try + { + if(rand() % 2) + { + mitk::ImageDataItem* iDi = im->GetSliceData(rand() % nrSlices); + while(!iDi->IsComplete()); + + //MITK_INFO << "pixeltype: " << im->GetPixelType().GetComponentTypeAsString(); + + if ((im->GetPixelType().GetComponentTypeAsString() == "short") && (im->GetDimension() == 3) ) + { + // Use pixeltype&dimension specific read accessor + + int xlength = im->GetDimension(0); + int ylength = im->GetDimension(1); + + mitk::ImagePixelReadAccessor readAccessor(im, iDi); + + itk::Index<2> idx; + for(int i=0; iGetSliceData(rand() % nrSlices); + while(!iDi->IsComplete()); + + + if ((im->GetPixelType().GetComponentTypeAsString() == "short") && (im->GetDimension() == 3) ) + { + // Use pixeltype&dimension specific read accessor + + int xlength = im->GetDimension(0); + int ylength = im->GetDimension(1); + + mitk::ImagePixelWriteAccessor writeAccessor(im, iDi); + + itk::Index<2> idx; + for(int i=0; im_Successful = false; + } + } + } + } + else + { + // use general accessor + mitk::ImageWriteAccessor iB(im,iDi); + void* pointer = iB.GetData(); + *((char*) pointer) = 0; + } } - catch(mitk::Exception e) { - e.Print(std::cout); + } + catch(mitk::MemoryIsLockedException e) + { + threadData->m_Successful = false; + e.Print(std::cout); + } + catch(mitk::Exception e) + { + threadData->m_Successful = false; + e.Print(std::cout); + } + + - } - } - } - // data processing end! - threadData->m_Barrier->Wait(); - return ITK_THREAD_RETURN_VALUE; + // data processing end! + threadData->m_Barrier->Wait(); + return ITK_THREAD_RETURN_VALUE; } int mitkImageAccessorTest(int argc, char* argv[]) { + MITK_TEST_BEGIN("mitkImageAccessorTest"); - std::cout << "Loading file: "; - if(argc==0) - { - std::cout<<"no file specified [FAILED]"<SetFileName( argv[1] ); - factory->Update(); - - if(factory->GetNumberOfOutputs()<1) - { - std::cout<<"file could not be loaded [FAILED]"<GetOutput( 0 ); - image = dynamic_cast(node->GetData()); - if(image.IsNull()) - { - std::cout<<"file not an image - test will not be applied [PASSED]"<GetGeometry()->Initialize(); - - itk::MultiThreader::Pointer threader = itk::MultiThreader::New(); - unsigned int noOfThreads = 100; - -// initialize barrier - itk::Barrier::Pointer barrier = itk::Barrier::New(); - barrier->Initialize( noOfThreads + 1); // add one for we stop the base thread when the worker threads are processing - - ThreadData* threadData = new ThreadData; - threadData->m_Barrier = barrier; - threadData->m_NoOfThreads = noOfThreads; - threadData->data = image; - - // spawn threads - for(unsigned int i=0; i < noOfThreads; ++i) - { - threader->SpawnThread(ThreadMethod, threadData); - } - // stop the base thread during worker thread execution - barrier->Wait(); - - // terminate threads - for(unsigned int j=0; j < noOfThreads; ++j) - { - threader->TerminateThread(j); - } - - delete threadData; - - //image = 0; - - std::cout<<"[TEST DONE]"<SetFileName( argv[1] ); + factory->Update(); + + if(factory->GetNumberOfOutputs()<1) + { + std::cout<<"file could not be loaded [FAILED]"<GetOutput( 0 ); + image = dynamic_cast(node->GetData()); + if(image.IsNull()) + { + std::cout<<"file not an image - test will not be applied [PASSED]"<GetGeometry()->Initialize(); + + itk::MultiThreader::Pointer threader = itk::MultiThreader::New(); + unsigned int noOfThreads = 100; + + // initialize barrier + itk::Barrier::Pointer barrier = itk::Barrier::New(); + barrier->Initialize( noOfThreads + 1); // add one for we stop the base thread when the worker threads are processing + + ThreadData* threadData = new ThreadData; + threadData->m_Barrier = barrier; + threadData->m_NoOfThreads = noOfThreads; + threadData->data = image; + threadData->m_Successful = true; + + // spawn threads + for(unsigned int i=0; i < noOfThreads; ++i) + { + threader->SpawnThread(ThreadMethod, threadData); + } + // stop the base thread during worker thread execution + barrier->Wait(); + + // terminate threads + for(unsigned int j=0; j < noOfThreads; ++j) + { + threader->TerminateThread(j); + } + + bool TestSuccessful = threadData->m_Successful ; + delete threadData; + + MITK_TEST_CONDITION_REQUIRED( TestSuccessful, "Testing image access from multiple threads"); + + MITK_TEST_END(); }