diff --git a/BlueBerry/Bundles/org.blueberry.core.expressions/CMakeLists.txt b/BlueBerry/Bundles/org.blueberry.core.expressions/CMakeLists.txt index d96a425db9..9c6ed4592a 100644 --- a/BlueBerry/Bundles/org.blueberry.core.expressions/CMakeLists.txt +++ b/BlueBerry/Bundles/org.blueberry.core.expressions/CMakeLists.txt @@ -1,4 +1,4 @@ project(org_blueberry_core_expressions) MACRO_CREATE_CTK_PLUGIN(EXPORT_DIRECTIVE BERRY_EXPRESSIONS - EXPORTED_INCLUDE_SUFFIXES src src/common) + EXPORTED_INCLUDE_SUFFIXES src) diff --git a/BlueBerry/Bundles/org.blueberry.ui/CMakeLists.txt b/BlueBerry/Bundles/org.blueberry.ui/CMakeLists.txt index 99825e877d..1a06997513 100644 --- a/BlueBerry/Bundles/org.blueberry.ui/CMakeLists.txt +++ b/BlueBerry/Bundles/org.blueberry.ui/CMakeLists.txt @@ -1,19 +1,18 @@ project(org_blueberry_ui) set(PLUGIN_exported_include_suffixes src src/application - src/commands src/dialogs src/guitk src/handlers src/intro src/presentations src/services src/testing src/tweaklets src/util ) MACRO_CREATE_CTK_PLUGIN(EXPORT_DIRECTIVE BERRY_UI EXPORTED_INCLUDE_SUFFIXES ${PLUGIN_exported_include_suffixes}) diff --git a/Core/Code/DataManagement/mitkPointSet.cpp b/Core/Code/DataManagement/mitkPointSet.cpp index 3266246244..6f1c7cf49f 100755 --- a/Core/Code/DataManagement/mitkPointSet.cpp +++ b/Core/Code/DataManagement/mitkPointSet.cpp @@ -1,880 +1,879 @@ /*=================================================================== 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 "mitkPointSet.h" #include "mitkPointOperation.h" #include "mitkInteractionConst.h" #include #include -mitk::PointSet::PointSet() +mitk::PointSet::PointSet() : m_CalculateBoundingBox(true) { this->InitializeEmpty(); } mitk::PointSet::PointSet(const PointSet &other) : BaseData(other) , m_PointSetSeries(other.GetPointSetSeriesSize()) , m_CalculateBoundingBox(true) { // Copy points for (std::size_t t = 0; t < m_PointSetSeries.size(); ++t) { m_PointSetSeries[t] = DataType::New(); DataType::Pointer otherPts = other.GetPointSet(t); for (PointsConstIterator i = other.Begin(t); i != other.End(t); ++i) { m_PointSetSeries[t]->SetPoint(i.Index(), i.Value()); PointDataType pointData; if (otherPts->GetPointData(i.Index(), &pointData)) { m_PointSetSeries[t]->SetPointData(i.Index(), pointData); } } } } mitk::PointSet::~PointSet() { this->ClearData(); } void mitk::PointSet::ClearData() { m_PointSetSeries.clear(); Superclass::ClearData(); } void mitk::PointSet::InitializeEmpty() { m_PointSetSeries.resize( 1 ); m_PointSetSeries[0] = DataType::New(); PointDataContainer::Pointer pointData = PointDataContainer::New(); m_PointSetSeries[0]->SetPointData( pointData ); m_CalculateBoundingBox = false; Superclass::InitializeTimeGeometry(1); m_Initialized = true; } bool mitk::PointSet::IsEmptyTimeStep(unsigned int t) const { return IsInitialized() && (GetSize(t) == 0); } void mitk::PointSet::Expand( unsigned int timeSteps ) { // Check if the vector is long enough to contain the new element // at the given position. If not, expand it with sufficient pre-initialized // elements. // // NOTE: This method will never REDUCE the vector size; it should only // be used to make sure that the vector has enough elements to include the // specified time step. unsigned int oldSize = m_PointSetSeries.size(); if ( timeSteps > oldSize ) { Superclass::Expand( timeSteps ); m_PointSetSeries.resize( timeSteps ); for ( unsigned int i = oldSize; i < timeSteps; ++i ) { m_PointSetSeries[i] = DataType::New(); PointDataContainer::Pointer pointData = PointDataContainer::New(); m_PointSetSeries[i]->SetPointData( pointData ); } //if the size changes, then compute the bounding box m_CalculateBoundingBox = true; this->InvokeEvent( PointSetExtendTimeRangeEvent() ); } } unsigned int mitk::PointSet::GetPointSetSeriesSize() const { return m_PointSetSeries.size(); } int mitk::PointSet::GetSize( unsigned int t ) const { if ( t < m_PointSetSeries.size() ) { return m_PointSetSeries[t]->GetNumberOfPoints(); } else { return 0; } } mitk::PointSet::DataType::Pointer mitk::PointSet::GetPointSet( int t ) const { if ( t < (int)m_PointSetSeries.size() ) { return m_PointSetSeries[t]; } else { return NULL; } } mitk::PointSet::PointsIterator mitk::PointSet::Begin( int t ) { if (t >= 0 && t < static_cast(m_PointSetSeries.size())) { return m_PointSetSeries[t]->GetPoints()->Begin(); } return PointsIterator(); } mitk::PointSet::PointsConstIterator mitk::PointSet::Begin(int t) const { if (t >= 0 && t < static_cast(m_PointSetSeries.size())) { return m_PointSetSeries[t]->GetPoints()->Begin(); } return PointsConstIterator(); } mitk::PointSet::PointsIterator mitk::PointSet::End( int t ) { if (t >= 0 && t < static_cast(m_PointSetSeries.size())) { return m_PointSetSeries[t]->GetPoints()->End(); } return PointsIterator(); } mitk::PointSet::PointsConstIterator mitk::PointSet::End(int t) const { if (t >= 0 && t < static_cast(m_PointSetSeries.size())) { return m_PointSetSeries[t]->GetPoints()->End(); } return PointsConstIterator(); } int mitk::PointSet::SearchPoint( Point3D point, ScalarType distance, int t ) const { if ( t >= (int)m_PointSetSeries.size() ) { return -1; } // Out is the point which is checked to be the searched point PointType out; out.Fill( 0 ); PointType indexPoint; this->GetGeometry( t )->WorldToIndex(point, indexPoint); // Searching the first point in the Set, that is +- distance far away fro // the given point unsigned int i; PointsContainer::Iterator it, end; end = m_PointSetSeries[t]->GetPoints()->End(); int bestIndex = -1; distance = distance * distance; // To correct errors from converting index to world and world to index if (distance == 0.0) { distance = 0.000001; } ScalarType bestDist = distance; ScalarType dist, tmp; for ( it = m_PointSetSeries[t]->GetPoints()->Begin(), i = 0; it != end; ++it, ++i ) { bool ok = m_PointSetSeries[t]->GetPoints() ->GetElementIfIndexExists( it->Index(), &out ); if ( !ok ) { return -1; } else if ( indexPoint == out ) //if totally equal { return it->Index(); } //distance calculation tmp = out[0] - indexPoint[0]; dist = tmp * tmp; tmp = out[1] - indexPoint[1]; dist += tmp * tmp; tmp = out[2] - indexPoint[2]; dist += tmp * tmp; if ( dist < bestDist ) { bestIndex = it->Index(); bestDist = dist; } } return bestIndex; } mitk::PointSet::PointType mitk::PointSet::GetPoint( PointIdentifier id, int t ) const { PointType out; out.Fill(0); if ( (unsigned int) t >= m_PointSetSeries.size() ) { return out; } if ( m_PointSetSeries[t]->GetPoints()->IndexExists(id) ) { m_PointSetSeries[t]->GetPoint( id, &out ); this->GetGeometry(t)->IndexToWorld( out, out ); return out; } else { return out; } } bool mitk::PointSet ::GetPointIfExists( PointIdentifier id, PointType* point, int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return false; } if ( m_PointSetSeries[t]->GetPoints()->GetElementIfIndexExists(id, point) ) { this->GetGeometry( t )->IndexToWorld( *point, *point ); return true; } else { return false; } } void mitk::PointSet::SetPoint( PointIdentifier id, PointType point, int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); mitk::Point3D indexPoint; this->GetGeometry( t )->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->SetPoint( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = mitk::PTUNDEFINED; m_PointSetSeries[t]->SetPointData( id, defaultPointData ); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } void mitk::PointSet::SetPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ) { // Adapt the size of the data vector if necessary this->Expand( t+1 ); mitk::Point3D indexPoint; this->GetGeometry( t )->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->SetPoint( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = spec; m_PointSetSeries[t]->SetPointData( id, defaultPointData ); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } void mitk::PointSet::InsertPoint( PointIdentifier id, PointType point, int t ) { this->InsertPoint(id, point, mitk::PTUNDEFINED, t); } void mitk::PointSet::InsertPoint( PointIdentifier id, PointType point, PointSpecificationType spec, int t ) { if ( (unsigned int) t < m_PointSetSeries.size() ) { mitk::Point3D indexPoint; mitk::BaseGeometry* tempGeometry = this->GetGeometry( t ); if (tempGeometry == NULL) { MITK_INFO<< __FILE__ << ", l." << __LINE__ << ": GetGeometry of "<< t <<" returned NULL!" << std::endl; return; } tempGeometry->WorldToIndex( point, indexPoint ); m_PointSetSeries[t]->GetPoints()->InsertElement( id, indexPoint ); PointDataType defaultPointData; defaultPointData.id = id; defaultPointData.selected = false; defaultPointData.pointSpec = spec; m_PointSetSeries[t]->GetPointData()->InsertElement(id, defaultPointData); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->Modified(); } } - bool mitk::PointSet::SwapPointPosition( PointIdentifier id, bool moveUpwards, int t ) { if(IndexExists(id, t) ) { PointType point = GetPoint(id,t); if(moveUpwards) {//up if(IndexExists(id-1,t)) { InsertPoint(id, GetPoint(id - 1, t), t); InsertPoint(id-1,point,t); this->Modified(); return true; } } else {//down if(IndexExists(id+1,t)) { InsertPoint(id, GetPoint(id + 1, t), t); InsertPoint(id+1,point,t); this->Modified(); return true; } } } return false; } bool mitk::PointSet::IndexExists( int position, int t ) const { if ( (unsigned int) t < m_PointSetSeries.size() ) { return m_PointSetSeries[t]->GetPoints()->IndexExists( position ); } else { return false; } } bool mitk::PointSet::GetSelectInfo( int position, int t ) const { if ( this->IndexExists( position, t ) ) { PointDataType pointData = { 0, false, PTUNDEFINED }; m_PointSetSeries[t]->GetPointData( position, &pointData ); return pointData.selected; } else { return false; } } void mitk::PointSet::SetSelectInfo( int position, bool selected, int t ) { if ( this->IndexExists( position, t ) ) { // timeStep to ms TimePointType timeInMS = this->GetTimeGeometry()->TimeStepToTimePoint( t ); // point Point3D point = this->GetPoint( position, t ); std::auto_ptr op; if (selected) { op.reset(new mitk::PointOperation(OpSELECTPOINT, timeInMS, point, position )); } else { op.reset(new mitk::PointOperation(OpDESELECTPOINT, timeInMS, point, position )); } this->ExecuteOperation( op.get() ); } } mitk::PointSpecificationType mitk::PointSet::GetSpecificationTypeInfo( int position, int t ) const { if ( this->IndexExists( position, t ) ) { PointDataType pointData = { 0, false, PTUNDEFINED }; m_PointSetSeries[t]->GetPointData( position, &pointData ); return pointData.pointSpec; } else { return PTUNDEFINED; } } int mitk::PointSet::GetNumberOfSelected( int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return 0; } int numberOfSelected = 0; PointDataIterator it; for ( it = m_PointSetSeries[t]->GetPointData()->Begin(); it != m_PointSetSeries[t]->GetPointData()->End(); it++ ) { if (it->Value().selected == true) { ++numberOfSelected; } } return numberOfSelected; } int mitk::PointSet::SearchSelectedPoint( int t ) const { if ( (unsigned int) t >= m_PointSetSeries.size() ) { return -1; } PointDataIterator it; for ( it = m_PointSetSeries[t]->GetPointData()->Begin(); it != m_PointSetSeries[t]->GetPointData()->End(); it++ ) { if ( it->Value().selected == true ) { return it->Index(); } } return -1; } void mitk::PointSet::ExecuteOperation( Operation* operation ) { int timeStep = -1; mitkCheckOperationTypeMacro(PointOperation, operation, pointOp); if ( pointOp ) { timeStep = this->GetTimeGeometry()->TimePointToTimeStep( pointOp->GetTimeInMS() ); } if ( timeStep < 0 ) { MITK_ERROR << "Time step (" << timeStep << ") outside of PointSet time bounds" << std::endl; return; } switch (operation->GetOperationType()) { case OpNOTHING: break; case OpINSERT://inserts the point at the given position and selects it. { int position = pointOp->GetIndex(); PointType pt; pt.CastFrom(pointOp->GetPoint()); //transfer from world to index coordinates mitk::BaseGeometry* geometry = this->GetGeometry( timeStep ); if (geometry == NULL) { MITK_INFO<<"GetGeometry returned NULL!\n"; return; } geometry->WorldToIndex(pt, pt); m_PointSetSeries[timeStep]->GetPoints()->InsertElement(position, pt); PointDataType pointData = { static_cast(pointOp->GetIndex()), pointOp->GetSelected(), pointOp->GetPointType() }; m_PointSetSeries[timeStep]->GetPointData() ->InsertElement(position, pointData); this->Modified(); //boundingbox has to be computed m_CalculateBoundingBox = true; this->InvokeEvent( PointSetAddEvent() ); this->OnPointSetChange(); } break; case OpMOVE://moves the point given by index { PointType pt; pt.CastFrom(pointOp->GetPoint()); //transfer from world to index coordinates this->GetGeometry( timeStep )->WorldToIndex(pt, pt); // Copy new point into container m_PointSetSeries[timeStep]->SetPoint(pointOp->GetIndex(), pt); // Insert a default point data object to keep the containers in sync // (if no point data object exists yet) PointDataType pointData; if ( !m_PointSetSeries[timeStep]->GetPointData( pointOp->GetIndex(), &pointData ) ) { m_PointSetSeries[timeStep]->SetPointData( pointOp->GetIndex(), pointData ); } this->OnPointSetChange(); this->Modified(); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->InvokeEvent( PointSetMoveEvent() ); } break; case OpREMOVE://removes the point at given by position { m_PointSetSeries[timeStep]->GetPoints()->DeleteIndex((unsigned)pointOp->GetIndex()); m_PointSetSeries[timeStep]->GetPointData()->DeleteIndex((unsigned)pointOp->GetIndex()); this->OnPointSetChange(); this->Modified(); //boundingbox has to be computed anyway m_CalculateBoundingBox = true; this->InvokeEvent( PointSetRemoveEvent() ); } break; case OpSELECTPOINT://select the given point { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.selected = true; m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpDESELECTPOINT://unselect the given point { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.selected = false; m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpSETPOINTTYPE: { PointDataType pointData = {0, false, PTUNDEFINED}; m_PointSetSeries[timeStep]->GetPointData(pointOp->GetIndex(), &pointData); pointData.pointSpec = pointOp->GetPointType(); m_PointSetSeries[timeStep]->SetPointData(pointOp->GetIndex(), pointData); this->Modified(); } break; case OpMOVEPOINTUP: // swap content of point with ID pointOp->GetIndex() with the point preceding it in the container // move point position within the pointset { PointIdentifier currentID = pointOp->GetIndex(); /* search for point with this id and point that precedes this one in the data container */ PointsContainer::STLContainerType points = m_PointSetSeries[timeStep]->GetPoints()->CastToSTLContainer(); PointsContainer::STLContainerType::iterator it = points.find(currentID); if (it == points.end()) // ID not found break; if (it == points.begin()) // we are at the first element, there is no previous element break; /* get and cache current point & pointdata and previous point & pointdata */ --it; PointIdentifier prevID = it->first; if (this->SwapPointContents(prevID, currentID, timeStep) == true) this->Modified(); } break; case OpMOVEPOINTDOWN: // move point position within the pointset { PointIdentifier currentID = pointOp->GetIndex(); /* search for point with this id and point that succeeds this one in the data container */ PointsContainer::STLContainerType points = m_PointSetSeries[timeStep]->GetPoints()->CastToSTLContainer(); PointsContainer::STLContainerType::iterator it = points.find(currentID); if (it == points.end()) // ID not found break; ++it; if (it == points.end()) // ID is already the last element, there is no succeeding element break; /* get and cache current point & pointdata and previous point & pointdata */ PointIdentifier nextID = it->first; if (this->SwapPointContents(nextID, currentID, timeStep) == true) this->Modified(); } break; default: itkWarningMacro("mitkPointSet could not understrand the operation. Please check!"); break; } //to tell the mappers, that the data is modified and has to be updated //only call modified if anything is done, so call in cases //this->Modified(); mitk::OperationEndEvent endevent(operation); ((const itk::Object*)this)->InvokeEvent(endevent); //*todo has to be done here, cause of update-pipeline not working yet // As discussed lately, don't mess with the rendering from inside data structures //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PointSet::UpdateOutputInformation() { if ( this->GetSource( ) ) { this->GetSource( )->UpdateOutputInformation( ); } // // first make sure, that the associated time sliced geometry has // the same number of geometry 3d's as PointSets are present // TimeGeometry* timeGeometry = GetTimeGeometry(); if ( timeGeometry->CountTimeSteps() != m_PointSetSeries.size() ) { itkExceptionMacro(<<"timeGeometry->CountTimeSteps() != m_PointSetSeries.size() -- use Initialize(timeSteps) with correct number of timeSteps!"); } // This is needed to detect zero objects mitk::ScalarType nullpoint[]={0,0,0,0,0,0}; BoundingBox::BoundsArrayType itkBoundsNull(nullpoint); // // Iterate over the PointSets and update the Geometry // information of each of the items. // if (m_CalculateBoundingBox) { for ( unsigned int i = 0 ; i < m_PointSetSeries.size() ; ++i ) { const DataType::BoundingBoxType *bb = m_PointSetSeries[i]->GetBoundingBox(); BoundingBox::BoundsArrayType itkBounds = bb->GetBounds(); if ( m_PointSetSeries[i].IsNull() || (m_PointSetSeries[i]->GetNumberOfPoints() == 0) || (itkBounds == itkBoundsNull) ) { itkBounds = itkBoundsNull; continue; } // Ensure minimal bounds of 1.0 in each dimension for ( unsigned int j = 0; j < 3; ++j ) { if ( itkBounds[j*2+1] - itkBounds[j*2] < 1.0 ) { BoundingBox::CoordRepType center = (itkBounds[j*2] + itkBounds[j*2+1]) / 2.0; itkBounds[j*2] = center - 0.5; itkBounds[j*2+1] = center + 0.5; } } this->GetGeometry(i)->SetBounds(itkBounds); } m_CalculateBoundingBox = false; } this->GetTimeGeometry()->Update(); } void mitk::PointSet::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PointSet::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PointSet::VerifyRequestedRegion() { return true; } void mitk::PointSet::SetRequestedRegion(const DataObject * ) { } void mitk::PointSet::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os, indent); os << indent << "Number timesteps: " << m_PointSetSeries.size() << "\n"; unsigned int i = 0; for (PointSetSeries::const_iterator it = m_PointSetSeries.begin(); it != m_PointSetSeries.end(); ++it) { os << indent << "Timestep " << i++ << ": \n"; MeshType::Pointer ps = *it; itk::Indent nextIndent = indent.GetNextIndent(); ps->Print(os, nextIndent); MeshType::PointsContainer* points = ps->GetPoints(); MeshType::PointDataContainer* datas = ps->GetPointData(); MeshType::PointDataContainer::Iterator dataIterator = datas->Begin(); for (MeshType::PointsContainer::Iterator pointIterator = points->Begin(); pointIterator != points->End(); ++pointIterator, ++dataIterator) { os << nextIndent << "Point " << pointIterator->Index() << ": ["; os << pointIterator->Value().GetElement(0); for (unsigned int i = 1; i < PointType::GetPointDimension(); ++i) { os << ", " << pointIterator->Value().GetElement(i); } os << "]"; os << ", selected: " << dataIterator->Value().selected << ", point spec: " << dataIterator->Value().pointSpec << "\n"; } } } bool mitk::PointSet::SwapPointContents(PointIdentifier id1, PointIdentifier id2, int timeStep) { /* search and cache contents */ PointType p1; if (m_PointSetSeries[timeStep]->GetPoint(id1, &p1) == false) return false; PointDataType data1; if (m_PointSetSeries[timeStep]->GetPointData(id1, &data1) == false) return false; PointType p2; if (m_PointSetSeries[timeStep]->GetPoint(id2, &p2) == false) return false; PointDataType data2; if (m_PointSetSeries[timeStep]->GetPointData(id2, &data2) == false) return false; /* now swap contents */ m_PointSetSeries[timeStep]->SetPoint(id1, p2); m_PointSetSeries[timeStep]->SetPointData(id1, data2); m_PointSetSeries[timeStep]->SetPoint(id2, p1); m_PointSetSeries[timeStep]->SetPointData(id2, data1); return true; } bool mitk::PointSet::PointDataType::operator ==(const mitk::PointSet::PointDataType &other) const { return id == other.id && selected == other.selected && pointSpec == other.pointSpec; } bool mitk::Equal( const mitk::PointSet* leftHandSide, const mitk::PointSet* rightHandSide, mitk::ScalarType eps, bool verbose ) { if((leftHandSide == NULL) || (rightHandSide == NULL)) { MITK_ERROR << "mitk::Equal( const mitk::PointSet* leftHandSide, const mitk::PointSet* rightHandSide, mitk::ScalarType eps, bool verbose ) does not work with NULL pointer input."; return false; } return Equal( *leftHandSide, *rightHandSide, eps, verbose); } bool mitk::Equal( const mitk::PointSet& leftHandSide, const mitk::PointSet& rightHandSide, mitk::ScalarType eps, bool verbose ) { bool result = true; if( !mitk::Equal( *leftHandSide.GetGeometry(), *rightHandSide.GetGeometry(), eps, verbose) ) { if(verbose) MITK_INFO << "[( PointSet )] Geometries differ."; result = false; } if ( leftHandSide.GetSize() != rightHandSide.GetSize()) { if(verbose) MITK_INFO << "[( PointSet )] Number of points differ."; result = false; } else { //if the size is equal, we compare the point values mitk::Point3D pointLeftHandSide; mitk::Point3D pointRightHandSide; int numberOfIncorrectPoints = 0; //Iterate over both pointsets in order to compare all points pair-wise mitk::PointSet::PointsConstIterator end = leftHandSide.End(); for( mitk::PointSet::PointsConstIterator pointSetIteratorLeft = leftHandSide.Begin(), pointSetIteratorRight = rightHandSide.Begin(); pointSetIteratorLeft != end; ++pointSetIteratorLeft, ++pointSetIteratorRight) //iterate simultaneously over both sets { pointLeftHandSide = pointSetIteratorLeft.Value(); pointRightHandSide = pointSetIteratorRight.Value(); if( !mitk::Equal( pointLeftHandSide, pointRightHandSide, eps, verbose ) ) { if(verbose) MITK_INFO << "[( PointSet )] Point values are different."; result = false; numberOfIncorrectPoints++; } } if((numberOfIncorrectPoints > 0) && verbose) { MITK_INFO << numberOfIncorrectPoints <<" of a total of " << leftHandSide.GetSize() << " points are different."; } } return result; } diff --git a/Core/Code/Testing/mitkExtractSliceFilterTest.cpp b/Core/Code/Testing/mitkExtractSliceFilterTest.cpp index 7a70c208dc..2d41170e8e 100644 --- a/Core/Code/Testing/mitkExtractSliceFilterTest.cpp +++ b/Core/Code/Testing/mitkExtractSliceFilterTest.cpp @@ -1,1169 +1,1169 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //use this to create the test volume on the fly #define CREATE_VOLUME //use this to save the created volume //#define SAVE_VOLUME //use this to calculate the error from the sphere mathematical model to our pixel based one //#define CALC_TESTFAILURE_DEVIATION //use this to render an oblique slice through a specified image //#define SHOW_SLICE_IN_RENDER_WINDOW //use this to have infos printed in mbilog //#define EXTRACTOR_DEBUG /*these are the deviations calculated by the function CalcTestFailureDeviation (see for details)*/ #define Testfailure_Deviation_Mean_128 0.853842 #define Testfailure_Deviation_Volume_128 0.145184 #define Testfailure_Deviation_Diameter_128 1.5625 #define Testfailure_Deviation_Mean_256 0.397693 #define Testfailure_Deviation_Volume_256 0.0141357 #define Testfailure_Deviation_Diameter_256 0.78125 #define Testfailure_Deviation_Mean_512 0.205277 #define Testfailure_Deviation_Volume_512 0.01993 #define Testfailure_Deviation_Diameter_512 0.390625 class mitkExtractSliceFilterTestClass{ public: static void TestSlice(mitk::PlaneGeometry* planeGeometry, std::string testname) { TestPlane = planeGeometry; TestName = testname; mitk::ScalarType centerCoordValue = TestvolumeSize / 2.0; mitk::ScalarType center[3] = {centerCoordValue, centerCoordValue, centerCoordValue}; mitk::Point3D centerIndex(center); double radius = TestvolumeSize / 4.0; if(TestPlane->Distance(centerIndex) >= radius ) return;//outside sphere //feed ExtractSliceFilter mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(TestVolume); slicer->SetWorldGeometry(TestPlane); slicer->Update(); MITK_TEST_CONDITION_REQUIRED(slicer->GetOutput() != NULL, "Extractor returned a slice"); mitk::Image::Pointer reslicedImage = slicer->GetOutput(); AccessFixedDimensionByItk(reslicedImage, TestSphereRadiusByItk, 2); AccessFixedDimensionByItk(reslicedImage, TestSphereAreaByItk, 2); /* double devArea, devDiameter; if(TestvolumeSize == 128.0){ devArea = Testfailure_Deviation_Volume_128; devDiameter = Testfailure_Deviation_Diameter_128; } else if(TestvolumeSize == 256.0){devArea = Testfailure_Deviation_Volume_256; devDiameter = Testfailure_Deviation_Diameter_256;} else if (TestvolumeSize == 512.0){devArea = Testfailure_Deviation_Volume_512; devDiameter = Testfailure_Deviation_Diameter_512;} else{devArea = Testfailure_Deviation_Volume_128; devDiameter = Testfailure_Deviation_Diameter_128;} */ std::string areatestName = TestName.append(" area"); std::string diametertestName = TestName.append(" testing diameter"); //TODO think about the deviation, 1% makes no sense at all MITK_TEST_CONDITION(std::abs(100 - testResults.percentageAreaCalcToPixel) < 1, areatestName ); MITK_TEST_CONDITION(std::abs(100 - testResults.percentageRadiusToPixel) < 1, diametertestName ); #ifdef EXTRACTOR_DEBUG MITK_INFO << TestName << " >>> " << "planeDistanceToSphereCenter: " << testResults.planeDistanceToSphereCenter; MITK_INFO << "area in pixels: " << testResults.areaInPixel << " <-> area in mm: " << testResults.areaCalculated << " = " << testResults.percentageAreaCalcToPixel << "%"; MITK_INFO << "calculated diameter: " << testResults.diameterCalculated << " <-> diameter in mm: " << testResults.diameterInMM << " <-> diameter in pixel: " << testResults.diameterInPixel << " = " << testResults.percentageRadiusToPixel << "%"; #endif } /* * get the radius of the slice of a sphere based on pixel distance from edge to edge of the circle. */ template static void TestSphereRadiusByItk (itk::Image* inputImage) { typedef itk::Image InputImageType; //set the index to the middle of the image's edge at x and y axis typename InputImageType::IndexType currentIndexX; currentIndexX[0] = (int)(TestvolumeSize / 2.0); currentIndexX[1] = 0; typename InputImageType::IndexType currentIndexY; currentIndexY[0] = 0; currentIndexY[1] = (int)(TestvolumeSize / 2.0); //remember the last pixel value double lastValueX = inputImage->GetPixel(currentIndexX); double lastValueY = inputImage->GetPixel(currentIndexY); //storage for the index marks std::vector indicesX; std::vector indicesY; /*Get four indices on the edge of the circle*/ while(currentIndexX[1] < TestvolumeSize && currentIndexX[0] < TestvolumeSize) { //move x direction currentIndexX[1] += 1; //move y direction currentIndexY[0] += 1; if(inputImage->GetPixel(currentIndexX) > lastValueX) { //mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexX[0]; markIndex[1] = currentIndexX[1]; indicesX.push_back(markIndex); } else if( inputImage->GetPixel(currentIndexX) < lastValueX) { //mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexX[0]; markIndex[1] = currentIndexX[1] - 1;//value inside the sphere indicesX.push_back(markIndex); } if(inputImage->GetPixel(currentIndexY) > lastValueY) { //mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexY[0]; markIndex[1] = currentIndexY[1]; indicesY.push_back(markIndex); } else if( inputImage->GetPixel(currentIndexY) < lastValueY) { //mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexY[0]; markIndex[1] = currentIndexY[1] - 1;//value inside the sphere indicesY.push_back(markIndex); } //found both marks? if(indicesX.size() == 2 && indicesY.size() == 2) break; //the new 'last' values lastValueX = inputImage->GetPixel(currentIndexX); lastValueY = inputImage->GetPixel(currentIndexY); } /* *If we are here we found the four marks on the edge of the circle. *For the case our plane is rotated and shifted, we have to calculate the center of the circle, *else the center is the intersection of both straight lines between the marks. *When we have the center, the diameter of the circle will be checked to the reference value(math!). */ //each distance from the first mark of each direction to the center of the straight line between the marks double distanceToCenterX = std::abs(indicesX[0][1] - indicesX[1][1]) / 2.0; //double distanceToCenterY = std::abs(indicesY[0][0] - indicesY[1][0]) / 2.0; //the center of the straight lines typename InputImageType::IndexType centerX; //typename InputImageType::IndexType centerY; centerX[0] = indicesX[0][0]; centerX[1] = indicesX[0][1] + distanceToCenterX; //TODO think about implicit cast to int. this is not the real center of the image, which could be between two pixels //centerY[0] = indicesY[0][0] + distanceToCenterY; //centerY[1] = inidcesY[0][1]; typename InputImageType::IndexType currentIndex(centerX); lastValueX = inputImage->GetPixel(currentIndex); long sumpixels = 0; std::vector diameterIndices; //move up while(currentIndex[1] < TestvolumeSize) { currentIndex[1] += 1; if( inputImage->GetPixel(currentIndex) != lastValueX) { typename InputImageType::IndexType markIndex; markIndex[0] = currentIndex[0]; markIndex[1] = currentIndex[1] - 1; diameterIndices.push_back(markIndex); break; } sumpixels++; lastValueX = inputImage->GetPixel(currentIndex); } currentIndex[1] -= sumpixels; //move back to center to go in the other direction lastValueX = inputImage->GetPixel(currentIndex); //move down while(currentIndex[1] >= 0) { currentIndex[1] -= 1; if( inputImage->GetPixel(currentIndex) != lastValueX) { typename InputImageType::IndexType markIndex; markIndex[0] = currentIndex[0]; markIndex[1] = currentIndex[1];//outside sphere because we want to calculate the distance from edge to edge diameterIndices.push_back(markIndex); break; } sumpixels++; lastValueX = inputImage->GetPixel(currentIndex); } /* *Now sumpixels should be the apromximate diameter of the circle. This is checked with the calculated diameter from the plane transformation(math). */ mitk::Point3D volumeCenter; volumeCenter[0] = volumeCenter[1] = volumeCenter[2] = TestvolumeSize / 2.0; double planeDistanceToSphereCenter = TestPlane->Distance(volumeCenter); double sphereRadius = TestvolumeSize/4.0; //calculate the radius of the circle cut from the sphere by the plane double diameter = 2.0 * std::sqrt(std::pow(sphereRadius, 2) - std::pow( planeDistanceToSphereCenter , 2)); double percentageRadiusToPixel = 100 / diameter * sumpixels; /* *calculate the radius in mm by the both marks of the center line by using the world coordinates */ //get the points as 3D coordinates mitk::Vector3D diameterPointRight, diameterPointLeft; diameterPointRight[2] = diameterPointLeft[2] = 0.0; diameterPointLeft[0] = diameterIndices[0][0]; diameterPointLeft[1] = diameterIndices[0][1]; diameterPointRight[0] = diameterIndices[1][0]; diameterPointRight[1] = diameterIndices[1][1]; //transform to worldcoordinates TestVolume->GetGeometry()->IndexToWorld(diameterPointLeft, diameterPointLeft); TestVolume->GetGeometry()->IndexToWorld(diameterPointRight, diameterPointRight); //euklidian distance double diameterInMM = ( (diameterPointLeft * -1.0) + diameterPointRight).GetNorm(); testResults.diameterInMM = diameterInMM; testResults.diameterCalculated = diameter; testResults.diameterInPixel = sumpixels; testResults.percentageRadiusToPixel = percentageRadiusToPixel; testResults.planeDistanceToSphereCenter = planeDistanceToSphereCenter; } /*brute force the area pixel by pixel*/ template static void TestSphereAreaByItk (itk::Image* inputImage) { typedef itk::Image InputImageType; typedef itk::ImageRegionConstIterator< InputImageType > ImageIterator; ImageIterator imageIterator( inputImage, inputImage->GetLargestPossibleRegion() ); imageIterator.GoToBegin(); int sumPixelsInArea = 0; while( !imageIterator.IsAtEnd() ) { if(inputImage->GetPixel(imageIterator.GetIndex()) == pixelValueSet) sumPixelsInArea++; ++imageIterator; } mitk::Point3D volumeCenter; volumeCenter[0] = volumeCenter[1] = volumeCenter[2] = TestvolumeSize / 2.0; double planeDistanceToSphereCenter = TestPlane->Distance(volumeCenter); double sphereRadius = TestvolumeSize/4.0; //calculate the radius of the circle cut from the sphere by the plane double radius = std::sqrt(std::pow(sphereRadius, 2) - std::pow( planeDistanceToSphereCenter , 2)); double areaInMM = 3.14159265358979 * std::pow(radius, 2); testResults.areaCalculated = areaInMM; testResults.areaInPixel = sumPixelsInArea; testResults.percentageAreaCalcToPixel = 100 / areaInMM * sumPixelsInArea; } /* * random a voxel. define plane through this voxel. reslice at the plane. compare the pixel vaues of the voxel * in the volume with the pixel value in the resliced image. * there are some indice shifting problems which causes the test to fail for oblique planes. seems like the chosen * worldcoordinate is not corrresponding to the index in the 2D image. and so the pixel values are not the same as * expected. */ static void PixelvalueBasedTest() { /* setup itk image */ typedef itk::Image ImageType; typedef itk::ImageRegionConstIterator< ImageType > ImageIterator; ImageType::Pointer image = ImageType::New(); ImageType::IndexType start; start[0] = start[1] = start[2] = 0; ImageType::SizeType size; size[0] = size[1] = size[2] = 32; ImageType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); image->SetRegions(imgRegion); image->SetSpacing(1.0); image->Allocate(); ImageIterator imageIterator( image, image->GetLargestPossibleRegion() ); imageIterator.GoToBegin(); unsigned short pixelValue = 0; //fill the image with distinct values while ( !imageIterator.IsAtEnd() ) { image->SetPixel(imageIterator.GetIndex(), pixelValue); ++imageIterator; ++pixelValue; } /* end setup itk image */ mitk::Image::Pointer imageInMitk; CastToMitkImage(image, imageInMitk); /*mitk::ImageWriter::Pointer writer = mitk::ImageWriter::New(); writer->SetInput(imageInMitk); std::string file = "C:\\Users\\schroedt\\Desktop\\cube.nrrd"; writer->SetFileName(file); writer->Update();*/ PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Frontal); PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Sagittal); PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Axial); } static void PixelvalueBasedTestByPlane(mitk::Image* imageInMitk, mitk::PlaneGeometry::PlaneOrientation orientation){ typedef itk::Image ImageType; //set the seed of the rand function srand((unsigned)time(0)); /* setup a random orthogonal plane */ int sliceindex = 17;//rand() % 32; bool isFrontside = true; bool isRotated = false; if( orientation == mitk::PlaneGeometry::Axial) { /*isFrontside = false; isRotated = true;*/ } mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->InitializeStandardPlane(imageInMitk->GetGeometry(), orientation, sliceindex, isFrontside, isRotated); mitk::Point3D origin = plane->GetOrigin(); mitk::Vector3D normal; normal = plane->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 plane->SetOrigin(origin); //we dont need this any more, because we are only testing orthogonal planes /*mitk::Vector3D rotationVector; rotationVector[0] = randFloat(); rotationVector[1] = randFloat(); rotationVector[2] = randFloat(); float degree = randFloat() * 180.0; mitk::RotationOperation* op = new mitk::RotationOperation(mitk::OpROTATE, plane->GetCenter(), rotationVector, degree); plane->ExecuteOperation(op); delete op;*/ /* end setup plane */ /* define a point in the 3D volume. * add the two axis vectors of the plane (each multiplied with a * random number) to the origin. now the two random numbers * become our index coordinates in the 2D image, because the * length of the axis vectors is 1. */ mitk::Point3D planeOrigin = plane->GetOrigin(); mitk::Vector3D axis0, axis1; axis0 = plane->GetAxisVector(0); axis1 = plane->GetAxisVector(1); axis0.Normalize(); axis1.Normalize(); unsigned char n1 = 7;// rand() % 32; unsigned char n2 = 13;// rand() % 32; mitk::Point3D testPoint3DInWorld; testPoint3DInWorld = planeOrigin + (axis0 * n1) + (axis1 * n2); //get the index of the point in the 3D volume ImageType::IndexType testPoint3DInIndex; imageInMitk->GetGeometry()->WorldToIndex(testPoint3DInWorld, testPoint3DInIndex); itk::Index<3> testPoint2DInIndex; /* end define a point in the 3D volume.*/ //do reslicing at the plane mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(imageInMitk); slicer->SetWorldGeometry(plane); slicer->Update(); mitk::Image::Pointer slice = slicer->GetOutput(); // Get TestPoiont3D as Index in Slice slice->GetGeometry()->WorldToIndex(testPoint3DInWorld,testPoint2DInIndex); mitk::Point3D p, sliceIndexToWorld, imageIndexToWorld; p[0] = testPoint2DInIndex[0]; p[1] = testPoint2DInIndex[1]; p[2] = testPoint2DInIndex[2]; slice->GetGeometry()->IndexToWorld(p, sliceIndexToWorld); p[0] = testPoint3DInIndex[0]; p[1] = testPoint3DInIndex[1]; p[2] = testPoint3DInIndex[2]; imageInMitk->GetGeometry()->IndexToWorld(p, imageIndexToWorld); itk::Index<2> testPoint2DIn2DIndex; testPoint2DIn2DIndex[0] = testPoint2DInIndex[0]; testPoint2DIn2DIndex[1] = testPoint2DInIndex[1]; typedef mitk::ImagePixelReadAccessor< unsigned short, 3 > VolumeReadAccessorType; typedef mitk::ImagePixelReadAccessor< unsigned short, 2 > SliceReadAccessorType; VolumeReadAccessorType VolumeReadAccessor( imageInMitk ); SliceReadAccessorType SliceReadAccessor( slice ); //compare the pixelvalues of the defined point in the 3D volume with the value of the resliced image unsigned short valueAt3DVolume = VolumeReadAccessor.GetPixelByIndex( testPoint3DInIndex ); unsigned short valueAtSlice = SliceReadAccessor.GetPixelByIndex( testPoint2DIn2DIndex ); //valueAt3DVolume == valueAtSlice is not always working. because of rounding errors //indices are shifted MITK_TEST_CONDITION(valueAt3DVolume == valueAtSlice, "comparing pixelvalues for orthogonal plane"); vtkSmartPointer imageInVtk = vtkSmartPointer::New(); imageInVtk = imageInMitk->GetVtkImageData(); vtkSmartPointer sliceInVtk = vtkSmartPointer::New(); sliceInVtk = slice->GetVtkImageData(); double PixelvalueByMitkOutput = sliceInVtk->GetScalarComponentAsDouble(n1, n2, 0, 0); //double valueVTKinImage = imageInVtk->GetScalarComponentAsDouble(testPoint3DInIndex[0], testPoint3DInIndex[1], testPoint3DInIndex[2], 0); /* Test that everything is working equally if vtkoutput is used instead of the default output * from mitk ImageToImageFilter */ mitk::ExtractSliceFilter::Pointer slicerWithVtkOutput = mitk::ExtractSliceFilter::New(); slicerWithVtkOutput->SetInput(imageInMitk); slicerWithVtkOutput->SetWorldGeometry(plane); slicerWithVtkOutput->SetVtkOutputRequest(true); slicerWithVtkOutput->Update(); vtkSmartPointer vtkImageByVtkOutput = vtkSmartPointer::New(); vtkImageByVtkOutput = slicerWithVtkOutput->GetVtkOutput(); double PixelvalueByVtkOutput = vtkImageByVtkOutput->GetScalarComponentAsDouble(n1, n2, 0, 0); MITK_TEST_CONDITION(PixelvalueByMitkOutput == PixelvalueByVtkOutput, "testing convertion of image output vtk->mitk by reslicer"); /*================ mbilog outputs ===========================*/ #ifdef EXTRACTOR_DEBUG MITK_INFO << "\n" << "TESTINFO index: " << sliceindex << " orientation: " << orientation << " frontside: " << isFrontside << " rotated: " << isRotated; MITK_INFO << "\n" << "slice index to world: " << sliceIndexToWorld; MITK_INFO << "\n" << "image index to world: " << imageIndexToWorld; MITK_INFO << "\n" << "vtk: slice: " << PixelvalueByMitkOutput << ", image: "<< valueVTKinImage; MITK_INFO << "\n" << "testPoint3D InWorld" << testPoint3DInWorld << " is " << testPoint2DInIndex << " in 2D"; MITK_INFO << "\n" << "randoms: " << ((int)n1) << ", " << ((int)n2); MITK_INFO << "\n" << "point is inside plane: " << plane->IsInside(testPoint3DInWorld) << " and volume: " << imageInMitk->GetGeometry()->IsInside(testPoint3DInWorld); MITK_INFO << "\n" << "volume idx: " << testPoint3DInIndex << " = " << valueAt3DVolume ; MITK_INFO << "\n" << "volume world: " << testPoint3DInWorld << " = " << valueAt3DVolumeByWorld ; MITK_INFO << "\n" << "slice idx: " << testPoint2DInIndex << " = " << valueAtSlice ; itk::Index<3> curr; curr[0] = curr[1] = curr[2] = 0; for( int i = 0; i < 32 ; ++i){ for( int j = 0; j < 32; ++j){ ++curr[1]; if(SliceReadAccessor.GetPixelByIndex( curr ) == valueAt3DVolume){ MITK_INFO << "\n" << valueAt3DVolume << " MATCHED mitk " << curr; } } curr[1] = 0; ++curr[0]; } typedef itk::Image Image2DType; Image2DType::Pointer img = Image2DType::New(); CastToItkImage(slice, img); typedef itk::ImageRegionConstIterator< Image2DType > Iterator2D; Iterator2D iter(img, img->GetLargestPossibleRegion()); iter.GoToBegin(); while( !iter.IsAtEnd() ){ if(img->GetPixel(iter.GetIndex()) == valueAt3DVolume) MITK_INFO << "\n" << valueAt3DVolume << " MATCHED itk " << iter.GetIndex(); ++iter; } #endif //EXTRACTOR_DEBUG } /* random a float value */ static float randFloat(){ return (((float)rand()+1.0) / ((float)RAND_MAX + 1.0)) + (((float)rand()+1.0) / ((float)RAND_MAX + 1.0)) / ((float)RAND_MAX + 1.0);} /* create a sphere with the size of the given testVolumeSize*/ static void InitializeTestVolume() { #ifdef CREATE_VOLUME //do sphere creation ItkVolumeGeneration(); #ifdef SAVE_VOLUME //save in file mitk::ImageWriter::Pointer writer = mitk::ImageWriter::New(); writer->SetInput(TestVolume); std::string file; std::ostringstream filename; filename << "C:\\home\\schroedt\\MITK\\Modules\\ImageExtraction\\Testing\\Data\\sphere_"; filename << TestvolumeSize; filename << ".nrrd"; file = filename.str(); writer->SetFileName(file); writer->Update(); #endif//SAVE_VOLUME #endif #ifndef CREATE_VOLUME //read from file mitk::StandardFileLocations::Pointer locator = mitk::StandardFileLocations::GetInstance(); std::string filename = locator->FindFile("sphere_512.nrrd.mhd", "Modules/ImageExtraction/Testing/Data"); mitk::ItkImageFileReader::Pointer reader = mitk::ItkImageFileReader::New(); reader->SetFileName(filename); reader->Update(); TestVolume = reader->GetOutput(); #endif #ifdef CALC_TESTFAILURE_DEVIATION //get the TestFailureDeviation in % AccessFixedDimensionByItk(TestVolume, CalcTestFailureDeviation, 3); #endif } //the test result of the sphere reslice struct SliceProperties{ double planeDistanceToSphereCenter; double diameterInMM; double diameterInPixel; double diameterCalculated; double percentageRadiusToPixel; double areaCalculated; double areaInPixel; double percentageAreaCalcToPixel; }; static mitk::Image::Pointer TestVolume; static double TestvolumeSize; static mitk::PlaneGeometry::Pointer TestPlane; static std::string TestName; static unsigned char pixelValueSet; static SliceProperties testResults; static double TestFailureDeviation; private: /* * Generate a sphere with a radius of TestvolumeSize / 4.0 */ static void ItkVolumeGeneration () { typedef itk::Image TestVolumeType; typedef itk::ImageRegionConstIterator< TestVolumeType > ImageIterator; TestVolumeType::Pointer sphereImage = TestVolumeType::New(); TestVolumeType::IndexType start; start[0] = start[1] = start[2] = 0; TestVolumeType::SizeType size; size[0] = size[1] = size[2] = TestvolumeSize; TestVolumeType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); sphereImage->SetRegions(imgRegion); sphereImage->SetSpacing(1.0); sphereImage->Allocate(); sphereImage->FillBuffer(0); mitk::Vector3D center; center[0] = center[1] = center[2] = TestvolumeSize / 2.0; double radius = TestvolumeSize / 4.0; double pixelValue = pixelValueSet; double distanceToCenter = 0.0; ImageIterator imageIterator( sphereImage, sphereImage->GetLargestPossibleRegion() ); imageIterator.GoToBegin(); mitk::Vector3D currentVoxelInIndex; while ( !imageIterator.IsAtEnd() ) { currentVoxelInIndex[0] = imageIterator.GetIndex()[0]; currentVoxelInIndex[1] = imageIterator.GetIndex()[1]; currentVoxelInIndex[2] = imageIterator.GetIndex()[2]; distanceToCenter = (center + ( currentVoxelInIndex * -1.0 )).GetNorm(); //if distance to center is smaller then the radius of the sphere if( distanceToCenter < radius) { sphereImage->SetPixel(imageIterator.GetIndex(), pixelValue); } ++imageIterator; } CastToMitkImage(sphereImage, TestVolume); } /* calculate the devation of the voxel object to the mathematical sphere object. * this is use to make a statement about the accuracy of the resliced image, eg. the circle's diameter or area. */ template static void CalcTestFailureDeviation (itk::Image* inputImage) { typedef itk::Image InputImageType; typedef itk::ImageRegionConstIterator< InputImageType > ImageIterator; ImageIterator iterator(inputImage, inputImage->GetLargestPossibleRegion()); iterator.GoToBegin(); int volumeInPixel = 0; while( !iterator.IsAtEnd() ) { if(inputImage->GetPixel(iterator.GetIndex()) == pixelValueSet) volumeInPixel++; ++iterator; } double diameter = TestvolumeSize / 2.0; double volumeCalculated = (1.0 / 6.0) * 3.14159265358979 * std::pow(diameter, 3); double volumeDeviation = std::abs( 100 - (100 / volumeCalculated * volumeInPixel) ); typename InputImageType::IndexType index; index[0] = index[1] = TestvolumeSize / 2.0; index[2] = 0; int sumpixels = 0; while (index[2] < TestvolumeSize ) { if(inputImage->GetPixel(index) == pixelValueSet) sumpixels++; index[2] += 1; } double diameterDeviation = std::abs( 100 - (100 / diameter * sumpixels) ); #ifdef DEBUG MITK_INFO << "volume deviation: " << volumeDeviation << " diameter deviation:" << diameterDeviation; #endif mitkExtractSliceFilterTestClass::TestFailureDeviation = (volumeDeviation + diameterDeviation) / 2.0; } }; /*================ #END class ================*/ /*================#BEGIN Instanciation of members ================*/ mitk::Image::Pointer mitkExtractSliceFilterTestClass::TestVolume = mitk::Image::New(); double mitkExtractSliceFilterTestClass::TestvolumeSize = 256.0; mitk::PlaneGeometry::Pointer mitkExtractSliceFilterTestClass::TestPlane = mitk::PlaneGeometry::New(); std::string mitkExtractSliceFilterTestClass::TestName = ""; unsigned char mitkExtractSliceFilterTestClass::pixelValueSet = 255; mitkExtractSliceFilterTestClass::SliceProperties mitkExtractSliceFilterTestClass::testResults = {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}; double mitkExtractSliceFilterTestClass::TestFailureDeviation = 0.0; /*================ #END Instanciation of members ================*/ /*================ #BEGIN test main ================*/ -int mitkExtractSliceFilterTest(int argc, char* argv[]) +int mitkExtractSliceFilterTest(int , char* []) { MITK_TEST_BEGIN("mitkExtractSliceFilterTest") //pixelvalue based testing mitkExtractSliceFilterTestClass::PixelvalueBasedTest(); //initialize sphere test volume mitkExtractSliceFilterTestClass::InitializeTestVolume(); mitk::Vector3D spacing = mitkExtractSliceFilterTestClass::TestVolume->GetGeometry()->GetSpacing(); //the center of the sphere = center of image double sphereCenter = mitkExtractSliceFilterTestClass::TestvolumeSize / 2.0; double planeSize = mitkExtractSliceFilterTestClass::TestvolumeSize; /* axial plane */ mitk::PlaneGeometry::Pointer geometryAxial = mitk::PlaneGeometry::New(); geometryAxial->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Axial, sphereCenter, false, true); geometryAxial->ChangeImageGeometryConsideringOriginOffset(true); mitk::Point3D origin = geometryAxial->GetOrigin(); mitk::Vector3D normal; normal = geometryAxial->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //geometryAxial->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometryAxial, "Testing axial plane"); /* end axial plane */ /* sagittal plane */ mitk::PlaneGeometry::Pointer geometrySagital = mitk::PlaneGeometry::New(); geometrySagital->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, sphereCenter, true, false); geometrySagital->ChangeImageGeometryConsideringOriginOffset(true); origin = geometrySagital->GetOrigin(); normal = geometrySagital->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //geometrySagital->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometrySagital, "Testing sagittal plane"); /* sagittal plane */ /* sagittal shifted plane */ mitk::PlaneGeometry::Pointer geometrySagitalShifted = mitk::PlaneGeometry::New(); geometrySagitalShifted->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, (sphereCenter - 14), true, false); geometrySagitalShifted->ChangeImageGeometryConsideringOriginOffset(true); origin = geometrySagitalShifted->GetOrigin(); normal = geometrySagitalShifted->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //geometrySagitalShifted->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometrySagitalShifted, "Testing sagittal plane shifted"); /* end sagittal shifted plane */ /* coronal plane */ mitk::PlaneGeometry::Pointer geometryCoronal = mitk::PlaneGeometry::New(); geometryCoronal->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Frontal, sphereCenter, true, false); geometryCoronal->ChangeImageGeometryConsideringOriginOffset(true); origin = geometryCoronal->GetOrigin(); normal = geometryCoronal->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //geometryCoronal->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometryCoronal, "Testing coronal plane"); /* end coronal plane */ /* oblique plane */ mitk::PlaneGeometry::Pointer obliquePlane = mitk::PlaneGeometry::New(); obliquePlane->InitializeStandardPlane(planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, sphereCenter, true, false); obliquePlane->ChangeImageGeometryConsideringOriginOffset(true); origin = obliquePlane->GetOrigin(); normal = obliquePlane->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 //obliquePlane->SetOrigin(origin); mitk::Vector3D rotationVector; rotationVector[0] = 0.2; rotationVector[1] = 0.4; rotationVector[2] = 0.62; float degree = 37.0; mitk::RotationOperation* op = new mitk::RotationOperation(mitk::OpROTATE, obliquePlane->GetCenter(), rotationVector, degree); obliquePlane->ExecuteOperation(op); delete op; mitkExtractSliceFilterTestClass::TestSlice(obliquePlane, "Testing oblique plane"); /* end oblique plane */ #ifdef SHOW_SLICE_IN_RENDER_WINDOW /*================ #BEGIN vtk render code ================*/ //set reslicer for renderwindow mitk::ItkImageFileReader::Pointer reader = mitk::ItkImageFileReader::New(); std::string filename = "C:\\home\\Pics\\Pic3D.nrrd"; reader->SetFileName(filename); reader->Update(); mitk::Image::Pointer pic = reader->GetOutput(); vtkSmartPointer slicer = vtkSmartPointer::New(); slicer->SetInput(pic->GetVtkImageData()); mitk::PlaneGeometry::Pointer obliquePl = mitk::PlaneGeometry::New(); obliquePl->InitializeStandardPlane(pic->GetGeometry(), mitk::PlaneGeometry::Sagittal, pic->GetGeometry()->GetCenter()[0], true, false); obliquePl->ChangeImageGeometryConsideringOriginOffset(true); mitk::Point3D origin2 = obliquePl->GetOrigin(); mitk::Vector3D n; n = obliquePl->GetNormal(); n.Normalize(); origin2 += n * 0.5;//pixelspacing is 1, so half the spacing is 0.5 obliquePl->SetOrigin(origin2); mitk::Vector3D rotation; rotation[0] = 0.534307; rotation[1] = 0.000439605; rotation[2] = 0.423017; MITK_INFO << rotation; float rotateDegree = 70; mitk::RotationOperation* operation = new mitk::RotationOperation(mitk::OpROTATE, obliquePl->GetCenter(), rotationVector, degree); obliquePl->ExecuteOperation(operation); delete operation; double origin[3]; origin[0] = obliquePl->GetOrigin()[0]; origin[1] = obliquePl->GetOrigin()[1]; origin[2] = obliquePl->GetOrigin()[2]; slicer->SetResliceAxesOrigin(origin); mitk::Vector3D right, bottom, normal; right = obliquePl->GetAxisVector( 0 ); bottom = obliquePl->GetAxisVector( 1 ); normal = obliquePl->GetNormal(); right.Normalize(); bottom.Normalize(); normal.Normalize(); double cosines[9]; mitk::vnl2vtk(right.GetVnlVector(), cosines);//x mitk::vnl2vtk(bottom.GetVnlVector(), cosines + 3);//y mitk::vnl2vtk(normal.GetVnlVector(), cosines + 6);//n slicer->SetResliceAxesDirectionCosines(cosines); slicer->SetOutputDimensionality(2); slicer->Update(); //set vtk renderwindow vtkSmartPointer vtkPlane = vtkSmartPointer::New(); vtkPlane->SetOrigin(0.0, 0.0, 0.0); //These two points define the axes of the plane in combination with the origin. //Point 1 is the x-axis and point 2 the y-axis. //Each plane is transformed according to the view (axial, coronal and saggital) afterwards. vtkPlane->SetPoint1(1.0, 0.0, 0.0); //P1: (xMax, yMin, depth) vtkPlane->SetPoint2(0.0, 1.0, 0.0); //P2: (xMin, yMax, depth) //these are not the correct values for all slices, only a square plane by now vtkSmartPointer imageMapper = vtkSmartPointer::New(); imageMapper->SetInputConnection(vtkPlane->GetOutputPort()); vtkSmartPointer lookupTable = vtkSmartPointer::New(); //built a default lookuptable lookupTable->SetRampToLinear(); lookupTable->SetSaturationRange( 0.0, 0.0 ); lookupTable->SetHueRange( 0.0, 0.0 ); lookupTable->SetValueRange( 0.0, 1.0 ); lookupTable->Build(); //map all black values to transparent lookupTable->SetTableValue(0, 0.0, 0.0, 0.0, 0.0); lookupTable->SetRange(-255.0, 255.0); //lookupTable->SetRange(-1022.0, 1184.0);//pic3D range vtkSmartPointer texture = vtkSmartPointer::New(); texture->SetInput(slicer->GetOutput()); texture->SetLookupTable(lookupTable); texture->SetMapColorScalarsThroughLookupTable(true); vtkSmartPointer imageActor = vtkSmartPointer::New(); imageActor->SetMapper(imageMapper); imageActor->SetTexture(texture); // Setup renderers vtkSmartPointer renderer = vtkSmartPointer::New(); renderer->AddActor(imageActor); // Setup render window vtkSmartPointer renderWindow = vtkSmartPointer::New(); renderWindow->AddRenderer(renderer); // Setup render window interactor vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); vtkSmartPointer style = vtkSmartPointer::New(); renderWindowInteractor->SetInteractorStyle(style); // Render and start interaction renderWindowInteractor->SetRenderWindow(renderWindow); //renderer->AddViewProp(imageActor); renderWindow->Render(); renderWindowInteractor->Start(); // always end with this! /*================ #END vtk render code ================*/ #endif //SHOW_SLICE_IN_RENDER_WINDOW MITK_TEST_END() } diff --git a/Core/Code/Testing/mitkImageDimensionConverterTest.cpp b/Core/Code/Testing/mitkImageDimensionConverterTest.cpp index ff084a8523..fffd3015d7 100644 --- a/Core/Code/Testing/mitkImageDimensionConverterTest.cpp +++ b/Core/Code/Testing/mitkImageDimensionConverterTest.cpp @@ -1,292 +1,292 @@ /*=================================================================== 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. ===================================================================*/ // mitk includes #include #include #include #include "mitkItkImageFileReader.h" #include #include #include #include #include #include #include #include "mitkTestingConfig.h" #include "mitkItkImageFileReader.h" // itk includes #include #include // stl includes #include // vtk includes #include -int mitkImageDimensionConverterTest(int argc, char* argv[]) +int mitkImageDimensionConverterTest(int , char* []) { MITK_TEST_BEGIN(mitkImageDimensionConverterTest); // Define an epsilon which is the allowed error float eps = 0.00001; // Define helper variables float error = 0; bool matrixIsEqual = true; std::stringstream sstream; mitk::ImageWriter::Pointer imageWriter = mitk::ImageWriter::New(); mitk::ItkImageFileReader::Pointer imageReader = mitk::ItkImageFileReader::New(); mitk::Convert2Dto3DImageFilter::Pointer convertFilter = mitk::Convert2Dto3DImageFilter::New(); /////////////////////////////////////// // Create 2D Image with a 3D rotation from scratch. typedef itk::Image ImageType; ImageType::Pointer itkImage = ImageType::New(); ImageType::RegionType myRegion; ImageType::SizeType mySize; ImageType::IndexType myIndex; ImageType::SpacingType mySpacing; mySpacing[0] = 1; mySpacing[1] = 1; myIndex[0] = 0; myIndex[1] = 0; mySize[0] = 50; mySize[1] = 50; myRegion.SetSize( mySize); myRegion.SetIndex( myIndex ); itkImage->SetSpacing(mySpacing); itkImage->SetRegions( myRegion); itkImage->Allocate(); itkImage->FillBuffer(50); mitk::Image::Pointer mitkImage2D; mitk::CastToMitkImage(itkImage,mitkImage2D); // rotate mitk::Point3D p; p[0] = 1; p[1] = 3; p[2] = 5; mitk::Vector3D v; v[0] = 0.3; v[1] = 1; v[2] = 0.1; mitk::RotationOperation op(mitk::OpROTATE, p, v, 35); mitkImage2D->GetGeometry()->ExecuteOperation(&op); // Save original Geometry infos mitk::Vector3D Original_col0, Original_col1, Original_col2; Original_col0.SetVnlVector(mitkImage2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); Original_col1.SetVnlVector(mitkImage2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); Original_col2.SetVnlVector(mitkImage2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); MITK_INFO << "Rotated Matrix: " << Original_col0 << " " << Original_col1 << " " << Original_col2; mitk::Point3D Original_Origin = mitkImage2D->GetGeometry()->GetOrigin(); mitk::Vector3D Original_Spacing = mitkImage2D->GetGeometry()->GetSpacing(); MITK_TEST_CONDITION_REQUIRED( mitkImage2D->GetDimension() == 2 , "Created Image is Dimension 2"); /////////////////////////////////////// // mitkImage2D is now a 2D image with 3D Geometry information. // Save it without conversion and load it again. It should have an identitiy matrix sstream.clear(); sstream << MITK_TEST_OUTPUT_DIR << "" << "/rotatedImage2D"; imageWriter->SetInput(mitkImage2D); imageWriter->SetFileName(sstream.str().c_str()); imageWriter->SetExtension(".nrrd"); imageWriter->Write(); sstream << ".nrrd"; imageReader->SetFileName(sstream.str().c_str()); imageReader->Update(); mitk::Image::Pointer imageLoaded2D = imageReader->GetOutput(); // check if image can be loaded MITK_TEST_CONDITION_REQUIRED( imageLoaded2D.IsNotNull() , "Loading saved 2D Image"); MITK_TEST_CONDITION_REQUIRED( imageLoaded2D->GetDimension() == 2 , "Loaded Image is Dimension 2"); // check if spacing is ok mitk::Vector3D Loaded2D_Spacing = imageLoaded2D->GetGeometry()->GetSpacing(); error = abs(Loaded2D_Spacing[0] - Original_Spacing[0]) + abs(Loaded2D_Spacing[1] - Original_Spacing[1]) + abs(Loaded2D_Spacing[2] - 1) ; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Spacing"); // Check origin mitk::Point3D Loaded2D_Origin = imageLoaded2D->GetGeometry()->GetOrigin(); error = abs(Loaded2D_Origin[0] - Original_Origin[0]) + abs(Loaded2D_Origin[1] - Original_Origin[1]) + abs(Loaded2D_Origin[2] - 0) ; MITK_TEST_CONDITION_REQUIRED( error < eps, "Compare Geometry: Origin"); // Check matrix mitk::Vector3D Loaded2D_col0, Loaded2D_col1, Loaded2D_col2; Loaded2D_col0.SetVnlVector(imageLoaded2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); Loaded2D_col1.SetVnlVector(imageLoaded2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); Loaded2D_col2.SetVnlVector(imageLoaded2D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); if ( (abs(1 - Loaded2D_col0[0]) > eps) || (abs(0 - Loaded2D_col0[1]) > eps) || (abs(0 - Loaded2D_col0[2]) > eps) || (abs(0 - Loaded2D_col1[0]) > eps) || (abs(1 - Loaded2D_col1[1]) > eps) || (abs(0 - Loaded2D_col1[2]) > eps) || (abs(0 - Loaded2D_col2[0]) > eps) || (abs(0 - Loaded2D_col2[1]) > eps) || (abs(1 - Loaded2D_col2[2]) > eps) ) { matrixIsEqual = false; } else matrixIsEqual = true; MITK_TEST_CONDITION_REQUIRED( matrixIsEqual , "Compare Geometry: Matrix"); /////////////////////////////////////// // mitkImage2D is a 2D image with 3D Geometry information. // Convert it with filter to a 3D image and check if everything went well convertFilter->SetInput(mitkImage2D); convertFilter->Update(); mitk::Image::Pointer mitkImage3D = convertFilter->GetOutput(); MITK_TEST_CONDITION_REQUIRED( mitkImage3D->GetDimension() == 3 , "Converted Image is Dimension 3"); // check if geometry is still same mitk::Vector3D Converted_Spacing = mitkImage3D->GetGeometry()->GetSpacing(); error = abs(Converted_Spacing[0] - Original_Spacing[0]) + abs(Converted_Spacing[1] - Original_Spacing[1]) + abs(Converted_Spacing[2] - Original_Spacing[2]) ; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Spacing"); mitk::Point3D Converted_Origin = mitkImage3D->GetGeometry()->GetOrigin(); error = abs(Converted_Origin[0] - Original_Origin[0]) + abs(Converted_Origin[1] - Original_Origin[1]) + abs(Converted_Origin[2] - Original_Origin[2]) ; MITK_INFO << Converted_Origin << " and " << Original_Origin; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Origin"); mitk::Vector3D Converted_col0, Converted_col1, Converted_col2; Converted_col0.SetVnlVector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); Converted_col1.SetVnlVector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); Converted_col2.SetVnlVector(mitkImage3D->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); if ( (abs(Original_col0[0] - Converted_col0[0]) > eps) || (abs(Original_col0[1] - Converted_col0[1]) > eps) || (abs(Original_col0[2] - Converted_col0[2]) > eps) || (abs(Original_col1[0] - Converted_col1[0]) > eps) || (abs(Original_col1[1] - Converted_col1[1]) > eps) || (abs(Original_col1[2] - Converted_col1[2]) > eps) || (abs(Original_col2[0] - Converted_col2[0]) > eps) || (abs(Original_col2[1] - Converted_col2[1]) > eps) || (abs(Original_col2[2] - Converted_col2[2]) > eps) ) { MITK_INFO << "Oh No! Original Image Matrix and Converted Image Matrix are different!"; MITK_INFO << "original Image:" << Original_col0 << " " << Original_col1 << " " << Original_col2; MITK_INFO << "converted Image:" << Converted_col0 << " " << Converted_col1 << " " << Converted_col2; matrixIsEqual = false; } else matrixIsEqual = true; MITK_TEST_CONDITION_REQUIRED( matrixIsEqual , "Compare Geometry: Matrix"); /////////////////////////////////////// // So far it seems good! now try to save and load the file std::stringstream sstream2; sstream2 << MITK_TEST_OUTPUT_DIR << "" << "/rotatedImage"; imageWriter->SetInput(mitkImage3D); imageWriter->SetFileName(sstream2.str().c_str()); imageWriter->SetExtension(".nrrd"); imageWriter->Write(); sstream2 << ".nrrd"; imageReader->SetFileName(sstream2.str().c_str()); imageReader->Update(); mitk::Image::Pointer imageLoaded = imageReader->GetOutput(); // check if image can be loaded MITK_TEST_CONDITION_REQUIRED( imageLoaded.IsNotNull() , "Loading saved Image"); // check if loaded image is still what it should be: MITK_TEST_CONDITION_REQUIRED( imageLoaded->GetDimension() == 3 , "Loaded Image is Dimension 3"); // check if geometry is still same mitk::Vector3D Loaded_Spacing = imageLoaded->GetGeometry()->GetSpacing(); error = abs(Loaded_Spacing[0] - Original_Spacing[0]) + abs(Loaded_Spacing[1] - Original_Spacing[1]) + abs(Loaded_Spacing[2] - Original_Spacing[2]) ; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Spacing"); mitk::Point3D Loaded_Origin = imageLoaded->GetGeometry()->GetOrigin(); error = abs(Loaded_Origin[0] - Original_Origin[0]) + abs(Loaded_Origin[1] - Original_Origin[1]) + abs(Loaded_Origin[2] - Original_Origin[2]) ; MITK_TEST_CONDITION_REQUIRED( error < eps , "Compare Geometry: Origin"); mitk::Vector3D Loaded_col0, Loaded_col1, Loaded_col2; Loaded_col0.SetVnlVector(imageLoaded->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); Loaded_col1.SetVnlVector(imageLoaded->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); Loaded_col2.SetVnlVector(imageLoaded->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); if ( (abs(Original_col0[0] - Loaded_col0[0]) > eps) || (abs(Original_col0[1] - Loaded_col0[1]) > eps) || (abs(Original_col0[2] - Loaded_col0[2]) > eps) || (abs(Original_col1[0] - Loaded_col1[0]) > eps) || (abs(Original_col1[1] - Loaded_col1[1]) > eps) || (abs(Original_col1[2] - Loaded_col1[2]) > eps) || (abs(Original_col2[0] - Loaded_col2[0]) > eps) || (abs(Original_col2[1] - Loaded_col2[1]) > eps) || (abs(Original_col2[2] - Loaded_col2[2]) > eps) ) { MITK_INFO << "Oh No! Original Image Matrix and Converted Image Matrix are different!"; MITK_INFO << "original Image:" << Original_col0 << " " << Original_col1 << " " << Original_col2; MITK_INFO << "converted Image:" << Loaded_col0 << " " << Loaded_col1 << " " << Loaded_col2; matrixIsEqual = false; } else matrixIsEqual = true; MITK_TEST_CONDITION_REQUIRED( matrixIsEqual , "Compare Geometry: Matrix"); return 0; MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageTimeSelectorTest.cpp b/Core/Code/Testing/mitkImageTimeSelectorTest.cpp index 265dc9a82d..e6e1464c66 100644 --- a/Core/Code/Testing/mitkImageTimeSelectorTest.cpp +++ b/Core/Code/Testing/mitkImageTimeSelectorTest.cpp @@ -1,119 +1,119 @@ /*=================================================================== 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 "mitkDataNodeFactory.h" #include "mitkImageTimeSelector.h" #include "mitkImageGenerator.h" #include "mitkTestingMacros.h" #include "mitkIOUtil.h" #include #include /** Global members common for all subtests */ namespace { std::string m_Filename; mitk::Image::Pointer m_Image; } // end of anonymous namespace /** @brief Global test setup */ static void Setup( ) { try { m_Image = mitk::IOUtil::LoadImage( m_Filename ); } catch( const itk::ExceptionObject &e) { MITK_TEST_FAILED_MSG(<< "(Setup) Caught exception from IOUtil while loading input : " << m_Filename <<"\n" << e.what()) } } static void Valid_AllInputTimesteps_ReturnsTrue() { Setup(); mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(m_Image); // test all timesteps const unsigned int maxTimeStep = m_Image->GetTimeSteps(); for( unsigned int t=0; tSetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer currentTimestepImage = timeSelector->GetOutput(); std::stringstream ss; ss << " : Valid image in timestep " << t ; MITK_TEST_CONDITION_REQUIRED( currentTimestepImage.IsNotNull() , ss.str().c_str() ); } } static void Valid_ImageExpandedByTimestep_ReturnsTrue() { Setup(); mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); const unsigned int maxTimeStep = m_Image->GetTimeSteps(); mitk::TimeGeometry* tsg = m_Image->GetTimeGeometry(); mitk::ProportionalTimeGeometry* ptg = dynamic_cast(tsg); ptg->Expand(maxTimeStep+1); ptg->SetTimeStepGeometry( ptg->GetGeometryForTimeStep(0), maxTimeStep ); mitk::Image::Pointer expandedImage = mitk::Image::New(); expandedImage->Initialize( m_Image->GetPixelType(0), *tsg ); timeSelector->SetInput(expandedImage); for( unsigned int t=0; tSetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer currentTimestepImage = timeSelector->GetOutput(); std::stringstream ss; ss << " : Valid image in timestep " << t ; MITK_TEST_CONDITION_REQUIRED( currentTimestepImage.IsNotNull() , ss.str().c_str() ); } } -int mitkImageTimeSelectorTest(int argc, char* argv[]) +int mitkImageTimeSelectorTest(int, char* []) { MITK_TEST_BEGIN(mitkImageTimeSelectorTest); m_Filename = std::string( argv[1] ); Valid_AllInputTimesteps_ReturnsTrue(); Valid_ImageExpandedByTimestep_ReturnsTrue(); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkMultiComponentImageDataComparisonFilterTest.cpp b/Core/Code/Testing/mitkMultiComponentImageDataComparisonFilterTest.cpp index 77a3033270..c64e14467e 100644 --- a/Core/Code/Testing/mitkMultiComponentImageDataComparisonFilterTest.cpp +++ b/Core/Code/Testing/mitkMultiComponentImageDataComparisonFilterTest.cpp @@ -1,81 +1,81 @@ /*=================================================================== 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. ===================================================================*/ // mitk includes #include "mitkTestingMacros.h" #include "mitkMultiComponentImageDataComparisonFilter.h" #include "mitkItkImageFileReader.h" #include "mitkImageReadAccessor.h" #include "itkNumericTraits.h" -int mitkMultiComponentImageDataComparisonFilterTest(int argc, char* argv[]) +int mitkMultiComponentImageDataComparisonFilterTest(int, char* []) { MITK_TEST_BEGIN("MultiComponentImageDataComparisonFilter"); // instantiation mitk::MultiComponentImageDataComparisonFilter::Pointer testObject = mitk::MultiComponentImageDataComparisonFilter::New(); MITK_TEST_CONDITION_REQUIRED(testObject.IsNotNull(), "Testing instantiation of test class!"); MITK_TEST_CONDITION_REQUIRED(testObject->GetCompareFilterResult() == NULL, "Testing initialization of result struct" ); MITK_TEST_CONDITION_REQUIRED(testObject->GetTolerance() == 0.0f, "Testing initialization of tolerance member"); MITK_TEST_CONDITION_REQUIRED(testObject->GetResult() == false, "Testing initialization of CompareResult member"); // initialize compare result struct and pass it to the filter mitk::CompareFilterResults compareResult; compareResult.m_MaximumDifference = 0.0f; compareResult.m_MinimumDifference = itk::NumericTraits::max(); compareResult.m_MeanDifference = 0.0f; compareResult.m_FilterCompleted = false; compareResult.m_TotalDifference = 0.0f; compareResult.m_PixelsWithDifference = 0; testObject->SetCompareFilterResult(&compareResult); MITK_TEST_CONDITION_REQUIRED(testObject->GetCompareFilterResult() != NULL, "Testing set/get of compare result struct" ); MITK_TEST_CONDITION_REQUIRED(testObject->GetResult() == false, "CompareResult still false" ); //now load an image with several components and present it to the filter mitk::ItkImageFileReader::Pointer imgReader = mitk::ItkImageFileReader::New(); imgReader->SetFileName(argv[1]); imgReader->Update(); mitk::Image::Pointer testImg = imgReader->GetOutput(); mitk::Image::Pointer testImg2 = testImg->Clone(); testObject->SetValidImage(testImg); testObject->SetTestImage(testImg2); MITK_TEST_CONDITION_REQUIRED(testObject->GetNumberOfIndexedInputs() == 2, "Testing correct handling of input images"); testObject->Update(); MITK_TEST_CONDITION_REQUIRED(testObject->GetResult(), "Testing filter processing with equal image data"); // now change some of the data and check if the response is correct mitk::ImageReadAccessor imgAcc(testImg2); unsigned char* imgData = (unsigned char*) imgAcc.GetData(); imgData[10] += 1; imgData[20] += 2; imgData[30] += 3; testObject->Update(); MITK_TEST_CONDITION_REQUIRED(testObject->GetResult() == false, "Testing filter processing with unequal image data"); MITK_TEST_CONDITION_REQUIRED(mitk::Equal((int)testObject->GetCompareFilterResult()->m_PixelsWithDifference, (int) 3) && mitk::Equal((double)testObject->GetCompareFilterResult()->m_MaximumDifference, (double) 3.0) && mitk::Equal((double)testObject->GetCompareFilterResult()->m_MeanDifference, (double) 2.0), "Assessing calculated image differences"); MITK_TEST_END(); } diff --git a/Core/Code/Testing/vtkMitkThickSlicesFilterTest.cpp b/Core/Code/Testing/vtkMitkThickSlicesFilterTest.cpp index 7975d10b56..887b83592b 100644 --- a/Core/Code/Testing/vtkMitkThickSlicesFilterTest.cpp +++ b/Core/Code/Testing/vtkMitkThickSlicesFilterTest.cpp @@ -1,174 +1,174 @@ /*=================================================================== 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 "mitkTestingMacros.h" #include #include "mitkImageWriteAccessor.h" #include "mitkImage.h" #include #include #include class vtkMitkThickSlicesFilterTestHelper { public: static mitk::Image::Pointer CreateTestImage( int min, int max ) { mitk::PixelType pixelType( mitk::MakeScalarPixelType() ); mitk::Image::Pointer testImage = mitk::Image::New(); unsigned int* dim = new unsigned int[3]; dim[0] = 10; dim[1] = 10; dim[2] = max+1-min; testImage->Initialize( pixelType, 3, dim ); size_t buffer_size = dim[0] * dim[1] * sizeof(unsigned char); for( int i=min; i<=max; ++i ) { mitk::ImageWriteAccessor writeAccess( testImage, testImage->GetSliceData( i-min ) ); memset( writeAccess.GetData(), i, buffer_size ); } return testImage; } static void EvaluateResult( unsigned char expectedValue, vtkImageData* image, const char* projection ) { MITK_TEST_CONDITION_REQUIRED( image->GetDimensions()[0] == 10 && image->GetDimensions()[1] == 10 && image->GetDimensions()[2] == 1, "Resulting image has correct size" ); unsigned char* value = static_cast( image->GetScalarPointer(0,0,0) ); MITK_INFO << "Evaluating projection mode: " << projection; MITK_INFO << "expected value: " << static_cast( expectedValue ); MITK_INFO << "actual value: " << static_cast( value[0] ); MITK_TEST_CONDITION_REQUIRED( value[0] == expectedValue, "Resulting image has correct pixel-value" ); } }; /** * Test for vtkMitkThickSlicesFilter. * */ -int vtkMitkThickSlicesFilterTest(int argc, char** const argv) +int vtkMitkThickSlicesFilterTest(int, char** ) { // always start with this! MITK_TEST_BEGIN("vtkMitkThickSlicesFilterTest") vtkMitkThickSlicesFilter* thickSliceFilter = vtkMitkThickSlicesFilter::New(); ////////////////////////////////////////////////////////////////////////// // Image looks like: // 000000000 // 111111111 // 222222222 mitk::Image::Pointer testImage1 = vtkMitkThickSlicesFilterTestHelper::CreateTestImage( 0, 2 ); thickSliceFilter->SetInputData( testImage1->GetVtkImageData() ); // MaxIP thickSliceFilter->SetThickSliceMode( 0 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 2, thickSliceFilter->GetOutput(), "MaxIP" ); // Sum thickSliceFilter->SetThickSliceMode( 1 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 1, thickSliceFilter->GetOutput(), "Sum" ); // Weighted thickSliceFilter->SetThickSliceMode( 2 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 1, thickSliceFilter->GetOutput(), "Weighted" ); // MinIP thickSliceFilter->SetThickSliceMode( 3 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 0, thickSliceFilter->GetOutput(), "MinIP" ); // Mean thickSliceFilter->SetThickSliceMode( 4 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 1, thickSliceFilter->GetOutput(), "Mean" ); ////////////////////////////////////////////////////////////////////////// // Image looks like: // 333333333 // 444444444 // 555555555 // 666666666 // 777777777 // 888888888 mitk::Image::Pointer testImage2 = vtkMitkThickSlicesFilterTestHelper::CreateTestImage( 3, 8 ); thickSliceFilter->SetInputData( testImage2->GetVtkImageData() ); // MaxIP thickSliceFilter->SetThickSliceMode( 0 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 8, thickSliceFilter->GetOutput(), "MaxIP" ); // Sum thickSliceFilter->SetThickSliceMode( 1 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 5, thickSliceFilter->GetOutput(), "Sum" ); // Weighted thickSliceFilter->SetThickSliceMode( 2 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 4, thickSliceFilter->GetOutput(), "Weighted" ); // MinIP thickSliceFilter->SetThickSliceMode( 3 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 3, thickSliceFilter->GetOutput(), "MinIP" ); // Mean thickSliceFilter->SetThickSliceMode( 4 ); thickSliceFilter->Modified(); thickSliceFilter->Update(); vtkMitkThickSlicesFilterTestHelper::EvaluateResult( 6, thickSliceFilter->GetOutput(), "Mean" ); thickSliceFilter->Delete(); MITK_TEST_END() } diff --git a/Core/Code/TestingHelper/mitkTestingMacros.h b/Core/Code/TestingHelper/mitkTestingMacros.h index ffa5dbd4c4..855d3787d0 100644 --- a/Core/Code/TestingHelper/mitkTestingMacros.h +++ b/Core/Code/TestingHelper/mitkTestingMacros.h @@ -1,386 +1,386 @@ /*=================================================================== 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 mitkTestingMacros_h #define mitkTestingMacros_h #include #include #include #include #include #include #include #include #include namespace mitk { /** @brief Indicate a failed test. */ class TestFailedException : public std::exception { public: TestFailedException() {} }; } /** * @brief Output some text without generating a terminating newline. Include * * @ingroup MITKTestingAPI */ #define MITK_TEST_OUTPUT_NO_ENDL(x) \ std::cout x ; /** * @brief Output some text. * * @ingroup MITKTestingAPI */ #define MITK_TEST_OUTPUT(x) \ MITK_TEST_OUTPUT_NO_ENDL(x << "\n") /** * @brief Do some general test preparations. Must be called first in the * main test function. * * @deprecatedSince{2013_09} Use MITK_TEST_SUITE_REGISTRATION instead. * @ingroup MITKTestingAPI */ #define MITK_TEST_BEGIN(testName) \ std::string mitkTestName(#testName); \ mitk::TestManager::GetInstance()->Initialize(); \ try { /** * @brief Fail and finish test with message MSG * * @deprecatedSince{2013_09} Use CPPUNIT_FAIL instead * @ingroup MITKTestingAPI */ #define MITK_TEST_FAILED_MSG(MSG) \ MITK_TEST_OUTPUT(MSG) \ throw mitk::TestFailedException(); /** * @brief Must be called last in the main test function. * * @deprecatedSince{2013_09} Use MITK_TEST_SUITE_REGISTRATION instead. * @ingroup MITKTestingAPI */ #define MITK_TEST_END() \ - } catch (mitk::TestFailedException ex) { \ + } catch (const mitk::TestFailedException& ex) { \ MITK_TEST_OUTPUT(<< "Further test execution skipped.") \ mitk::TestManager::GetInstance()->TestFailed(); \ - } catch (std::exception ex) { \ + } catch (const std::exception& ex) { \ MITK_TEST_OUTPUT(<< "std::exception occured " << ex.what()) \ mitk::TestManager::GetInstance()->TestFailed(); \ } \ if (mitk::TestManager::GetInstance()->NumberOfFailedTests() > 0) { \ MITK_TEST_OUTPUT(<< mitkTestName << ": [DONE FAILED] , subtests passed: " << \ mitk::TestManager::GetInstance()->NumberOfPassedTests() << " failed: " << \ mitk::TestManager::GetInstance()->NumberOfFailedTests() ) \ return EXIT_FAILURE; \ } else { \ MITK_TEST_OUTPUT(<< mitkTestName << ": " \ << mitk::TestManager::GetInstance()->NumberOfPassedTests() \ << " tests [DONE PASSED]") \ return EXIT_SUCCESS; \ } \ /** * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT or CPPUNIT_ASSERT_MESSAGE instead. */ #define MITK_TEST_CONDITION(COND,MSG) \ MITK_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ mitk::TestManager::GetInstance()->TestFailed(); \ MITK_TEST_OUTPUT(<< " [FAILED]\n" << "In " << __FILE__ \ << ", line " << __LINE__ \ << ": " #COND " : [FAILED]") \ } else { \ MITK_TEST_OUTPUT(<< " [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } /** * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT or CPPUNIT_ASSERT_MESSAGE instead. */ #define MITK_TEST_CONDITION_REQUIRED(COND,MSG) \ MITK_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ MITK_TEST_FAILED_MSG(<< " [FAILED]\n" << " +--> in " << __FILE__ \ << ", line " << __LINE__ \ << ", expression is false: \"" #COND "\"") \ } else { \ MITK_TEST_OUTPUT(<< " [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } /** * \brief Begin block which should be checked for exceptions * * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT_THROW instead. * @ingroup MITKTestingAPI * * This macro, together with MITK_TEST_FOR_EXCEPTION_END, can be used * to test whether a code block throws an expected exception. The test FAILS if the * exception is NOT thrown. A simple example: * MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ImageFileReaderException) typedef itk::ImageFileReader< itk::Image > ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName("/tmp/not-existing"); reader->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ImageFileReaderException) * */ #define MITK_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ try { /** * @deprecatedSince{2013_09} */ #define MITK_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) \ mitk::TestManager::GetInstance()->TestFailed(); \ MITK_TEST_OUTPUT( << "Expected an '" << #EXCEPTIONCLASS << "' exception. [FAILED]") \ } \ catch (EXCEPTIONCLASS) { \ MITK_TEST_OUTPUT( << "Caught an expected '" << #EXCEPTIONCLASS \ << "' exception. [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } /** * @brief Simplified version of MITK_TEST_FOR_EXCEPTION_BEGIN / END for * a single statement * * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT_THROW instead. * @ingroup MITKTestingAPI */ #define MITK_TEST_FOR_EXCEPTION(EXCEPTIONCLASS, STATEMENT) \ MITK_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ STATEMENT ; \ MITK_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) /** * @brief Testing macro to test if two objects are equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. * Feel free to implement mitk::Equal for your own datatype or purpose. * * @deprecatedSince{2013_09} Use MITK_ASSERT_EQUAL instead. * * @param OBJ1 First object. * @param OBJ2 Second object. * @param MSG Message to appear with the test. */ #define MITK_TEST_EQUAL(OBJ1,OBJ2,MSG) \ MITK_TEST_CONDITION_REQUIRED( mitk::Equal(OBJ1, OBJ2, mitk::eps, true)==true, MSG) /** * @brief Testing macro to test if two objects are equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. * Feel free to implement mitk::Equal for your own datatype or purpose. * * @param EXPECTED First object. * @param ACTUAL Second object. * @param MSG Message to appear with the test. * @throw Throws mitkException if a NULL pointer is given as input. */ #define MITK_ASSERT_EQUAL(EXPECTED, ACTUAL, MSG) \ if(((EXPECTED).IsNull()) || ((ACTUAL).IsNull())) { \ mitkThrow() << "mitk::Equal does not work with NULL pointer input."; \ } \ CPPUNIT_ASSERT_MESSAGE(MSG, mitk::Equal(*(EXPECTED), *(ACTUAL), mitk::eps, true)) /** * @brief Testing macro to test if two objects are not equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. * * @deprecatedSince{2013_09} Use MITK_ASSERT_NOT_EQUAL instead. * * @param OBJ1 First object. * @param OBJ2 Second object. * @param MSG Message to appear with the test. * * \sa MITK_TEST_EQUAL */ #define MITK_TEST_NOT_EQUAL(OBJ1,OBJ2,MSG) \ CPPUNIT_ASSERT_MESSAGE(MSG, !mitk::Equal(*(OBJ1), *(OBJ2), mitk::eps, true)) /** * @brief Testing macro to test if two objects are not equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. * * @param OBJ1 First object. * @param OBJ2 Second object. * @param MSG Message to appear with the test. * @throw Throws mitkException if a NULL pointer is given as input. * * \sa MITK_ASSERT_EQUAL */ #define MITK_ASSERT_NOT_EQUAL(OBJ1, OBJ2, MSG) \ if(((OBJ1).IsNull()) || ((OBJ2).IsNull())) { \ mitkThrow() << "mitk::Equal does not work with NULL pointer input."; \ } \ CPPUNIT_ASSERT_MESSAGE(MSG, !mitk::Equal(*(OBJ1), *(OBJ2), mitk::eps, true)) /** * @brief Registers the given test suite. * * @ingroup MITKTestingAPI * * @param TESTSUITE_NAME The name of the test suite class, without "TestSuite" * at the end. */ #define MITK_TEST_SUITE_REGISTRATION(TESTSUITE_NAME) \ int TESTSUITE_NAME ## Test(int /*argc*/, char* /*argv*/[]) \ { \ CppUnit::TextUi::TestRunner runner; \ runner.addTest(TESTSUITE_NAME ## TestSuite::suite()); \ return runner.run() ? 0 : 1; \ } /** * @brief Adds a test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases. * The macro internally just calls the CPPUNIT_TEST macro. * * @param TESTMETHOD The name of the member funtion test. */ #define MITK_TEST(TESTMETHOD) CPPUNIT_TEST(TESTMETHOD) /** * @brief Adds a parameterized test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases * which need custom parameters. * * @param TESTMETHOD The name of the member function test. * @param ARGS A std::vector object containing test parameter. * * @note Use the macro MITK_PARAMETERIZED_TEST only if you know what * you are doing. If you are not sure, use MITK_TEST instead. */ #define MITK_PARAMETERIZED_TEST(TESTMETHOD, ARGS) \ { \ std::string testName = #TESTMETHOD; \ for (std::size_t i = 0; i < ARGS.size(); ++i) \ { \ testName += "_" + ARGS[i]; \ } \ CPPUNIT_TEST_SUITE_ADD_TEST( \ ( new mitk::TestCaller( \ context.getTestNameFor(testName), \ &TestFixtureType::TESTMETHOD, \ context.makeFixture(), args ) ) ); \ } /** * @brief Adds a parameterized test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases * which need parameters from the command line. * * @warning Use the macro MITK_PARAMETERIZED_CMD_LINE_TEST only * if you know what you are doing. If you are not sure, use * MITK_TEST instead. MITK_PARAMETERIZED_CMD_LINE_TEST is meant * for migrating from ctest to CppUnit. If you implement new * tests, the MITK_TEST macro will be sufficient. * * @param TESTMETHOD The name of the member function test. */ #define MITK_PARAMETERIZED_CMD_LINE_TEST(TESTMETHOD) \ CPPUNIT_TEST_SUITE_ADD_TEST( \ ( new mitk::TestCaller( \ context.getTestNameFor( #TESTMETHOD), \ &TestFixtureType::TESTMETHOD, \ context.makeFixture() ) ) ); /** * @brief Adds a parameterized test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases * which need one custom parameter. * * @param TESTMETHOD The name of the member function test. * @param arg1 A custom string parameter being passed to the fixture. * * @note Use the macro MITK_PARAMETERIZED_TEST_1 only if you know what * you are doing. If you are not sure, use MITK_TEST instead. * * @see MITK_PARAMETERIZED_TEST */ #define MITK_PARAMETERIZED_TEST_1(TESTMETHOD, arg1) \ { \ std::vector args; \ args.push_back(arg1); \ MITK_PARAMETERIZED_TEST(TESTMETHOD, args) \ } /** * @brief Adds a parameterized test to the current test suite. * * @ingroup MITKTestingAPI * * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases * which need two custom parameter. * * @param TESTMETHOD The name of the member function test. * @param arg1 A custom string parameter being passed to the fixture. * * @note Use the macro MITK_PARAMETERIZED_TEST_2 only if you know what * you are doing. If you are not sure, use MITK_TEST instead. * * @see MITK_PARAMETERIZED_TEST */ #define MITK_PARAMETERIZED_TEST_2(TESTMETHOD, arg1, arg2) \ { \ std::vector args; \ args.push_back(arg1); \ args.push_back(arg2); \ MITK_PARAMETERIZED_TEST(TESTMETHOD, args) \ } #endif diff --git a/Modules/QtWidgetsExt/CMakeLists.txt b/Modules/QtWidgetsExt/CMakeLists.txt index 7916170c25..fb35dcde93 100644 --- a/Modules/QtWidgetsExt/CMakeLists.txt +++ b/Modules/QtWidgetsExt/CMakeLists.txt @@ -1,6 +1,6 @@ MITK_CREATE_MODULE( - INCLUDE_DIRS QmitkApplicationBase QmitkPropertyObservers QmitkFunctionalityComponents + INCLUDE_DIRS QmitkApplicationBase QmitkPropertyObservers DEPENDS MitkImageStatistics MitkQtWidgets PACKAGE_DEPENDS Qt4|QtWebKit Qwt Qxt WARNINGS_AS_ERRORS ) diff --git a/Modules/SceneSerialization/CMakeLists.txt b/Modules/SceneSerialization/CMakeLists.txt index 461ad17ea5..56710c481d 100644 --- a/Modules/SceneSerialization/CMakeLists.txt +++ b/Modules/SceneSerialization/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE( - INCLUDE_DIRS BaseDataSerializer BasePropertySerializer BasePropertyDeserializer + INCLUDE_DIRS BaseDataSerializer DEPENDS MitkSceneSerializationBase PACKAGE_DEPENDS Poco WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/SceneSerializationBase/CMakeLists.txt b/Modules/SceneSerializationBase/CMakeLists.txt index 7d5f63c169..c1517fa523 100644 --- a/Modules/SceneSerializationBase/CMakeLists.txt +++ b/Modules/SceneSerializationBase/CMakeLists.txt @@ -1,7 +1,7 @@ MITK_CREATE_MODULE( - INCLUDE_DIRS BaseDataSerializer BasePropertySerializer + INCLUDE_DIRS BasePropertySerializer DEPENDS MitkCore WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/Segmentation/CMakeLists.txt b/Modules/Segmentation/CMakeLists.txt index fef70bd1b5..5a35144363 100644 --- a/Modules/Segmentation/CMakeLists.txt +++ b/Modules/Segmentation/CMakeLists.txt @@ -1,7 +1,7 @@ MITK_CREATE_MODULE( - INCLUDE_DIRS Algorithms Controllers DataManagement Interactions IO Rendering SegmentationUtilities/BooleanOperations SegmentationUtilities/MorphologicalOperations + INCLUDE_DIRS Algorithms Controllers DataManagement Interactions Rendering SegmentationUtilities/BooleanOperations SegmentationUtilities/MorphologicalOperations DEPENDS MitkAlgorithmsExt MitkIpSegmentation MitkIpFunc MitkLegacyAdaptors MitkSurfaceInterpolation MitkGraphAlgorithms MitkContourModel PACKAGE_DEPENDS ITK|ITKBinaryMathematicalMorphology+ITKLabelVoting+ITKRegionGrowing+ITKFastMarching+ITKAnisotropicSmoothing+ITKWatersheds ) add_subdirectory(Testing) diff --git a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp index 02184e6764..12226baf69 100644 --- a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp +++ b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp @@ -1,282 +1,282 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include int ObliquePlaneTestVolumeSize = 128; static void OverwriteObliquePlaneTest(mitk::Image* workingImage, mitk::Image* refImg) { /*==============TEST WITHOUT MITK CONVERTION=============================*/ /* ============= setup plane ============*/ int sliceindex = (int)(ObliquePlaneTestVolumeSize /2);//rand() % 32; bool isFrontside = true; bool isRotated = false; mitk::PlaneGeometry::Pointer obliquePlane = mitk::PlaneGeometry::New(); obliquePlane->InitializeStandardPlane(workingImage->GetGeometry(), mitk::PlaneGeometry::Axial, sliceindex, isFrontside, isRotated); mitk::Point3D origin = obliquePlane->GetOrigin(); mitk::Vector3D normal; normal = obliquePlane->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 obliquePlane->SetOrigin(origin); mitk::Vector3D rotationVector = obliquePlane->GetAxisVector(0); rotationVector.Normalize(); float degree = 45.0; mitk::RotationOperation* op = new mitk::RotationOperation(mitk::OpROTATE, obliquePlane->GetCenter(), rotationVector, degree); obliquePlane->ExecuteOperation(op); delete op; /* ============= extract slice ============*/ mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(workingImage); slicer->SetWorldGeometry(obliquePlane); slicer->SetVtkOutputRequest(true); slicer->Modified(); slicer->Update(); vtkSmartPointer slice = vtkSmartPointer::New(); slice = slicer->GetVtkOutput(); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer overwriter = mitk::ExtractSliceFilter::New(resliceIdx); resliceIdx->SetOverwriteMode(true); resliceIdx->SetInputSlice(slice); resliceIdx->Modified(); overwriter->SetInput(workingImage); overwriter->SetWorldGeometry(obliquePlane); overwriter->SetVtkOutputRequest(true); overwriter->Modified(); overwriter->Update(); typedef mitk::ImagePixelReadAccessor< unsigned short, 3 > ReadAccessorType; ReadAccessorType refImgReadAccessor( refImg ); ReadAccessorType workingImgReadAccessor( workingImage ); /* ============= check ref == working ============*/ bool areSame = true; itk::Index<3> id; id[0] = id[1] = id[2] = 0; for (int x = 0; x < ObliquePlaneTestVolumeSize ; ++x){ id[0] = x; for (int y = 0; y < ObliquePlaneTestVolumeSize ; ++y){ id[1] = y; for (int z = 0; z < ObliquePlaneTestVolumeSize ; ++z){ id[2] = z; areSame = refImgReadAccessor.GetPixelByIndex(id) == workingImgReadAccessor.GetPixelByIndex(id); if(!areSame) goto stop; } } } stop: MITK_TEST_CONDITION(areSame,"comparing images (no mitk convertion) [oblique]"); /*==============TEST WITH MITK CONVERTION=============================*/ /* ============= extract slice ============*/ mitk::ExtractSliceFilter::Pointer slicer2 = mitk::ExtractSliceFilter::New(); slicer2->SetInput(workingImage); slicer2->SetWorldGeometry(obliquePlane); slicer2->Modified(); slicer2->Update(); mitk::Image::Pointer sliceInMitk = slicer2->GetOutput(); vtkSmartPointer slice2 = vtkSmartPointer::New(); slice2 = sliceInMitk->GetVtkImageData(); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx2 = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer overwriter2 = mitk::ExtractSliceFilter::New(resliceIdx2); resliceIdx2->SetOverwriteMode(true); resliceIdx2->SetInputSlice(slice2); resliceIdx2->Modified(); overwriter2->SetInput(workingImage); overwriter2->SetWorldGeometry(obliquePlane); overwriter2->SetVtkOutputRequest(true); overwriter2->Modified(); overwriter2->Update(); /* ============= check ref == working ============*/ areSame = true; id[0] = id[1] = id[2] = 0; for (int x = 0; x < ObliquePlaneTestVolumeSize ; ++x){ id[0] = x; for (int y = 0; y < ObliquePlaneTestVolumeSize ; ++y){ id[1] = y; for (int z = 0; z < ObliquePlaneTestVolumeSize ; ++z){ id[2] = z; areSame = refImgReadAccessor.GetPixelByIndex(id) == workingImgReadAccessor.GetPixelByIndex(id); if(!areSame) goto stop2; } } } stop2: MITK_TEST_CONDITION(areSame,"comparing images (with mitk convertion) [oblique]"); /*==============TEST EDIT WITHOUT MITK CONVERTION=============================*/ /* ============= edit slice ============*/ int idX = std::abs(ObliquePlaneTestVolumeSize -59); int idY = std::abs(ObliquePlaneTestVolumeSize -23); int idZ = 0; int component = 0; double val = 33.0; slice->SetScalarComponentFromDouble(idX,idY,idZ,component,val); mitk::Vector3D indx; indx[0] = idX; indx[1] = idY; indx[2] = idZ; sliceInMitk->GetGeometry()->IndexToWorld(indx, indx); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx3 = vtkSmartPointer::New(); resliceIdx3->SetOverwriteMode(true); resliceIdx3->SetInputSlice(slice); mitk::ExtractSliceFilter::Pointer overwriter3 = mitk::ExtractSliceFilter::New(resliceIdx3); overwriter3->SetInput(workingImage); overwriter3->SetWorldGeometry(obliquePlane); overwriter3->SetVtkOutputRequest(true); overwriter3->Modified(); overwriter3->Update(); /* ============= check ============*/ areSame = true; int x,y,z; for ( x = 0; x < ObliquePlaneTestVolumeSize ; ++x){ id[0] = x; for ( y = 0; y < ObliquePlaneTestVolumeSize ; ++y){ id[1] = y; for ( z = 0; z < ObliquePlaneTestVolumeSize ; ++z){ id[2] = z; areSame = refImgReadAccessor.GetPixelByIndex(id) == workingImgReadAccessor.GetPixelByIndex(id); if(!areSame) goto stop3; } } } stop3: //MITK_INFO << "index: [" << x << ", " << y << ", " << z << "]"; //MITK_INFO << indx; MITK_TEST_CONDITION(x==idX && y==z,"overwrited the right index [oblique]"); } /*================ #BEGIN test main ================*/ -int mitkOverwriteSliceFilterObliquePlaneTest(int argc, char* argv[]) +int mitkOverwriteSliceFilterObliquePlaneTest(int , char* []) { MITK_TEST_BEGIN("mitkOverwriteSliceFilterObliquePlaneTest") typedef itk::Image ImageType; typedef itk::ImageRegionConstIterator< ImageType > ImageIterator; ImageType::Pointer image = ImageType::New(); ImageType::IndexType start; start[0] = start[1] = start[2] = 0; ImageType::SizeType size; size[0] = size[1] = size[2] = ObliquePlaneTestVolumeSize ; ImageType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); image->SetRegions(imgRegion); image->SetSpacing(1.0); image->Allocate(); ImageIterator imageIterator( image, image->GetLargestPossibleRegion() ); imageIterator.GoToBegin(); unsigned short pixelValue = 0; //fill the image with distinct values while ( !imageIterator.IsAtEnd() ) { image->SetPixel(imageIterator.GetIndex(), pixelValue); ++imageIterator; ++pixelValue; } /* end setup itk image */ mitk::Image::Pointer refImage; CastToMitkImage(image, refImage); mitk::Image::Pointer workingImg; CastToMitkImage(image, workingImg); OverwriteObliquePlaneTest(workingImg, refImage); MITK_TEST_END() } diff --git a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp index 36f9f1a528..ae61e53f0b 100644 --- a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp +++ b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp @@ -1,205 +1,205 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include int VolumeSize = 128; /*================ #BEGIN test main ================*/ -int mitkOverwriteSliceFilterTest(int argc, char* argv[]) +int mitkOverwriteSliceFilterTest(int, char* []) { MITK_TEST_BEGIN("mitkOverwriteSliceFilterTest") typedef itk::Image ImageType; typedef itk::ImageRegionConstIterator< ImageType > ImageIterator; ImageType::Pointer image = ImageType::New(); ImageType::IndexType start; start[0] = start[1] = start[2] = 0; ImageType::SizeType size; size[0] = size[1] = size[2] = VolumeSize; ImageType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); image->SetRegions(imgRegion); image->SetSpacing(1.0); image->Allocate(); ImageIterator imageIterator( image, image->GetLargestPossibleRegion() ); imageIterator.GoToBegin(); unsigned short pixelValue = 0; //fill the image with distinct values while ( !imageIterator.IsAtEnd() ) { image->SetPixel(imageIterator.GetIndex(), pixelValue); ++imageIterator; ++pixelValue; } /* end setup itk image */ mitk::Image::Pointer referenceImage; CastToMitkImage(image, referenceImage); mitk::Image::Pointer workingImage; CastToMitkImage(image, workingImage); typedef mitk::ImagePixelReadAccessor< unsigned short, 3 > ReadAccessorType; ReadAccessorType refImgReadAccessor( referenceImage ); ReadAccessorType workingImgReadAccessor( workingImage ); /* ============= setup plane ============*/ int sliceindex = 55;//rand() % 32; bool isFrontside = true; bool isRotated = false; mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->InitializeStandardPlane(workingImage->GetGeometry(), mitk::PlaneGeometry::Axial, sliceindex, isFrontside, isRotated); mitk::Point3D origin = plane->GetOrigin(); mitk::Vector3D normal; normal = plane->GetNormal(); normal.Normalize(); origin += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 plane->SetOrigin(origin); /* ============= extract slice ============*/ vtkSmartPointer resliceIdx = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(resliceIdx); slicer->SetInput(workingImage); slicer->SetWorldGeometry(plane); slicer->SetVtkOutputRequest(true); slicer->Modified(); slicer->Update(); vtkSmartPointer slice = vtkSmartPointer::New(); slice = slicer->GetVtkOutput(); /* ============= overwrite slice ============*/ resliceIdx->SetOverwriteMode(true); resliceIdx->Modified(); slicer->Modified(); slicer->Update();//implicit overwrite /* ============= check ref == working ============*/ bool areSame = true; itk::Index<3> id; id[0] = id[1] = id[2] = 0; for (int x = 0; x < VolumeSize; ++x){ id[0] = x; for (int y = 0; y < VolumeSize; ++y){ id[1] = y; for (int z = 0; z < VolumeSize; ++z){ id[2] = z; areSame = refImgReadAccessor.GetPixelByIndex( id ) == workingImgReadAccessor.GetPixelByIndex( id ); if(!areSame) goto stop; } } } stop: MITK_TEST_CONDITION(areSame,"test overwrite unmodified slice"); /* ============= edit slice ============*/ int idX = std::abs(VolumeSize-59); int idY = std::abs(VolumeSize-23); int idZ = 0; int component = 0; double val = 33.0; slice->SetScalarComponentFromDouble(idX,idY,idZ,component,val); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx2 = vtkSmartPointer::New(); resliceIdx2->SetOverwriteMode(true); resliceIdx2->SetInputSlice(slice); mitk::ExtractSliceFilter::Pointer slicer2 = mitk::ExtractSliceFilter::New(resliceIdx2); slicer2->SetInput(workingImage); slicer2->SetWorldGeometry(plane); slicer2->SetVtkOutputRequest(true); slicer2->Modified(); slicer2->Update(); /* ============= check ============*/ areSame = true; int xx,yy,zz; for ( xx = 0; xx < VolumeSize; ++xx){ id[0] = xx; for ( yy = 0; yy < VolumeSize; ++yy){ id[1] = yy; for ( zz = 0; zz < VolumeSize; ++zz){ id[2] = zz; areSame = refImgReadAccessor.GetPixelByIndex( id ) == workingImgReadAccessor.GetPixelByIndex( id ); if(!areSame) goto stop2; } } } stop2: //MITK_INFO << "index: [" << x << ", " << y << ", " << z << "]"; MITK_TEST_CONDITION(xx==idX && yy==idY && zz==sliceindex,"test overwrite modified slice"); MITK_TEST_END() } diff --git a/Modules/SegmentationUI/Qmitk/QmitkToolReferenceDataSelectionBox.cpp b/Modules/SegmentationUI/Qmitk/QmitkToolReferenceDataSelectionBox.cpp index 8b6767c953..fef5292321 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkToolReferenceDataSelectionBox.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkToolReferenceDataSelectionBox.cpp @@ -1,236 +1,236 @@ /*=================================================================== 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 "QmitkToolReferenceDataSelectionBox.h" #include "QmitkDataStorageComboBox.h" //#include "QmitkPropertyListPopup.h" #include "mitkNodePredicateProperty.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateNot.h" #include "mitkRenderingManager.h" #include "mitkToolManagerProvider.h" -QmitkToolReferenceDataSelectionBox::QmitkToolReferenceDataSelectionBox(QWidget* parent, mitk::DataStorage* storage) +QmitkToolReferenceDataSelectionBox::QmitkToolReferenceDataSelectionBox(QWidget* parent) :QWidget(parent), m_SelfCall(false), m_DisplayMode(ListDataIfAnyToolMatches ), m_ToolGroupsForFiltering("default") { m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_Layout = new QVBoxLayout( this ); this->setLayout( m_Layout ); m_ReferenceDataSelectionBox = new QmitkDataStorageComboBox( this ); m_Layout->addWidget(m_ReferenceDataSelectionBox); connect( m_ReferenceDataSelectionBox, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnReferenceDataSelected(const mitk::DataNode*)) ); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkToolReferenceDataSelectionBox::OnToolManagerReferenceDataModified ); } QmitkToolReferenceDataSelectionBox::~QmitkToolReferenceDataSelectionBox() { m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate( this, &QmitkToolReferenceDataSelectionBox::OnToolManagerReferenceDataModified ); } mitk::DataStorage* QmitkToolReferenceDataSelectionBox::GetDataStorage() { return m_ToolManager->GetDataStorage(); } void QmitkToolReferenceDataSelectionBox::SetDataStorage(mitk::DataStorage& storage) { m_ToolManager->SetDataStorage(storage); } void QmitkToolReferenceDataSelectionBox::Initialize(mitk::DataStorage* storage ) { m_ReferenceDataSelectionBox->SetDataStorage( storage ); UpdateDataDisplay(); } mitk::ToolManager* QmitkToolReferenceDataSelectionBox::GetToolManager() { return m_ToolManager; } void QmitkToolReferenceDataSelectionBox::SetToolManager(mitk::ToolManager& newManager) // no NULL pointer allowed here, a manager is required { m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate( this, &QmitkToolReferenceDataSelectionBox::OnToolManagerReferenceDataModified ); m_ToolManager = &newManager; m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkToolReferenceDataSelectionBox::OnToolManagerReferenceDataModified ); UpdateDataDisplay(); } void QmitkToolReferenceDataSelectionBox::UpdateDataDisplay() { m_ReferenceDataSelectionBox->SetPredicate( GetAllPossibleReferenceImagesPredicate().GetPointer() ); EnsureOnlyReferenceImageIsVisibile(); } void QmitkToolReferenceDataSelectionBox::OnReferenceDataSelected(const mitk::DataNode* selectedNode) { emit ReferenceNodeSelected(selectedNode); m_SelfCall = true; m_ToolManager->SetReferenceData( const_cast< mitk::DataNode*>(selectedNode)); // maybe NULL m_SelfCall = false; EnsureOnlyReferenceImageIsVisibile(); } void QmitkToolReferenceDataSelectionBox::EnsureOnlyReferenceImageIsVisibile() { mitk::DataNode* selectedNode = m_ToolManager->GetReferenceData(0); mitk::DataStorage::SetOfObjects::ConstPointer allImageNodes = GetAllPossibleReferenceImages(); for ( mitk::DataStorage::SetOfObjects::const_iterator nodeIter = allImageNodes->begin(); nodeIter != allImageNodes->end(); ++nodeIter ) { mitk::DataNode* currentNode = (*nodeIter).GetPointer(); currentNode->SetVisibility( currentNode == selectedNode ); // only the selected one is visible, everything else is invisible } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkToolReferenceDataSelectionBox::OnToolManagerReferenceDataModified() { if (m_SelfCall) return; const mitk::DataNode* node = m_ToolManager->GetReferenceData(0); emit ReferenceNodeSelected(node); UpdateDataDisplay(); } mitk::NodePredicateBase::ConstPointer QmitkToolReferenceDataSelectionBox::GetAllPossibleReferenceImagesPredicate() { /** * Build up predicate: * - ask each tool that is displayed for a predicate (indicating the type of data that this tool will work with) * - connect all predicates using AND or OR, depending on the parameter m_DisplayMode (ListDataIfAllToolsMatch or ListDataIfAnyToolMatches) * \sa SetDisplayMode */ std::vector< mitk::NodePredicateBase::ConstPointer > m_Predicates; m_Predicates.clear(); mitk::NodePredicateBase::ConstPointer completePredicate = NULL; const mitk::ToolManager::ToolVectorTypeConst allTools = m_ToolManager->GetTools(); for ( mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allTools.begin(); iter != allTools.end(); ++iter ) { const mitk::Tool* tool = *iter; if ( (m_ToolGroupsForFiltering.empty()) || ( m_ToolGroupsForFiltering.find( tool->GetGroup() ) != std::string::npos ) || ( m_ToolGroupsForFiltering.find( tool->GetName() ) != std::string::npos ) ) { if (completePredicate) { if ( m_DisplayMode == ListDataIfAnyToolMatches ) { m_Predicates.push_back( mitk::NodePredicateOr::New( completePredicate, tool->GetReferenceDataPreference() ).GetPointer() ); } else { m_Predicates.push_back( mitk::NodePredicateAnd::New( completePredicate, tool->GetReferenceDataPreference() ).GetPointer() ); } completePredicate = m_Predicates.back(); } else { completePredicate = tool->GetReferenceDataPreference(); } } } return completePredicate; } mitk::DataStorage::SetOfObjects::ConstPointer QmitkToolReferenceDataSelectionBox::GetAllPossibleReferenceImages() { mitk::DataStorage* dataStorage = m_ToolManager->GetDataStorage(); if (!dataStorage) { return mitk::DataStorage::SetOfObjects::New().GetPointer(); } mitk::NodePredicateBase::ConstPointer completePredicate = GetAllPossibleReferenceImagesPredicate(); mitk::DataStorage::SetOfObjects::ConstPointer allObjects; /** * display everything matching the predicate */ if (completePredicate.IsNotNull()) { allObjects = dataStorage->GetSubset( completePredicate ); } else { allObjects = dataStorage->GetAll(); } mitk::ToolManager::DataVectorType resultVector; for ( mitk::DataStorage::SetOfObjects::const_iterator objectIter = allObjects->begin(); objectIter != allObjects->end(); ++objectIter ) { mitk::DataNode* node = (*objectIter).GetPointer(); resultVector.push_back( node ); } mitk::DataStorage::SetOfObjects::ConstPointer sceneImages = dataStorage->GetSubset( completePredicate ); return sceneImages; } void QmitkToolReferenceDataSelectionBox::SetToolGroupsForFiltering(const std::string& groups) { m_ToolGroupsForFiltering = groups; UpdateDataDisplay(); } void QmitkToolReferenceDataSelectionBox::SetDisplayMode( QmitkToolReferenceDataSelectionBox::DisplayMode mode ) { if (m_DisplayMode != mode) { m_DisplayMode = mode; UpdateDataDisplay(); } } diff --git a/Modules/SegmentationUI/Qmitk/QmitkToolReferenceDataSelectionBox.h b/Modules/SegmentationUI/Qmitk/QmitkToolReferenceDataSelectionBox.h index b0abd11981..083700775e 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkToolReferenceDataSelectionBox.h +++ b/Modules/SegmentationUI/Qmitk/QmitkToolReferenceDataSelectionBox.h @@ -1,128 +1,128 @@ /*=================================================================== 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 QmitkToolReferenceDataSelectionBox_h_Included #define QmitkToolReferenceDataSelectionBox_h_Included #include "mitkToolManager.h" #include #include "mitkDataStorage.h" #include #include class QmitkDataStorageComboBox; /** \brief Display the data selection of a ToolManager. \sa mitk::ToolManager \sa mitk::DataStorage \ingroup ToolManagerEtAl \ingroup Widgets There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage Shows the reference data of a ToolManager in a segmentation setting. The reference image can be selected from a combobox, where all images of the scene are listed. $Author: maleike $ */ class MitkSegmentationUI_EXPORT QmitkToolReferenceDataSelectionBox : public QWidget { Q_OBJECT public: /** * \brief What kind of items should be displayed. * * Every mitk::Tool holds a NodePredicateBase object, telling the kind of data that this * tool will successfully work with. There are two ways that this list box deals with * these predicates. * * DEFAULT is: list data if ANY one of the displayed tools' predicate matches. * Other option: list data if ALL one of the displayed tools' predicate matches */ enum DisplayMode { ListDataIfAllToolsMatch, ListDataIfAnyToolMatches}; - QmitkToolReferenceDataSelectionBox(QWidget* parent = 0, mitk::DataStorage* storage = 0); + QmitkToolReferenceDataSelectionBox(QWidget* parent = 0); virtual ~QmitkToolReferenceDataSelectionBox(); mitk::DataStorage* GetDataStorage(); void SetDataStorage(mitk::DataStorage& storage); /// initialization with a data storage object void Initialize(mitk::DataStorage*); void UpdateDataDisplay(); mitk::ToolManager* GetToolManager(); void SetToolManager(mitk::ToolManager&); // no NULL pointer allowed here, a manager is required void OnToolManagerReferenceDataModified(); /** * \brief No brief description. * * Should be called to restrict the number of tools that are * evaluated to build up the list. Default is to ask all tools for their predicate, by * setting the 'groups' string this can be restricted to certain groups of tools * or single tools. */ void SetToolGroupsForFiltering(const std::string& groups); /** * \brief How the list contents is determined. * * See also documentation of DisplayMode. * * \sa DisplayMode */ void SetDisplayMode( DisplayMode mode ); signals: void ReferenceNodeSelected(const mitk::DataNode*); protected slots: void OnReferenceDataSelected(const mitk::DataNode* node); void EnsureOnlyReferenceImageIsVisibile(); protected: mitk::DataStorage::SetOfObjects::ConstPointer GetAllPossibleReferenceImages(); mitk::NodePredicateBase::ConstPointer GetAllPossibleReferenceImagesPredicate(); mitk::ToolManager::Pointer m_ToolManager; QmitkDataStorageComboBox* m_ReferenceDataSelectionBox; bool m_SelfCall; DisplayMode m_DisplayMode; std::string m_ToolGroupsForFiltering; QVBoxLayout* m_Layout; }; #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkToolWorkingDataSelectionBox.cpp b/Modules/SegmentationUI/Qmitk/QmitkToolWorkingDataSelectionBox.cpp index 141456760f..fb91ee9a14 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkToolWorkingDataSelectionBox.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkToolWorkingDataSelectionBox.cpp @@ -1,298 +1,298 @@ /*=================================================================== 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 "QmitkToolWorkingDataSelectionBox.h" #include "mitkToolManagerProvider.h" -QmitkToolWorkingDataSelectionBox::QmitkToolWorkingDataSelectionBox(QWidget* parent, mitk::DataStorage* storage) +QmitkToolWorkingDataSelectionBox::QmitkToolWorkingDataSelectionBox(QWidget* parent) :QListWidget(parent), m_SelfCall(false), m_LastSelectedReferenceData(NULL), m_ToolGroupsForFiltering("default"), m_DisplayOnlyDerivedNodes(true) { m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); // this widget should be placeable from designer so it can't take other than the defaul parameters QListWidget::setSelectionMode( QListWidget::MultiSelection ); QListWidget::setDragDropMode(QListWidget::InternalMove); connect( this, SIGNAL(itemSelectionChanged()), this, SLOT(OnWorkingDataSelectionChanged()) ); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkToolWorkingDataSelectionBox::OnToolManagerReferenceDataModified ); m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkToolWorkingDataSelectionBox::OnToolManagerWorkingDataModified ); } QmitkToolWorkingDataSelectionBox::~QmitkToolWorkingDataSelectionBox() { } mitk::DataStorage* QmitkToolWorkingDataSelectionBox::GetDataStorage() { return m_ToolManager->GetDataStorage(); } void QmitkToolWorkingDataSelectionBox::SetDataStorage(mitk::DataStorage& storage) { m_ToolManager->SetDataStorage(storage); } mitk::ToolManager* QmitkToolWorkingDataSelectionBox::GetToolManager() { return m_ToolManager; } void QmitkToolWorkingDataSelectionBox::SetToolManager(mitk::ToolManager& newManager) // no NULL pointer allowed here, a manager is required { m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate( this, &QmitkToolWorkingDataSelectionBox::OnToolManagerReferenceDataModified ); m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate( this, &QmitkToolWorkingDataSelectionBox::OnToolManagerWorkingDataModified ); m_ToolManager = &newManager; m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkToolWorkingDataSelectionBox::OnToolManagerReferenceDataModified ); m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkToolWorkingDataSelectionBox::OnToolManagerWorkingDataModified ); UpdateDataDisplay(); } void QmitkToolWorkingDataSelectionBox::OnWorkingDataSelectionChanged() { static mitk::ToolManager::DataVectorType previouslySelectedNodes; mitk::ToolManager::DataVectorType selection = this->GetSelectedNodes(); previouslySelectedNodes = selection; if (selection.size() >0) { const mitk::DataNode* node = selection[0]; emit WorkingNodeSelected(node); } else { emit WorkingNodeSelected(NULL); } m_SelfCall = true; m_ToolManager->SetWorkingData( selection ); // maybe empty m_SelfCall = false; } void QmitkToolWorkingDataSelectionBox::OnToolManagerWorkingDataModified() { if (m_SelfCall) return; const mitk::DataNode* node = m_ToolManager->GetWorkingData(0); emit WorkingNodeSelected(node); UpdateDataDisplay(); } void QmitkToolWorkingDataSelectionBox::OnToolManagerReferenceDataModified() { if ( m_ToolManager->GetReferenceData(0) != m_LastSelectedReferenceData ) { m_ToolManager->SetWorkingData(NULL); UpdateDataDisplay(); m_LastSelectedReferenceData = m_ToolManager->GetReferenceData(0); } } void QmitkToolWorkingDataSelectionBox::UpdateDataDisplay() { // clear all QListWidget::clear(); m_Node.clear(); // rebuild contents mitk::ToolManager::DataVectorType allObjects = GetAllNodes( false ); for ( mitk::ToolManager::DataVectorType::const_iterator objectIter = allObjects.begin(); objectIter != allObjects.end(); ++objectIter) { mitk::DataNode* node = *objectIter; if (node) // delete this check when datastorage is really used { // get name and color std::string name = node->GetName(); float rgb[3]; rgb[0] = 1.0; rgb[1] = 0.0; rgb[2] = 0.0; node->GetColor(rgb); QRgb qrgb = qRgb( (int)(rgb[0]*255.0), (int)(rgb[1]*255.0), (int)(rgb[2]*255.0) ); QPixmap pixmap(25,18); pixmap.fill(QColor(qrgb)); // create a list item QListWidgetItem* newItem = new QListWidgetItem(); QString qname = QString::fromLocal8Bit(name.c_str()); //set name and color newItem->setText(qname); newItem->setIcon(QIcon(pixmap)); this->addItem(newItem); m_Node.insert( std::make_pair( newItem, node ) ); } } } mitk::ToolManager::DataVectorType QmitkToolWorkingDataSelectionBox::GetSelectedNodes() { mitk::ToolManager::DataVectorType result; QList items; for (int j=0; jcount(); j++) { if (this->item(j)->isSelected()) items.append(this->item(j)); } for (int i=0; isecond; if (node) result.push_back(node); } } } return result; } mitk::DataNode* QmitkToolWorkingDataSelectionBox::GetSelectedNode() { QListWidgetItem* item = QListWidget::selectedItems().first(); if (item) { ItemNodeMapType::iterator iter = m_Node.find(item); if ( iter != m_Node.end() ) { return iter->second; } } return NULL; } mitk::ToolManager::DataVectorType QmitkToolWorkingDataSelectionBox::GetAllNodes( bool onlyDerivedFromOriginal ) { mitk::DataStorage* dataStorage = m_ToolManager->GetDataStorage(); if (!dataStorage) { return mitk::ToolManager::DataVectorType(); } /** * Build up predicate: * - ask each tool that is displayed for a predicate (indicating the type of data that this tool will work with) * - connect all predicates using AND or OR, depending on the parameter m_DisplayMode (ListDataIfAllToolsMatch or ListDataIfAnyToolMatches) * \sa SetDisplayMode */ std::vector< mitk::NodePredicateBase::ConstPointer > m_Predicates; mitk::NodePredicateBase::ConstPointer completePredicate = NULL; bool rebuildNeeded = true; if (rebuildNeeded) { m_Predicates.clear(); const mitk::ToolManager::ToolVectorTypeConst allTools = m_ToolManager->GetTools(); for ( mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allTools.begin(); iter != allTools.end(); ++iter ) { const mitk::Tool* tool = *iter; if ( (m_ToolGroupsForFiltering.empty()) || ( m_ToolGroupsForFiltering.find( tool->GetGroup() ) != std::string::npos ) || ( m_ToolGroupsForFiltering.find( tool->GetName() ) != std::string::npos ) ) { if (completePredicate.IsNotNull()) { m_Predicates.push_back( mitk::NodePredicateOr::New( completePredicate, tool->GetWorkingDataPreference()).GetPointer() ); completePredicate = m_Predicates.back(); } else { completePredicate = tool->GetWorkingDataPreference(); } } } } // TODO delete all m_Predicates mitk::DataStorage::SetOfObjects::ConstPointer allObjects; /** * Two modes here: * - display only nodes below reference data from ToolManager (onlyDerivedFromOriginal == true) * - display everything matching the predicate (else) */ if ( onlyDerivedFromOriginal ) { mitk::DataNode* sourceNode( m_ToolManager->GetReferenceData(0) ); if (sourceNode) { allObjects = dataStorage->GetDerivations( sourceNode, completePredicate, false ); } else { allObjects = mitk::DataStorage::SetOfObjects::New(); } } else { if (completePredicate) { allObjects = dataStorage->GetSubset( completePredicate ); } else { allObjects = dataStorage->GetAll(); } } m_Predicates.clear(); completePredicate = NULL; mitk::ToolManager::DataVectorType resultVector; for ( mitk::DataStorage::SetOfObjects::const_iterator objectIter = allObjects->begin(); objectIter != allObjects->end(); ++objectIter ) { mitk::DataNode* node = (*objectIter).GetPointer(); resultVector.push_back( node ); } return resultVector; } diff --git a/Modules/SegmentationUI/Qmitk/QmitkToolWorkingDataSelectionBox.h b/Modules/SegmentationUI/Qmitk/QmitkToolWorkingDataSelectionBox.h index d2ca79ef0c..51b419fd18 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkToolWorkingDataSelectionBox.h +++ b/Modules/SegmentationUI/Qmitk/QmitkToolWorkingDataSelectionBox.h @@ -1,142 +1,142 @@ /*=================================================================== 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 QmitkToolWorkingDataSelectionListBox_h_Included #define QmitkToolWorkingDataSelectionListBox_h_Included // mmueller #include #include #include "mitkToolManager.h" #include "mitkProperties.h" /** \brief Display the data selection of a ToolManager. \sa mitk::ToolManager \sa mitk::DataStorage \ingroup Widgets There is a separate page describing the general design of QmitkInteractiveSegmentation: \ref QmitkInteractiveSegmentationTechnicalPage Shows the working data of a ToolManager in a segmentation setting. By default only the segmentation name is shown. The working images (segmentations) are listed in a QListView, each row telling the color and name of a single segmentation. One or several segmentations can be selected to be the "active" segmentations. $Author: maleike $ */ class MitkSegmentationUI_EXPORT QmitkToolWorkingDataSelectionBox : public QListWidget { Q_OBJECT public: /** * \brief What kind of items should be displayed. * * Every mitk::Tool holds a NodePredicateBase object, telling the kind of data that this * tool will successfully work with. There are two ways that this list box deals with * these predicates. * * DEFAULT is: list data if ANY one of the displayed tools' predicate matches. * Other option: list data if ALL one of the displayed tools' predicate matches */ enum DisplayMode { ListDataIfAllToolsMatch, ListDataIfAnyToolMatches}; - QmitkToolWorkingDataSelectionBox(QWidget* parent = 0, mitk::DataStorage* storage = 0); + QmitkToolWorkingDataSelectionBox(QWidget* parent = 0); virtual ~QmitkToolWorkingDataSelectionBox(); mitk::DataStorage* GetDataStorage(); void SetDataStorage(mitk::DataStorage& storage); /** \brief Can be called to trigger an update of the list contents. */ void UpdateDataDisplay(); /** \brief Returns the associated mitk::ToolManager. */ mitk::ToolManager* GetToolManager(); /** \brief Tell this object to listen to another ToolManager. */ void SetToolManager(mitk::ToolManager&); // no NULL pointer allowed here, a manager is required /** * \brief A list of all displayed DataNode objects. * This method might be convenient for program modules that want to display * additional information about these nodes, like a total volume of all segmentations, etc. */ mitk::ToolManager::DataVectorType GetAllNodes( bool onlyDerivedFromOriginal = true ); /** * \brief A list of all selected DataNode objects. * This method might be convenient for program modules that want to display * additional information about these nodes, like a total volume of all segmentations, etc. */ mitk::ToolManager::DataVectorType GetSelectedNodes(); /** * \brief Like GetSelectedNodes(), but will only return one object. * Will only return what QListView gives as selected object (documentation says nothing is returned if list is in Single selection mode). */ mitk::DataNode* GetSelectedNode(); /** * \brief Callback function, no need to call it. * This is used to observe and react to changes in the mitk::ToolManager object. */ void OnToolManagerWorkingDataModified(); /** * \brief Callback function, no need to call it. * This is used to observe and react to changes in the mitk::ToolManager object. */ void OnToolManagerReferenceDataModified(); signals: void WorkingNodeSelected(const mitk::DataNode*); protected slots: void OnWorkingDataSelectionChanged(); protected: typedef std::map< QListWidgetItem*, mitk::DataNode* > ItemNodeMapType; mitk::ToolManager::Pointer m_ToolManager; ItemNodeMapType m_Node; bool m_SelfCall; mitk::DataNode* m_LastSelectedReferenceData; std::string m_ToolGroupsForFiltering; bool m_DisplayOnlyDerivedNodes; }; #endif