diff --git a/Modules/Bundles/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp b/Modules/Bundles/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp index 78f8e00b7e..c89b974df2 100644 --- a/Modules/Bundles/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp @@ -1,521 +1,522 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2010-03-31 16:40:27 +0200 (Mi, 31 Mrz 2010) $ Version: $Revision: 21975 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ // Qmitk #include "QmitkToFUtilView.h" #include #include // Qt #include #include // MITK #include #include #include #include #include #include // VTK #include // ITK #include const std::string QmitkToFUtilView::VIEW_ID = "org.mitk.views.tofutil"; QmitkToFUtilView::QmitkToFUtilView() : QmitkFunctionality() , m_Controls(NULL), m_MultiWidget( NULL ) , m_MitkDistanceImage(NULL), m_MitkAmplitudeImage(NULL), m_MitkIntensityImage(NULL), m_Surface(NULL) , m_DistanceImageNode(NULL), m_AmplitudeImageNode(NULL), m_IntensityImageNode(NULL), m_SurfaceNode(NULL) , m_ToFImageRecorder(NULL), m_ToFImageGrabber(NULL), m_ToFDistanceImageToSurfaceFilter(NULL), m_ToFCompositeFilter(NULL) , m_SurfaceDisplayCount(0), m_2DDisplayCount(0) , m_RealTimeClock(NULL) , m_StepsForFramerate(100) , m_2DTimeBefore(0.0) , m_2DTimeAfter(0.0) , m_VideoEnabled(false) { this->m_Frametimer = new QTimer(this); this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); this->m_ToFSurfaceVtkMapper3D = mitk::ToFSurfaceVtkMapper3D::New(); } QmitkToFUtilView::~QmitkToFUtilView() { OnToFCameraStopped(); OnToFCameraDisconnected(); } void QmitkToFUtilView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkToFUtilViewControls; m_Controls->setupUi( parent ); connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraConnected()), this, SLOT(OnToFCameraConnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraDisconnected()), this, SLOT(OnToFCameraDisconnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraSelected(const QString)), this, SLOT(OnToFCameraSelected(const QString)) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStarted()), this, SLOT(OnToFCameraStarted()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStopped()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_TextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTextureCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_VideoTextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnVideoTextureCheckBoxChecked(bool)) ); } } void QmitkToFUtilView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkToFUtilView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkToFUtilView::Activated() { QmitkFunctionality::Activated(); // configure views m_MultiWidget->SetWidgetPlanesVisibility(false); m_MultiWidget->mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); m_MultiWidget->mitkWidget1->GetSliceNavigationController()->SliceLockedOn(); m_MultiWidget->mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); m_MultiWidget->mitkWidget2->GetSliceNavigationController()->SliceLockedOn(); m_MultiWidget->mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); m_MultiWidget->mitkWidget3->GetSliceNavigationController()->SliceLockedOn(); this->UseToFVisibilitySettings(true); m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); + m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDefaultDataStorage()); if (this->m_ToFImageGrabber.IsNull()) { m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); } } void QmitkToFUtilView::Deactivated() { m_MultiWidget->SetWidgetPlanesVisibility(true); m_MultiWidget->mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); m_MultiWidget->mitkWidget1->GetSliceNavigationController()->SliceLockedOff(); m_MultiWidget->mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); m_MultiWidget->mitkWidget2->GetSliceNavigationController()->SliceLockedOff(); m_MultiWidget->mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); m_MultiWidget->mitkWidget3->GetSliceNavigationController()->SliceLockedOff(); this->UseToFVisibilitySettings(false); mitk::RenderingManager::GetInstance()->InitializeViews(); mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); QmitkFunctionality::Deactivated(); } void QmitkToFUtilView::OnToFCameraConnected() { this->m_SurfaceDisplayCount = 0; this->m_2DDisplayCount = 0; this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); this->m_ToFImageRecorder->SetCameraDevice(this->m_ToFImageGrabber->GetCameraDevice()); m_Controls->m_ToFRecorderWidget->SetParameter(this->m_ToFImageGrabber, this->m_ToFImageRecorder); m_Controls->m_ToFRecorderWidget->setEnabled(true); m_Controls->m_ToFRecorderWidget->ResetGUIToInitial(); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(true); //TODO this->m_RealTimeClock = mitk::RealTimeClock::New(); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); try { this->m_VideoSource = mitk::OpenCVVideoSource::New(); this->m_VideoSource->SetVideoCameraInput(0, false); this->m_VideoSource->StartCapturing(); if(!this->m_VideoSource->IsCapturingEnabled()) { MITK_INFO << "unable to initialize video grabbing/playback"; this->m_VideoEnabled = false; m_Controls->m_VideoTextureCheckBox->setEnabled(false); } else { this->m_VideoEnabled = true; m_Controls->m_VideoTextureCheckBox->setEnabled(true); } if (this->m_VideoEnabled) { this->m_VideoSource->FetchFrame(); this->m_VideoCaptureHeight = this->m_VideoSource->GetImageHeight(); this->m_VideoCaptureWidth = this->m_VideoSource->GetImageWidth(); int videoTexSize = this->m_VideoCaptureWidth * this->m_VideoCaptureHeight * 3; // for each pixel three values for rgb are needed!! this->m_VideoTexture = this->m_VideoSource->GetVideoTexture(); unsigned int dimensions[2]; dimensions[0] = this->m_VideoCaptureWidth; dimensions[1] = this->m_VideoCaptureHeight; this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageWidth(this->m_VideoCaptureWidth); this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageHeight(this->m_VideoCaptureHeight); this->m_ToFSurfaceVtkMapper3D->SetTextureWidth(this->m_VideoCaptureWidth); this->m_ToFSurfaceVtkMapper3D->SetTextureHeight(this->m_VideoCaptureHeight); } m_MultiWidget->DisableGradientBackground(); } catch (std::logic_error& e) { QMessageBox::warning(NULL, "Warning", QString(e.what())); MITK_ERROR << e.what(); return; } mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkToFUtilView::OnToFCameraDisconnected() { m_Controls->m_ToFRecorderWidget->OnStop(); m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); if(this->m_VideoSource) { this->m_VideoSource->StopCapturing(); this->m_VideoSource = NULL; } mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkToFUtilView::OnToFCameraStarted() { if (m_ToFImageGrabber.IsNotNull()) { // initial update of image grabber this->m_ToFImageGrabber->Update(); this->m_ToFCompositeFilter->SetInput(0,this->m_ToFImageGrabber->GetOutput(0)); this->m_ToFCompositeFilter->SetInput(1,this->m_ToFImageGrabber->GetOutput(1)); this->m_ToFCompositeFilter->SetInput(2,this->m_ToFImageGrabber->GetOutput(2)); // initial update of composite filter this->m_ToFCompositeFilter->Update(); this->m_MitkDistanceImage = m_ToFCompositeFilter->GetOutput(0); this->m_DistanceImageNode = ReplaceNodeData("Distance image",m_MitkDistanceImage); this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); this->m_MitkIntensityImage = m_ToFCompositeFilter->GetOutput(2); this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(0,m_MitkDistanceImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(1,m_MitkAmplitudeImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(2,m_MitkIntensityImage); this->m_Surface = this->m_ToFDistanceImageToSurfaceFilter->GetOutput(0); this->m_SurfaceNode = ReplaceNodeData("Surface",m_Surface); this->UseToFVisibilitySettings(true); this->m_Frametimer->start(0); m_Controls->m_ToFCompositeFilterWidget->UpdateFilterParameter(); // initialize visualization widget m_Controls->m_ToFVisualisationSettingsWidget->Initialize(this->m_MitkDistanceImage, this->m_MitkAmplitudeImage, this->m_MitkIntensityImage); if (m_Controls->m_TextureCheckBox->isChecked()) { OnTextureCheckBoxChecked(true); } if (m_Controls->m_VideoTextureCheckBox->isChecked()) { OnVideoTextureCheckBoxChecked(true); } } m_Controls->m_TextureCheckBox->setEnabled(true); // initialize point set measurement m_Controls->tofMeasurementWidget->InitializeWidget(m_MultiWidget,this->GetDefaultDataStorage(),m_MitkDistanceImage); } void QmitkToFUtilView::OnToFCameraStopped() { this->m_Frametimer->stop(); } void QmitkToFUtilView::OnToFCameraSelected(const QString selected) { if ((selected=="PMD CamBoard")||(selected=="PMD O3D")) { MITK_INFO<<"Surface representation currently not available for CamBoard and O3. Intrinsic parameters missing."; this->m_Controls->m_SurfaceCheckBox->setEnabled(false); this->m_Controls->m_TextureCheckBox->setEnabled(false); this->m_Controls->m_VideoTextureCheckBox->setEnabled(false); this->m_Controls->m_SurfaceCheckBox->setChecked(false); this->m_Controls->m_TextureCheckBox->setChecked(false); this->m_Controls->m_VideoTextureCheckBox->setChecked(false); } else { this->m_Controls->m_SurfaceCheckBox->setEnabled(true); this->m_Controls->m_TextureCheckBox->setEnabled(true); // TODO enable when bug 8106 is solved this->m_Controls->m_VideoTextureCheckBox->setEnabled(true); } } void QmitkToFUtilView::OnUpdateCamera() { int currentImageSequence = 0; if (m_Controls->m_VideoTextureCheckBox->isChecked() && this->m_VideoEnabled && this->m_VideoSource) { this->m_VideoTexture = this->m_VideoSource->GetVideoTexture(); ProcessVideoTransform(); } vtkColorTransferFunction* colorTransferFunction1; colorTransferFunction1 = m_Controls->m_ToFVisualisationSettingsWidget->GetWidget1ColorTransferFunction(); mitk::TransferFunction::Pointer tf1 = mitk::TransferFunction::New(); tf1->SetColorTransferFunction( colorTransferFunction1 ); m_DistanceImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf1)); vtkColorTransferFunction* colorTransferFunction2; colorTransferFunction2 = m_Controls->m_ToFVisualisationSettingsWidget->GetWidget2ColorTransferFunction(); mitk::TransferFunction::Pointer tf2 = mitk::TransferFunction::New(); tf2->SetColorTransferFunction( colorTransferFunction2 ); m_AmplitudeImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf2)); vtkColorTransferFunction* colorTransferFunction3; colorTransferFunction3 = m_Controls->m_ToFVisualisationSettingsWidget->GetWidget3ColorTransferFunction(); mitk::TransferFunction::Pointer tf3 = mitk::TransferFunction::New(); tf3->SetColorTransferFunction( colorTransferFunction3 ); m_IntensityImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf3)); if (m_Controls->m_SurfaceCheckBox->isChecked()) { // update surface m_ToFDistanceImageToSurfaceFilter->SetTextureIndex(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedImageIndex()); this->m_Surface->Update(); vtkColorTransferFunction* colorTransferFunction = m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedColorTransferFunction(); this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(colorTransferFunction); if (this->m_SurfaceDisplayCount<2) { this->m_SurfaceNode->SetData(this->m_Surface); this->m_SurfaceNode->SetMapper(mitk::BaseRenderer::Standard3D, m_ToFSurfaceVtkMapper3D); mitk::RenderingManager::GetInstance()->InitializeViews( this->m_Surface->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS, true); mitk::Point3D surfaceCenter= this->m_Surface->GetGeometry()->GetCenter(); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(0,0,-50); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(0,-1,0); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(0,0,surfaceCenter[2]); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewAngle(40); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetClippingRange(1, 10000); } this->m_SurfaceDisplayCount++; } else { // update pipeline this->m_MitkDistanceImage->Update(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->m_2DDisplayCount++; if ((this->m_2DDisplayCount % this->m_StepsForFramerate) == 0) { this->m_2DTimeAfter = this->m_RealTimeClock->GetCurrentStamp() - this->m_2DTimeBefore; MITK_INFO << " 2D-Display-framerate (fps): " << this->m_StepsForFramerate / (this->m_2DTimeAfter/1000); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); } } void QmitkToFUtilView::ProcessVideoTransform() { IplImage *src, *dst; src = cvCreateImageHeader(cvSize(this->m_VideoCaptureWidth, this->m_VideoCaptureHeight), IPL_DEPTH_8U, 3); src->imageData = (char*)this->m_VideoTexture; CvPoint2D32f srcTri[3], dstTri[3]; CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1); CvMat* warp_mat = cvCreateMat(2,3,CV_32FC1); dst = cvCloneImage(src); dst->origin = src->origin; cvZero( dst ); // Create angle and scale double angle = 0.0; double scale = 1.0; int xOffset = 0;//m_Controls->m_XOffsetSpinBox->value(); int yOffset = 0;//m_Controls->m_YOffsetSpinBox->value(); int zoom = 0;//m_Controls->m_ZoomSpinBox->value(); // Compute warp matrix srcTri[0].x = 0 + zoom; srcTri[0].y = 0 + zoom; srcTri[1].x = src->width - 1 - zoom; srcTri[1].y = 0 + zoom; srcTri[2].x = 0 + zoom; srcTri[2].y = src->height - 1 - zoom; dstTri[0].x = 0; dstTri[0].y = 0; dstTri[1].x = src->width - 1; dstTri[1].y = 0; dstTri[2].x = 0; dstTri[2].y = src->height - 1; cvGetAffineTransform( srcTri, dstTri, warp_mat ); cvWarpAffine( src, dst, warp_mat ); cvCopy ( dst, src ); // Compute warp matrix srcTri[0].x = 0; srcTri[0].y = 0; srcTri[1].x = src->width - 1; srcTri[1].y = 0; srcTri[2].x = 0; srcTri[2].y = src->height - 1; dstTri[0].x = srcTri[0].x + xOffset; dstTri[0].y = srcTri[0].y + yOffset; dstTri[1].x = srcTri[1].x + xOffset; dstTri[1].y = srcTri[1].y + yOffset; dstTri[2].x = srcTri[2].x + xOffset; dstTri[2].y = srcTri[2].y + yOffset; cvGetAffineTransform( srcTri, dstTri, warp_mat ); cvWarpAffine( src, dst, warp_mat ); cvCopy ( dst, src ); src->imageData = NULL; cvReleaseImage( &src ); cvReleaseImage( &dst ); cvReleaseMat( &rot_mat ); cvReleaseMat( &warp_mat ); } void QmitkToFUtilView::OnTextureCheckBoxChecked(bool checked) { if(m_SurfaceNode.IsNotNull()) { if (checked) { this->m_SurfaceNode->SetBoolProperty("scalar visibility", true); } else { this->m_SurfaceNode->SetBoolProperty("scalar visibility", false); } } } void QmitkToFUtilView::OnVideoTextureCheckBoxChecked(bool checked) { if (checked) { if (this->m_VideoEnabled) { this->m_ToFSurfaceVtkMapper3D->SetTexture(this->m_VideoTexture); } else { this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); } } else { this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); } } mitk::DataNode::Pointer QmitkToFUtilView::ReplaceNodeData( std::string nodeName, mitk::BaseData* data ) { mitk::DataNode::Pointer node = this->GetDefaultDataStorage()->GetNamedNode(nodeName); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetData(data); node->SetName(nodeName); this->GetDefaultDataStorage()->Add(node); } else { node->SetData(data); } return node; } void QmitkToFUtilView::UseToFVisibilitySettings(bool useToF) { // set node properties if (m_DistanceImageNode.IsNotNull()) { this->m_DistanceImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget2->GetRenderWindow() ) ); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget3->GetRenderWindow() ) ); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow() ) ); this->m_DistanceImageNode->SetBoolProperty("use color",!useToF); this->m_DistanceImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if (m_AmplitudeImageNode.IsNotNull()) { this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget1->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget3->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetBoolProperty("use color",!useToF); this->m_AmplitudeImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if (m_IntensityImageNode.IsNotNull()) { this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget1->GetRenderWindow() ) ); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget2->GetRenderWindow() ) ); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow() ) ); this->m_IntensityImageNode->SetBoolProperty("use color",!useToF); this->m_IntensityImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } // initialize images if (m_MitkDistanceImage.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( this->m_MitkDistanceImage->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS, true); } } diff --git a/Modules/ToFProcessing/mitkToFCompositeFilter.cpp b/Modules/ToFProcessing/mitkToFCompositeFilter.cpp index 02346165c1..1e5e53ac6c 100644 --- a/Modules/ToFProcessing/mitkToFCompositeFilter.cpp +++ b/Modules/ToFProcessing/mitkToFCompositeFilter.cpp @@ -1,419 +1,395 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Module: $RCSfile$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include #include //#include #include -mitk::ToFCompositeFilter::ToFCompositeFilter() : m_ImageWidth(0), m_ImageHeight(0), m_ImageSize(0), +mitk::ToFCompositeFilter::ToFCompositeFilter() : m_SegmentationMask(NULL), m_ImageWidth(0), m_ImageHeight(0), m_ImageSize(0), m_IplDistanceImage(NULL), m_IplOutputImage(NULL), m_ItkInputImage(NULL), m_ApplyTemporalMedianFilter(false), m_ApplyAverageFilter(false), -m_ApplyMedianFilter(false), m_ApplyThresholdFilter(false), m_ApplyBilateralFilter(false), m_DataBuffer(NULL), + m_ApplyMedianFilter(false), m_ApplyThresholdFilter(false), m_ApplyMaskSegmentation(false), m_ApplyBilateralFilter(false), m_DataBuffer(NULL), m_DataBufferCurrentIndex(0), m_DataBufferMaxSize(0), m_TemporalMedianFilterNumOfFrames(10), m_ThresholdFilterMin(1), m_ThresholdFilterMax(7000), m_BilateralFilterDomainSigma(2), m_BilateralFilterRangeSigma(60), m_BilateralFilterKernelRadius(0) { } mitk::ToFCompositeFilter::~ToFCompositeFilter() { cvReleaseImage(&(this->m_IplDistanceImage)); cvReleaseImage(&(this->m_IplOutputImage)); if (m_DataBuffer!=NULL) { delete [] m_DataBuffer; } } void mitk::ToFCompositeFilter::SetInput( mitk::Image* distanceImage ) { this->SetInput(0, distanceImage); } void mitk::ToFCompositeFilter::SetInput( unsigned int idx, mitk::Image* distanceImage ) { if ((distanceImage == NULL) && (idx == this->GetNumberOfInputs() - 1)) // if the last input is set to NULL, reduce the number of inputs by one { this->SetNumberOfInputs(this->GetNumberOfInputs() - 1); } else { if (idx==0) //create IPL image holding distance data { if (distanceImage->GetData()) { this->m_ImageWidth = distanceImage->GetDimension(0); this->m_ImageHeight = distanceImage->GetDimension(1); this->m_ImageSize = this->m_ImageWidth * this->m_ImageHeight * sizeof(float); if (this->m_IplDistanceImage != NULL) { cvReleaseImage(&(this->m_IplDistanceImage)); } float* distanceFloatData = (float*)distanceImage->GetSliceData(0, 0, 0)->GetData(); this->m_IplDistanceImage = cvCreateImage(cvSize(this->m_ImageWidth, this->m_ImageHeight), IPL_DEPTH_32F, 1); memcpy(this->m_IplDistanceImage->imageData, (void*)distanceFloatData, this->m_ImageSize); if (this->m_IplOutputImage != NULL) { cvReleaseImage(&(this->m_IplOutputImage)); } this->m_IplOutputImage = cvCreateImage(cvSize(this->m_ImageWidth, this->m_ImageHeight), IPL_DEPTH_32F, 1); CreateItkImage(this->m_ItkInputImage); } } this->ProcessObject::SetNthInput(idx, distanceImage); // Process object is not const-correct so the const_cast is required here } this->CreateOutputsForAllInputs(); } mitk::Image* mitk::ToFCompositeFilter::GetInput() { return this->GetInput(0); } mitk::Image* mitk::ToFCompositeFilter::GetInput( unsigned int idx ) { if (this->GetNumberOfInputs() < 1) return NULL; //TODO: geeignete exception werfen return static_cast< mitk::Image*>(this->ProcessObject::GetInput(idx)); } void mitk::ToFCompositeFilter::GenerateData() { // copy input 1...n to output 1...n for (unsigned int idx=0; idxGetNumberOfOutputs(); idx++) { mitk::Image::Pointer outputImage = this->GetOutput(idx); mitk::Image::Pointer inputImage = this->GetInput(idx); if (outputImage.IsNotNull()&&inputImage.IsNotNull()) { outputImage->CopyInformation(inputImage); - outputImage->Initialize(inputImage); + outputImage->Initialize(*inputImage->GetPixelType().GetTypeId(),inputImage->GetDimension(),inputImage->GetDimensions()); outputImage->SetSlice(inputImage->GetSliceData()->GetData()); } } mitk::Image::Pointer outputDistanceImage = this->GetOutput(0); float* outputDistanceFloatData = (float*)outputDistanceImage->GetSliceData(0, 0, 0)->GetData(); mitk::Image::Pointer inputDistanceImage = this->GetInput(); // copy initial distance image to ipl image float* distanceFloatData = (float*)inputDistanceImage->GetSliceData(0, 0, 0)->GetData(); memcpy(this->m_IplDistanceImage->imageData, (void*)distanceFloatData, this->m_ImageSize); - if (m_ApplyThresholdFilter) + if (m_ApplyThresholdFilter||m_ApplyMaskSegmentation) { - ProcessThresholdFilter(this->m_IplDistanceImage, this->m_ThresholdFilterMin, this->m_ThresholdFilterMax); + ProcessSegmentation(this->m_IplDistanceImage); } if (this->m_ApplyTemporalMedianFilter||this->m_ApplyAverageFilter) { - ProcessStreamedQuickSelectMedianImageFilter(this->m_IplDistanceImage, this->m_TemporalMedianFilterNumOfFrames); + ProcessStreamedQuickSelectMedianImageFilter(this->m_IplDistanceImage); } if (this->m_ApplyMedianFilter) { ProcessCVMedianFilter(this->m_IplDistanceImage, this->m_IplOutputImage); memcpy( this->m_IplDistanceImage->imageData, this->m_IplOutputImage->imageData, this->m_ImageSize ); } if (this->m_ApplyBilateralFilter) { float* itkFloatData = this->m_ItkInputImage->GetBufferPointer(); memcpy(itkFloatData, this->m_IplDistanceImage->imageData, this->m_ImageSize ); - ItkImageType2D::Pointer itkOutputImage = ProcessItkBilateralFilter(this->m_ItkInputImage, - this->m_BilateralFilterDomainSigma, this->m_BilateralFilterRangeSigma, this->m_BilateralFilterKernelRadius); + ItkImageType2D::Pointer itkOutputImage = ProcessItkBilateralFilter(this->m_ItkInputImage); memcpy( this->m_IplDistanceImage->imageData, itkOutputImage->GetBufferPointer(), this->m_ImageSize ); //ProcessCVBilateralFilter(this->m_IplDistanceImage, this->m_OutputIplImage, domainSigma, rangeSigma, kernelRadius); //memcpy( distanceFloatData, this->m_OutputIplImage->imageData, distanceImageSize ); } memcpy( outputDistanceFloatData, this->m_IplDistanceImage->imageData, this->m_ImageSize ); } void mitk::ToFCompositeFilter::CreateOutputsForAllInputs() { this->SetNumberOfOutputs(this->GetNumberOfInputs()); // create outputs for all inputs for (unsigned int idx = 0; idx < this->GetNumberOfOutputs(); ++idx) if (this->GetOutput(idx) == NULL) { DataObjectPointer newOutput = this->MakeOutput(idx); this->SetNthOutput(idx, newOutput); } this->Modified(); } void mitk::ToFCompositeFilter::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if (output->IsInitialized()) return; itkDebugMacro(<<"GenerateOutputInformation()"); output->Initialize(input->GetPixelType(), *input->GetTimeSlicedGeometry()); - output->SetPropertyList(input->GetPropertyList()->Clone()); + output->SetPropertyList(input->GetPropertyList()->Clone()); } -void mitk::ToFCompositeFilter::ProcessThresholdFilter(IplImage* inputIplImage, int min, int max) +void mitk::ToFCompositeFilter::ProcessSegmentation(IplImage* inputIplImage) { + char* segmentationMask; + if (m_SegmentationMask.IsNotNull()) + { + segmentationMask = (char*)m_SegmentationMask->GetSliceData(0, 0, 0)->GetData(); + } + else + { + segmentationMask = NULL; + } + float *f = (float*)inputIplImage->imageData; for(int i=0; im_ImageWidth*this->m_ImageHeight; i++) { - float *f = (float*)inputIplImage->imageData; - if (f[i]<=min) + if (this->m_ApplyThresholdFilter) { - f[i] = 0.0; + if (f[i]<=m_ThresholdFilterMin) + { + f[i] = 0.0; + } + else if (f[i]>=m_ThresholdFilterMax) + { + f[i] = 0.0; + } } - else if (f[i]>=max) + if (this->m_ApplyMaskSegmentation) { - f[i] = 0.0; + if (segmentationMask) + { + if (segmentationMask[i]==0) + { + f[i] = 0.0; + } + } } } } -ItkImageType2D::Pointer mitk::ToFCompositeFilter::ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage, double domainSigma, double rangeSigma, int kernelRadius) +ItkImageType2D::Pointer mitk::ToFCompositeFilter::ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage) { ItkImageType2D::Pointer outputItkImage; BilateralFilterType::Pointer bilateralFilter = BilateralFilterType::New(); bilateralFilter->SetInput(inputItkImage); - bilateralFilter->SetDomainSigma(domainSigma); - bilateralFilter->SetRangeSigma(rangeSigma); - //bilateralFilter->SetRadius(kernelRadius); + bilateralFilter->SetDomainSigma(m_BilateralFilterDomainSigma); + bilateralFilter->SetRangeSigma(m_BilateralFilterRangeSigma); + //bilateralFilter->SetRadius(m_BilateralFilterKernelRadius); outputItkImage = bilateralFilter->GetOutput(); outputItkImage->Update(); return outputItkImage; } -void mitk::ToFCompositeFilter::ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage, double domainSigma, double rangeSigma, int kernelRadius) +void mitk::ToFCompositeFilter::ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage) { - int diameter = kernelRadius; - double sigmaColor = rangeSigma; - double sigmaSpace = domainSigma; + int diameter = m_BilateralFilterKernelRadius; + double sigmaColor = m_BilateralFilterRangeSigma; + double sigmaSpace = m_BilateralFilterDomainSigma; cvSmooth(inputIplImage, outputIplImage, CV_BILATERAL, diameter, 0, sigmaColor, sigmaSpace); } void mitk::ToFCompositeFilter::ProcessCVMedianFilter(IplImage* inputIplImage, IplImage* outputIplImage, int radius) { cvSmooth(inputIplImage, outputIplImage, CV_MEDIAN, radius, 0, 0, 0); } -void mitk::ToFCompositeFilter::ProcessStreamedQuickSelectMedianImageFilter(IplImage* inputIplImage, int numOfImages) +void mitk::ToFCompositeFilter::ProcessStreamedQuickSelectMedianImageFilter(IplImage* inputIplImage) { float* data = (float*)inputIplImage->imageData; int imageSize = inputIplImage->width * inputIplImage->height; float* tmpArray; - if (numOfImages == 0) + if (this->m_TemporalMedianFilterNumOfFrames == 0) { return; } - if (numOfImages != this->m_DataBufferMaxSize) // reset + if (m_TemporalMedianFilterNumOfFrames != this->m_DataBufferMaxSize) // reset { //delete current buffer for( int i=0; im_DataBufferMaxSize; i++ ) { delete[] this->m_DataBuffer[i]; } if (this->m_DataBuffer != NULL) { delete[] this->m_DataBuffer; } - this->m_DataBufferMaxSize = numOfImages; + this->m_DataBufferMaxSize = m_TemporalMedianFilterNumOfFrames; // create new buffer with current size this->m_DataBuffer = new float*[this->m_DataBufferMaxSize]; for(int i=0; im_DataBufferMaxSize; i++) { this->m_DataBuffer[i] = NULL; } this->m_DataBufferCurrentIndex = 0; } int currentBufferSize = this->m_DataBufferMaxSize; tmpArray = new float[this->m_DataBufferMaxSize]; // copy data to buffer if (this->m_DataBuffer[this->m_DataBufferCurrentIndex] == NULL) { this->m_DataBuffer[this->m_DataBufferCurrentIndex] = new float[imageSize]; currentBufferSize = this->m_DataBufferCurrentIndex + 1; } for(int j=0; jm_DataBuffer[this->m_DataBufferCurrentIndex][j] = data[j]; } float tmpValue = 0.0f; for(int i=0; im_DataBuffer[j][i]; } data[i] = tmpValue/currentBufferSize; } else if (m_ApplyTemporalMedianFilter) { for(int j=0; jm_DataBuffer[j][i]; } data[i] = quick_select(tmpArray, currentBufferSize); } } this->m_DataBufferCurrentIndex = (this->m_DataBufferCurrentIndex + 1) % this->m_DataBufferMaxSize; delete[] tmpArray; } #define ELEM_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; } float mitk::ToFCompositeFilter::quick_select(float arr[], int n) { int low = 0; int high = n-1; int median = (low + high)/2; int middle = 0; int ll = 0; int hh = 0; for (;;) { if (high <= low) /* One element only */ return arr[median] ; if (high == low + 1) { /* Two elements only */ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; return arr[median] ; } /* Find median of low, middle and high items; swap into position low */ middle = (low + high) / 2; if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; /* Swap low item (now in position middle) into position (low+1) */ ELEM_SWAP(arr[middle], arr[low+1]) ; /* Nibble from each end towards middle, swapping items when stuck */ ll = low + 1; hh = high; for (;;) { do ll++; while (arr[low] > arr[ll]) ; do hh--; while (arr[hh] > arr[low]) ; if (hh < ll) break; ELEM_SWAP(arr[ll], arr[hh]) ; } /* Swap middle item (in position low) back into correct position */ ELEM_SWAP(arr[low], arr[hh]) ; /* Re-set active partition */ if (hh <= median) low = ll; if (hh >= median) high = hh - 1; } } #undef ELEM_SWAP -bool mitk::ToFCompositeFilter::GetApplyTemporalMedianFilter() -{ - return this->m_ApplyTemporalMedianFilter; -} - -bool mitk::ToFCompositeFilter::GetApplyMedianFilter() -{ - return this->m_ApplyMedianFilter; -} - -bool mitk::ToFCompositeFilter::GetApplyThresholdFilter() -{ - return this->m_ApplyThresholdFilter; -} - -bool mitk::ToFCompositeFilter::GetApplyBilateralFilter() -{ - return this->m_ApplyBilateralFilter; -} - -void mitk::ToFCompositeFilter::SetApplyTemporalMedianFilter(bool flag) -{ - this->m_ApplyTemporalMedianFilter = flag; -} - -void mitk::ToFCompositeFilter::SetApplyAverageFilter(bool flag) -{ - this->m_ApplyAverageFilter = flag; -} - -void mitk::ToFCompositeFilter::SetApplyMedianFilter(bool flag) -{ - this->m_ApplyMedianFilter = flag; -} - -void mitk::ToFCompositeFilter::SetApplyThresholdFilter(bool flag) -{ - this->m_ApplyThresholdFilter = flag; -} - -void mitk::ToFCompositeFilter::SetApplyBilateralFilter(bool flag) -{ - this->m_ApplyBilateralFilter = flag; -} - void mitk::ToFCompositeFilter::SetTemporalMedianFilterParameter(int tmporalMedianFilterNumOfFrames) { this->m_TemporalMedianFilterNumOfFrames = tmporalMedianFilterNumOfFrames; } void mitk::ToFCompositeFilter::SetThresholdFilterParameter(int min, int max) { if (min > max) { min = max; } this->m_ThresholdFilterMin = min; this->m_ThresholdFilterMax = max; } void mitk::ToFCompositeFilter::SetBilateralFilterParameter(double domainSigma, double rangeSigma, int kernelRadius = 0) { this->m_BilateralFilterDomainSigma = domainSigma; this->m_BilateralFilterRangeSigma = rangeSigma; this->m_BilateralFilterKernelRadius = kernelRadius; } void mitk::ToFCompositeFilter::CreateItkImage(ItkImageType2D::Pointer &itkInputImage) { itkInputImage = ItkImageType2D::New(); ItkImageType2D::IndexType startIndex; startIndex[0] = 0; // first index on X startIndex[1] = 0; // first index on Y ItkImageType2D::SizeType size; size[0] = this->m_ImageWidth; // size along X size[1] = this->m_ImageHeight; // size along Y ItkImageType2D::RegionType region; region.SetSize( size ); region.SetIndex( startIndex ); itkInputImage->SetRegions( region ); itkInputImage->Allocate(); } diff --git a/Modules/ToFProcessing/mitkToFCompositeFilter.h b/Modules/ToFProcessing/mitkToFCompositeFilter.h index 11cc4578a0..5ca5d5a76f 100644 --- a/Modules/ToFProcessing/mitkToFCompositeFilter.h +++ b/Modules/ToFProcessing/mitkToFCompositeFilter.h @@ -1,241 +1,201 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Module: $RCSfile$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __mitkToFCompositeFilter_h #define __mitkToFCompositeFilter_h #include #include "mitkImageToImageFilter.h" #include #include #include typedef itk::Image ItkImageType2D; typedef itk::Image ItkImageType3D; typedef itk::BilateralImageFilter BilateralFilterType; namespace mitk { /** * @brief Applies a common filter-pipeline to the first input of this filter * * This class intends to allow quick preprocessing of (ToF) range data. Input 0 of this filter, holding the range image, * is processed using the following image processing filters: * - threshold filter + * - mask segmentation * - temporal median filter * - spatial median filter * - bilateral filter * * @ingroup ToFProcessing */ class mitkToFProcessing_EXPORT ToFCompositeFilter : public ImageToImageFilter { public: mitkClassMacro( ToFCompositeFilter , ImageToImageFilter ); itkNewMacro( Self ); + itkSetMacro(SegmentationMask,mitk::Image::Pointer); + itkSetMacro(ApplyTemporalMedianFilter,bool); + itkGetConstMacro(ApplyTemporalMedianFilter,bool); + itkSetMacro(ApplyAverageFilter,bool); + itkGetConstMacro(ApplyAverageFilter,bool); + itkSetMacro(ApplyMedianFilter,bool); + itkGetConstMacro(ApplyMedianFilter,bool); + itkSetMacro(ApplyThresholdFilter,bool); + itkGetConstMacro(ApplyThresholdFilter,bool); + itkSetMacro(ApplyMaskSegmentation,bool); + itkGetConstMacro(ApplyMaskSegmentation,bool); + itkSetMacro(ApplyBilateralFilter,bool); + itkGetConstMacro(ApplyBilateralFilter,bool); + /*! \brief sets the input of this filter \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput( Image* distanceImage); /*! \brief sets the input of this filter at idx \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera \param CameraModel This is the camera model which holds parameters like focal length, pixel size, etc. which are needed for the reconstruction of the surface. */ virtual void SetInput(unsigned int idx, Image* distanceImage); /*! \brief returns the input of this filter */ Image* GetInput(); /*! \brief returns the input with id idx of this filter */ Image* GetInput(unsigned int idx); /*! - \brief Returns if the temporal median filter is currently selected for application to the distance image - \return flag m_ApplyTemporalMedianFilter - */ - bool GetApplyTemporalMedianFilter(); - /*! - \brief Returns if the average filter is currently selected for application to the distance image - \return flag m_ApplyAverageFilter - */ - bool GetApplyAverageFilter(); - /*! - \brief Returns if the median filter is currently selected for application to the distance image - \return flag m_ApplyMedianFilter - */ - bool GetApplyMedianFilter(); - /*! - \brief Returns if the threshold filter is currently selected for application to the distance image - \return flag m_ApplyThresholdFilter - */ - bool GetApplyThresholdFilter(); - /*! - \brief Returns if the bilateral filter is currently selected for application to the distance image - \return flag m_ApplyBilateralFilter - */ - bool GetApplyBilateralFilter(); - /*! - \brief Set if the temporal median filter should be applied to the distance image - \param flag flag m_ApplyTemporalMedianFilter will be set to - */ - void SetApplyTemporalMedianFilter(bool flag); - /*! - \brief Set if the average filter should be applied to the distance image - \param flag flag m_ApplyAverageFilter will be set to - */ - void SetApplyAverageFilter(bool flag); - /*! - \brief Set if the median filter should be applied to the distance image - \param flag flag m_ApplyMedianFilter will be set to - */ - void SetApplyMedianFilter(bool flag); - /*! - \brief Set if the threshold filter should be applied to the distance image - \param flag flag m_ApplyThresholdFilter will be set to - */ - void SetApplyThresholdFilter(bool flag); - /*! - \brief Sets if the bilateral filter should be applied to the distance image - \param flag flag m_ApplyBilateralFilter will be set to - */ - void SetApplyBilateralFilter(bool flag); - /*! \brief Sets the parameter of the temporal median filter \param tmporalMedianFilterNumOfFrames number of frames to be considered for calulating the temporal median */ void SetTemporalMedianFilterParameter(int tmporalMedianFilterNumOfFrames); /*! \brief Sets the parameters (lower, upper threshold) of the threshold filter \param min lower threshold of the threshold filter \param max upper threshold of the threshold filter */ void SetThresholdFilterParameter(int min, int max); /*! \brief Sets the parameters (domain sigma, range sigma, kernel radius) of the bilateral filter \param domainSigma Parameter controlling the smoothing effect of the bilateral filter. Default value: 2 \param rangeSigma Parameter controlling the edge preserving effect of the bilateral filter. Default value: 60 \param kernelRadius radius of the filter mask of the bilateral filter */ void SetBilateralFilterParameter(double domainSigma, double rangeSigma, int kernelRadius); protected: /*! \brief standard constructor */ ToFCompositeFilter(); /*! \brief standard destructor */ ~ToFCompositeFilter(); virtual void GenerateOutputInformation(); /*! \brief method generating the output of this filter. Called in the updated process of the pipeline. This method generates the output of the ToFSurfaceSource: The generated surface of the 3d points */ virtual void GenerateData(); /** * \brief Create an output for each input * * This Method sets the number of outputs to the number of inputs * and creates missing outputs objects. * \warning any additional outputs that exist before the method is called are deleted */ void CreateOutputsForAllInputs(); /*! - \brief Applies a thresholding to the input image. - All pixels with values below the lower threshold (min) and above the upper threshold (max) + \brief Applies a mask and/or threshold segmentation to the input image. + All pixels with values outside the mask, below the lower threshold (min) and above the upper threshold (max) are assigned the pixel value 0 - \param min lower threshold - \param max upper thresold */ - void ProcessThresholdFilter(IplImage* inputIplImage, int min, int max); + void ProcessSegmentation(IplImage* inputIplImage); /*! \brief Applies the ITK bilateral filter to the input image See http://www.itk.org/Doxygen320/html/classitk_1_1BilateralImageFilter.html for more details. - \param domainSigma parameter controlling the smoothing effect of the filter - \param rangeSigma parameter controlling the edge preserving effect of the filter - \param kernelRadius radius of the filter mask of the bilateral filter */ - ItkImageType2D::Pointer ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage, double domainSigma, double rangeSigma, int kernelRadius); + ItkImageType2D::Pointer ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage); /*! \brief Applies the OpenCV bilateral filter to the input image. See http://opencv.willowgarage.com/documentation/c/image_filtering.html#smooth for more details - \param domainSigma parameter controlling the smoothing effect of the filter - \param rangeSigma parameter controlling the edge preserving effect of the filter - \param kernelRadius radius of the filter mask of the bilateral filter */ - void ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage, double domainSigma, double rangeSigma, int kernelRadius); + void ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage); /*! \brief Applies the OpenCV median filter to the input image. See http://opencv.willowgarage.com/documentation/c/image_filtering.html#smooth for more details */ void ProcessCVMedianFilter(IplImage* inputIplImage, IplImage* outputIplImage, int radius = 3); /*! \brief Performs temporal median filter on an image given the number of frames to be considered */ - void ProcessStreamedQuickSelectMedianImageFilter(IplImage* inputIplImage, int numOfImages); + void ProcessStreamedQuickSelectMedianImageFilter(IplImage* inputIplImage); /*! \brief Quickselect algorithm * This Quickselect routine is based on the algorithm described in * "Numerical recipes in C", Second Edition, * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 * This code by Nicolas Devillard - 1998. Public domain. */ float quick_select(float arr[], int n); /*! \brief Initialize and allocate a 2D ITK image of dimension m_ImageWidth*m_ImageHeight */ void CreateItkImage(ItkImageType2D::Pointer &itkInputImage); + mitk::Image::Pointer m_SegmentationMask; ///< mask image used for segmenting the image + int m_ImageWidth; ///< x-dimension of the image int m_ImageHeight; ///< y-dimension of the image int m_ImageSize; ///< size of the image in bytes IplImage* m_IplDistanceImage; ///< OpenCV-representation of the distance image IplImage* m_IplOutputImage; ///< OpenCV-representation of the output image ItkImageType2D::Pointer m_ItkInputImage; ///< ITK representation of the distance image bool m_ApplyTemporalMedianFilter; ///< Flag indicating if the temporal median filter is currently active for processing the distance image bool m_ApplyAverageFilter; ///< Flag indicating if the average filter is currently active for processing the distance image bool m_ApplyMedianFilter; ///< Flag indicating if the spatial median filter is currently active for processing the distance image bool m_ApplyThresholdFilter; ///< Flag indicating if the threshold filter is currently active for processing the distance image + bool m_ApplyMaskSegmentation; ///< Flag indicating if a mask segmentation is performed bool m_ApplyBilateralFilter; ///< Flag indicating if the bilateral filter is currently active for processing the distance image float** m_DataBuffer; ///< Buffer used for calculating the pixel-wise median over the last n (m_TemporalMedianFilterNumOfFrames) number of frames int m_DataBufferCurrentIndex; ///< Current index in the buffer of the temporal median filter int m_DataBufferMaxSize; ///< Maximal size for the buffer of the temporal median filter (m_DataBuffer) int m_TemporalMedianFilterNumOfFrames; ///< Number of frames to be used in the calculation of the temporal median int m_ThresholdFilterMin; ///< Lower threshold of the threshold filter. Pixels with values below will be assigned value 0 when applying the threshold filter int m_ThresholdFilterMax; ///< Lower threshold of the threshold filter. Pixels with values above will be assigned value 0 when applying the threshold filter double m_BilateralFilterDomainSigma; ///< Parameter of the bilateral filter controlling the smoothing effect of the filter. Default value: 2 double m_BilateralFilterRangeSigma; ///< Parameter of the bilateral filter controlling the edge preserving effect of the filter. Default value: 60 int m_BilateralFilterKernelRadius; ///< Kernel radius of the bilateral filter mask }; } //END mitk namespace #endif diff --git a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp index e0ae5f65fb..f99b13f6ed 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp @@ -1,213 +1,239 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Module: $RCSfile$ Language: C++ Date: $Date: 2009-05-20 13:35:09 +0200 (Mi, 20 Mai 2009) $ Version: $Revision: 17332 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include //QT headers #include +#include +#include +#include +#include + const std::string QmitkToFCompositeFilterWidget::VIEW_ID = "org.mitk.views.qmitktofcompositefilterwidget"; QmitkToFCompositeFilterWidget::QmitkToFCompositeFilterWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { this->m_ToFCompositeFilter = NULL; m_Controls = NULL; CreateQtPartControl(this); } QmitkToFCompositeFilterWidget::~QmitkToFCompositeFilterWidget() { } void QmitkToFCompositeFilterWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFCompositeFilterWidgetControls; m_Controls->setupUi(parent); QPlastiqueStyle *sliderStyle = new QPlastiqueStyle(); int min = m_Controls->m_ThresholdFilterMinValueSpinBox->value(); int max = m_Controls->m_ThresholdFilterMaxValueSpinBox->value(); m_Controls->m_ThresholdFilterRangeSlider->setMinimum(min); m_Controls->m_ThresholdFilterRangeSlider->setMaximum(max); m_Controls->m_ThresholdFilterRangeSlider->setLowerValue(min); m_Controls->m_ThresholdFilterRangeSlider->setUpperValue(max); m_Controls->m_ThresholdFilterRangeSlider->setHandleMovementMode(QxtSpanSlider::NoOverlapping); m_Controls->m_ThresholdFilterRangeSlider->setStyle(sliderStyle); - this->CreateConnections(); } } void QmitkToFCompositeFilterWidget::CreateConnections() { if ( m_Controls ) { connect(m_Controls->m_TemporalMedianFilterNumOfFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnTemporalMedianFilterNumOfFramesSpinBoxValueChanged(int))); connect(m_Controls->m_BilateralFilterDomainSigmaSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnBilateralFilterDomainSigmaSpinBoxValueChanged(double))); connect(m_Controls->m_BilateralFilterRangeSigmaSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnBilateralFilterRangeSigmaSpinBoxValueChanged(double))); connect(m_Controls->m_BilateralFilterKernelRadiusSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnBilateralFilterKernelRadiusSpinBoxValueChanged(int))); connect(m_Controls->m_ThresholdFilterMinValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnThresholdFilterMinValueChanged(int))); connect(m_Controls->m_ThresholdFilterMaxValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnThresholdFilterMaxValueChanged(int))); connect( (QObject*)(m_Controls->m_TemporalMedianFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTemporalMedianFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_AverageFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnAverageFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_ThresholdFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnThresholdFilterCheckBoxChecked(bool)) ); + connect( (QObject*)(m_Controls->maskSegmentationCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnMaskSegmentationCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_BilateralFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnBilateralFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_MedianFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnMedianFilterCheckBoxChecked(bool)) ); connect(m_Controls->m_ThresholdFilterRangeSlider, SIGNAL(spanChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); //reset button connect(m_Controls->m_ThresholdFilterRangeSliderReset, SIGNAL(pressed()), this, SLOT(OnResetThresholdFilterRangeSlider())); } } void QmitkToFCompositeFilterWidget::SetToFCompositeFilter(mitk::ToFCompositeFilter* toFCompositeFilter) { this->m_ToFCompositeFilter = toFCompositeFilter; } mitk::ToFCompositeFilter* QmitkToFCompositeFilterWidget::GetToFCompositeFilter() { if (this->m_ToFCompositeFilter.IsNull()) { this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); } return this->m_ToFCompositeFilter; } +void QmitkToFCompositeFilterWidget::SetDataStorage(mitk::DataStorage::Pointer dataStorage) +{ + m_DataStorage = dataStorage; + m_Controls->maskImageComboBox->SetDataStorage(dataStorage); + m_Controls->maskImageComboBox->SetPredicate(mitk::NodePredicateAnd::New(mitk::NodePredicateDataType::New("Image"),mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)))); +} + void QmitkToFCompositeFilterWidget::UpdateFilterParameter() { OnTemporalMedianFilterCheckBoxChecked(m_Controls->m_TemporalMedianFilterCheckBox->isChecked()); OnAverageFilterCheckBoxChecked(m_Controls->m_AverageFilterCheckBox->isChecked()); OnMedianFilterCheckBoxChecked(m_Controls->m_MedianFilterCheckBox->isChecked()); OnThresholdFilterCheckBoxChecked(m_Controls->m_ThresholdFilterCheckBox->isChecked()); OnBilateralFilterCheckBoxChecked(m_Controls->m_BilateralFilterCheckBox->isChecked()); } void QmitkToFCompositeFilterWidget::OnTemporalMedianFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyTemporalMedianFilter(checked); // disable average filter if temporal median filter is enabled if (checked) { m_Controls->m_AverageFilterCheckBox->setChecked(false); this->m_ToFCompositeFilter->SetApplyAverageFilter(false); } } void QmitkToFCompositeFilterWidget::OnAverageFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyAverageFilter(checked); // disable temporal median filter if average filter is enabled if (checked) { m_Controls->m_TemporalMedianFilterCheckBox->setChecked(false); this->m_ToFCompositeFilter->SetApplyTemporalMedianFilter(false); } } void QmitkToFCompositeFilterWidget::OnThresholdFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyThresholdFilter(checked); } +void QmitkToFCompositeFilterWidget::OnMaskSegmentationCheckBoxChecked(bool checked) +{ + this->m_ToFCompositeFilter->SetApplyMaskSegmentation(checked); + if (checked) + { + mitk::DataNode::Pointer maskImageNode = m_Controls->maskImageComboBox->GetSelectedNode(); + if (maskImageNode.IsNotNull()) + { + mitk::Image::Pointer maskImage = dynamic_cast(maskImageNode->GetData()); + this->m_ToFCompositeFilter->SetSegmentationMask(maskImage); + } + } +} + void QmitkToFCompositeFilterWidget::OnMedianFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyMedianFilter(checked); } void QmitkToFCompositeFilterWidget::OnBilateralFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyBilateralFilter(checked); } void QmitkToFCompositeFilterWidget::OnTemporalMedianFilterNumOfFramesSpinBoxValueChanged(int value) { this->m_ToFCompositeFilter->SetTemporalMedianFilterParameter(value); } void QmitkToFCompositeFilterWidget::OnBilateralFilterDomainSigmaSpinBoxValueChanged(double value) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnBilateralFilterRangeSigmaSpinBoxValueChanged(double value) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnBilateralFilterKernelRadiusSpinBoxValueChanged(int value) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnThresholdFilterMinValueChanged(int value) { m_Controls->m_ThresholdFilterRangeSlider->setLowerValue(value); SetThresholdFilterParameter(); } void QmitkToFCompositeFilterWidget::OnThresholdFilterMaxValueChanged(int value) { m_Controls->m_ThresholdFilterRangeSlider->setUpperValue(value); SetThresholdFilterParameter(); } void QmitkToFCompositeFilterWidget::SetThresholdFilterParameter() { int min = m_Controls->m_ThresholdFilterMinValueSpinBox->value(); int max = m_Controls->m_ThresholdFilterMaxValueSpinBox->value(); this->m_ToFCompositeFilter->SetThresholdFilterParameter(min, max); } void QmitkToFCompositeFilterWidget::SetBilateralFilterParameter() { double domainSigma = m_Controls->m_BilateralFilterDomainSigmaSpinBox->value(); double rangeSigma = m_Controls->m_BilateralFilterRangeSigmaSpinBox->value(); int kernelRadius = m_Controls->m_BilateralFilterKernelRadiusSpinBox->value(); this->m_ToFCompositeFilter->SetBilateralFilterParameter(domainSigma, rangeSigma, kernelRadius); } void QmitkToFCompositeFilterWidget::OnSpanChanged(int lower, int upper) { int lowerVal = m_Controls->m_ThresholdFilterRangeSlider->lowerValue(); int upperVal = m_Controls->m_ThresholdFilterRangeSlider->upperValue(); m_Controls->m_ThresholdFilterMinValueSpinBox->setValue(lowerVal); m_Controls->m_ThresholdFilterMaxValueSpinBox->setValue(upperVal); } void QmitkToFCompositeFilterWidget::OnResetThresholdFilterRangeSlider() { int lower = 1; int upper = 7000; m_Controls->m_ThresholdFilterRangeSlider->setLowerValue(lower); m_Controls->m_ThresholdFilterRangeSlider->setUpperValue(upper); m_Controls->m_ThresholdFilterMinValueSpinBox->setValue(lower); m_Controls->m_ThresholdFilterMaxValueSpinBox->setValue(upper); } diff --git a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.h b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.h index 426f92ef60..79541ddadf 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.h +++ b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.h @@ -1,143 +1,151 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Module: $RCSfile$ Language: C++ Date: $Date: 2009-05-20 13:35:09 +0200 (Mi, 20 Mai 2009) $ Version: $Revision: 17332 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _QMITKTOFCOMPOSITEFILTERWIDGET_H_INCLUDED #define _QMITKTOFCOMPOSITEFILTERWIDGET_H_INCLUDED #include "mitkTOFUIExports.h" #include "ui_QmitkToFCompositeFilterWidgetControls.h" //mitk headers #include /** * @brief Widget for controlling the ToFCompositeFilter (located in module ToFProcessing) * * The widget allows to enable/disable the filters internally used in the ToFCompositeFilter * and to set the individual filter parameters using GUI elements * * @ingroup ToFUI */ class mitkTOFUI_EXPORT QmitkToFCompositeFilterWidget :public QWidget { //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkToFCompositeFilterWidget(QWidget* p = 0, Qt::WindowFlags f1 = 0); virtual ~QmitkToFCompositeFilterWidget(); /* @brief This method is part of the widget an needs not to be called seperately. */ virtual void CreateQtPartControl(QWidget *parent); /* @brief This method is part of the widget an needs not to be called seperately. (Creation of the connections of main and control widget.)*/ virtual void CreateConnections(); /*! \brief Sets the ToFCompositeFilter used by this widget \param tofCompositeFilter pointer to the internally used ToFCompositeFilter */ void SetToFCompositeFilter(mitk::ToFCompositeFilter* toFCompositeFilter); /*! \brief Returns the ToFCompositeFilter used by this widget \return tofCompositeFilter pointer to the internally used ToFCompositeFilter */ mitk::ToFCompositeFilter* GetToFCompositeFilter(); /*! \brief update parameters of ToFCompositeFilter according to current GUI setting */ void UpdateFilterParameter(); + + void SetDataStorage(mitk::DataStorage::Pointer dataStorage); signals: protected slots: /*! \brief slot en-/disabling temporal median filter in internal ToFCompositeFilter */ void OnTemporalMedianFilterCheckBoxChecked(bool checked); /*! \brief slot en-/disabling average filter in internal ToFCompositeFilter */ void OnAverageFilterCheckBoxChecked(bool checked); /*! \brief slot en-/disabling threshold filter in internal ToFCompositeFilter */ void OnThresholdFilterCheckBoxChecked(bool checked); /*! + \brief slot en-/disabling the mask segmentation in internal ToFCompositeFilter + */ + void OnMaskSegmentationCheckBoxChecked(bool checked); + /*! \brief slot en-/disabling median filter in internal ToFCompositeFilter */ void OnMedianFilterCheckBoxChecked(bool checked); /*! \brief slot en-/disabling bilateral filter in internal ToFCompositeFilter */ void OnBilateralFilterCheckBoxChecked(bool checked); /*! \brief slot updating threshold spin boxes according to slider position */ void OnSpanChanged(int lower, int upper); /*! \brief slot resetting threshold range slider to default values (min: 1, max: 7000) */ void OnResetThresholdFilterRangeSlider(); /*! \brief slot updating the parameter "number of frames" of the temporal median filter in the ToFCompositeFilter */ void OnTemporalMedianFilterNumOfFramesSpinBoxValueChanged(int value); /*! \brief slot updating the parameter "domain sigma" of the bilateral filter in the ToFCompositeFilter */ void OnBilateralFilterDomainSigmaSpinBoxValueChanged(double value); /*! \brief slot updating the paramter "range sigma" of the bilateral filter in the ToFCompositeFilter */ void OnBilateralFilterRangeSigmaSpinBoxValueChanged(double value); /*! \brief slot updating the paramter "kernel radius" of the bilateral filter in the ToFCompositeFilter */ void OnBilateralFilterKernelRadiusSpinBoxValueChanged(int value); /*! \brief slot updating the paramter "minimal threshold" of the threshold filter in the ToFCompositeFilter */ void OnThresholdFilterMinValueChanged(int value); /*! \brief slot updating the paramter "maximal threshold" of the threshold filter in the ToFCompositeFilter */ void OnThresholdFilterMaxValueChanged(int value); protected: Ui::QmitkToFCompositeFilterWidgetControls* m_Controls; ///< member holding the UI elements of this widget mitk::ToFCompositeFilter::Pointer m_ToFCompositeFilter; ///< member holding the internally used ToFCompositeFilter private: /*! \brief method updating the parameters of the bilateral filter in the ToFCompositeFilter */ void SetBilateralFilterParameter(); /*! \brief method updating the parameters of the threshold filter in the ToFCompositeFilter */ void SetThresholdFilterParameter(); + + mitk::DataStorage::Pointer m_DataStorage; }; #endif // _QMITKTOFCOMPOSITEFILTERWIDGET_H_INCLUDED diff --git a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui index 5f65a7fffe..729e70364e 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui @@ -1,206 +1,221 @@ QmitkToFCompositeFilterWidgetControls 0 0 - 597 - 166 + 611 + 199 0 0 QmitkToFCompositeFilter 11 ToF Preprocessing Threshold Filter 7000 0 QFrame::StyledPanel QFrame::Raised 0 0 modify actual seen window by dragging left and right slider. Qt::Horizontal 0 0 48 16777215 Resets range to histogram minimum and maximum. Reset 7000 7000 - + + + + Mask segmentation + + + + true Median Filter (t) - + Average Filter - + + + + 100 + + + 10 + + + + true Median Filter - + Bilateral Filter - + Domain σ: - - - - Range σ: + + + + 2.000000000000000 - - + + - Kernel Radius: + Range σ: - - - - - - - 100 - + + - 10 + 60.000000000000000 - - - - 2.000000000000000 + + + + Kernel Radius: - - - - 60.000000000000000 - - + + + + + QxtSpanSlider QSlider
qxtspanslider.h
+ + QmitkDataStorageComboBox + QComboBox +
QmitkDataStorageComboBox.h
+