diff --git a/Core/Code/DataManagement/mitkImage.cpp b/Core/Code/DataManagement/mitkImage.cpp index 0eca049404..68fbdcaa4f 100644 --- a/Core/Code/DataManagement/mitkImage.cpp +++ b/Core/Code/DataManagement/mitkImage.cpp @@ -1,1440 +1,1462 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkImage.h" #include "mitkHistogramGenerator.h" #include "mitkPicHelper.h" #include "mitkImageTimeSelector.h" #include "ipFunc/mitkIpFunc.h" #include "mitkIpPicTypeMultiplex.h" #include #include template class MITK_CORE_EXPORT itk::SmartPointerForwardReference; mitk::Image::Image() : m_Dimension(0), m_Dimensions(NULL), m_OffsetTable(NULL), m_CompleteData(NULL), m_PixelType(NULL), m_TimeSelectorForExtremaObject(NULL) { m_CountOfMinValuedVoxels.resize(1, 0); m_CountOfMaxValuedVoxels.resize(1, 0); m_ScalarMin.resize(1, itk::NumericTraits::max()); m_ScalarMax.resize(1, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.resize(1, itk::NumericTraits::max()); m_Scalar2ndMax.resize(1, itk::NumericTraits::NonpositiveMin()); m_Initialized = false; mitk::HistogramGenerator::Pointer generator = mitk::HistogramGenerator::New(); m_HistogramGeneratorObject = generator; } -mitk::Image::Image(const Image &other ) : m_Dimension(other.m_Dimension), -m_Dimensions(other.m_Dimensions), m_OffsetTable(other.m_OffsetTable), m_CompleteData(NULL), m_PixelType(NULL), -m_TimeSelectorForExtremaObject(NULL) +mitk::Image::Image(const Image &other) + : m_Dimension(0), m_Dimensions(NULL), m_OffsetTable(NULL), + m_CompleteData(NULL), m_PixelType(NULL), + m_TimeSelectorForExtremaObject(NULL) { - + m_Initialized = false; + + this->Initialize(&other); + + if (this->GetDimension() > 3) + { + const unsigned int time_steps = this->GetDimension(3); + + for (unsigned int i = 0u; i < time_steps; ++i) + { + ImageDataItemPointer volume = const_cast(other).GetVolumeData(i); + + this->SetVolume(volume->GetData(), i); + } + } + else + { + ImageDataItemPointer volume = const_cast(other).GetVolumeData(0); + + this->SetVolume(volume->GetData(), 0); + } } + mitk::Image::~Image() { Clear(); m_ReferenceCountLock.Lock(); m_ReferenceCount = 3; m_ReferenceCountLock.Unlock(); m_HistogramGeneratorObject = NULL; m_TimeSelectorForExtremaObject = NULL; m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); delete [] m_OffsetTable; } const mitk::PixelType& mitk::Image::GetPixelType(int /*n*/) const { return m_PixelType; } unsigned int mitk::Image::GetDimension() const { return m_Dimension; } unsigned int mitk::Image::GetDimension(int i) const { if((i>=0) && (i<(int)m_Dimension)) return m_Dimensions[i]; return 1; } void* mitk::Image::GetData() { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } m_CompleteData=GetChannelData(); return m_CompleteData->GetData(); } template void AccessPixel(mitkIpPicDescriptor* pic, const mitk::Index3D& p, double& value, int timestep) { if ( (p[0]>=0 && p[1] >=0 && p[2]>=0 && timestep>=0) && (unsigned int)p[0] < pic->n[0] && (unsigned int)p[1] < pic->n[1] && (unsigned int)p[2] < pic->n[2] && (unsigned int)timestep < pic->n[3] ) { if(pic->bpe!=24) { value = (double) (((T*) pic->data)[ p[0] + p[1]*pic->n[0] + p[2]*pic->n[0]*pic->n[1] + timestep*pic->n[0]*pic->n[1]*pic->n[2] ]); } else { double returnvalue = (((T*) pic->data)[p[0]*3 + 0 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3 ]); returnvalue += (((T*) pic->data)[p[0]*3 + 1 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3]); returnvalue += (((T*) pic->data)[p[0]*3 + 2 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 + timestep*pic->n[0]*pic->n[1]*pic->n[2]*3]); value = returnvalue; } } else { value = 0; } }; double mitk::Image::GetPixelValueByIndex(const mitk::Index3D &position, unsigned int timestep) { mitkIpPicDescriptor* pic = this->GetPic(); double value = 0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } mitkIpPicTypeMultiplex3(AccessPixel, pic, position, value, timestep); return value; } double mitk::Image::GetPixelValueByWorldCoordinate(const mitk::Point3D& position, unsigned int timestep) { mitkIpPicDescriptor* pic = this->GetPic(); double value = 0; if (this->GetTimeSteps() < timestep) { timestep = this->GetTimeSteps(); } Index3D itkIndex; this->GetGeometry()->WorldToIndex(position,itkIndex); mitkIpPicTypeMultiplex3(AccessPixel, pic, itkIndex, value, timestep); return value; } vtkImageData* mitk::Image::GetVtkImageData(int t, int n) { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } ImageDataItemPointer volume=GetVolumeData(t, n); if(volume.GetPointer()==NULL || volume->GetVtkImageData() == NULL) return NULL; #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) float *fspacing = const_cast(GetSlicedGeometry(t)->GetFloatSpacing()); double dspacing[3] = {fspacing[0],fspacing[1],fspacing[2]}; volume->GetVtkImageData()->SetSpacing( dspacing ); #else volume->GetVtkImageData()->SetSpacing(const_cast(GetSlicedGeometry(t)->GetFloatSpacing())); #endif return volume->GetVtkImageData(); } mitkIpPicDescriptor* mitk::Image::GetPic() { if(m_Initialized==false) { if(GetSource()==NULL) return NULL; if(GetSource()->Updating()==false) GetSource()->UpdateOutputInformation(); } m_CompleteData=GetChannelData(); if(m_CompleteData.GetPointer()==NULL) return NULL; return m_CompleteData->GetPicDescriptor(); } mitk::Image::ImageDataItemPointer mitk::Image::GetSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return NULL; // slice directly available? int pos=GetSliceIndex(s,t,n); if(m_Slices[pos].GetPointer()!=NULL) return m_Slices[pos]; // is slice available as part of a volume that is available? ImageDataItemPointer sl, ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) { sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // is slice available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) { sl=new ImageDataItem(*ch, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // slice is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir mussen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, s); m_RequestedRegion.SetIndex(3, t); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, 1); m_RequestedRegion.SetSize(3, 1); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); if(IsSliceSet(s,t,n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetSliceData(s,t,n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateSliceData(s,t,n,data,importMemoryManagement); item->SetComplete(true); return item; } } mitk::Image::ImageDataItemPointer mitk::Image::GetVolumeData(int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidVolume(t,n)==false) return NULL; ImageDataItemPointer ch, vol; // volume directly available? int pos=GetVolumeIndex(t,n); vol=m_Volumes[pos]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return vol; // is volume available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) { vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); vol->SetComplete(true); return m_Volumes[pos]=vol; } // let's see if all slices of the volume are set, so that we can (could) combine them to a volume bool complete=true; unsigned int s; for(s=0;sSetComplete(true); } else { vol=m_Volumes[pos]; // ok, let's combine the slices! if(vol.GetPointer()==NULL) vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, NULL, true); vol->SetComplete(true); size_t size=m_OffsetTable[2]*(m_PixelType.GetBpe()/8); for(s=0;sGetParent()!=vol) { // copy data of slices in volume size_t offset = ((size_t) s)*size; std::memcpy(static_cast(vol->GetData())+offset, sl->GetData(), size); mitkIpPicDescriptor * pic = sl->GetPicDescriptor(); // replace old slice with reference to volume sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*size); sl->SetComplete(true); mitkIpFuncCopyTags(sl->GetPicDescriptor(), pic); m_Slices[posSl]=sl; } } if(vol->GetPicDescriptor()->info->tags_head==NULL) mitkIpFuncCopyTags(vol->GetPicDescriptor(), m_Slices[GetSliceIndex(0,t,n)]->GetPicDescriptor()); } return m_Volumes[pos]=vol; } // volume is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir muessen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, 0); m_RequestedRegion.SetIndex(3, t); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, m_Dimensions[2]); m_RequestedRegion.SetSize(3, 1); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); if(IsVolumeSet(t,n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetVolumeData(t,n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateVolumeData(t,n,data,importMemoryManagement); item->SetComplete(true); return item; } } mitk::Image::ImageDataItemPointer mitk::Image::GetChannelData(int n, void *data, ImportMemoryManagementType importMemoryManagement) { if(IsValidChannel(n)==false) return NULL; ImageDataItemPointer ch, vol; ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return ch; // let's see if all volumes are set, so that we can (could) combine them to a channel if(IsChannelSet(n)) { // if there is only one time frame we do not need to combine anything if(m_Dimensions[3]<=1) { vol=GetVolumeData(0,n,data,importMemoryManagement); ch=new ImageDataItem(*vol, 3, data, importMemoryManagement == ManageMemory); ch->SetComplete(true); } else { ch=m_Channels[n]; // ok, let's combine the volumes! if(ch.GetPointer()==NULL) ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, NULL, true); ch->SetComplete(true); size_t size=m_OffsetTable[m_Dimension-1]*(m_PixelType.GetBpe()/8); unsigned int t; ImageDataItemPointerArray::iterator slicesIt = m_Slices.begin()+n*m_Dimensions[2]*m_Dimensions[3]; for(t=0;tGetParent()!=ch) { // copy data of volume in channel size_t offset = ((size_t) t)*m_OffsetTable[3]*(m_PixelType.GetBpe()/8); std::memcpy(static_cast(ch->GetData())+offset, vol->GetData(), size); mitkIpPicDescriptor * pic = vol->GetPicDescriptor(); // replace old volume with reference to channel vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, offset); vol->SetComplete(true); mitkIpFuncCopyTags(vol->GetPicDescriptor(), pic); m_Volumes[posVol]=vol; // get rid of slices - they may point to old volume ImageDataItemPointer dnull=NULL; for(unsigned int i = 0; i < m_Dimensions[2]; ++i, ++slicesIt) { assert(slicesIt != m_Slices.end()); *slicesIt = dnull; } } } if(ch->GetPicDescriptor()->info->tags_head==NULL) mitkIpFuncCopyTags(ch->GetPicDescriptor(), m_Volumes[GetVolumeIndex(0,n)]->GetPicDescriptor()); } return m_Channels[n]=ch; } // channel is unavailable. Can we calculate it? if((GetSource()!=NULL) && (GetSource()->Updating()==false)) { // ... wir muessen rechnen!!! .... m_RequestedRegion.SetIndex(0, 0); m_RequestedRegion.SetIndex(1, 0); m_RequestedRegion.SetIndex(2, 0); m_RequestedRegion.SetIndex(3, 0); m_RequestedRegion.SetIndex(4, n); m_RequestedRegion.SetSize(0, m_Dimensions[0]); m_RequestedRegion.SetSize(1, m_Dimensions[1]); m_RequestedRegion.SetSize(2, m_Dimensions[2]); m_RequestedRegion.SetSize(3, m_Dimensions[3]); m_RequestedRegion.SetSize(4, 1); m_RequestedRegionInitialized=true; GetSource()->Update(); // did it work? if(IsChannelSet(n)) //yes: now we can call ourselves without the risk of a endless loop (see "if" above) return GetChannelData(n,data,importMemoryManagement); else return NULL; } else { ImageDataItemPointer item = AllocateChannelData(n,data,importMemoryManagement); item->SetComplete(true); return item; } } bool mitk::Image::IsSliceSet(int s, int t, int n) const { if(IsValidSlice(s,t,n)==false) return false; if(m_Slices[GetSliceIndex(s,t,n)].GetPointer()!=NULL) return true; ImageDataItemPointer ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return true; ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return true; return false; } bool mitk::Image::IsVolumeSet(int t, int n) const { if(IsValidVolume(t,n)==false) return false; ImageDataItemPointer ch, vol; // volume directly available? vol=m_Volumes[GetVolumeIndex(t,n)]; if((vol.GetPointer()!=NULL) && (vol->IsComplete())) return true; // is volume available as part of a channel that is available? ch=m_Channels[n]; if((ch.GetPointer()!=NULL) && (ch->IsComplete())) return true; // let's see if all slices of the volume are set, so that we can (could) combine them to a volume unsigned int s; for(s=0;sIsComplete())) return true; // let's see if all volumes are set, so that we can (could) combine them to a channel unsigned int t; for(t=0;t(data), s, t, n, CopyMemory); } bool mitk::Image::SetVolume(const void *data, int t, int n) { // const_cast is no risk for ImportMemoryManagementType == CopyMemory return SetImportVolume(const_cast(data), t, n, CopyMemory); } bool mitk::Image::SetChannel(const void *data, int n) { // const_cast is no risk for ImportMemoryManagementType == CopyMemory return SetImportChannel(const_cast(data), n, CopyMemory); } bool mitk::Image::SetImportSlice(void *data, int s, int t, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidSlice(s,t,n)==false) return false; ImageDataItemPointer sl; if(IsSliceSet(s,t,n)) { sl=GetSliceData(s,t,n,data,importMemoryManagement); if(sl->GetManageMemory()==false) { sl=AllocateSliceData(s,t,n,data,importMemoryManagement); if(sl.GetPointer()==NULL) return false; } if ( sl->GetData() != data ) std::memcpy(sl->GetData(), data, m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->Modified(); //we have changed the data: call Modified()! Modified(); } else { sl=AllocateSliceData(s,t,n,data,importMemoryManagement); if(sl.GetPointer()==NULL) return false; if ( sl->GetData() != data ) std::memcpy(sl->GetData(), data, m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); //we just added a missing slice, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetImportVolume(void *data, int t, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidVolume(t,n)==false) return false; ImageDataItemPointer vol; if(IsVolumeSet(t,n)) { vol=GetVolumeData(t,n,data,importMemoryManagement); if(vol->GetManageMemory()==false) { vol=AllocateVolumeData(t,n,data,importMemoryManagement); if(vol.GetPointer()==NULL) return false; } if ( vol->GetData() != data ) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); vol->Modified(); vol->SetComplete(true); //we have changed the data: call Modified()! Modified(); } else { vol=AllocateVolumeData(t,n,data,importMemoryManagement); if(vol.GetPointer()==NULL) return false; if ( vol->GetData() != data ) { std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); } vol->SetComplete(true); //we just added a missing Volume, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetImportChannel(void *data, int n, ImportMemoryManagementType importMemoryManagement) { if(IsValidChannel(n)==false) return false; ImageDataItemPointer ch; if(IsChannelSet(n)) { ch=GetChannelData(n,data,importMemoryManagement); if(ch->GetManageMemory()==false) { ch=AllocateChannelData(n,data,importMemoryManagement); if(ch.GetPointer()==NULL) return false; } if ( ch->GetData() != data ) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); ch->Modified(); ch->SetComplete(true); //we have changed the data: call Modified()! Modified(); } else { ch=AllocateChannelData(n,data,importMemoryManagement); if(ch.GetPointer()==NULL) return false; if ( ch->GetData() != data ) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); ch->SetComplete(true); //we just added a missing Channel, which is not regarded as modification. //Therefore, we do not call Modified()! } return true; } bool mitk::Image::SetPicSlice(const mitkIpPicDescriptor *pic, int s, int t, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if(pic->dim!=2) return false; if((pic->n[0]!=m_Dimensions[0]) || (pic->n[1]!=m_Dimensions[1])) return false; if(SetSlice(pic->data,s,t,n)) //@todo: add geometry! { ImageDataItemPointer sl; sl=GetSliceData(s,t,n,NULL,CopyMemory); mitkIpFuncCopyTags(sl->GetPicDescriptor(), const_cast(pic)); return true; } else return false; } bool mitk::Image::SetPicVolume(const mitkIpPicDescriptor *pic, int t, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if((pic->dim==2) && ((m_Dimension==2) || ((m_Dimension>2) && (m_Dimensions[2]==1)))) return SetPicSlice(pic, 0, t, n); if(pic->dim!=3) return false; if((pic->n[0]!=m_Dimensions[0]) || (pic->n[1]!=m_Dimensions[1]) || (pic->n[2]!=m_Dimensions[2])) return false; if(SetVolume(pic->data,t,n)) //@todo: add geometry! { ImageDataItemPointer vol; vol=GetVolumeData(t,n,NULL,CopyMemory); mitkIpFuncCopyTags(vol->GetPicDescriptor(), const_cast(pic)); return true; } else return false; } bool mitk::Image::SetPicChannel(const mitkIpPicDescriptor *pic, int n, ImportMemoryManagementType /*importMemoryManagement*/) { if(pic==NULL) return false; if(pic->dim<=3) return SetPicVolume(pic, 0, n); if(pic->dim!=m_Dimension) return false; unsigned int i; for(i=0;in[i]!=m_Dimensions[i]) return false; } if(SetChannel(pic->data,n)) //@todo: add geometry! { ImageDataItemPointer ch; ch=GetChannelData(n,NULL,CopyMemory); // commented the next line, because // it crashes when called from mitkDICOMFileReader for the Live3D data // mitkIpFuncCopyTags(ch->GetPicDescriptor(), pic); return true; } else return false; } void mitk::Image::Initialize() { ImageDataItemPointerArray::iterator it, end; for( it=m_Slices.begin(), end=m_Slices.end(); it!=end; ++it ) { (*it)=NULL; } for( it=m_Volumes.begin(), end=m_Volumes.end(); it!=end; ++it ) { (*it)=NULL; } for( it=m_Channels.begin(), end=m_Channels.end(); it!=end; ++it ) { (*it)=NULL; } m_CompleteData = NULL; this->GetTimeSelector(); // just to create m_TimeSelectorForExtremaObject SetRequestedRegionToLargestPossibleRegion(); } mitk::ImageTimeSelector* mitk::Image::GetTimeSelector() const { if(m_TimeSelectorForExtremaObject.IsNull()) { m_TimeSelectorForExtremaObject = ImageTimeSelector::New(); ImageTimeSelector* timeSelector = static_cast( m_TimeSelectorForExtremaObject.GetPointer() ); timeSelector->SetInput(this); this->UnRegister(); } return static_cast( m_TimeSelectorForExtremaObject.GetPointer() ); } void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, unsigned int channels) { Clear(); m_Dimension=dimension; if(!dimensions) itkExceptionMacro(<< "invalid zero dimension image"); unsigned int i; for(i=0;i4?m_Dimension:4]; std::memcpy(m_Dimensions, dimensions, sizeof(unsigned int)*m_Dimension); if(m_Dimension<4) { unsigned int *p; for(i=0,p=m_Dimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } for(i=0;i<4;++i) { m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize (i, m_Dimensions[i]); } m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize(i, channels); if(m_LargestPossibleRegion.GetNumberOfPixels()==0) { delete [] m_Dimensions; m_Dimensions = NULL; return; } m_PixelType=type; PlaneGeometry::Pointer planegeometry = PlaneGeometry::New(); planegeometry->InitializeStandardPlane(m_Dimensions[0], m_Dimensions[1]); SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(planegeometry, m_Dimensions[2]); if(dimension>=4) { TimeBounds timebounds; timebounds[0] = 0.0; timebounds[1] = 1.0; slicedGeometry->SetTimeBounds(timebounds); } TimeSlicedGeometry::Pointer timeSliceGeometry = TimeSlicedGeometry::New(); timeSliceGeometry->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); timeSliceGeometry->ImageGeometryOn(); SetGeometry(timeSliceGeometry); ImageDataItemPointer dnull=NULL; m_Channels.assign(GetNumberOfChannels(), dnull); m_Volumes.assign(GetNumberOfChannels()*m_Dimensions[3], dnull); m_Slices.assign(GetNumberOfChannels()*m_Dimensions[3]*m_Dimensions[2], dnull); ComputeOffsetTable(); Initialize(); m_Initialized = true; } void mitk::Image::Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int channels, int tDim ) { unsigned int dimensions[5]; dimensions[0] = (unsigned int)(geometry.GetExtent(0)+0.5); dimensions[1] = (unsigned int)(geometry.GetExtent(1)+0.5); dimensions[2] = (unsigned int)(geometry.GetExtent(2)+0.5); dimensions[3] = 0; dimensions[4] = 0; unsigned int dimension = 2; if ( dimensions[2] > 1 ) dimension = 3; if ( tDim > 0) { dimensions[3] = tDim; } else { const mitk::TimeSlicedGeometry* timeGeometry = dynamic_cast(&geometry); if ( timeGeometry != NULL ) { dimensions[3] = timeGeometry->GetTimeSteps(); } } if ( dimensions[3] > 1 ) dimension = 4; Initialize( type, dimension, dimensions, channels ); SetGeometry(static_cast(geometry.Clone().GetPointer())); mitk::BoundingBox::BoundsArrayType bounds = geometry.GetBoundingBox()->GetBounds(); if( (bounds[0] != 0.0) || (bounds[2] != 0.0) || (bounds[4] != 0.0) ) { SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); mitk::Point3D origin; origin.Fill(0.0); slicedGeometry->IndexToWorld(origin, origin); bounds[1]-=bounds[0]; bounds[3]-=bounds[2]; bounds[5]-=bounds[4]; bounds[0] = 0.0; bounds[2] = 0.0; bounds[4] = 0.0; slicedGeometry->SetBounds(bounds); slicedGeometry->GetIndexToWorldTransform()->SetOffset(origin.Get_vnl_vector().data_block()); GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); } } void mitk::Image::Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped, unsigned int channels, int tDim ) { SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); slicedGeometry->InitializeEvenlySpaced(static_cast(geometry2d.Clone().GetPointer()), sDim, flipped); Initialize(type, *slicedGeometry, channels, tDim); } void mitk::Image::Initialize(const mitk::Image* image) { Initialize(*image->GetPixelType().GetTypeId(), *image->GetTimeSlicedGeometry()); } void mitk::Image::Initialize(vtkImageData* vtkimagedata, int channels, int tDim, int sDim) { if(vtkimagedata==NULL) return; m_Dimension=vtkimagedata->GetDataDimension(); unsigned int i, *tmpDimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; for(i=0;iGetDimensions()[i]; if(m_Dimension<4) { unsigned int *p; for(i=0,p=tmpDimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } if(sDim>=0) { tmpDimensions[2]=sDim; if(m_Dimension < 3) m_Dimension = 3; } if(tDim>=0) { tmpDimensions[3]=tDim; if(m_Dimension < 4) m_Dimension = 4; } mitk::PixelType pixelType; switch ( vtkimagedata->GetScalarType() ) { case VTK_BIT: case VTK_CHAR: pixelType.Initialize(typeid(char), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_CHAR: pixelType.Initialize(typeid(unsigned char), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_SHORT: pixelType.Initialize(typeid(short), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_SHORT: pixelType.Initialize(typeid(unsigned short), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_INT: pixelType.Initialize(typeid(int), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_INT: pixelType.Initialize(typeid(unsigned int), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_LONG: pixelType.Initialize(typeid(long), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_UNSIGNED_LONG: pixelType.Initialize(typeid(unsigned long), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_FLOAT: pixelType.Initialize(typeid(float), vtkimagedata->GetNumberOfScalarComponents()); break; case VTK_DOUBLE: pixelType.Initialize(typeid(double), vtkimagedata->GetNumberOfScalarComponents()); break; default: break; } Initialize(pixelType, m_Dimension, tmpDimensions, channels); #if ((VTK_MAJOR_VERSION > 4) || ((VTK_MAJOR_VERSION==4) && (VTK_MINOR_VERSION>=4) )) const double *spacinglist = vtkimagedata->GetSpacing(); #else const float *spacinglist = vtkimagedata->GetSpacing(); #endif Vector3D spacing; FillVector3D(spacing, spacinglist[0], 1.0, 1.0); if(m_Dimension>=2) spacing[1]=spacinglist[1]; if(m_Dimension>=3) spacing[2]=spacinglist[2]; // access origin of vtkImage Point3D origin; vtkFloatingPointType vtkorigin[3]; vtkimagedata->GetOrigin(vtkorigin); FillVector3D(origin, vtkorigin[0], 0.0, 0.0); if(m_Dimension>=2) origin[1]=vtkorigin[1]; if(m_Dimension>=3) origin[2]=vtkorigin[2]; SlicedGeometry3D* slicedGeometry = GetSlicedGeometry(0); // re-initialize PlaneGeometry with origin and direction PlaneGeometry* planeGeometry = static_cast(slicedGeometry->GetGeometry2D(0)); planeGeometry->SetOrigin(origin); // re-initialize SlicedGeometry3D slicedGeometry->SetOrigin(origin); slicedGeometry->SetSpacing(spacing); GetTimeSlicedGeometry()->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); delete [] tmpDimensions; } void mitk::Image::Initialize(const mitkIpPicDescriptor* pic, int channels, int tDim, int sDim) { if(pic==NULL) return; Clear(); m_Dimension=pic->dim; m_Dimensions=new unsigned int[m_Dimension>4?m_Dimension:4]; std::memcpy(m_Dimensions, pic->n, sizeof(unsigned int)*m_Dimension); if(m_Dimension<4) { unsigned int i, *p; for(i=0,p=m_Dimensions+m_Dimension;i<4-m_Dimension;++i, ++p) *p=1; } if(sDim>=0) { m_Dimensions[2]=sDim; if(m_Dimension < 3) m_Dimension = 3; } if(tDim>=0) { m_Dimensions[3]=tDim; if(m_Dimension < 4) m_Dimension = 4; } unsigned int i; for(i=0;i<4;++i) { m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize (i, m_Dimensions[i]); } m_LargestPossibleRegion.SetIndex(i, 0); m_LargestPossibleRegion.SetSize(i, channels); m_PixelType=PixelType(pic); SlicedGeometry3D::Pointer slicedGeometry = SlicedGeometry3D::New(); PicHelper::InitializeEvenlySpaced(pic, m_Dimensions[2], slicedGeometry); TimeSlicedGeometry::Pointer timeSliceGeometry = TimeSlicedGeometry::New(); timeSliceGeometry->InitializeEvenlyTimed(slicedGeometry, m_Dimensions[3]); timeSliceGeometry->ImageGeometryOn(); SetGeometry(timeSliceGeometry); ImageDataItemPointer dnull=NULL; m_Channels.assign(GetNumberOfChannels(), dnull); m_Volumes.assign(GetNumberOfChannels()*m_Dimensions[3], dnull); m_Slices.assign(GetNumberOfChannels()*m_Dimensions[3]*m_Dimensions[2], dnull); ComputeOffsetTable(); Initialize(); m_Initialized = true; } bool mitk::Image::IsValidSlice(int s, int t, int n) const { if(m_Initialized) return ((s>=0) && (s<(int)m_Dimensions[2]) && (t>=0) && (t< (int) m_Dimensions[3]) && (n>=0) && (n< (int)GetNumberOfChannels())); else return false; } bool mitk::Image::IsValidVolume(int t, int n) const { if(m_Initialized) return IsValidSlice(0, t, n); else return false; } bool mitk::Image::IsValidChannel(int n) const { if(m_Initialized) return IsValidSlice(0, 0, n); else return false; } void mitk::Image::ComputeOffsetTable() { if(m_OffsetTable!=NULL) delete [] m_OffsetTable; m_OffsetTable=new size_t[m_Dimension>4 ? m_Dimension+1 : 4+1]; unsigned int i; size_t num=1; m_OffsetTable[0] = 1; for (i=0; i < m_Dimension; ++i) { num *= m_Dimensions[i]; m_OffsetTable[i+1] = num; } for (;i < 4; ++i) m_OffsetTable[i+1] = num; } int mitk::Image::GetSliceIndex(int s, int t, int n) const { if(IsValidSlice(s,t,n)==false) return false; return ((size_t)s)+((size_t) t)*m_Dimensions[2]+((size_t) n)*m_Dimensions[3]*m_Dimensions[2]; //?? } int mitk::Image::GetVolumeIndex(int t, int n) const { if(IsValidVolume(t,n)==false) return false; return ((size_t)t)+((size_t) n)*m_Dimensions[3]; //?? } mitk::Image::ImageDataItemPointer mitk::Image::AllocateSliceData(int s, int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { int pos; pos=GetSliceIndex(s,t,n); // is slice available as part of a volume that is available? ImageDataItemPointer sl, ch, vol; vol=m_Volumes[GetVolumeIndex(t,n)]; if(vol.GetPointer()!=NULL) { sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // is slice available as part of a channel that is available? ch=m_Channels[n]; if(ch.GetPointer()!=NULL) { sl=new ImageDataItem(*ch, 2, data, importMemoryManagement == ManageMemory, (((size_t) s)*m_OffsetTable[2]+((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; } // allocate new volume (instead of a single slice to keep data together!) m_Volumes[GetVolumeIndex(t,n)]=vol=AllocateVolumeData(t,n,NULL,importMemoryManagement); sl=new ImageDataItem(*vol, 2, data, importMemoryManagement == ManageMemory, ((size_t) s)*m_OffsetTable[2]*(m_PixelType.GetBpe()/8)); sl->SetComplete(true); return m_Slices[pos]=sl; ////ALTERNATIVE: //// allocate new slice //sl=new ImageDataItem(m_PixelType, 2, m_Dimensions); //m_Slices[pos]=sl; //return vol; } mitk::Image::ImageDataItemPointer mitk::Image::AllocateVolumeData(int t, int n, void *data, ImportMemoryManagementType importMemoryManagement) { int pos; pos=GetVolumeIndex(t,n); // is volume available as part of a channel that is available? ImageDataItemPointer ch, vol; ch=m_Channels[n]; if(ch.GetPointer()!=NULL) { vol=new ImageDataItem(*ch, 3, data, importMemoryManagement == ManageMemory, (((size_t) t)*m_OffsetTable[3])*(m_PixelType.GetBpe()/8)); return m_Volumes[pos]=vol; } // allocate new volume if(importMemoryManagement == CopyMemory) { vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, NULL, true); if(data != NULL) std::memcpy(vol->GetData(), data, m_OffsetTable[3]*(m_PixelType.GetBpe()/8)); } else { vol=new ImageDataItem(m_PixelType, 3, m_Dimensions, data, importMemoryManagement == ManageMemory); } m_Volumes[pos]=vol; return vol; } mitk::Image::ImageDataItemPointer mitk::Image::AllocateChannelData(int n, void *data, ImportMemoryManagementType importMemoryManagement) { ImageDataItemPointer ch; // allocate new channel if(importMemoryManagement == CopyMemory) { ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, NULL, true); if(data != NULL) std::memcpy(ch->GetData(), data, m_OffsetTable[4]*(m_PixelType.GetBpe()/8)); } else { ch=new ImageDataItem(m_PixelType, m_Dimension, m_Dimensions, data, importMemoryManagement == ManageMemory); } m_Channels[n]=ch; return ch; } unsigned int* mitk::Image::GetDimensions() const { return m_Dimensions; } void mitk::Image::Clear() { Superclass::Clear(); delete [] m_Dimensions; m_Dimensions = NULL; } void mitk::Image::SetGeometry(Geometry3D* aGeometry3D) { // Please be aware of the 0.5 offset/pixel-center issue! See Geometry documentation for further information if(aGeometry3D->GetImageGeometry()==false) { MITK_INFO << "WARNING: Applied a non-image geometry onto an image. Please be SURE that this geometry is pixel-center-based! If it is not, you need to call Geometry3D->ChangeImageGeometryConsideringOriginOffset(true) before calling image->setGeometry(..)\n"; } Superclass::SetGeometry(aGeometry3D); GetTimeSlicedGeometry()->ImageGeometryOn(); } const mitk::Image::HistogramType* mitk::Image::GetScalarHistogram(int t) const { mitk::ImageTimeSelector* timeSelector = this->GetTimeSelector(); if(timeSelector!=NULL) { timeSelector->SetTimeNr(t); timeSelector->UpdateLargestPossibleRegion(); mitk::HistogramGenerator* generator = static_cast(m_HistogramGeneratorObject.GetPointer()); generator->SetImage(timeSelector->GetOutput()); generator->ComputeHistogram(); return static_cast(generator->GetHistogram()); } return NULL; } #include "mitkImageAccessByItk.h" //#define BOUNDINGOBJECT_IGNORE template < typename ItkImageType > void mitk::_ComputeExtremaInItkImage(ItkImageType* itkImage, mitk::Image* mitkImage, int t) { typename ItkImageType::RegionType region; region = itkImage->GetBufferedRegion(); if(region.Crop(itkImage->GetRequestedRegion()) == false) return; if(region != itkImage->GetRequestedRegion()) return; itk::ImageRegionConstIterator it(itkImage, region); typedef typename ItkImageType::PixelType TPixel; TPixel value = 0; if ( !mitkImage || !mitkImage->IsValidTimeStep( t ) ) return; mitkImage->Expand(t+1); // make sure we have initialized all arrays mitkImage->m_CountOfMinValuedVoxels[t] = 0; mitkImage->m_CountOfMaxValuedVoxels[t] = 0; mitkImage->m_Scalar2ndMin[t]= mitkImage->m_ScalarMin[t] = itk::NumericTraits::max(); mitkImage->m_Scalar2ndMax[t]= mitkImage->m_ScalarMax[t] = itk::NumericTraits::NonpositiveMin(); while( !it.IsAtEnd() ) { value = it.Get(); // if ( (value > mitkImage->m_ScalarMin) && (value < mitkImage->m_Scalar2ndMin) ) mitkImage->m_Scalar2ndMin = value; // else if ( (value < mitkImage->m_ScalarMax) && (value > mitkImage->m_Scalar2ndMax) ) mitkImage->m_Scalar2ndMax = value; // else if (value > mitkImage->m_ScalarMax) mitkImage->m_ScalarMax = value; // else if (value < mitkImage->m_ScalarMin) mitkImage->m_ScalarMin = value; // if numbers start with 2ndMin or 2ndMax and never have that value again, the previous above logic failed #ifdef BOUNDINGOBJECT_IGNORE if( value > -32765) { #endif // update min if ( value < mitkImage->m_ScalarMin[t] ) { mitkImage->m_Scalar2ndMin[t] = mitkImage->m_ScalarMin[t]; mitkImage->m_ScalarMin[t] = value; mitkImage->m_CountOfMinValuedVoxels[t] = 1; } else if ( value == mitkImage->m_ScalarMin[t] ) { ++mitkImage->m_CountOfMinValuedVoxels[t]; } else if ( value < mitkImage->m_Scalar2ndMin[t] ) { mitkImage->m_Scalar2ndMin[t] = value; } // update max if ( value > mitkImage->m_ScalarMax[t] ) { mitkImage->m_Scalar2ndMax[t] = mitkImage->m_ScalarMax[t]; mitkImage->m_ScalarMax[t] = value; mitkImage->m_CountOfMaxValuedVoxels[t] = 1; } else if ( value == mitkImage->m_ScalarMax[t] ) { ++mitkImage->m_CountOfMaxValuedVoxels[t]; } else if ( value > mitkImage->m_Scalar2ndMax[t] ) { mitkImage->m_Scalar2ndMax[t] = value; } #ifdef BOUNDINGOBJECT_IGNORE } #endif ++it; } //// guard for wrong 2dMin/Max on single constant value images if (mitkImage->m_ScalarMax[t] == mitkImage->m_ScalarMin[t]) { mitkImage->m_Scalar2ndMax[t] = mitkImage->m_Scalar2ndMin[t] = mitkImage->m_ScalarMax[t]; } mitkImage->m_LastRecomputeTimeStamp.Modified(); //MITK_DEBUG <<"extrema "<::NonpositiveMin()<<" "<m_ScalarMin<<" "<m_Scalar2ndMin<<" "<m_Scalar2ndMax<<" "<m_ScalarMax<<" "<::max(); } bool mitk::Image::IsValidTimeStep(int t) const { return ( ( m_Dimension >= 4 && t <= (int)m_Dimensions[3] && t > 0 ) || (t == 0) ); } void mitk::Image::Expand( int timeSteps ) const { if(timeSteps < 1) itkExceptionMacro(<< "Invalid timestep in Image!"); if(! IsValidTimeStep( timeSteps-1 ) ) return; if(timeSteps > (int)m_ScalarMin.size() ) { m_ScalarMin.resize(timeSteps, itk::NumericTraits::max()); m_ScalarMax.resize(timeSteps, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.resize(timeSteps, itk::NumericTraits::max()); m_Scalar2ndMax.resize(timeSteps, itk::NumericTraits::NonpositiveMin()); m_CountOfMinValuedVoxels.resize(timeSteps, 0); m_CountOfMaxValuedVoxels.resize(timeSteps, 0); } } void mitk::Image::ResetImageStatistics() const { m_ScalarMin.assign(1, itk::NumericTraits::max()); m_ScalarMax.assign(1, itk::NumericTraits::NonpositiveMin()); m_Scalar2ndMin.assign(1, itk::NumericTraits::max()); m_Scalar2ndMax.assign(1, itk::NumericTraits::NonpositiveMin()); m_CountOfMinValuedVoxels.assign(1, 0); m_CountOfMaxValuedVoxels.assign(1, 0); } void mitk::Image::ComputeImageStatistics(int t) const { // timestep valid? if (!IsValidTimeStep(t)) return; // image modified? if (this->GetMTime() > m_LastRecomputeTimeStamp.GetMTime()) this->ResetImageStatistics(); // adapt vector length this->Expand(t+1); // do we have valid information already? if( m_ScalarMin[t] != itk::NumericTraits::max() || m_Scalar2ndMin[t] != itk::NumericTraits::max() ) return; // Values already calculated before... if(this->m_PixelType.GetNumberOfComponents() == 1) { // recompute mitk::ImageTimeSelector* timeSelector = this->GetTimeSelector(); if(timeSelector!=NULL) { timeSelector->SetTimeNr(t); timeSelector->UpdateLargestPossibleRegion(); mitk::Image* image = timeSelector->GetOutput(); mitk::Image* thisImage = const_cast(this); AccessByItk_2( image, _ComputeExtremaInItkImage, thisImage, t ); } } else if(this->m_PixelType.GetNumberOfComponents() > 1) { m_ScalarMin[t] = 0; m_ScalarMax[t] = 255; } } mitk::ScalarType mitk::Image::GetScalarValueMin(int t) const { ComputeImageStatistics(t); return m_ScalarMin[t]; } mitk::ScalarType mitk::Image::GetScalarValueMax(int t) const { ComputeImageStatistics(t); return m_ScalarMax[t]; } mitk::ScalarType mitk::Image::GetScalarValue2ndMin(int t) const { ComputeImageStatistics(t); return m_Scalar2ndMin[t]; } mitk::ScalarType mitk::Image::GetScalarValue2ndMax(int t) const { ComputeImageStatistics(t); return m_Scalar2ndMax[t]; } mitk::ScalarType mitk::Image::GetCountOfMinValuedVoxels(int t) const { ComputeImageStatistics(t); return m_CountOfMinValuedVoxels[t]; } mitk::ScalarType mitk::Image::GetCountOfMaxValuedVoxels(int t) const { ComputeImageStatistics(t); return m_CountOfMaxValuedVoxels[t]; } void mitk::Image::PrintSelf(std::ostream& os, itk::Indent indent) const { unsigned char i; if(m_Initialized) { os << indent << " PixelType: " << m_PixelType.GetTypeId()->name() << std::endl; os << indent << " BitsPerElement: " << m_PixelType.GetBpe() << std::endl; os << indent << " NumberOfComponents: " << m_PixelType.GetNumberOfComponents() << std::endl; os << indent << " BitsPerComponent: " << m_PixelType.GetBitsPerComponent() << std::endl; os << indent << " Dimension: " << m_Dimension << std::endl; os << indent << " Dimensions: "; for(i=0; i < m_Dimension; ++i) os << GetDimension(i) << " "; os << std::endl; } else { os << indent << " Image not initialized: m_Initialized: false" << std::endl; } Superclass::PrintSelf(os,indent); } bool mitk::Image::IsRotated() const { const mitk::Geometry3D* geo = this->GetGeometry(); bool ret = false; if(geo) { const vnl_matrix_fixed & mx = geo->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); float ref = 0; for(short k = 0; k < 3; ++k) ref += mx[k][k]; ref/=1000; // Arbitrary value; if a non-diagonal (nd) element is bigger then this, matrix is considered nd. for(short i = 0; i < 3; ++i) { for(short j = 0; j < 3; ++j) { if(i != j) { if(abs(mx[i][j]) > ref) // matrix is nd ret = true; } } } } return ret; } diff --git a/Core/Code/DataManagement/mitkImageDataItem.cpp b/Core/Code/DataManagement/mitkImageDataItem.cpp index 08634d1fdb..569cff7471 100644 --- a/Core/Code/DataManagement/mitkImageDataItem.cpp +++ b/Core/Code/DataManagement/mitkImageDataItem.cpp @@ -1,224 +1,231 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkImageDataItem.h" #include "mitkMemoryUtilities.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipFunc/mitkIpFunc.h" mitk::ImageDataItem::ImageDataItem(const ImageDataItem& aParent, unsigned int dimension, void *data, bool manageMemory, size_t offset) : m_Data(NULL), m_ManageMemory(false), m_PicDescriptor(NULL), m_VtkImageData(NULL), m_Offset(offset), m_IsComplete(false), m_Size(0), m_Parent(&aParent) { m_PixelType = aParent.GetPixelType(); m_PicDescriptor=mitkIpPicNew(); m_PicDescriptor->bpe=m_PixelType.GetBpe(); m_PicDescriptor->type=m_PixelType.GetType(); m_PicDescriptor->dim=dimension; memcpy(m_PicDescriptor->n, aParent.GetPicDescriptor()->n, sizeof(mitkIpUInt4_t)*_mitkIpPicNDIM); m_PicDescriptor->data=m_Data=static_cast(aParent.GetData())+offset; mitkIpFuncCopyTags(m_PicDescriptor, aParent.GetPicDescriptor()); m_Size = _mitkIpPicSize(m_PicDescriptor); if(data != NULL) { memcpy(m_Data, data, m_Size); if(manageMemory) { delete [] (unsigned char*) data; } } m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); } mitk::ImageDataItem::~ImageDataItem() { if(m_VtkImageData!=NULL) m_VtkImageData->Delete(); if(m_PicDescriptor!=NULL) { m_PicDescriptor->data=NULL; mitkIpPicFree(m_PicDescriptor); } if(m_Parent.IsNull()) { if(m_ManageMemory) delete [] m_Data; } } mitk::ImageDataItem::ImageDataItem(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, void *data, bool manageMemory) : m_Data((unsigned char*)data), m_ManageMemory(manageMemory), m_PicDescriptor(NULL), m_VtkImageData(NULL), m_Offset(0), m_IsComplete(false), m_Size(0), m_Parent(NULL) { //const std::type_info & typeId=*type.GetTypeId(); m_PixelType = type; m_PicDescriptor=mitkIpPicNew(); m_PicDescriptor->bpe=m_PixelType.GetBpe(); m_PicDescriptor->type=m_PixelType.GetType(); m_PicDescriptor->dim=dimension; memcpy(m_PicDescriptor->n, dimensions, sizeof(mitkIpUInt4_t)*(dimension<=_mitkIpPicNDIM?dimension:_mitkIpPicNDIM)); unsigned char i; for(i=dimension; i < _mitkIpPicNDIM; ++i) m_PicDescriptor->n[i] = 1; m_Size = _mitkIpPicSize(m_PicDescriptor); if(m_Data == NULL) { m_Data = mitk::MemoryUtilities::AllocateElements( m_Size ); m_ManageMemory = true; } m_PicDescriptor->data=m_Data; m_ReferenceCountLock.Lock(); m_ReferenceCount = 0; m_ReferenceCountLock.Unlock(); } +mitk::ImageDataItem::ImageDataItem(const ImageDataItem &other) + : m_PixelType(other.m_PixelType), m_ManageMemory(other.m_ManageMemory), m_Offset(other.m_Offset), + m_IsComplete(other.m_IsComplete), m_Size(other.m_Size) +{ + +} + void mitk::ImageDataItem::ConstructVtkImageData() const { vtkImageData *inData = vtkImageData::New(); vtkDataArray *scalars = NULL; unsigned long size = 0; if ( m_PicDescriptor->dim == 1 ) { inData->SetDimensions( m_PicDescriptor->n[0] -1, 1, 1); size = m_PicDescriptor->n[0]; inData->SetOrigin( ((float) m_PicDescriptor->n[0]) / 2.0f, 0, 0 ); } else if ( m_PicDescriptor->dim == 2 ) { inData->SetDimensions( m_PicDescriptor->n[0] , m_PicDescriptor->n[1] , 1 ); size = m_PicDescriptor->n[0] * m_PicDescriptor->n[1]; inData->SetOrigin( ((float) m_PicDescriptor->n[0]) / 2.0f, ((float) m_PicDescriptor->n[1]) / 2.0f, 0 ); } else if ( m_PicDescriptor->dim >= 3 ) { inData->SetDimensions( m_PicDescriptor->n[0], m_PicDescriptor->n[1], m_PicDescriptor->n[2] ); size = m_PicDescriptor->n[0] * m_PicDescriptor->n[1] * m_PicDescriptor->n[2]; // Test //inData->SetOrigin( (float) m_PicDescriptor->n[0] / 2.0f, (float) m_PicDescriptor->n[1] / 2.0f, (float) m_PicDescriptor->n[2] / 2.0f ); inData->SetOrigin( 0, 0, 0 ); } else { inData->Delete () ; return; } inData->SetNumberOfScalarComponents(m_PixelType.GetNumberOfComponents()); if ( ( m_PixelType.GetType() == mitkIpPicInt || m_PixelType.GetType() == mitkIpPicUInt ) && m_PixelType.GetBitsPerComponent() == 1 ) { inData->SetScalarType( VTK_BIT ); scalars = vtkBitArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicInt && m_PixelType.GetBitsPerComponent() == 8 ) { inData->SetScalarType( VTK_CHAR ); scalars = vtkCharArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicUInt && m_PixelType.GetBitsPerComponent() == 8 ) { inData->SetScalarType( VTK_UNSIGNED_CHAR ); scalars = vtkUnsignedCharArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicInt && m_PixelType.GetBitsPerComponent() == 16 ) { inData->SetScalarType( VTK_SHORT ); scalars = vtkShortArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicUInt && m_PixelType.GetBitsPerComponent() == 16 ) { inData->SetScalarType( VTK_UNSIGNED_SHORT ); scalars = vtkUnsignedShortArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicInt && m_PixelType.GetBitsPerComponent() == 32 ) { inData->SetScalarType( VTK_INT ); scalars = vtkIntArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicUInt && m_PixelType.GetBitsPerComponent() == 32 ) { inData->SetScalarType( VTK_UNSIGNED_INT ); scalars = vtkUnsignedIntArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicInt && m_PixelType.GetBitsPerComponent() == 64 ) { inData->SetScalarType( VTK_LONG ); scalars = vtkLongArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicUInt && m_PixelType.GetBitsPerComponent() == 64 ) { inData->SetScalarType( VTK_UNSIGNED_LONG ); scalars = vtkUnsignedLongArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicFloat && m_PixelType.GetBitsPerComponent() == 32 ) { inData->SetScalarType( VTK_FLOAT ); scalars = vtkFloatArray::New(); } else if ( m_PixelType.GetType() == mitkIpPicFloat && m_PixelType.GetBitsPerComponent() == 64 ) { inData->SetScalarType( VTK_DOUBLE ); scalars = vtkDoubleArray::New(); } else { inData->Delete(); return; } m_VtkImageData = inData; // allocate the new scalars scalars->SetNumberOfComponents(m_VtkImageData->GetNumberOfScalarComponents()); scalars->SetVoidArray(m_PicDescriptor->data, _mitkIpPicElements(m_PicDescriptor)*m_VtkImageData->GetNumberOfScalarComponents(), 1); m_VtkImageData->GetPointData()->SetScalars(scalars); scalars->Delete(); } void mitk::ImageDataItem::Modified() const { if(m_VtkImageData) m_VtkImageData->Modified(); } diff --git a/Core/Code/DataManagement/mitkImageDataItem.h b/Core/Code/DataManagement/mitkImageDataItem.h index b1bad1d95f..9cc0ad757d 100644 --- a/Core/Code/DataManagement/mitkImageDataItem.h +++ b/Core/Code/DataManagement/mitkImageDataItem.h @@ -1,136 +1,137 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef IMAGEDATAITEM_H #define IMAGEDATAITEM_H #include "mitkCommon.h" #include "mitkPixelType.h" class vtkImageData; namespace mitk { //##Documentation //## @brief Internal class for managing references on sub-images //## //## ImageDataItem is a container for image data which is used internal in //## mitk::Image to handle the communication between the different data types for images //## used in MITK (ipPicDescriptor, mitk::Image, vtkImageData). Common for these image data //## types is the actual image data, but they differ in representation of pixel type etc. //## The class is also used to convert ipPic images to vtkImageData. //## //## The class is mainly used to extract sub-images inside of mitk::Image, like single slices etc. //## It should not be used outside of this. //## //## @param manageMemory Determines if image data is removed while destruction of ImageDataItem or not. //## @ingroup Data class MITK_CORE_EXPORT ImageDataItem : public itk::LightObject { public: mitkClassMacro(ImageDataItem, itk::LightObject); ImageDataItem(const ImageDataItem& aParent, unsigned int dimension, void *data = NULL, bool manageMemory = false, size_t offset = 0); ~ImageDataItem(); ImageDataItem(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, void *data, bool manageMemory); + ImageDataItem(const ImageDataItem &other); void* GetData() const { return m_Data; } bool IsComplete() const { return m_IsComplete; } void SetComplete(bool complete) { m_IsComplete = complete; } int GetOffset() const { return m_Offset; } PixelType GetPixelType() const { return m_PixelType; } ImageDataItem::ConstPointer GetParent() const { return m_Parent; } mitkIpPicDescriptor* GetPicDescriptor() const { return m_PicDescriptor; } //## Returns a vtkImageData; if non is present, a new one is constructed. vtkImageData* GetVtkImageData() const { if(m_VtkImageData==NULL) ConstructVtkImageData(); return m_VtkImageData; } // Returns if image data should be deleted on destruction of ImageDataItem. bool GetManageMemory() const { return m_ManageMemory; } virtual void ConstructVtkImageData() const; unsigned long GetSize() const { return m_Size; } virtual void Modified() const; protected: unsigned char* m_Data; PixelType m_PixelType; bool m_ManageMemory; mitkIpPicDescriptor* m_PicDescriptor; mutable vtkImageData* m_VtkImageData; int m_Offset; bool m_IsComplete; unsigned long m_Size; private: ImageDataItem::ConstPointer m_Parent; template unsigned char *ConvertTensorsToRGB() const; }; } // namespace mitk #endif /* IMAGEDATAITEM_H */ diff --git a/Core/Code/Testing/CMakeLists.txt b/Core/Code/Testing/CMakeLists.txt index 19897d57e1..63b08c7cc0 100644 --- a/Core/Code/Testing/CMakeLists.txt +++ b/Core/Code/Testing/CMakeLists.txt @@ -1,32 +1,34 @@ MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) # MITK_INSTALL_TARGETS(EXECUTABLES MitkTestDriver) mitkAddCustomModuleTest(mitkPicFileReaderTest_emptyFile mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic) mitkAddCustomModuleTest(mitkPicFileReaderTest_emptyGzipFile mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic.gz) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_CT mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-ct.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_MR mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-mr.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_SC mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-sc.dcm) mitkAddCustomModuleTest(mitkEventMapperTest_Test1And2 mitkEventMapperTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.pic.gz) mitkAddCustomModuleTest(mitkStateMachineFactoryTest_TestStateMachine1_2 mitkStateMachineFactoryTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) ADD_TEST(mitkPointSetLocaleTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPointSetLocaleTest ${MITK_DATA_DIR}/pointSet.mps) SET_PROPERTY(TEST mitkPointSetLocaleTest PROPERTY LABELS MITK-Core) ADD_TEST(mitkPicFileReaderTest_emptyGzipFile ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPicFileReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/emptyFile.pic.gz) SET_PROPERTY(TEST mitkPicFileReaderTest_emptyGzipFile PROPERTY LABELS MITK-Core) ADD_TEST(mitkImageTest_brainImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageTest ${MITK_DATA_DIR}/brain.mhd) SET_PROPERTY(TEST mitkImageTest_brainImage PROPERTY LABELS MITK-Core) +ADD_TEST(mitkImageTest_4DImageData ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageTest ${MITK_DATA_DIR}/US4DCyl.pic.gz) +SET_PROPERTY(TEST mitkImageTest_4DImageData PROPERTY LABELS MITK-Core) ADD_TEST(mitkImageWriterTest_nrrdImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) SET_PROPERTY(TEST mitkImageWriterTest_nrrdImage PROPERTY LABELS MITK-Core) add_subdirectory(DICOMTesting) diff --git a/Core/Code/Testing/mitkImageTest.cpp b/Core/Code/Testing/mitkImageTest.cpp index 976c0185e0..c911017441 100644 --- a/Core/Code/Testing/mitkImageTest.cpp +++ b/Core/Code/Testing/mitkImageTest.cpp @@ -1,486 +1,495 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include #include #include #include #include #include #include #include #include int mitkImageTest(int argc, char* argv[]) { MITK_TEST_BEGIN(mitkImageTest); //Create Image out of nowhere mitk::Image::Pointer imgMem; mitk::PixelType pt(typeid(int)); unsigned int dim[]={100,100,20}; std::cout << "Testing creation of Image: "; imgMem=mitk::Image::New(); if(imgMem.IsNull()) { std::cout<<"[FAILED]"<Initialize(mitk::PixelType(typeid(int)), 3, dim); std::cout<<"[PASSED]"<IsInitialized()==false) { std::cout<<"[FAILED]"<GetData(); if(p==NULL) { std::cout<<"[FAILED]"<GetData(); if(p2==NULL) { std::cout<<"[FAILED]"<IsInitialized()==false) { std::cout<<"[FAILED]"<GetSliceData(dim[2]/2)->GetData(); unsigned int xy_size = dim[0]*dim[1]; unsigned int start_mid_slice = (dim[2]/2)*xy_size; for(i=0; iGetSliceData(dim[2]/2)->GetPicDescriptor()); imgMem=mitk::Image::New(); std::cout << "Testing reinitializing via Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions): "; imgMem->Initialize(mitk::PixelType(typeid(int)), 3, dim); std::cout<<"[PASSED]"<SetPicSlice(pic_slice, i, 0, 0); } std::cout<<"[PASSED]"<GetData(); if(p2==NULL) { std::cout<<"[FAILED]"<IsInitialized()==false) { std::cout<<"[FAILED]"<SetPicVolume(mitkIpPicClone(imgMem->GetVolumeData(0)->GetPicDescriptor()),0); std::cout<<"[PASSED]"<data,0,xy_size*sizeof(int)); imgMem->SetPicSlice(pic_slice, 1); std::cout << "Getting the volume again and compare the check the changed slice: "; p2 = (int*)imgMem->GetData(); if(p2==NULL) { std::cout<<"[FAILED]"<SetVolume(imgMem->GetData()); std::cout<<"[PASSED]"<data,0,xy_size*sizeof(int)); imgMem->SetSlice(pic_slice->data, 0); std::cout << "Getting the volume again and compare the check the changed slice: "; p2 = (int*)imgMem->GetData(); if(p2==NULL) { std::cout<<"[FAILED]"<SetVolume(data); //std::cout<<"[PASSED]"<InitializeStandardPlane(100, 100, right, bottom, &spacing); planegeometry->SetOrigin(origin); std::cout << "done" << std::endl; std::cout << "Testing Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int slices) with PlaneGeometry and GetData(): "; imgMem->Initialize(mitk::PixelType(typeid(int)), *planegeometry); p = (int*)imgMem->GetData(); if(p==NULL) { std::cout<<"[FAILED]"<Initialize(mitk::PixelType(typeid(int)), 40, *planegeometry); p = (int*)imgMem->GetData(); if(p==NULL) { std::cout<<"[FAILED]"<GetOrigin(): "; if( mitk::Equal(imgMem->GetGeometry()->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<GetOrigin(): "; if( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<SetOrigin(origin); std::cout<<"[PASSED]"<GetOrigin(): "; if( mitk::Equal(imgMem->GetGeometry()->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<GetOrigin(): "; if( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<GetGeometry2D(0)->GetOrigin(): "; if( mitk::Equal(imgMem->GetSlicedGeometry()->GetGeometry2D(0)->GetOrigin(), origin) == false) { std::cout<<"[FAILED]"<GetSpacing(): "; if( mitk::Equal(imgMem->GetGeometry()->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<GetSpacing(): "; if( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<SetSpacing(spacing); std::cout<<"[PASSED]"<GetSpacing(): "; if( mitk::Equal(imgMem->GetGeometry()->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<GetSpacing(): "; if( mitk::Equal(imgMem->GetTimeSlicedGeometry()->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<GetGeometry2D(0)->GetSpacing(): "; if( mitk::Equal(imgMem->GetSlicedGeometry()->GetGeometry2D(0)->GetSpacing(), spacing) == false) { std::cout<<"[FAILED]"<Initialize(*imgMem->GetPixelType().GetTypeId(), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/ ); vecImg->SetImportChannel(imgMem->GetData(), 0, mitk::Image::CopyMemory ); vecImg->SetImportChannel(imgMem->GetData(), 1, mitk::Image::CopyMemory ); std::cout<<"[PASSED]"<IsValidSlice(0,0,1) , ""); MITK_TEST_OUTPUT(<< " Testing whether CopyMemory worked"); MITK_TEST_CONDITION_REQUIRED(imgMem->GetData() != vecImg->GetData(), ""); MITK_TEST_OUTPUT(<< " Testing destruction after SetImportChannel"); vecImg = NULL; std::cout<<"[PASSED]"<Initialize(); vtkimage->SetDimensions( 2, 3, 4); double vtkorigin[] = {-350,-358.203, -1363.5}; vtkimage->SetOrigin(vtkorigin); mitk::Point3D vtkoriginAsMitkPoint; mitk::vtk2itk(vtkorigin, vtkoriginAsMitkPoint); double vtkspacing[] = {1.367, 1.367, 2}; vtkimage->SetSpacing(vtkspacing); vtkimage->SetScalarType( VTK_SHORT ); vtkimage->AllocateScalars(); std::cout<<"[PASSED]"<Initialize(vtkimage); MITK_TEST_CONDITION_REQUIRED(mitkByVtkImage->IsInitialized(), ""); MITK_TEST_OUTPUT(<< " vtkimage->Delete"); vtkimage->Delete(); std::cout<<"[PASSED]"<GetGeometry()->GetSpacing(); mitk::Vector3D vtkspacingAsMitkVector; mitk::vtk2itk(vtkspacing, vtkspacingAsMitkVector); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(spacing2,vtkspacingAsMitkVector), ""); MITK_TEST_OUTPUT(<< " Testing whether GetSlicedGeometry(0)->GetOrigin() has been correctly initialized from vtkImageData"); mitk::Point3D origin2 = mitkByVtkImage->GetSlicedGeometry(0)->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); MITK_TEST_OUTPUT(<< " Testing whether GetGeometry()->GetOrigin() has been correctly initialized from vtkImageData"); origin2 = mitkByVtkImage->GetGeometry()->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); MITK_TEST_OUTPUT(<< " Testing whether GetTimeSlicedGeometry()->GetOrigin() has been correctly initialized from vtkImageData"); origin2 = mitkByVtkImage->GetTimeSlicedGeometry()->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2,vtkoriginAsMitkPoint), ""); // TODO test the following initializers on channel-incorporation // void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, unsigned int channels) // void mitk::Image::Initialize(const mitk::PixelType& type, int sDim, const mitk::Geometry2D& geometry2d, bool flipped, unsigned int channels, int tDim ) // void mitk::Image::Initialize(const mitk::Image* image) // void mitk::Image::Initialize(const mitkIpPicDescriptor* pic, int channels, int tDim, int sDim) //mitk::Image::Pointer vecImg = mitk::Image::New(); //vecImg->Initialize(PixelType(typeid(float), 6, itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/, false /*shiftBoundingBoxMinimumToZero*/ ); //vecImg->Initialize(PixelType(typeid(itk::Vector)), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/, false /*shiftBoundingBoxMinimumToZero*/ ); // testing access by index coordinates and by world coordinates mitk::DataNode::Pointer node; mitk::DataNodeFactory::Pointer nodeReader = mitk::DataNodeFactory::New(); MITK_TEST_CONDITION_REQUIRED(argc == 2, "Check if test image is accessible!"); + const std::string filename = std::string(argv[1]); try { - const std::string filename = std::string(argv[1]); nodeReader->SetFileName(filename); nodeReader->Update(); node = nodeReader->GetOutput(); } catch(...) { - MITK_TEST_FAILED_MSG(<< "Could not read file for testing: " << "brain.mhd"); + MITK_TEST_FAILED_MSG(<< "Could not read file for testing: " << filename); return NULL; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); // test by index coordinates mitk::Index3D index; mitk::FillVector3D(index, 55, 39, 50); MITK_TEST_OUTPUT(<< "Testing mitk::Image::GetPixelValueByIndex"); double val = image->GetPixelValueByIndex(index); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(val,112.22475433349609), ""); //test by world coordinates MITK_TEST_OUTPUT(<< "Testing mitk::Image::GetPixelValueByWorldCoordinate"); mitk::Point3D point; mitk::FillVector3D(point, -5.93752, 18.7199, 6.74218); val = image->GetPixelValueByWorldCoordinate(point); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(val,94.456184387207031), ""); MITK_TEST_OUTPUT(<< "Convert to index and access value by mitk::Image::GetPixelValueByIndex again"); mitk::Index3D index2; image->GetGeometry()->WorldToIndex(point, index2); float val2 = image->GetPixelValueByIndex(index2); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(val2,94.456184387207031), ""); //access via itk MITK_TEST_OUTPUT(<< "Test conversion to itk::Image"); typedef itk::Image ItkFloatImage3D; ItkFloatImage3D::Pointer itkimage; mitk::CastToItkImage(image, itkimage); std::cout<<"[PASSED]"<itk-physical->world consistency"); mitk::Point3D itkPhysicalPoint; image->GetGeometry()->WorldToItkPhysicalPoint(point, itkPhysicalPoint); mitk::Point3D backTransformedPoint; image->GetGeometry()->ItkPhysicalPointToWorld(itkPhysicalPoint, backTransformedPoint); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(point,backTransformedPoint), ""); MITK_TEST_OUTPUT(<< "Compare value of pixel returned by mitk in comparison to itk"); itk::Index<3> idx; itkimage->TransformPhysicalPointToIndex(itkPhysicalPoint, idx); float valByItk = itkimage->GetPixel(idx); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(valByItk,94.456184387207031), ""); + mitk::Image::Pointer cloneImage = image->Clone(); + MITK_TEST_CONDITION_REQUIRED(cloneImage->GetDimension() == image->GetDimension(), "Clone (testing dimension)"); + MITK_TEST_CONDITION_REQUIRED(cloneImage->GetPixelType() == image->GetPixelType(), "Clone (testing pixel type)"); + + for (unsigned int i = 0u; i < cloneImage->GetDimension(); ++i) + { + MITK_TEST_CONDITION_REQUIRED(cloneImage->GetDimension(i) == image->GetDimension(i), "Clone (testing dimension " << i << ")"); + } + MITK_TEST_END(); return EXIT_SUCCESS; } diff --git a/Core/Code/Testing/mitkSurfaceTest.cpp b/Core/Code/Testing/mitkSurfaceTest.cpp index c25d9db9a1..b3d7420f00 100644 --- a/Core/Code/Testing/mitkSurfaceTest.cpp +++ b/Core/Code/Testing/mitkSurfaceTest.cpp @@ -1,153 +1,153 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkSurface.h" #include "mitkCommon.h" #include "mitkVector.h" #include "mitkTestingMacros.h" #include "mitkTimeSlicedGeometry.h" #include "vtkPolyData.h" #include "vtkSphereSource.h" #include int mitkSurfaceTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("Surface"); mitk::Surface::Pointer surface = mitk::Surface::New(); MITK_TEST_CONDITION_REQUIRED( surface.GetPointer(), "Testing initialization!" ); mitk::Surface::Pointer cloneSurface = surface->Clone(); MITK_TEST_CONDITION_REQUIRED( cloneSurface.GetPointer(), "Testing clone surface initialization!" ); std::filebuf fb; - std::ostream s = std::ostream(&fb); - surface->PrintSelf( s, 0); - MITK_INFO<PrintSelf( s, 0); +// MITK_INFO<SetCenter(0,0,0); sphereSource->SetRadius(5.0); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); vtkPolyData* polys = sphereSource->GetOutput(); MITK_TEST_CONDITION_REQUIRED(surface->GetVtkPolyData() == NULL, "Testing initial state of vtkPolyData"); surface->SetVtkPolyData( polys ); sphereSource->Delete(); MITK_TEST_CONDITION_REQUIRED(surface->GetVtkPolyData()!= NULL, "Testing set vtkPolyData"); cloneSurface = surface->Clone(); MITK_TEST_CONDITION_REQUIRED(cloneSurface->GetVtkPolyData()!= NULL, "Testing set vtkPolyData of cloned surface!"); vtkFloatingPointType bounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; polys->ComputeBounds(); polys->GetBounds( bounds ); surface->UpdateOutputInformation(); surface->SetRequestedRegionToLargestPossibleRegion(); mitk::BoundingBox* bb = const_cast(surface->GetGeometry()->GetBoundingBox()); mitk::BoundingBox::BoundsArrayType surfBounds = bb->GetBounds(); bool passed = false; if ( bounds[0] == surfBounds[0] && bounds[1] == surfBounds[1] && bounds[2] == surfBounds[2] && bounds[3] == surfBounds[3] && bounds[4] == surfBounds[4] && bounds[5] == surfBounds[5] ) { passed = true; } MITK_TEST_CONDITION_REQUIRED(passed, "Testing GetBoundingBox()!"); surface->Expand(5); surface->Update(); surface->SetRequestedRegionToLargestPossibleRegion(); mitk::Surface::RegionType requestedRegion = surface->GetRequestedRegion(); MITK_TEST_CONDITION_REQUIRED(requestedRegion.GetSize(3) == 5, "Testing mitk::Surface::Expand( timesteps ): "); vtkFloatingPointType boundsMat[5][6]; for (int i=0;i<5;i++) { vtkSphereSource* sphereSource = vtkSphereSource::New(); sphereSource->SetCenter(0,0,0); sphereSource->SetRadius(1.0 * (i+1.0)); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); sphereSource->GetOutput()->ComputeBounds(); sphereSource->GetOutput()->GetBounds( boundsMat[i] ); surface->SetVtkPolyData( sphereSource->GetOutput(),i ); sphereSource->Delete(); } surface->UpdateOutputInformation(); surface->SetRequestedRegionToLargestPossibleRegion(); passed = true; for (int i=0;i<5;i++) { mitk::BoundingBox::BoundsArrayType surfBounds = (const_cast(surface->GetTimeSlicedGeometry()->GetGeometry3D(i)->GetBoundingBox()))->GetBounds(); if ( boundsMat[i][0] != surfBounds[0] || boundsMat[i][1] != surfBounds[1] || boundsMat[i][2] != surfBounds[2] || boundsMat[i][3] != surfBounds[3] || boundsMat[i][4] != surfBounds[4] || boundsMat[i][5] != surfBounds[5] ) { passed = false; break; } } MITK_TEST_CONDITION_REQUIRED(passed, "Testing mitk::Surface::Testing 4D surface data creation!" ); const mitk::TimeSlicedGeometry* inputTimeGeometry = surface->GetUpdatedTimeSlicedGeometry(); int time = 3; int timestep=0; timestep = inputTimeGeometry->MSToTimeStep( time ); MITK_TEST_CONDITION_REQUIRED(time == timestep, "Testing correctness of geometry for surface->GetUpdatedTimeSlicedGeometry()!"); sphereSource = vtkSphereSource::New(); sphereSource->SetCenter(0,0,0); sphereSource->SetRadius( 100.0 ); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); surface->SetVtkPolyData( sphereSource->GetOutput(), 3 ); sphereSource->Delete(); inputTimeGeometry = surface->GetUpdatedTimeSlicedGeometry(); time = 3; timestep=0; timestep = inputTimeGeometry->MSToTimeStep( time ); MITK_TEST_CONDITION_REQUIRED(time == timestep, "Explicitly changing the data of timestep 3 and checking for timebounds correctness of surface's geometry again!"); unsigned int numberoftimesteps = surface->GetTimeSteps(); mitk::Surface::Pointer dummy = mitk::Surface::New(); dummy->Graft(surface); MITK_TEST_CONDITION_REQUIRED( dummy->GetVtkPolyData() != NULL, "Testing copying a Surface with Graft()!"); MITK_TEST_CONDITION_REQUIRED( dummy->GetTimeSteps() == numberoftimesteps, "orig-numberofTimeSteps:" << numberoftimesteps << " copy-numberofTimeSteps:" << dummy->GetTimeSteps()); MITK_TEST_END(); }