void mitk::CorrectorAlgorithm::GenerateData() { Image::Pointer inputImage = const_cast<Image*>(ImageToImageFilter::GetInput(0)); if (inputImage.IsNull() || inputImage->GetDimension() != 2) { itkExceptionMacro("CorrectorAlgorithm needs a 2D image as input."); } if (m_Contour.IsNull()) { itkExceptionMacro("CorrectorAlgorithm needs a Contour object as input."); } // copy the input (since m_WorkingImage will be changed later) m_WorkingImage = inputImage; TimeGeometry::Pointer originalGeometry = NULL; if (inputImage->GetTimeGeometry() ) { originalGeometry = inputImage->GetTimeGeometry()->Clone(); m_WorkingImage->SetTimeGeometry( originalGeometry ); } else { itkExceptionMacro("Original image does not have a 'Time sliced geometry'! Cannot copy."); } Image::Pointer temporarySlice; // Convert to ipMITKSegmentationTYPE (because TobiasHeimannCorrectionAlgorithm relys on that data type) { itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage; CastToItkImage( m_WorkingImage, correctPixelTypeImage ); assert (correctPixelTypeImage.IsNotNull() ); // possible bug in CastToItkImage ? // direction maxtrix is wrong/broken/not working after CastToItkImage, leading to a failed assertion in // mitk/Core/DataStructures/mitkSlicedGeometry3D.cpp, 479: // virtual void mitk::SlicedGeometry3D::SetSpacing(const mitk::Vector3D&): Assertion `aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0' failed // solution here: we overwrite it with an unity matrix itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection; imageDirection.SetIdentity(); //correctPixelTypeImage->SetDirection(imageDirection); temporarySlice = this->GetOutput(); // temporarySlice = ImportItkImage( correctPixelTypeImage ); m_FillColor = 1; m_EraseColor = 0; ImprovedHeimannCorrectionAlgorithm(correctPixelTypeImage); CastToMitkImage( correctPixelTypeImage, temporarySlice ); } temporarySlice->SetTimeGeometry(originalGeometry); }
void mitk::CollectionGrayOpening::PerformGrayOpening(mitk::DataCollection *dataCollection, std::string name, std::string suffix) { for (size_t patient = 0; patient < dataCollection->Size(); ++patient) { DataCollection *dataPatient = dynamic_cast<DataCollection *>(dataCollection->GetData(patient).GetPointer()); if (dataPatient == nullptr) MITK_ERROR << "PerformGrayOpening - Structure of DataCollection is invalid at patient level. Data inconsistent!"; if (dataPatient->Size() == 0) MITK_ERROR << "Empty Patient Collective. Probably Fatal."; for (size_t timeStep = 0; timeStep < dataPatient->Size(); ++timeStep) { DataCollection *dataTimeStep = dynamic_cast<DataCollection *>(dataPatient->GetData(timeStep).GetPointer()); if (dataTimeStep == nullptr) MITK_ERROR << "DilateBinaryByName- Structure of DataCollection is invalid at time step level. Data inconsistent!"; // BinaryImage::Pointer itkImage = BinaryImage::New(); ImageType::Pointer itkImage = ImageType::New(); Image::Pointer tmp = dataTimeStep->GetMitkImage(name).GetPointer(); if (tmp.IsNull()) MITK_ERROR << "null"; CastToItkImage(tmp, itkImage); if (itkImage.IsNull()) MITK_ERROR << "Image " << name << " does not exist. Fatal."; typedef itk::FlatStructuringElement<3> StructuringElementType; StructuringElementType::RadiusType elementRadius; elementRadius.Fill(1); elementRadius[2] = 0; StructuringElementType structuringElement = StructuringElementType::Box(elementRadius); typedef itk::GrayscaleMorphologicalOpeningImageFilter<ImageType, ImageType, StructuringElementType> DilateImageFilterType; DilateImageFilterType::Pointer dilateFilter0 = DilateImageFilterType::New(); dilateFilter0->SetInput(itkImage); dilateFilter0->SetKernel(structuringElement); dilateFilter0->Update(); DilateImageFilterType::Pointer dilateFilter1 = DilateImageFilterType::New(); dilateFilter1->SetInput(dilateFilter0->GetOutput()); dilateFilter1->SetKernel(structuringElement); dilateFilter1->Update(); Image::Pointer dil = GrabItkImageMemory(dilateFilter1->GetOutput()); dataTimeStep->AddData(dil.GetPointer(), name + suffix, ""); } } }
void mitk::SetRegionTool::OnMouseReleased(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast<mitk::InteractionPositionEvent *>(interactionEvent); if (!positionEvent) return; assert(positionEvent->GetSender()->GetRenderWindow()); // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's // working image corresponds to that FeedbackContourTool::SetFeedbackContourVisible(false); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); int timeStep = positionEvent->GetSender()->GetTimeStep(); DataNode *workingNode(m_ToolManager->GetWorkingData(0)); if (!workingNode) return; auto *image = dynamic_cast<Image *>(workingNode->GetData()); const PlaneGeometry *planeGeometry((positionEvent->GetSender()->GetCurrentWorldPlaneGeometry())); if (!image || !planeGeometry) return; Image::Pointer slice = FeedbackContourTool::GetAffectedImageSliceAs2DImage(positionEvent, image); if (slice.IsNull()) { MITK_ERROR << "Unable to extract slice." << std::endl; return; } ContourModel *feedbackContour(FeedbackContourTool::GetFeedbackContour()); ContourModel::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( slice, feedbackContour, false, false); // false: don't add 0.5 (done by FillContourInSlice) // false: don't constrain the contour to the image's inside if (projectedContour.IsNull()) return; auto *labelImage = dynamic_cast<LabelSetImage *>(image); int activeColor = 1; if (labelImage != nullptr) { activeColor = labelImage->GetActiveLabel()->GetValue(); } mitk::ContourModelUtils::FillContourInSlice( projectedContour, timeStep, slice, image, m_PaintingPixelValue * activeColor); this->WriteBackSegmentationResult(positionEvent, slice); }
/** Close the contour, project it to the image slice and fill it in 2D. */ bool mitk::ContourTool::OnMouseReleased( StateMachineAction*, InteractionEvent* interactionEvent ) { // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's working image corresponds to that FeedbackContourTool::SetFeedbackContourVisible(false); mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>( interactionEvent ); //const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent()); if (!positionEvent) return false; assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if (!workingNode) return false; Image* image = dynamic_cast<Image*>(workingNode->GetData()); const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); if ( !image || !planeGeometry ) return false; const AbstractTransformGeometry* abstractTransformGeometry( dynamic_cast<const AbstractTransformGeometry*> (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); if ( !image || abstractTransformGeometry ) return false; // 2. Slice is known, now we try to get it as a 2D image and project the contour into index coordinates of this slice Image::Pointer slice = SegTool2D::GetAffectedImageSliceAs2DImage( positionEvent, image ); if ( slice.IsNull() ) { MITK_ERROR << "Unable to extract slice." << std::endl; return false; } ContourModel* feedbackContour = FeedbackContourTool::GetFeedbackContour(); ContourModel::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( slice, feedbackContour, true, false ); // true: actually no idea why this is neccessary, but it works :-( if (projectedContour.IsNull()) return false; int timestep = positionEvent->GetSender()->GetTimeStep(); FeedbackContourTool::FillContourInSlice( projectedContour, timestep, slice, m_PaintingPixelValue ); this->WriteBackSegmentationResult(positionEvent, slice); // 4. Make sure the result is drawn again --> is visible then. assert( positionEvent->GetSender()->GetRenderWindow() ); return true; }
bool mitk::SetRegionTool::OnMouseReleased( StateMachineAction*, InteractionEvent* interactionEvent ) { // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's working image corresponds to that FeedbackContourTool::SetFeedbackContourVisible(false); mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>( interactionEvent ); if (!positionEvent) return false; assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); int timeStep = positionEvent->GetSender()->GetTimeStep(); if (!m_FillContour && !m_StatusFillWholeSlice) return true; DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if (!workingNode) return false; Image* image = dynamic_cast<Image*>(workingNode->GetData()); const AbstractTransformGeometry* abstractTransformGeometry( dynamic_cast<const AbstractTransformGeometry*> (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); const PlaneGeometry* planeGeometry( dynamic_cast<const PlaneGeometry*> (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); if ( !image || !planeGeometry || abstractTransformGeometry ) return false; Image::Pointer slice = FeedbackContourTool::GetAffectedImageSliceAs2DImage( positionEvent, image ); if ( slice.IsNull() ) { MITK_ERROR << "Unable to extract slice." << std::endl; return false; } ContourModel* feedbackContour( FeedbackContourTool::GetFeedbackContour() ); ContourModel::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( slice, feedbackContour, false, false ); // false: don't add 0.5 (done by FillContourInSlice) // false: don't constrain the contour to the image's inside if (projectedContour.IsNull()) return false; FeedbackContourTool::FillContourInSlice( projectedContour, timeStep, slice, m_PaintingPixelValue ); this->WriteBackSegmentationResult(positionEvent, slice); m_WholeImageContourInWorldCoordinates = NULL; m_SegmentationContourInWorldCoordinates = NULL; return true; }
bool mitk::AutoCropTool::ProcessOneWorkingData( DataNode* node ) { if (node) { Image::Pointer image = dynamic_cast<Image*>( node->GetData() ); if (image.IsNull()) return false; // if (image->GetDimension() == 4) // { // Tool::ErrorMessage.Send("Cropping 3D+t segmentations is not implemented. Sorry. Bug #1281"); // return false; // } AutoCropImageFilter::Pointer cropFilter = AutoCropImageFilter::New(); cropFilter->SetInput( image ); cropFilter->SetBackgroundValue( 0 ); try { cropFilter->Update(); image = cropFilter->GetOutput(); if (image.IsNotNull()) { node->SetData( image ); } else { return false; } } catch(...) { return false; } } return true; }
void mitk::SetRegionTool::OnMousePressed(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast<mitk::InteractionPositionEvent *>(interactionEvent); if (!positionEvent) return; m_LastEventSender = positionEvent->GetSender(); m_LastEventSlice = m_LastEventSender->GetSlice(); // 1. Get the working image Image::Pointer workingSlice = FeedbackContourTool::GetAffectedWorkingSlice(positionEvent); if (workingSlice.IsNull()) return; // can't do anything without the segmentation // if click was outside the image, don't continue const BaseGeometry *sliceGeometry = workingSlice->GetGeometry(); itk::Index<3> projectedPointIn2D; sliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), projectedPointIn2D); if (!sliceGeometry->IsIndexInside(projectedPointIn2D)) { MITK_ERROR << "point apparently not inside segmentation slice" << std::endl; return; // can't use that as a seed point } typedef itk::Image<DefaultSegmentationDataType, 2> InputImageType; typedef InputImageType::IndexType IndexType; typedef itk::ConnectedThresholdImageFilter<InputImageType, InputImageType> RegionGrowingFilterType; RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New(); // convert world coordinates to image indices IndexType seedIndex; sliceGeometry->WorldToIndex(positionEvent->GetPositionInWorld(), seedIndex); // perform region growing in desired segmented region InputImageType::Pointer itkImage = InputImageType::New(); CastToItkImage(workingSlice, itkImage); regionGrower->SetInput(itkImage); regionGrower->AddSeed(seedIndex); InputImageType::PixelType bound = itkImage->GetPixel(seedIndex); regionGrower->SetLower(bound); regionGrower->SetUpper(bound); regionGrower->SetReplaceValue(1); itk::BinaryFillholeImageFilter<InputImageType>::Pointer fillHolesFilter = itk::BinaryFillholeImageFilter<InputImageType>::New(); fillHolesFilter->SetInput(regionGrower->GetOutput()); fillHolesFilter->SetForegroundValue(1); // Store result and preview mitk::Image::Pointer resultImage = mitk::GrabItkImageMemory(fillHolesFilter->GetOutput()); resultImage->SetGeometry(workingSlice->GetGeometry()); // Get the current working color DataNode *workingNode(m_ToolManager->GetWorkingData(0)); if (!workingNode) return; mitk::ImageToContourModelFilter::Pointer contourextractor = mitk::ImageToContourModelFilter::New(); contourextractor->SetInput(resultImage); contourextractor->Update(); mitk::ContourModel::Pointer awesomeContour = contourextractor->GetOutput(); FeedbackContourTool::SetFeedbackContour(awesomeContour); FeedbackContourTool::SetFeedbackContourVisible(true); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); }
void QmitkCreatePolygonModelAction::Run(const QList<DataNode::Pointer> &selectedNodes) { DataNode::Pointer selectedNode = selectedNodes[0]; Image::Pointer image = dynamic_cast<mitk::Image *>(selectedNode->GetData()); if (image.IsNull()) { return; } try { // Get preference properties for smoothing and decimation IPreferencesService::Pointer prefService = Platform::GetServiceRegistry().GetServiceById<IPreferencesService>(IPreferencesService::ID); IPreferences::Pointer segPref = prefService->GetSystemPreferences()->Node("/org.mitk.views.segmentation"); bool smoothingHint = segPref->GetBool("smoothing hint", true); ScalarType smoothing = segPref->GetDouble("smoothing value", 1.0); ScalarType decimation = segPref->GetDouble("decimation rate", 0.5); if (smoothingHint) { smoothing = 0.0; Vector3D spacing = image->GetGeometry()->GetSpacing(); for (Vector3D::Iterator iter = spacing.Begin(); iter != spacing.End(); ++iter) smoothing = max(smoothing, *iter); } ShowSegmentationAsSurface::Pointer surfaceFilter = ShowSegmentationAsSurface::New(); // Activate callback functions itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::Pointer successCommand = itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::New(); successCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); surfaceFilter->AddObserver(ResultAvailable(), successCommand); itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::Pointer errorCommand = itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::New(); errorCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); surfaceFilter->AddObserver(ProcessingError(), errorCommand); // set filter parameter surfaceFilter->SetDataStorage(*m_DataStorage); surfaceFilter->SetPointerParameter("Input", image); surfaceFilter->SetPointerParameter("Group node", selectedNode); surfaceFilter->SetParameter("Show result", true); surfaceFilter->SetParameter("Sync visibility", false); surfaceFilter->SetParameter("Median kernel size", 3u); surfaceFilter->SetParameter("Decimate mesh", m_IsDecimated); surfaceFilter->SetParameter("Decimation rate", (float) decimation); if (m_IsSmoothed) { surfaceFilter->SetParameter("Apply median", true); surfaceFilter->SetParameter("Smooth", true); surfaceFilter->SetParameter("Gaussian SD", sqrtf(smoothing)); // use sqrt to account for setting of variance in preferences StatusBar::GetInstance()->DisplayText("Smoothed surface creation started in background..."); } else { surfaceFilter->SetParameter("Apply median", false); surfaceFilter->SetParameter("Smooth", false); StatusBar::GetInstance()->DisplayText("Surface creation started in background..."); } surfaceFilter->StartAlgorithm(); } catch(...) { MITK_ERROR << "Surface creation failed!"; } }
void mitk::CorrectorAlgorithm::GenerateData() { Image::Pointer inputImage = const_cast<Image*>(ImageToImageFilter::GetInput(0)); if (inputImage.IsNull() || inputImage->GetDimension() != 2) { itkExceptionMacro("CorrectorAlgorithm needs a 2D image as input."); } if (m_Contour.IsNull()) { itkExceptionMacro("CorrectorAlgorithm needs a Contour object as input."); } // copy the input (since m_WorkingImage will be changed later) m_WorkingImage = Image::New(); m_WorkingImage->Initialize( inputImage ); m_WorkingImage->SetVolume( inputImage.GetPointer()->GetData() ); if (inputImage->GetTimeSlicedGeometry() ) { AffineGeometryFrame3D::Pointer originalGeometryAGF = inputImage->GetTimeSlicedGeometry()->Clone(); TimeSlicedGeometry::Pointer originalGeometry = dynamic_cast<TimeSlicedGeometry*>( originalGeometryAGF.GetPointer() ); m_WorkingImage->SetGeometry( originalGeometry ); } else { itkExceptionMacro("Original image does not have a 'Time sliced geometry'! Cannot copy."); } // Convert to ipMITKSegmentationTYPE (because TobiasHeimannCorrectionAlgorithm relys on that data type) itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage; CastToItkImage( m_WorkingImage, correctPixelTypeImage ); assert (correctPixelTypeImage.IsNotNull() ); // possible bug in CastToItkImage ? // direction maxtrix is wrong/broken/not working after CastToItkImage, leading to a failed assertion in // mitk/Core/DataStructures/mitkSlicedGeometry3D.cpp, 479: // virtual void mitk::SlicedGeometry3D::SetSpacing(const mitk::Vector3D&): Assertion `aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0' failed // solution here: we overwrite it with an unity matrix itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection; imageDirection.SetIdentity(); correctPixelTypeImage->SetDirection(imageDirection); Image::Pointer temporarySlice = this->GetOutput(); // temporarySlice = ImportItkImage( correctPixelTypeImage ); CastToMitkImage( correctPixelTypeImage, temporarySlice ); TobiasHeimannCorrectionAlgorithm( temporarySlice->GetSliceData()->GetPicDescriptor() ); // temporarySlice is our return value (user can get it by calling GetOutput() ) CalculateDifferenceImage( temporarySlice, inputImage ); if ( m_DifferenceImage.IsNotNull() && inputImage->GetTimeSlicedGeometry() ) { AffineGeometryFrame3D::Pointer originalGeometryAGF = inputImage->GetTimeSlicedGeometry()->Clone(); TimeSlicedGeometry::Pointer originalGeometry = dynamic_cast<TimeSlicedGeometry*>( originalGeometryAGF.GetPointer() ); m_DifferenceImage->SetGeometry( originalGeometry ); } else { itkExceptionMacro("Original image does not have a 'Time sliced geometry'! Cannot copy."); } }
void mitk::SurfaceBasedInterpolationController::Interpolate() { if (m_MapOfContourLists[m_ActiveLabel].size() < 2) { // If no interpolation is possible reset the interpolation result m_InterpolationResult = nullptr; return; } m_InterpolateSurfaceFilter->Reset(); // MLI TODO // m_InterpolateSurfaceFilter->SetReferenceImage( m_WorkingImage ); // CreateDistanceImageFromSurfaceFilter::Pointer interpolateSurfaceFilter = // CreateDistanceImageFromSurfaceFilter::New(); vtkSmartPointer<vtkAppendPolyData> polyDataAppender = vtkSmartPointer<vtkAppendPolyData>::New(); for (unsigned int i = 0; i < m_MapOfContourLists[m_ActiveLabel].size(); i++) { mitk::ContourModelToSurfaceFilter::Pointer converter = mitk::ContourModelToSurfaceFilter::New(); converter->SetInput(m_MapOfContourLists[m_ActiveLabel].at(i).first); converter->Update(); mitk::Surface::Pointer surface = converter->GetOutput(); surface->DisconnectPipeline(); ReduceContourSetFilter::Pointer reduceFilter = ReduceContourSetFilter::New(); reduceFilter->SetUseProgressBar(false); reduceFilter->SetInput(surface); reduceFilter->SetMinSpacing(m_MinSpacing); reduceFilter->SetMaxSpacing(m_MaxSpacing); reduceFilter->Update(); ComputeContourSetNormalsFilter::Pointer normalsFilter = ComputeContourSetNormalsFilter::New(); normalsFilter->SetUseProgressBar(false); normalsFilter->SetInput(reduceFilter->GetOutput()); normalsFilter->SetMaxSpacing(m_MaxSpacing); // MLI TODO // normalsFilter->SetSegmentationBinaryImage(m_WorkingImage, m_ActiveLabel); // normalsFilter->Update(); m_InterpolateSurfaceFilter->SetInput(i, normalsFilter->GetOutput()); polyDataAppender->AddInputData(reduceFilter->GetOutput()->GetVtkPolyData()); } polyDataAppender->Update(); m_Contours->SetVtkPolyData(polyDataAppender->GetOutput()); // update the filter and get the resulting distance-image m_InterpolateSurfaceFilter->Update(); Image::Pointer distanceImage = m_InterpolateSurfaceFilter->GetOutput(); if (distanceImage.IsNull()) { // If no interpolation is possible reset the interpolation result m_InterpolationResult = nullptr; return; } // create a surface from the distance-image mitk::ImageToSurfaceFilter::Pointer imageToSurfaceFilter = mitk::ImageToSurfaceFilter::New(); imageToSurfaceFilter->SetInput(distanceImage); imageToSurfaceFilter->SetThreshold(0); imageToSurfaceFilter->SetSmooth(true); imageToSurfaceFilter->SetSmoothIteration(20); imageToSurfaceFilter->Update(); m_InterpolationResult = imageToSurfaceFilter->GetOutput(); m_InterpolationResult->DisconnectPipeline(); }
void QmitkCreatePolygonModelAction::Run(const QList<DataNode::Pointer> &selectedNodes) { DataNode::Pointer selectedNode = selectedNodes[0]; Image::Pointer image = dynamic_cast<mitk::Image *>(selectedNode->GetData()); if (image.IsNull()) return; try { if (!m_IsSmoothed) { ShowSegmentationAsSurface::Pointer surfaceFilter = ShowSegmentationAsSurface::New(); itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::Pointer successCommand = itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::New(); successCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); surfaceFilter->AddObserver(ResultAvailable(), successCommand); itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::Pointer errorCommand = itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::New(); errorCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); surfaceFilter->AddObserver(ProcessingError(), errorCommand); surfaceFilter->SetDataStorage(*m_DataStorage); surfaceFilter->SetPointerParameter("Input", image); surfaceFilter->SetPointerParameter("Group node", selectedNode); surfaceFilter->SetParameter("Show result", true); surfaceFilter->SetParameter("Sync visibility", false); surfaceFilter->SetParameter("Smooth", false); surfaceFilter->SetParameter("Apply median", false); surfaceFilter->SetParameter("Median kernel size", 3u); surfaceFilter->SetParameter("Gaussian SD", 1.5f); surfaceFilter->SetParameter("Decimate mesh", m_IsDecimated); surfaceFilter->SetParameter("Decimation rate", 0.8f); StatusBar::GetInstance()->DisplayText("Surface creation started in background..."); surfaceFilter->StartAlgorithm(); } else { ShowSegmentationAsSmoothedSurface::Pointer surfaceFilter = ShowSegmentationAsSmoothedSurface::New(); itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::Pointer successCommand = itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::New(); successCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); surfaceFilter->AddObserver(mitk::ResultAvailable(), successCommand); itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::Pointer errorCommand = itk::SimpleMemberCommand<QmitkCreatePolygonModelAction>::New(); errorCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); surfaceFilter->AddObserver(mitk::ProcessingError(), errorCommand); surfaceFilter->SetDataStorage(*m_DataStorage); surfaceFilter->SetPointerParameter("Input", image); surfaceFilter->SetPointerParameter("Group node", selectedNode); berry::IWorkbenchPart::Pointer activePart = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->GetActivePart(); mitk::IRenderWindowPart* renderPart = dynamic_cast<mitk::IRenderWindowPart*>(activePart.GetPointer()); mitk::SliceNavigationController* timeNavController = 0; if (renderPart != 0) { timeNavController = renderPart->GetRenderingManager()->GetTimeNavigationController(); } int timeNr = timeNavController != 0 ? timeNavController->GetTime()->GetPos() : 0; surfaceFilter->SetParameter("TimeNr", timeNr); IPreferencesService::Pointer prefService = Platform::GetServiceRegistry().GetServiceById<IPreferencesService>(IPreferencesService::ID); IPreferences::Pointer segPref = prefService->GetSystemPreferences()->Node("/org.mitk.views.segmentation"); bool smoothingHint = segPref->GetBool("smoothing hint", true); float smoothing = (float)segPref->GetDouble("smoothing value", 1.0); float decimation = (float)segPref->GetDouble("decimation rate", 0.5); float closing = (float)segPref->GetDouble("closing ratio", 0.0); if (smoothingHint) { smoothing = 0.0; Vector3D spacing = image->GetGeometry()->GetSpacing(); for (Vector3D::Iterator iter = spacing.Begin(); iter != spacing.End(); ++iter) smoothing = max(smoothing, *iter); } surfaceFilter->SetParameter("Smoothing", smoothing); surfaceFilter->SetParameter("Decimation", decimation); surfaceFilter->SetParameter("Closing", closing); ProgressBar::GetInstance()->AddStepsToDo(8); StatusBar::GetInstance()->DisplayText("Smoothed surface creation started in background..."); try { surfaceFilter->StartAlgorithm(); } catch (...) { MITK_ERROR<<"Error creating smoothed polygon model: Not enough memory!"; } } } catch(...) { MITK_ERROR << "Surface creation failed!"; } }
bool mitk::SetRegionTool::OnMousePressed ( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast<mitk::InteractionPositionEvent*>( interactionEvent ); //const PositionEvent* positionEvent = dynamic_cast<const PositionEvent*>(stateEvent->GetEvent()); if (!positionEvent) return false; m_LastEventSender = positionEvent->GetSender(); m_LastEventSlice = m_LastEventSender->GetSlice(); int timeStep = positionEvent->GetSender()->GetTimeStep(); // 1. Get the working image Image::Pointer workingSlice = FeedbackContourTool::GetAffectedWorkingSlice( positionEvent ); if ( workingSlice.IsNull() ) return false; // can't do anything without the segmentation // if click was outside the image, don't continue const BaseGeometry* sliceGeometry = workingSlice->GetGeometry(); itk::Index<2> projectedPointIn2D; sliceGeometry->WorldToIndex( positionEvent->GetPositionInWorld(), projectedPointIn2D ); if ( !sliceGeometry->IsIndexInside( projectedPointIn2D ) ) { MITK_ERROR << "point apparently not inside segmentation slice" << std::endl; return false; // can't use that as a seed point } // Convert to ipMITKSegmentationTYPE (because ipMITKSegmentationGetContour8N relys on that data type) itk::Image< ipMITKSegmentationTYPE, 2 >::Pointer correctPixelTypeImage; CastToItkImage( workingSlice, correctPixelTypeImage ); assert (correctPixelTypeImage.IsNotNull() ); // possible bug in CastToItkImage ? // direction maxtrix is wrong/broken/not working after CastToItkImage, leading to a failed assertion in // mitk/Core/DataStructures/mitkSlicedGeometry3D.cpp, 479: // virtual void mitk::SlicedGeometry3D::SetSpacing(const mitk::Vector3D&): Assertion `aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0' failed // solution here: we overwrite it with an unity matrix itk::Image< ipMITKSegmentationTYPE, 2 >::DirectionType imageDirection; imageDirection.SetIdentity(); correctPixelTypeImage->SetDirection(imageDirection); Image::Pointer temporarySlice = Image::New(); // temporarySlice = ImportItkImage( correctPixelTypeImage ); CastToMitkImage( correctPixelTypeImage, temporarySlice ); // check index positions mitkIpPicDescriptor* originalPicSlice = mitkIpPicNew(); CastToIpPicDescriptor( temporarySlice, originalPicSlice ); int m_SeedPointMemoryOffset = projectedPointIn2D[1] * originalPicSlice->n[0] + projectedPointIn2D[0]; if ( m_SeedPointMemoryOffset >= static_cast<int>( originalPicSlice->n[0] * originalPicSlice->n[1] ) || m_SeedPointMemoryOffset < 0 ) { MITK_ERROR << "Memory offset calculation if mitk::SetRegionTool has some serious flaw! Aborting.." << std::endl; return false; } // 2. Determine the contour that surronds the selected "piece of the image" // find a contour seed point unsigned int oneContourOffset = static_cast<unsigned int>( m_SeedPointMemoryOffset ); // safe because of earlier check if m_SeedPointMemoryOffset < 0 /** * The logic of finding a starting point for the contour is the following: * * - If the initial seed point is 0, we are either inside a hole or outside of every segmentation. * We move to the right until we hit a 1, which must be part of a contour. * * - If the initial seed point is 1, then ... * we now do the same (running to the right) until we hit a 1 * * In both cases the found contour point is used to extract a contour and * then a test is applied to find out if the initial seed point is contained * in the contour. If this is the case, filling should be applied, otherwise * nothing is done. */ unsigned int size = originalPicSlice->n[0] * originalPicSlice->n[1]; /* unsigned int rowSize = originalPicSlice->n[0]; */ ipMITKSegmentationTYPE* data = static_cast<ipMITKSegmentationTYPE*>(originalPicSlice->data); if ( data[oneContourOffset] == 0 ) // initial seed 0 { for ( ; oneContourOffset < size; ++oneContourOffset ) { if ( data[oneContourOffset] > 0 ) break; } } else if ( data[oneContourOffset] == 1 ) // initial seed 1 { unsigned int lastValidPixel = size-1; // initialization, will be changed lateron bool inSeg = true; // inside segmentation? for ( ; oneContourOffset < size; ++oneContourOffset ) { if ( ( data[oneContourOffset] == 0 ) && inSeg ) // pixel 0 and inside-flag set: this happens at the first pixel outside a filled region { inSeg = false; lastValidPixel = oneContourOffset - 1; // store the last pixel position inside a filled region break; } else // pixel 1, inside-flag doesn't matter: this happens while we are inside a filled region { inSeg = true; // first iteration lands here } } oneContourOffset = lastValidPixel; } else { MITK_ERROR << "Fill/Erase was never intended to work with other than binary images." << std::endl; m_FillContour = false; return false; } if (oneContourOffset == size) // nothing found until end of slice { m_FillContour = false; return false; } int numberOfContourPoints( 0 ); int newBufferSize( 0 ); //MITK_INFO << "getting contour from offset " << oneContourOffset << " ("<<oneContourOffset%originalPicSlice->n[0]<<","<<oneContourOffset/originalPicSlice->n[0]<<")"<<std::endl; float* contourPoints = ipMITKSegmentationGetContour8N( originalPicSlice, oneContourOffset, numberOfContourPoints, newBufferSize ); // memory allocated with malloc //MITK_INFO << "contourPoints " << contourPoints << " (N="<<numberOfContourPoints<<")"<<std::endl; assert(contourPoints == NULL || numberOfContourPoints > 0); bool cursorInsideContour = ipMITKSegmentationIsInsideContour( contourPoints, numberOfContourPoints, projectedPointIn2D[0], projectedPointIn2D[1]); // decide if contour should be filled or not m_FillContour = cursorInsideContour; if (m_FillContour) { // copy point from float* to mitk::Contour ContourModel::Pointer contourInImageIndexCoordinates = ContourModel::New(); contourInImageIndexCoordinates->Expand(timeStep + 1); contourInImageIndexCoordinates->SetClosed(true, timeStep); Point3D newPoint; for (int index = 0; index < numberOfContourPoints; ++index) { newPoint[0] = contourPoints[ 2 * index + 0 ] - 0.5; newPoint[1] = contourPoints[ 2 * index + 1] - 0.5; newPoint[2] = 0; contourInImageIndexCoordinates->AddVertex(newPoint, timeStep); } m_SegmentationContourInWorldCoordinates = FeedbackContourTool::BackProjectContourFrom2DSlice( workingSlice->GetGeometry(), contourInImageIndexCoordinates, true ); // true, correct the result from ipMITKSegmentationGetContour8N // 3. Show the contour FeedbackContourTool::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates ); FeedbackContourTool::SetFeedbackContourVisible(true); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } // always generate a second contour, containing the whole image (used when CTRL is pressed) { // copy point from float* to mitk::Contour ContourModel::Pointer contourInImageIndexCoordinates = ContourModel::New(); contourInImageIndexCoordinates->Expand(timeStep + 1); contourInImageIndexCoordinates->SetClosed(true, timeStep); Point3D newPoint; newPoint[0] = 0; newPoint[1] = 0; newPoint[2] = 0.0; contourInImageIndexCoordinates->AddVertex( newPoint, timeStep ); newPoint[0] = originalPicSlice->n[0]; newPoint[1] = 0; newPoint[2] = 0.0; contourInImageIndexCoordinates->AddVertex( newPoint, timeStep ); newPoint[0] = originalPicSlice->n[0]; newPoint[1] = originalPicSlice->n[1]; newPoint[2] = 0.0; contourInImageIndexCoordinates->AddVertex( newPoint, timeStep ); newPoint[0] = 0; newPoint[1] = originalPicSlice->n[1]; newPoint[2] = 0.0; contourInImageIndexCoordinates->AddVertex( newPoint, timeStep ); m_WholeImageContourInWorldCoordinates = FeedbackContourTool::BackProjectContourFrom2DSlice( workingSlice->GetGeometry(), contourInImageIndexCoordinates, true ); // true, correct the result from ipMITKSegmentationGetContour8N // 3. Show the contour FeedbackContourTool::SetFeedbackContour( *m_SegmentationContourInWorldCoordinates ); FeedbackContourTool::SetFeedbackContourVisible(true); mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } free(contourPoints); return true; }