diff --git a/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.cpp b/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.cpp index 489b324b75..b1476eaa09 100644 --- a/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.cpp +++ b/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.cpp @@ -1,235 +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. ===================================================================*/ #if(_MSC_VER==1200) #include #include #include #endif #include "mitkBoundingObjectCutter.h" #include "mitkBoundingObjectCutter.txx" #include "mitkTimeHelper.h" #include "mitkImageAccessByItk.h" #include "mitkBoundingObject.h" #include "mitkGeometry3D.h" +#include //#include "itkImageRegionIteratorWithIndex.h" namespace mitk { void BoundingObjectCutter::SetBoundingObject( const mitk::BoundingObject* boundingObject ) { m_BoundingObject = const_cast(boundingObject); // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(1, const_cast< mitk::BoundingObject * >( boundingObject ) ); } const mitk::BoundingObject* BoundingObjectCutter::GetBoundingObject() const { return m_BoundingObject.GetPointer(); } BoundingObjectCutter::BoundingObjectCutter() : m_BoundingObject(NULL), m_InsideValue(1), m_OutsideValue(0), m_AutoOutsideValue(false), m_UseInsideValue(false), m_OutsidePixelCount(0), m_InsidePixelCount(0), m_UseWholeInputRegion(false) { this->SetNumberOfIndexedInputs(2); this->SetNumberOfRequiredInputs(2); m_InputTimeSelector = mitk::ImageTimeSelector::New(); m_OutputTimeSelector = mitk::ImageTimeSelector::New(); } BoundingObjectCutter::~BoundingObjectCutter() { } const mitk::PixelType BoundingObjectCutter::GetOutputPixelType() { return this->GetInput()->GetPixelType(); } void BoundingObjectCutter::GenerateInputRequestedRegion() { mitk::Image* output = this->GetOutput(); if((output->IsInitialized()==false) || (m_BoundingObject.IsNull()) || (m_BoundingObject->GetTimeSlicedGeometry()->GetTimeSteps() == 0)) return; // we have already calculated the spatial part of the // input-requested-region in m_InputRequestedRegion in // GenerateOutputInformation (which is called before // GenerateInputRequestedRegion). GenerateTimeInInputRegion(output, const_cast< mitk::Image * > ( this->GetInput() )); GenerateTimeInInputRegion(output, m_BoundingObject.GetPointer()); } void BoundingObjectCutter::GenerateOutputInformation() { mitk::Image::Pointer output = this->GetOutput(); if ((output->IsInitialized()) && (output->GetPipelineMTime() <= m_TimeOfHeaderInitialization.GetMTime())) return; mitk::Image::Pointer input = const_cast< mitk::Image * > ( this->GetInput() ); if(input.IsNull()) { MITK_WARN << "Input is not a mitk::Image"; return; } itkDebugMacro(<<"GenerateOutputInformation()"); unsigned int dimension = input->GetDimension(); if (dimension < 3) { MITK_WARN << "ImageCropper cannot handle 1D or 2D Objects. Operation aborted."; return; } if((m_BoundingObject.IsNull()) || (m_BoundingObject->GetTimeSlicedGeometry()->GetTimeSteps() == 0)) return; mitk::Geometry3D* boGeometry = m_BoundingObject->GetGeometry(); mitk::Geometry3D* inputImageGeometry = input->GetSlicedGeometry(); // calculate bounding box of bounding-object relative to the geometry // of the input image. The result is in pixel coordinates of the input // image (because the m_IndexToWorldTransform includes the spacing). mitk::BoundingBox::Pointer boBoxRelativeToImage = boGeometry->CalculateBoundingBoxRelativeToTransform( inputImageGeometry->GetIndexToWorldTransform() ); // PART I: initialize input requested region. We do this already here (and not // later when GenerateInputRequestedRegion() is called), because we // also need the information to setup the output. // pre-initialize input-requested-region to largest-possible-region // and correct time-region; spatial part will be cropped by // bounding-box of bounding-object below m_InputRequestedRegion = input->GetLargestPossibleRegion(); // build region out of bounding-box of bounding-object mitk::SlicedData::IndexType index=m_InputRequestedRegion.GetIndex(); //init times and channels mitk::BoundingBox::PointType min = boBoxRelativeToImage->GetMinimum(); - index[0] = (mitk::SlicedData::IndexType::IndexValueType)(min[0]); - index[1] = (mitk::SlicedData::IndexType::IndexValueType)(min[1]); - index[2] = (mitk::SlicedData::IndexType::IndexValueType)(min[2]); + index[0] = (mitk::SlicedData::IndexType::IndexValueType)(std::ceil(min[0])); + index[1] = (mitk::SlicedData::IndexType::IndexValueType)(std::ceil(min[1])); + index[2] = (mitk::SlicedData::IndexType::IndexValueType)(std::ceil(min[2])); mitk::SlicedData::SizeType size = m_InputRequestedRegion.GetSize(); //init times and channels mitk::BoundingBox::PointType max = boBoxRelativeToImage->GetMaximum(); - size[0] = (mitk::SlicedData::SizeType::SizeValueType)(max[0])-index[0]; - size[1] = (mitk::SlicedData::SizeType::SizeValueType)(max[1])-index[1]; - size[2] = (mitk::SlicedData::SizeType::SizeValueType)(max[2])-index[2]; + size[0] = (mitk::SlicedData::SizeType::SizeValueType)(std::ceil(max[0])-index[0]); + size[1] = (mitk::SlicedData::SizeType::SizeValueType)(std::ceil(max[1])-index[1]); + size[2] = (mitk::SlicedData::SizeType::SizeValueType)(std::ceil(max[2])-index[2]); mitk::SlicedData::RegionType boRegion(index, size); if(m_UseWholeInputRegion == false) { // crop input-requested-region with region of bounding-object if(m_InputRequestedRegion.Crop(boRegion)==false) { // crop not possible => do nothing: set time size to 0. size.Fill(0); m_InputRequestedRegion.SetSize(size); boRegion.SetSize(size); m_BoundingObject->SetRequestedRegion(&boRegion); return; } } // set input-requested-region, because we access it later in // GenerateInputRequestedRegion (there we just set the time) input->SetRequestedRegion(&m_InputRequestedRegion); // PART II: initialize output image unsigned int *dimensions = new unsigned int [dimension]; itk2vtk(m_InputRequestedRegion.GetSize(), dimensions); if(dimension>3) memcpy(dimensions+3, input->GetDimensions()+3, (dimension-3)*sizeof(unsigned int)); output->Initialize(mitk::PixelType(GetOutputPixelType()), dimension, dimensions); delete [] dimensions; // now we have everything to initialize the transform of the output mitk::SlicedGeometry3D* slicedGeometry = output->GetSlicedGeometry(); // set the transform: use the transform of the input; // the origin will be replaced afterwards AffineTransform3D::Pointer indexToWorldTransform = AffineTransform3D::New(); indexToWorldTransform->SetParameters(input->GetSlicedGeometry()->GetIndexToWorldTransform()->GetParameters()); slicedGeometry->SetIndexToWorldTransform(indexToWorldTransform); // Position the output Image to match the corresponding region of the input image const mitk::SlicedData::IndexType& start = m_InputRequestedRegion.GetIndex(); mitk::Point3D origin; vtk2itk(start, origin); inputImageGeometry->IndexToWorld(origin, origin); slicedGeometry->SetOrigin(origin); mitk::TimeSlicedGeometry* timeSlicedGeometry = output->GetTimeSlicedGeometry(); timeSlicedGeometry->InitializeEvenlyTimed(slicedGeometry, output->GetDimension(3)); timeSlicedGeometry->CopyTimes(input->GetTimeSlicedGeometry()); m_TimeOfHeaderInitialization.Modified(); } void BoundingObjectCutter::ComputeData(mitk::Image* input3D, int boTimeStep) { AccessFixedDimensionByItk_2(input3D, CutImage, 3, this, boTimeStep); } void BoundingObjectCutter::GenerateData() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if(input.IsNull()) return; if((output->IsInitialized()==false) || (m_BoundingObject.IsNull()) || (m_BoundingObject->GetTimeSlicedGeometry()->GetTimeSteps() == 0)) return; m_InputTimeSelector->SetInput(input); m_OutputTimeSelector->SetInput(this->GetOutput()); mitk::Surface::RegionType outputRegion = output->GetRequestedRegion(); const mitk::TimeSlicedGeometry *outputTimeGeometry = output->GetTimeSlicedGeometry(); const mitk::TimeSlicedGeometry *inputTimeGeometry = input->GetTimeSlicedGeometry(); const mitk::TimeSlicedGeometry *boundingObjectTimeGeometry = m_BoundingObject->GetTimeSlicedGeometry(); ScalarType timeInMS; int timestep=0; int tstart=outputRegion.GetIndex(3); int tmax=tstart+outputRegion.GetSize(3); int t; for(t=tstart;tTimeStepToMS( t ); timestep = inputTimeGeometry->MSToTimeStep( timeInMS ); m_InputTimeSelector->SetTimeNr(timestep); m_InputTimeSelector->UpdateLargestPossibleRegion(); m_OutputTimeSelector->SetTimeNr(t); m_OutputTimeSelector->UpdateLargestPossibleRegion(); timestep = boundingObjectTimeGeometry->MSToTimeStep( timeInMS ); ComputeData(m_InputTimeSelector->GetOutput(), timestep); } m_InputTimeSelector->SetInput(NULL); m_OutputTimeSelector->SetInput(NULL); m_TimeOfHeaderInitialization.Modified(); } } // of namespace mitk diff --git a/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.txx b/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.txx index f10c0474a7..9c602b2a60 100644 --- a/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.txx +++ b/Modules/MitkExt/Algorithms/mitkBoundingObjectCutter.txx @@ -1,152 +1,151 @@ /*=================================================================== 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 MITKBOUNDINGOBJECTCUTTER_TXX #define MITKBOUNDINGOBJECTCUTTER_TXX #include "mitkStatusBar.h" #include "mitkImageToItk.h" #include "itkImageRegionIteratorWithIndex.h" namespace mitk { template < typename TPixel, unsigned int VImageDimension, typename TOutputPixel > void CutImageWithOutputTypeSelect ( itk::Image* inputItkImage, mitk::BoundingObjectCutter* cutter, int /* boTimeStep */, TOutputPixel* /* dummy */) { typedef itk::Image ItkInputImageType; typedef itk::Image ItkOutputImageType; typedef typename itk::ImageBase::RegionType ItkRegionType; typedef itk::ImageRegionIteratorWithIndex< ItkInputImageType > ItkInputImageIteratorType; typedef itk::ImageRegionIteratorWithIndex< ItkOutputImageType > ItkOutputImageIteratorType; if(cutter->m_BoundingObject.IsNull()) return; if (inputItkImage == NULL) { mitk::StatusBar::GetInstance()->DisplayErrorText ("An internal error occurred. Can't convert Image. Please report to bugs@mitk.org"); std::cout << " image is NULL...returning" << std::endl; return; } - // PART 1: convert m_InputRequestedRegion (type mitk::SlicedData::RegionType) + // PART 1: convert m_InputRequestedReg ion (type mitk::SlicedData::RegionType) // into ITK-image-region (ItkImageType::RegionType) // unfortunately, we cannot use input->GetRequestedRegion(), because it // has been destroyed by the mitk::CastToItkImage call of PART 1 // (which sets the m_RequestedRegion to the LargestPossibleRegion). // Thus, use our own member m_InputRequestedRegion insead. // first convert the index typename ItkRegionType::IndexType::IndexValueType tmpIndex[3]; itk2vtk(cutter->m_InputRequestedRegion.GetIndex(), tmpIndex); typename ItkRegionType::IndexType index; index.SetIndex(tmpIndex); // then convert the size typename ItkRegionType::SizeType::SizeValueType tmpSize[3]; itk2vtk(cutter->m_InputRequestedRegion.GetSize(), tmpSize); typename ItkRegionType::SizeType size; size.SetSize(tmpSize); //create the ITK-image-region out of index and size ItkRegionType inputRegionOfInterest(index, size); // PART 2: get access to the MITK output image via an ITK image typename mitk::ImageToItk::Pointer outputimagetoitk = mitk::ImageToItk::New(); outputimagetoitk->SetInput(cutter->m_OutputTimeSelector->GetOutput()); outputimagetoitk->Update(); typename ItkOutputImageType::Pointer outputItkImage = outputimagetoitk->GetOutput(); // PART 3: iterate over input and output using ITK iterators // create the iterators ItkInputImageIteratorType inputIt( inputItkImage, inputRegionOfInterest ); ItkOutputImageIteratorType outputIt( outputItkImage, outputItkImage->GetLargestPossibleRegion() ); // Cut the boundingbox out of the image by iterating through // all pixels and checking if they are inside using IsInside() cutter->m_OutsidePixelCount = 0; cutter->m_InsidePixelCount = 0; mitk::Point3D p; mitk::Geometry3D* inputGeometry = cutter->GetInput()->GetGeometry(); TOutputPixel outsideValue; if(cutter->m_AutoOutsideValue) { outsideValue = itk::NumericTraits::min(); } else { outsideValue = (TOutputPixel) cutter->m_OutsideValue; } - //shall we use a fixed value for each inside pixel? if (cutter->GetUseInsideValue()) { TOutputPixel insideValue = (TOutputPixel) cutter->m_InsideValue; // yes, use a fixed value for each inside pixel (create a binary mask of the bounding object) for ( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); ++inputIt, ++outputIt) { vtk2itk(inputIt.GetIndex(), p); inputGeometry->IndexToWorld(p, p); if(cutter->m_BoundingObject->IsInside(p)) { outputIt.Set(insideValue); ++cutter->m_InsidePixelCount; } else { outputIt.Set(outsideValue); ++cutter->m_OutsidePixelCount; } } } else { // no, use the pixel value of the original image (normal cutting) for ( inputIt.GoToBegin(), outputIt.GoToBegin(); !inputIt.IsAtEnd(); ++inputIt, ++outputIt) { vtk2itk(inputIt.GetIndex(), p); inputGeometry->IndexToWorld(p, p); if(cutter->m_BoundingObject->IsInside(p)) { outputIt.Set( (TOutputPixel) inputIt.Value() ); ++cutter->m_InsidePixelCount; } else { outputIt.Set( outsideValue ); ++cutter->m_OutsidePixelCount; } } } } template < typename TPixel, unsigned int VImageDimension > void CutImage( itk::Image< TPixel, VImageDimension >* inputItkImage, mitk::BoundingObjectCutter* cutter, int boTimeStep ) { TPixel* dummy = NULL; CutImageWithOutputTypeSelect(inputItkImage, cutter, boTimeStep, dummy); } } // of namespace mitk #include "mitkImageCast.h" #endif // of MITKBOUNDINGOBJECTCUTTER_TXX