diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index 40913afa64..44956fe6a7 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,717 +1,709 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSDevice.h" #include "mitkImageReadAccessor.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" // Microservices #include #include #include #include mitk::USDevice::PropertyKeys mitk::USDevice::GetPropertyKeys() { static mitk::USDevice::PropertyKeys propertyKeys; return propertyKeys; } mitk::USDevice::USImageCropArea mitk::USDevice::GetCropArea() { MITK_INFO << "Return Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; return m_CropArea; } unsigned int mitk::USDevice::GetSizeOfImageVector() { return m_ImageVector.size(); } mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource(), m_FreezeBarrier(nullptr), m_FreezeMutex(), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_ImageVector(), m_Spacing(), m_IGTLServer(nullptr), m_IGTLMessageProvider(nullptr), m_ImageToIGTLMsgFilter(nullptr), m_IsFreezed(false), m_DeviceState(State_NoState), m_NumberOfOutputs(1), m_ServiceProperties(), m_ServiceRegistration(), m_Manufacturer(manufacturer), m_Name(model), m_Comment(), m_SpawnAcquireThread(true), m_UnregisteringStarted(false) { USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(m_NumberOfOutputs); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::USDevice(mitk::USImageMetadata::Pointer metadata) : mitk::ImageSource(), m_FreezeBarrier(nullptr), m_FreezeMutex(), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_ImageVector(), m_Spacing(), m_IGTLServer(nullptr), m_IGTLMessageProvider(nullptr), m_ImageToIGTLMsgFilter(nullptr), m_IsFreezed(false), m_DeviceState(State_NoState), m_NumberOfOutputs(1), m_ServiceProperties(), m_ServiceRegistration(), m_SpawnAcquireThread(true), m_UnregisteringStarted(false) { m_Manufacturer = metadata->GetDeviceManufacturer(); m_Name = metadata->GetDeviceModel(); m_Comment = metadata->GetDeviceComment(); USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(m_NumberOfOutputs); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::~USDevice() { if (m_ThreadID >= 0) { m_MultiThreader->TerminateThread(m_ThreadID); } // make sure that the us device is not registered at the micro service // anymore after it is destructed this->UnregisterOnService(); } mitk::USAbstractControlInterface::Pointer mitk::USDevice::GetControlInterfaceCustom() { MITK_INFO << "Custom control interface does not exist for this object."; return nullptr; } mitk::USControlInterfaceBMode::Pointer mitk::USDevice::GetControlInterfaceBMode() { MITK_INFO << "Control interface BMode does not exist for this object."; return nullptr; } mitk::USControlInterfaceProbes::Pointer mitk::USDevice::GetControlInterfaceProbes() { MITK_INFO << "Control interface Probes does not exist for this object."; return nullptr; } mitk::USControlInterfaceDoppler::Pointer mitk::USDevice::GetControlInterfaceDoppler() { MITK_INFO << "Control interface Doppler does not exist for this object."; return nullptr; } void mitk::USDevice::SetManufacturer(std::string manufacturer) { m_Manufacturer = manufacturer; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER, manufacturer); } } void mitk::USDevice::SetName(std::string name) { m_Name = name; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME, name); } } void mitk::USDevice::SetComment(std::string comment) { m_Comment = comment; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_COMMENT, comment); } } us::ServiceProperties mitk::USDevice::ConstructServiceProperties() { mitk::USDevice::PropertyKeys propertyKeys = mitk::USDevice::GetPropertyKeys(); us::ServiceProperties props; props[propertyKeys.US_PROPKEY_ISCONNECTED] = this->GetIsConnected() ? "true" : "false"; props[propertyKeys.US_PROPKEY_ISACTIVE] = this->GetIsActive() ? "true" : "false"; props[propertyKeys.US_PROPKEY_LABEL] = this->GetServicePropertyLabel(); // get identifier of selected probe if there is one selected mitk::USControlInterfaceProbes::Pointer probesControls = this->GetControlInterfaceProbes(); if (probesControls.IsNotNull() && probesControls->GetIsActive()) { mitk::USProbe::Pointer probe = probesControls->GetSelectedProbe(); if (probe.IsNotNull()) { props[propertyKeys.US_PROPKEY_PROBES_SELECTED] = probe->GetName(); } } props[propertyKeys.US_PROPKEY_CLASS] = GetDeviceClass(); props[propertyKeys.US_PROPKEY_MANUFACTURER] = m_Manufacturer; props[propertyKeys.US_PROPKEY_NAME] = m_Name; props[propertyKeys.US_PROPKEY_COMMENT] = m_Comment; m_ServiceProperties = props; return props; } void mitk::USDevice::UnregisterOnService() { // unregister on micro service if (m_ServiceRegistration && !m_UnregisteringStarted) { // make sure that unregister is not started a second // time due to a callback during unregister for example m_UnregisteringStarted = true; m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } } bool mitk::USDevice::Initialize() { if (!this->OnInitialization()) { return false; } m_DeviceState = State_Initialized; // Get Context and Module us::ModuleContext* context = us::GetModuleContext(); us::ServiceProperties props = this->ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); return true; } bool mitk::USDevice::Connect() { MITK_DEBUG << "mitk::USDevice::Connect() called"; if (this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Tried to connect an ultrasound device that " "was already connected. Ignoring call..."; return true; } if (!this->GetIsInitialized()) { MITK_ERROR("mitkUSDevice") << "Cannot connect device if it is not in initialized state."; return false; } // Prepare connection, fail if this fails. if (!this->OnConnection()) { return false; } // Update state m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, true); return true; } void mitk::USDevice::ConnectAsynchron() { this->m_MultiThreader->SpawnThread(this->ConnectThread, this); } bool mitk::USDevice::Disconnect() { if (!GetIsConnected()) { MITK_WARN << "Tried to disconnect an ultrasound device that was not " "connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (!this->OnDisconnection()) return false; // Update state m_DeviceState = State_Initialized; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, false); return true; } bool mitk::USDevice::Activate() { if (!this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Cannot activate device if it is not in connected state."; return true; } if (OnActivation()) { m_DeviceState = State_Activated; m_FreezeBarrier = itk::ConditionVariable::New(); // spawn thread for aquire images if us device is active if (m_SpawnAcquireThread) { this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); } this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, true); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); // initialize the b mode control properties of the micro service mitk::USControlInterfaceBMode::Pointer bmodeControls = this->GetControlInterfaceBMode(); if (bmodeControls.IsNotNull()) { bmodeControls->Initialize(); } + MITK_INFO("mitkUSDevice") + << "Activated Device!"; } this->ProvideViaOIGTL(); return m_DeviceState == State_Activated; } void mitk::USDevice::ProvideViaOIGTL() { // create a new OpenIGTLink Server if (m_IGTLServer.IsNull()) m_IGTLServer = mitk::IGTLServer::New(true); m_IGTLServer->SetName(this->GetName()); // create a new OpenIGTLink Device source if (m_IGTLMessageProvider.IsNull()) m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); // set the OpenIGTLink server as the source for the device source m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); // register the provider so that it can be configured with the IGTL manager // plugin. This could be hardcoded but now I already have the fancy plugin. m_IGTLMessageProvider->RegisterAsMicroservice(); m_ImageToIGTLMsgFilter = mitk::ImageToIGTLMessageFilter::New(); m_ImageToIGTLMsgFilter->ConnectTo(this); // set the name of this filter to identify it easier m_ImageToIGTLMsgFilter->SetName(this->GetName()); // register this filter as micro service. The message provider looks for // provided IGTLMessageSources, once it found this microservice and someone // requested this data type then the provider will connect with this filter // automatically. m_ImageToIGTLMsgFilter->RegisterAsMicroservice(); } void mitk::USDevice::Deactivate() { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot deactivate a device which is not activae."; return; } if (!OnDeactivation()) { return; } DisableOIGTL(); m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, false); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); } void mitk::USDevice::DisableOIGTL() { // TODO: This seems not to be enough cleanup to catch all cases. For example, if the device is disconnected // from the OIGTL GUI, this won't get cleaned up correctly. m_IGTLServer->CloseConnection(); m_IGTLMessageProvider->UnRegisterMicroservice(); m_ImageToIGTLMsgFilter->UnRegisterMicroservice(); } void mitk::USDevice::SetIsFreezed(bool freeze) { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") - << "Cannot freeze or unfreeze if device is not active."; - return; + << "Device is not active, freezing or unfreezing might not have an effect!"; } this->OnFreeze(freeze); if (freeze) { m_IsFreezed = true; } else { m_IsFreezed = false; // wake up the image acquisition thread m_FreezeBarrier->Signal(); } } bool mitk::USDevice::GetIsFreezed() { - /* - if (!this->GetIsActive()) - { - MITK_WARN("mitkUSDevice")("mitkUSTelemedDevice") - << "Cannot get freeze state if the hardware interface is not ready. " - "Returning false..."; - return false; - }*/ - return m_IsFreezed; } void mitk::USDevice::PushFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } imageSource->PushFilter(filter); } void mitk::USDevice::PushFilterIfNotPushedBefore( AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } if (!imageSource->GetIsFilterInThePipeline(filter)) { imageSource->PushFilter(filter); } } bool mitk::USDevice::RemoveFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when removing a filter."; } return imageSource->RemoveFilter(filter); } void mitk::USDevice::UpdateServiceProperty(std::string key, std::string value) { m_ServiceProperties[key] = value; m_ServiceRegistration.SetProperties(m_ServiceProperties); // send event to notify listeners about the changed property m_PropertyChangedMessage(key, value); } void mitk::USDevice::UpdateServiceProperty(std::string key, double value) { std::stringstream stream; stream << value; this->UpdateServiceProperty(key, stream.str()); } void mitk::USDevice::UpdateServiceProperty(std::string key, bool value) { this->UpdateServiceProperty( key, value ? std::string("true") : std::string("false")); } /** mitk::Image* mitk::USDevice::GetOutput() { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetPrimaryOutput()); } mitk::Image* mitk::USDevice::GetOutput(unsigned int idx) { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetOutput(idx)); } void mitk::USDevice::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::USDevice::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter only has " << this->GetNumberOfOutputs() << " Outputs."); } if ( !graft ) { itkExceptionMacro(<<"Requested to graft output with a nullptr pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a nullptr pointer" ); } // Call Graft on USImage to copy member data output->Graft( graft ); } */ void mitk::USDevice::GrabImage() { std::vector image = this->GetUSImageSource()->GetNextImage(); m_ImageMutex->Lock(); this->SetImageVector(image); m_ImageMutex->Unlock(); } //########### GETTER & SETTER ##################// bool mitk::USDevice::GetIsInitialized() { return m_DeviceState == State_Initialized; } bool mitk::USDevice::GetIsActive() { return m_DeviceState == State_Activated; } bool mitk::USDevice::GetIsConnected() { return m_DeviceState == State_Connected; } std::string mitk::USDevice::GetDeviceManufacturer() { return m_Manufacturer; } std::string mitk::USDevice::GetDeviceModel() { return m_Name; } std::string mitk::USDevice::GetDeviceComment() { return m_Comment; } void mitk::USDevice::SetSpacing(double xSpacing, double ySpacing) { m_Spacing[0] = xSpacing; m_Spacing[1] = ySpacing; m_Spacing[2] = 1; if( m_ImageVector.size() > 0 ) { for( size_t index = 0; index < m_ImageVector.size(); ++index ) { auto& image = m_ImageVector[index]; if( image.IsNotNull() && image->IsInitialized() ) { image->GetGeometry()->SetSpacing(m_Spacing); } } this->Modified(); } MITK_INFO << "Spacing: " << m_Spacing; } void mitk::USDevice::GenerateData() { m_ImageMutex->Lock(); for (unsigned int i = 0; i < m_ImageVector.size() && i < this->GetNumberOfIndexedOutputs(); ++i) { auto& image = m_ImageVector[i]; if (image.IsNull() || !image->IsInitialized()) { // skip image } else { mitk::Image::Pointer output = this->GetOutput(i); if (!output->IsInitialized() || output->GetDimension(0) != image->GetDimension(0) || output->GetDimension(1) != image->GetDimension(1) || output->GetDimension(2) != image->GetDimension(2) || output->GetPixelType() != image->GetPixelType()) { output->Initialize(image->GetPixelType(), image->GetDimension(), image->GetDimensions()); } // copy contents of the given image into the member variable mitk::ImageReadAccessor inputReadAccessor(image); output->SetImportVolume(inputReadAccessor.GetData()); output->SetGeometry(image->GetGeometry()); } } m_ImageMutex->Unlock(); }; std::string mitk::USDevice::GetServicePropertyLabel() { std::string isActive; if (this->GetIsActive()) { isActive = " (Active)"; } else { isActive = " (Inactive)"; } // e.g.: Zonare MyLab5 (Active) return m_Manufacturer + " " + m_Name + isActive; } ITK_THREAD_RETURN_TYPE mitk::USDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; while (device->GetIsActive()) { // lock this thread when ultrasound device is freezed if (device->m_IsFreezed) { itk::SimpleMutexLock* mutex = &(device->m_FreezeMutex); mutex->Lock(); if (device->m_FreezeBarrier.IsNotNull()) { device->m_FreezeBarrier->Wait(mutex); } } device->GrabImage(); } return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::USDevice::ConnectThread(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; device->Connect(); return ITK_THREAD_RETURN_VALUE; } void mitk::USDevice::ProbeChanged(std::string probename) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED, probename); } void mitk::USDevice::DepthChanged(double depth) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH, depth); } diff --git a/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp index 8bb5a8975b..96a0ad824f 100644 --- a/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp +++ b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.cpp @@ -1,473 +1,485 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkAbstractUltrasoundTrackerDevice.h" #include "mitkImageReadAccessor.h" #include "mitkNavigationDataSmoothingFilter.h" #include "mitkNavigationDataDelayFilter.h" #include "mitkNavigationDataDisplacementFilter.h" #include "mitkTrackingDeviceSource.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" //Microservices #include #include #include #include #include //TempIncludes #include const std::string mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier = "org.mitk.modules.us.AbstractUltrasoundTrackerDevice"; const char* mitk::AbstractUltrasoundTrackerDevice::DefaultProbeIdentifier = "default"; const char* mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator = "_"; const std::string mitk::AbstractUltrasoundTrackerDevice::US_INTERFACE_NAME = "org.mitk.services.AbstractUltrasoundTrackerDevice"; const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_DEVICENAME = US_INTERFACE_NAME + ".devicename"; const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_CLASS = US_INTERFACE_NAME + ".class"; const std::string mitk::AbstractUltrasoundTrackerDevice::US_PROPKEY_ID = US_INTERFACE_NAME + ".id"; //____ mitk::AbstractUltrasoundTrackerDevice::AbstractUltrasoundTrackerDevice( USDevice::Pointer usDevice, NavigationDataSource::Pointer trackingDevice, bool trackedUltrasoundActive ) : m_UltrasoundDevice(usDevice), m_TrackingDeviceDataSource(trackingDevice), m_SmoothingFilter(mitk::NavigationDataSmoothingFilter::New()), m_DelayFilter(mitk::NavigationDataDelayFilter::New(0)), m_DisplacementFilter(mitk::NavigationDataDisplacementFilter::New()), m_LastFilterOfIGTPipeline(nullptr), m_NumberOfSmoothingValues(0), m_DelayCount(0), m_IsTrackedUltrasoundActive( trackedUltrasoundActive ) { m_DisplacementFilter->SetTransform6DOF(true); this->RebuildFilterPipeline(); //create a new output (for the image data) //___ mitk::Image::Pointer newOutput = mitk::Image::New(); //___ this->SetNthOutput(0, newOutput); // Combined Modality should not spawn an own acquire thread, because // image acquiring is done by the included us device //___ m_UltrasoundDevice->SetSpawnAcquireThread(false); } mitk::AbstractUltrasoundTrackerDevice::~AbstractUltrasoundTrackerDevice() { if (m_ServiceRegistration != nullptr) { m_ServiceRegistration.Unregister(); } m_ServiceRegistration = 0; } mitk::AffineTransform3D::Pointer mitk::AbstractUltrasoundTrackerDevice::GetCalibration() { return this->GetCalibration( this->GetCurrentDepthValue(), this->GetIdentifierForCurrentProbe() ); } mitk::AffineTransform3D::Pointer mitk::AbstractUltrasoundTrackerDevice::GetCalibration(std::string depth) { return this->GetCalibration(depth, this->GetIdentifierForCurrentProbe()); } mitk::AffineTransform3D::Pointer mitk::AbstractUltrasoundTrackerDevice::GetCalibration( std::string depth, std::string probe ) { // make sure that there is no '/' which would cause problems for TinyXML std::replace(probe.begin(), probe.end(), '/', '-'); // create identifier for calibration from probe and depth std::string calibrationKey = probe + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + depth; // find calibration for combination of probe identifier and depth std::map::iterator calibrationIterator = m_Calibrations.find(calibrationKey); if (calibrationIterator == m_Calibrations.end()) { return 0; } return calibrationIterator->second; } void mitk::AbstractUltrasoundTrackerDevice::SetCalibration( mitk::AffineTransform3D::Pointer calibration ) { if( calibration.IsNull() ) { MITK_WARN << "Null pointer passed to SetCalibration of mitk::USDevice. Ignoring call."; return; } std::string calibrationKey = this->GetIdentifierForCurrentCalibration(); if( calibrationKey.empty() ) { MITK_WARN << "Could not get a key for the calibration -> Calibration cannot be set."; return; } m_Calibrations[calibrationKey] = calibration; } bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration() { return this->RemoveCalibration( this->GetCurrentDepthValue(), this->GetIdentifierForCurrentProbe() ); } bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration(std::string depth) { return this->RemoveCalibration( depth, this->GetIdentifierForCurrentProbe() ); } bool mitk::AbstractUltrasoundTrackerDevice::RemoveCalibration( std::string depth, std::string probe ) { // make sure that there is no '/' which would cause problems for TinyXML std::replace(probe.begin(), probe.end(), '/', '-'); // create identifier for calibration from probe and depth std::string calibrationKey = probe + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + depth; return m_Calibrations.erase(calibrationKey) > 0; } std::string mitk::AbstractUltrasoundTrackerDevice::GetDeviceClass() { return DeviceClassIdentifier; } mitk::USImageSource::Pointer mitk::AbstractUltrasoundTrackerDevice::GetUSImageSource() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("AbstractUltrasoundTrackerDevice")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetUSImageSource(); } mitk::NavigationDataSource::Pointer mitk::AbstractUltrasoundTrackerDevice::GetNavigationDataSource() { if( m_LastFilterOfIGTPipeline.IsNull() ) { this->RebuildFilterPipeline(); } return m_LastFilterOfIGTPipeline; } bool mitk::AbstractUltrasoundTrackerDevice::GetIsCalibratedForCurrentStatus() { return m_Calibrations.find(this->GetIdentifierForCurrentCalibration()) != m_Calibrations.end(); } bool mitk::AbstractUltrasoundTrackerDevice::GetContainsAtLeastOneCalibration() { return !m_Calibrations.empty(); } +void mitk::AbstractUltrasoundTrackerDevice::SetIsFreezed(bool freezed) +{ + if (m_UltrasoundDevice.IsNull() || m_TrackingDeviceDataSource.IsNull()) + { + MITK_WARN << "Device not correctly initialized, aborting!"; + return; + } + m_UltrasoundDevice->SetIsFreezed(freezed); + if (freezed) { m_TrackingDeviceDataSource->Freeze(); } + else { m_TrackingDeviceDataSource->UnFreeze(); } +} + std::string mitk::AbstractUltrasoundTrackerDevice::SerializeCalibration() { std::stringstream result; result << "" << std::endl; // For each calibration in the set for( std::map::iterator it = m_Calibrations.begin(); it != m_Calibrations.end(); it++ ) { mitk::AffineTransform3D::MatrixType matrix = it->second->GetMatrix(); mitk::AffineTransform3D::TranslationType translation = it->second->GetTranslation(); TiXmlElement elem(it->first); // Serialize Matrix elem.SetDoubleAttribute("M00", matrix[0][0]); elem.SetDoubleAttribute("M01", matrix[0][1]); elem.SetDoubleAttribute("M02", matrix[0][2]); elem.SetDoubleAttribute("M10", matrix[1][0]); elem.SetDoubleAttribute("M11", matrix[1][1]); elem.SetDoubleAttribute("M12", matrix[1][2]); elem.SetDoubleAttribute("M20", matrix[2][0]); elem.SetDoubleAttribute("M21", matrix[2][1]); elem.SetDoubleAttribute("M22", matrix[2][2]); // Serialize Offset elem.SetDoubleAttribute("T0", translation[0]); elem.SetDoubleAttribute("T1", translation[1]); elem.SetDoubleAttribute("T2", translation[2]); result << elem << std::endl; } result << "" << std::endl; return result.str(); } void mitk::AbstractUltrasoundTrackerDevice::DeserializeCalibration( const std::string& xmlString, bool clearPreviousCalibrations ) { // Sanitize Input if (xmlString == "") { MITK_ERROR << "Empty string passed to Deserialize() method of CombinedModality. Aborting..."; mitkThrow() << "Empty string passed to Deserialize() method of CombinedModality. Aborting..."; return; } // Clear previous calibrations if necessary if (clearPreviousCalibrations) m_Calibrations.clear(); // Parse Input TiXmlDocument doc; if (!doc.Parse(xmlString.c_str())) { MITK_ERROR << "Unable to deserialize calibrations in CombinedModality. Error was: " << doc.ErrorDesc(); mitkThrow() << "Unable to deserialize calibrations in CombinedModality. Error was: " << doc.ErrorDesc(); return; } TiXmlElement* root = doc.FirstChildElement(); if (root == nullptr) { MITK_ERROR << "Unable to deserialize calibrations in CombinedModality. String contained no root element."; mitkThrow() << "Unable to deserialize calibrations in CombinedModality. String contained no root element."; return; } // Read Calibrations for (TiXmlElement* elem = root->FirstChildElement(); elem != nullptr; elem = elem->NextSiblingElement()) { mitk::AffineTransform3D::MatrixType matrix; mitk::AffineTransform3D::OffsetType translation; std::string calibName = elem->Value(); // Deserialize Matrix elem->QueryDoubleAttribute("M00", &matrix[0][0]); elem->QueryDoubleAttribute("M01", &matrix[0][1]); elem->QueryDoubleAttribute("M02", &matrix[0][2]); elem->QueryDoubleAttribute("M10", &matrix[1][0]); elem->QueryDoubleAttribute("M11", &matrix[1][1]); elem->QueryDoubleAttribute("M12", &matrix[1][2]); elem->QueryDoubleAttribute("M20", &matrix[2][0]); elem->QueryDoubleAttribute("M21", &matrix[2][1]); elem->QueryDoubleAttribute("M22", &matrix[2][2]); // Deserialize Offset elem->QueryDoubleAttribute("T0", &translation[0]); elem->QueryDoubleAttribute("T1", &translation[1]); elem->QueryDoubleAttribute("T2", &translation[2]); mitk::AffineTransform3D::Pointer calibration = mitk::AffineTransform3D::New(); calibration->SetMatrix(matrix); calibration->SetTranslation(translation); m_Calibrations[calibName] = calibration; } } void mitk::AbstractUltrasoundTrackerDevice::SetNumberOfSmoothingValues( unsigned int numberOfSmoothingValues ) { unsigned int oldNumber = m_NumberOfSmoothingValues; m_NumberOfSmoothingValues = numberOfSmoothingValues; // if filter should be activated or deactivated if ((oldNumber == 0 && numberOfSmoothingValues != 0) || (oldNumber != 0 && numberOfSmoothingValues == 0)) { this->RebuildFilterPipeline(); } m_SmoothingFilter->SetNumerOfValues(numberOfSmoothingValues); } void mitk::AbstractUltrasoundTrackerDevice::SetDelayCount( unsigned int delayCount ) { unsigned int oldCount = m_DelayCount; m_DelayCount = delayCount; // if filter should be activated or deactivated if ((oldCount == 0 && delayCount != 0) || (oldCount != 0 && delayCount == 0)) { this->RebuildFilterPipeline(); } m_DelayFilter->SetDelay(delayCount); } void mitk::AbstractUltrasoundTrackerDevice::GenerateData() { } std::string mitk::AbstractUltrasoundTrackerDevice::GetIdentifierForCurrentCalibration() { return this->GetIdentifierForCurrentProbe() + mitk::AbstractUltrasoundTrackerDevice::ProbeAndDepthSeperator + this->GetCurrentDepthValue(); } std::string mitk::AbstractUltrasoundTrackerDevice::GetIdentifierForCurrentProbe() { us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); us::ServiceProperties::const_iterator probeIt = usdeviceProperties.find( mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED); // get probe identifier from control interface for probes std::string probeName = mitk::AbstractUltrasoundTrackerDevice::DefaultProbeIdentifier; if (probeIt != usdeviceProperties.end()) { probeName = (probeIt->second).ToString(); } // make sure that there is no '/' which would cause problems for TinyXML std::replace(probeName.begin(), probeName.end(), '/', '-'); return probeName; } std::string mitk::AbstractUltrasoundTrackerDevice::GetCurrentDepthValue() { us::ServiceProperties usdeviceProperties = m_UltrasoundDevice->GetServiceProperties(); // get string for depth value from the micro service properties std::string depth; us::ServiceProperties::iterator depthIterator = usdeviceProperties.find( mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH); if (depthIterator != usdeviceProperties.end()) { depth = depthIterator->second.ToString(); } else { depth = "0"; } return depth; } void mitk::AbstractUltrasoundTrackerDevice::RebuildFilterPipeline() { m_LastFilterOfIGTPipeline = m_TrackingDeviceDataSource; if( m_NumberOfSmoothingValues > 0 ) { m_SmoothingFilter->ConnectTo(m_LastFilterOfIGTPipeline.GetPointer()); m_LastFilterOfIGTPipeline = m_SmoothingFilter; } if( m_DelayCount > 0 ) { m_DelayFilter->ConnectTo(m_LastFilterOfIGTPipeline.GetPointer()); m_LastFilterOfIGTPipeline = m_DelayFilter; } if( m_IsTrackedUltrasoundActive ) { m_DisplacementFilter->ConnectTo(m_LastFilterOfIGTPipeline.GetPointer()); m_LastFilterOfIGTPipeline = m_DisplacementFilter; } } void mitk::AbstractUltrasoundTrackerDevice::UnregisterOnService() { if (m_UltrasoundDevice->GetDeviceState() == USDevice::State_Activated) { m_UltrasoundDevice->Deactivate(); } if (m_UltrasoundDevice->GetDeviceState() == USDevice::State_Connected) { m_UltrasoundDevice->Disconnect(); } if (m_ServiceRegistration != nullptr) m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } void mitk::AbstractUltrasoundTrackerDevice::RegisterAsMicroservice() { //Get Context us::ModuleContext* context = us::GetModuleContext(); //Define ServiceProps //us::ServiceProperties props; mitk::UIDGenerator uidGen = mitk::UIDGenerator("org.mitk.services.AbstractUltrasoundTrackerDevice", 16); m_ServiceProperties[US_PROPKEY_ID] = uidGen.GetUID(); m_ServiceProperties[US_PROPKEY_DEVICENAME] = m_UltrasoundDevice->GetName(); m_ServiceProperties[US_PROPKEY_CLASS] = mitk::AbstractUltrasoundTrackerDevice::DeviceClassIdentifier; m_ServiceRegistration = context->RegisterService(this, m_ServiceProperties); } mitk::USAbstractControlInterface::Pointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceCustom() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetControlInterfaceCustom(); } mitk::USControlInterfaceBMode::Pointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceBMode() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetControlInterfaceBMode(); } mitk::USControlInterfaceProbes::Pointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceProbes() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetControlInterfaceProbes(); } mitk::USControlInterfaceDoppler::Pointer mitk::AbstractUltrasoundTrackerDevice::GetControlInterfaceDoppler() { if (m_UltrasoundDevice.IsNull()) { MITK_ERROR("USCombinedModality")("USDevice") << "UltrasoundDevice must not be null."; mitkThrow() << "UltrasoundDevice must not be null."; } return m_UltrasoundDevice->GetControlInterfaceDoppler(); } diff --git a/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h index 8e0f8bf705..f49ef00b73 100644 --- a/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h +++ b/Modules/US/USNavigation/mitkAbstractUltrasoundTrackerDevice.h @@ -1,257 +1,263 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkAbstractUltrasoundTrackerDevice_h #define __mitkAbstractUltrasoundTrackerDevice_h #include #include "mitkUSDevice.h" #include "mitkImageSource.h" #include "mitkNavigationDataSource.h" // Microservices #include #include #include #include #include #include namespace itk { template class SmartPointer; } namespace mitk { class NavigationDataSmoothingFilter; class NavigationDataDelayFilter; class NavigationDataDisplacementFilter; /** * \brief Abstract class for an easy handling of a combination of an USDevice and * a NavigationDataSource. * This class can be used as an ImageSource subclass. Additionally tracking data be * retrieved from the NavigationDataSource returned by GetTrackingDevice(). * * A calibration of the ultrasound image stream to the navigation datas can be set * for the currently active zoom level (of the ultrasound device) by SetCalibration() * The ultrasound images are transformed according to this calibration in the * GenerateData() method. */ class MITKUSNAVIGATION_EXPORT AbstractUltrasoundTrackerDevice : public mitk::ImageSource { public: static const std::string DeviceClassIdentifier; static const char* DefaultProbeIdentifier; static const char* ProbeAndDepthSeperator; static const std::string US_INTERFACE_NAME; static const std::string US_PROPKEY_DEVICENAME; static const std::string US_PROPKEY_CLASS; static const std::string US_PROPKEY_ID; mitkClassMacro(AbstractUltrasoundTrackerDevice, mitk::ImageSource); mitkNewMacro3Param(AbstractUltrasoundTrackerDevice, USDevice::Pointer, itk::SmartPointer, bool); itkGetMacro(UltrasoundDevice, itk::SmartPointer); itkSetMacro(UltrasoundDevice, itk::SmartPointer); itkGetMacro(TrackingDeviceDataSource, itk::SmartPointer); itkSetMacro(TrackingDeviceDataSource, itk::SmartPointer); itkGetMacro(IsTrackedUltrasoundActive, bool); /** * \brief Getter for calibration data of the currently active depth and probe. * * \return Transformation for calibration or null if no calibration is available. */ AffineTransform3D::Pointer GetCalibration(); /** * \brief Getter for calibration data of the given depth and the currently active probe. * * \param depth depth of the b mode ultrasound image for which the calibration should be returned * \return Transformation for calibration or null if no calibration is available. */ AffineTransform3D::Pointer GetCalibration(std::string depth); /** * \brief Getter for calibration data of the given depth and probe. * * \param depth depth of the b mode ultrasound image for which the calibration should be returned * \param probe probe of the ultrasound device for which the calibration should be returned * \return Transformation for calibration or null if no calibration is available. */ AffineTransform3D::Pointer GetCalibration(std::string depth, std::string probe); /** * \brief Sets a transformation as calibration data. * Calibration data is set for the currently activated probe and their current * zoom factor. It also marks the device as calibrated. */ void SetCalibration(AffineTransform3D::Pointer calibration); /** * \brief Removes the calibration data of the currently active depth and probe. * \return true on success, false if there was no calibration */ bool RemoveCalibration(); /** * \brief Removes the calibration data of the given depth and the currently active probe. * * \param depth depth of the b mode ultrasound image for which the calibration should be removed * \return true on success, false if there was no calibration */ bool RemoveCalibration(std::string depth); /** * \brief Removes the calibration data of the given depth and probe. * * \param depth depth of the b mode ultrasound image for which the calibration should be removed * \param probe probe of the ultrasound device for which the calibration should be removed * \return true on success, false if there was no calibration */ bool RemoveCalibration(std::string depth, std::string probe); /** * \brief Returns the Class of the Device. */ std::string GetDeviceClass(); /** * \brief Wrapper for returning USImageSource of the UltrasoundDevice. */ USImageSource::Pointer GetUSImageSource(); itk::SmartPointer GetNavigationDataSource(); /** * \return true if the device is calibrated for the currently selected probe with the current zoom level */ bool GetIsCalibratedForCurrentStatus(); /** * \return true if a calibration was loaded for at least one probe and depth */ bool GetContainsAtLeastOneCalibration(); + /** + * Freezes or unfreezes the modality which means tracker and ultrasound device + * are freezed / unfreezed. + */ + virtual void SetIsFreezed(bool freezed); + /** * \brief Serializes all contained calibrations into an xml fragment. * * The returned string contains one parent node named "calibrations" and several * subnodes, one for each calibration that is present. */ std::string SerializeCalibration(); /** * \brief Deserializes a string provided by a prior call to Serialize(). * If the bool flag is true, all prior calibrations will be deleted. * If the flag is set to false, prior calibrations will be retained, but overwritten * if one of equal name is present. * * \throws mitk::Exception if the given string could not be parsed correctly. */ void DeserializeCalibration(const std::string &xmlString, bool clearPreviousCalibrations = true); void SetNumberOfSmoothingValues(unsigned int numberOfSmoothingValues); void SetDelayCount(unsigned int delayCount); /** * \brief Remove this device from the micro service. * This method is public for mitk::USCombinedModality, because this devices * can be completly removed. This is not possible for API devices, which * should be available while their sub module is loaded. */ void UnregisterOnService(); virtual void RegisterAsMicroservice(); /** * \brief Wrapper for returning custom control interface of the UltrasoundDevice. */ virtual itk::SmartPointer GetControlInterfaceCustom(); /** * \brief Wrapper for returning B mode control interface of the UltrasoundDevice. */ virtual itk::SmartPointer GetControlInterfaceBMode(); /** * \brief Wrapper for returning probes control interface of the UltrasoundDevice. */ virtual itk::SmartPointer GetControlInterfaceProbes(); /** * \brief Wrapper for returning doppler control interface of the UltrasoundDevice. */ virtual itk::SmartPointer GetControlInterfaceDoppler(); protected: AbstractUltrasoundTrackerDevice( USDevice::Pointer usDevice, itk::SmartPointer trackingDevice, bool trackedUltrasoundActive ); virtual ~AbstractUltrasoundTrackerDevice(); /** * \brief Grabs the next frame from the input. * Must be implemented by the derived class. * This method is called internally, whenever Update() is invoked by an Output. */ virtual void GenerateData() override; std::string GetIdentifierForCurrentCalibration(); std::string GetIdentifierForCurrentProbe(); std::string GetCurrentDepthValue(); void RebuildFilterPipeline(); USDevice::Pointer m_UltrasoundDevice; itk::SmartPointer m_TrackingDeviceDataSource; std::map m_Calibrations; itk::SmartPointer m_SmoothingFilter; itk::SmartPointer m_DelayFilter; itk::SmartPointer m_DisplacementFilter; itk::SmartPointer m_LastFilterOfIGTPipeline; unsigned int m_NumberOfSmoothingValues; unsigned int m_DelayCount; /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ us::ServiceRegistration m_ServiceRegistration; /** * \brief Properties of the device's Microservice. */ us::ServiceProperties m_ServiceProperties; private: bool m_IsTrackedUltrasoundActive; }; } // namespace mitk MITK_DECLARE_SERVICE_INTERFACE(mitk::AbstractUltrasoundTrackerDevice, "org.mitk.services.AbstractUltrasoundTrackerDevice") #endif diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp index 035a7266e5..781dc5ad12 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.cpp @@ -1,430 +1,430 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationStepTumourSelection.h" #include "ui_QmitkUSNavigationStepTumourSelection.h" #include "usModuleRegistry.h" #include "mitkDataNode.h" #include "mitkSurface.h" #include "mitkUSCombinedModality.h" #include "../Interactors/mitkUSZonesInteractor.h" #include "mitkNodeDisplacementFilter.h" #include "QmitkUSNavigationStepCombinedModality.h" #include "../QmitkUSNavigationMarkerPlacement.h" #include "mitkIOUtil.h" #include "vtkSmartPointer.h" #include "vtkDoubleArray.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkWarpScalar.h" QmitkUSNavigationStepTumourSelection::QmitkUSNavigationStepTumourSelection(QWidget* parent) : QmitkUSAbstractNavigationStep(parent), m_targetSelectionOptional(false), m_SecurityDistance(0), m_Interactor(mitk::USZonesInteractor::New()), m_NodeDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_StateMachineFilename("USZoneInteractions.xml"), m_ReferenceSensorIndex(1), m_ListenerChangeNode(this, &QmitkUSNavigationStepTumourSelection::TumourNodeChanged), ui(new Ui::QmitkUSNavigationStepTumourSelection) { ui->setupUi(this); connect(ui->freezeImageButton, SIGNAL(SignalFreezed(bool)), this, SLOT(OnFreeze(bool))); connect(ui->tumourSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTumourSizeChanged(int))); connect(ui->deleteTumourButton, SIGNAL(clicked()), this, SLOT(OnDeleteButtonClicked())); m_SphereColor = mitk::Color(); //default color: green m_SphereColor[0] = 0; m_SphereColor[1] = 255; m_SphereColor[2] = 0; } void QmitkUSNavigationStepTumourSelection::SetTumorColor(mitk::Color c) { m_SphereColor = c; } void QmitkUSNavigationStepTumourSelection::SetTargetSelectionOptional(bool t) { m_targetSelectionOptional = t; } QmitkUSNavigationStepTumourSelection::~QmitkUSNavigationStepTumourSelection() { delete ui; } bool QmitkUSNavigationStepTumourSelection::OnStartStep() { m_TumourNode = this->GetNamedDerivedNodeAndCreate( QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR, QmitkUSAbstractNavigationStep::DATANAME_BASENODE); m_TumourNode->SetColor(m_SphereColor[0], m_SphereColor[1], m_SphereColor[2]); // load state machine and event config for data interactor m_Interactor->LoadStateMachine(m_StateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); m_Interactor->SetEventConfig("globalConfig.xml"); this->GetDataStorage()->ChangedNodeEvent.AddListener(m_ListenerChangeNode); m_TargetSurfaceNode = this->GetNamedDerivedNodeAndCreate( QmitkUSNavigationMarkerPlacement::DATANAME_TARGETSURFACE, QmitkUSNavigationMarkerPlacement::DATANAME_TUMOUR); // do not show the surface until this is requested m_TargetSurfaceNode->SetBoolProperty("visible", false); // make sure that scalars will be renderer on the surface m_TargetSurfaceNode->SetBoolProperty("scalar visibility", true); m_TargetSurfaceNode->SetBoolProperty("color mode", true); m_TargetSurfaceNode->SetBoolProperty("Backface Culling", true); return true; } bool QmitkUSNavigationStepTumourSelection::OnStopStep() { // make sure that imaging isn't freezed anymore ui->freezeImageButton->Unfreeze(); m_NodeDisplacementFilter->ResetNodes(); mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if (dataStorage.IsNotNull()) { // remove target surface node from data storage, if available there if (m_TargetSurfaceNode.IsNotNull()) { dataStorage->Remove(m_TargetSurfaceNode); } dataStorage->ChangedNodeEvent.RemoveListener(m_ListenerChangeNode); dataStorage->Remove(m_TumourNode); m_TumourNode = 0; } MITK_INFO("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Removing tumour."; return true; } bool QmitkUSNavigationStepTumourSelection::OnRestartStep() { ui->tumourSizeExplanationLabel->setEnabled(false); ui->tumourSizeLabel->setEnabled(false); ui->tumourSizeSlider->setEnabled(false); ui->deleteTumourButton->setEnabled(false); ui->tumourSizeSlider->blockSignals(true); ui->tumourSizeSlider->setValue(0); ui->tumourSizeSlider->blockSignals(false); return QmitkUSAbstractNavigationStep::OnRestartStep(); } bool QmitkUSNavigationStepTumourSelection::OnFinishStep() { // make sure that the surface has the right extent (in case the // tumor size was changed since the initial surface creation) m_TargetSurfaceNode->SetData(this->CreateTargetSurface()); return true; } bool QmitkUSNavigationStepTumourSelection::OnActivateStep() { m_Interactor = mitk::USZonesInteractor::New(); m_Interactor->LoadStateMachine(m_StateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); m_Interactor->SetEventConfig("globalConfig.xml"); m_NodeDisplacementFilter->ConnectTo(this->GetCombinedModality()->GetNavigationDataSource()); m_NodeDisplacementFilter->SelectInput(1);//m_ReferenceSensorIndex //target selection is optional if (m_targetSelectionOptional) { emit SignalReadyForNextStep(); } return true; } bool QmitkUSNavigationStepTumourSelection::OnDeactivateStep() { m_Interactor->SetDataNode(0); bool value; if (m_TumourNode.IsNotNull() && !(m_TumourNode->GetBoolProperty("zone.created", value) && value)) { m_TumourNode->SetData(0); } // make sure that imaging isn't freezed anymore ui->freezeImageButton->Unfreeze(); return true; } void QmitkUSNavigationStepTumourSelection::OnUpdate() { if (m_NavigationDataSource.IsNull()) { return; } m_NavigationDataSource->Update(); m_NodeDisplacementFilter->Update(); bool valid = m_NavigationDataSource->GetOutput(m_ReferenceSensorIndex)->IsDataValid(); if (valid) { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } ui->freezeImageButton->setEnabled(valid); bool created; if (m_TumourNode.IsNull() || !m_TumourNode->GetBoolProperty("zone.created", created) || !created) { ui->tumourSearchExplanationLabel->setEnabled(valid); } } void QmitkUSNavigationStepTumourSelection::OnSettingsChanged(const itk::SmartPointer settingsNode) { if (settingsNode.IsNull()) { return; } float securityDistance; if (settingsNode->GetFloatProperty("settings.security-distance", securityDistance)) { m_SecurityDistance = securityDistance; } std::string stateMachineFilename; if (settingsNode->GetStringProperty("settings.interaction-concept", stateMachineFilename) && stateMachineFilename != m_StateMachineFilename) { m_StateMachineFilename = stateMachineFilename; m_Interactor->LoadStateMachine(stateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); } std::string referenceSensorName; if (settingsNode->GetStringProperty("settings.reference-name-selected", referenceSensorName)) { m_ReferenceSensorName = referenceSensorName; } this->UpdateReferenceSensorName(); } QString QmitkUSNavigationStepTumourSelection::GetTitle() { return "Localisation of Tumour Position"; } QmitkUSAbstractNavigationStep::FilterVector QmitkUSNavigationStepTumourSelection::GetFilter() { return FilterVector(1, m_NodeDisplacementFilter.GetPointer()); } void QmitkUSNavigationStepTumourSelection::OnFreeze(bool freezed) { - if (freezed) this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(true); + if (freezed) this->GetCombinedModality()->SetIsFreezed(true); ui->tumourSelectionExplanation1Label->setEnabled(freezed); ui->tumourSelectionExplanation2Label->setEnabled(freezed); if (freezed) { if (!m_TumourNode->GetData()) { // load state machine and event config for data interactor m_Interactor->LoadStateMachine(m_StateMachineFilename, us::ModuleRegistry::GetModule("MitkUS")); m_Interactor->SetEventConfig("globalConfig.xml"); m_Interactor->SetDataNode(m_TumourNode); // feed reference pose to node displacement filter m_NodeDisplacementFilter->SetInitialReferencePose(this->GetCombinedModality()->GetNavigationDataSource()->GetOutput(m_ReferenceSensorIndex)->Clone()); } } else { bool value; if (m_TumourNode->GetBoolProperty("zone.created", value) && value) { ui->freezeImageButton->setEnabled(false); ui->tumourSearchExplanationLabel->setEnabled(false); } } - if (!freezed) this->GetCombinedModality()->GetUltrasoundDevice()->SetIsFreezed(false); + if (!freezed) this->GetCombinedModality()->SetIsFreezed(false); } void QmitkUSNavigationStepTumourSelection::OnSetCombinedModality() { mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->GetCombinedModality(false); if (combinedModality.IsNotNull()) { m_NavigationDataSource = combinedModality->GetNavigationDataSource(); } else { m_NavigationDataSource = 0; } ui->freezeImageButton->SetCombinedModality(combinedModality, m_ReferenceSensorIndex); this->UpdateReferenceSensorName(); } void QmitkUSNavigationStepTumourSelection::OnTumourSizeChanged(int size) { m_TumourNode->SetFloatProperty("zone.size", static_cast(size)); mitk::USZonesInteractor::UpdateSurface(m_TumourNode); MITK_INFO("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Changing tumour radius to " << size << "."; } void QmitkUSNavigationStepTumourSelection::OnDeleteButtonClicked() { this->OnRestartStep(); } void QmitkUSNavigationStepTumourSelection::TumourNodeChanged(const mitk::DataNode* dataNode) { // only changes of tumour node are of interest if (dataNode != m_TumourNode) { return; } float size; dataNode->GetFloatProperty("zone.size", size); ui->tumourSizeSlider->setValue(static_cast(size)); bool created; if (dataNode->GetBoolProperty("zone.created", created) && created) { if (ui->freezeImageButton->isChecked()) { m_NodeDisplacementFilter->AddNode(const_cast(dataNode)); m_TargetSurfaceNode->SetData(this->CreateTargetSurface()); m_NodeDisplacementFilter->AddNode(m_TargetSurfaceNode); MITK_INFO("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Tumour created with center " << dataNode->GetData()->GetGeometry()->GetOrigin() << " and radius " << size << "."; mitk::DataNode::Pointer tumourResultNode = mitk::DataNode::New(); tumourResultNode->SetName("TumourResult"); tumourResultNode->SetProperty("USNavigation::TumourCenter", mitk::Point3dProperty::New(dataNode->GetData()->GetGeometry()->GetOrigin())); tumourResultNode->SetProperty("USNavigation::TumourRadius", mitk::DoubleProperty::New(size)); emit SignalIntermediateResult(tumourResultNode); ui->freezeImageButton->Unfreeze(); } ui->tumourSearchExplanationLabel->setEnabled(false); ui->tumourSizeExplanationLabel->setEnabled(true); ui->tumourSizeLabel->setEnabled(true); ui->tumourSizeSlider->setEnabled(true); ui->deleteTumourButton->setEnabled(true); emit SignalReadyForNextStep(); } } mitk::Surface::Pointer QmitkUSNavigationStepTumourSelection::CreateTargetSurface() { mitk::Surface::Pointer tumourSurface = dynamic_cast(m_TumourNode->GetData()); if (tumourSurface.IsNull()) { MITK_WARN << "No target selected, cannot create surface!"; return mitk::Surface::New(); //return a empty surface in this case... } // make a deep copy of the tumour surface polydata vtkSmartPointer tumourSurfaceVtk = vtkSmartPointer::New(); tumourSurfaceVtk->DeepCopy(tumourSurface->GetVtkPolyData()); // create scalars for moving every point the same size onto its normal vector vtkSmartPointer scalars = vtkSmartPointer::New(); int numberOfPoints = tumourSurfaceVtk->GetNumberOfPoints(); scalars->SetNumberOfTuples(numberOfPoints); // set scalars for warp filter for (vtkIdType i = 0; i < numberOfPoints; ++i) { scalars->SetTuple1(i, m_SecurityDistance * 10); } tumourSurfaceVtk->GetPointData()->SetScalars(scalars); vtkSmartPointer warpScalar = vtkSmartPointer::New(); warpScalar->SetInputData(tumourSurfaceVtk); warpScalar->SetScaleFactor(1); // use the scalars themselves warpScalar->Update(); vtkSmartPointer targetSurfaceVtk = warpScalar->GetPolyDataOutput(); // set the moved points to the deep copied tumour surface; this is // necessary as setting the targetSurfaceVtk as polydata for the // targetSurface would result in flat shading for the surface (seems // to be a bug in MITK or VTK) tumourSurfaceVtk->SetPoints(targetSurfaceVtk->GetPoints()); mitk::Surface::Pointer targetSurface = mitk::Surface::New(); targetSurface->SetVtkPolyData(tumourSurfaceVtk); targetSurface->GetGeometry()->SetOrigin(tumourSurface->GetGeometry()->GetOrigin()); return targetSurface; } itk::SmartPointer QmitkUSNavigationStepTumourSelection::GetTumourNodeDisplacementFilter() { return m_NodeDisplacementFilter; } void QmitkUSNavigationStepTumourSelection::UpdateReferenceSensorName() { if (m_NavigationDataSource.IsNull()) { return; } if (!m_ReferenceSensorName.empty()) { try { m_ReferenceSensorIndex = m_NavigationDataSource->GetOutputIndex(m_ReferenceSensorName); } catch (const std::exception &e) { MITK_WARN("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepTumourSelection") << "Cannot get index for reference sensor name: " << e.what(); } } if (this->GetNavigationStepState() >= QmitkUSAbstractNavigationStep::State_Active) { MITK_INFO << "############### " << m_NodeDisplacementFilter->GetNumberOfIndexedInputs(); m_NodeDisplacementFilter->SelectInput(m_ReferenceSensorIndex); } ui->freezeImageButton->SetCombinedModality(this->GetCombinedModality(false), m_ReferenceSensorIndex); } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp index 1ef3a3241d..e305cb4718 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/QmitkUltrasoundCalibration.cpp @@ -1,1156 +1,1156 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkUltrasoundCalibration.h" #include // Qt #include #include #include #include // MITK #include //#include #include #include #include #include #include #include "mitkIRenderingManager.h" // us #include //VTK #include #include #include #include #include #include #include "internal/org_mbi_gui_qt_usnavigation_Activator.h" //sleep headers #include #include const std::string QmitkUltrasoundCalibration::VIEW_ID = "org.mitk.views.ultrasoundcalibration"; QmitkUltrasoundCalibration::QmitkUltrasoundCalibration() : m_USDeviceChanged(this, &QmitkUltrasoundCalibration::OnUSDepthChanged) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeviceServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } QmitkUltrasoundCalibration::~QmitkUltrasoundCalibration() { m_Controls.m_CombinedModalityManagerWidget->blockSignals(true); mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_USDeviceChanged); } m_Timer->stop(); // Sleep(500); //This might be problematic... seems like sometimes some ressources are still in use at calling time. this->OnStopCalibrationProcess(); this->OnStopPlusCalibration(); /*mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Tool Calibration Points"); if (node.IsNotNull())this->GetDataStorage()->Remove(node); node = this->GetDataStorage()->GetNamedNode("Image Calibration Points"); if (node.IsNotNull())this->GetDataStorage()->Remove(node); node = this->GetDataStorage()->GetNamedNode("US Image Stream"); if (node.IsNotNull())this->GetDataStorage()->Remove(node);*/ mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path"); if (node.IsNotNull())this->GetDataStorage()->Remove(node); this->GetDataStorage()->Remove(m_VerificationReferencePointsDataNode); delete m_Timer; } void QmitkUltrasoundCalibration::SetFocus() { m_Controls.m_ToolBox->setFocus(); } void QmitkUltrasoundCalibration::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Controls.m_CombinedModalityManagerWidget->SetCalibrationLoadedNecessary(false); m_Timer = new QTimer(this); m_StreamingTimer = new QTimer(this); m_Controls.m_SpacingBtnFreeze->setEnabled(true); m_Controls.m_SpacingAddPoint->setEnabled(false); m_Controls.m_CalculateSpacing->setEnabled(false); m_SpacingPointsCount = 0; m_SpacingPoints = mitk::PointSet::New(); m_SpacingNode = mitk::DataNode::New(); m_SpacingNode->SetName("Spacing Points"); m_SpacingNode->SetData(this->m_SpacingPoints); this->GetDataStorage()->Add(m_SpacingNode); // Pointset for Calibration Points m_CalibPointsTool = mitk::PointSet::New(); // Pointset for Worldpoints m_CalibPointsImage = mitk::PointSet::New(); m_CalibPointsCount = 0; // Evaluation Pointsets (Non-Visualized) m_EvalPointsImage = mitk::PointSet::New(); m_EvalPointsTool = mitk::PointSet::New(); m_EvalPointsProjected = mitk::PointSet::New(); // Neelde Projection Filter m_NeedleProjectionFilter = mitk::NeedleProjectionFilter::New(); // Tracking Status Widgets m_Controls.m_CalibTrackingStatus->ShowStatusLabels(); m_Controls.m_EvalTrackingStatus->ShowStatusLabels(); // General & Device Selection connect(m_Timer, SIGNAL(timeout()), this, SLOT(Update())); //connect(m_Controls.m_ToolBox, SIGNAL(currentChanged(int)), this, SLOT(OnTabSwitch(int))); // Calibration connect(m_Controls.m_CalibBtnFreeze, SIGNAL(clicked()), this, SLOT(SwitchFreeze())); // Freeze connect(m_Controls.m_CalibBtnAddPoint, SIGNAL(clicked()), this, SLOT(OnAddCalibPoint())); // Tracking & Image Points (Calibration) connect(m_Controls.m_CalibBtnCalibrate, SIGNAL(clicked()), this, SLOT(OnCalibration())); // Perform Calibration // Evaluation connect(m_Controls.m_EvalBtnStep1, SIGNAL(clicked()), this, SLOT(OnAddEvalProjectedPoint())); // Needle Projection connect(m_Controls.m_EvalBtnStep2, SIGNAL(clicked()), this, SLOT(SwitchFreeze())); // Freeze connect(m_Controls.m_EvalBtnStep3, SIGNAL(clicked()), this, SLOT(OnAddEvalTargetPoint())); // Tracking & Image Points (Evaluation) connect(m_Controls.m_EvalBtnSave, SIGNAL(clicked()), this, SLOT(OnSaveEvaluation())); // Save Evaluation Results connect(m_Controls.m_CalibBtnSaveCalibration, SIGNAL(clicked()), this, SLOT(OnSaveCalibration())); // Save Evaluation Results connect(m_Controls.m_BtnReset, SIGNAL(clicked()), this, SLOT(OnReset())); // Reset Pointsets // PLUS Calibration connect(m_Controls.m_GetCalibrationFromPLUS, SIGNAL(clicked()), this, SLOT(OnGetPlusCalibration())); connect(m_Controls.m_StartStreaming, SIGNAL(clicked()), this, SLOT(OnStartStreaming())); connect(m_StreamingTimer, SIGNAL(timeout()), this, SLOT(OnStreamingTimerTimeout())); connect(m_Controls.m_StopPlusCalibration, SIGNAL(clicked()), this, SLOT(OnStopPlusCalibration())); connect(m_Controls.m_SavePlusCalibration, SIGNAL(clicked()), this, SLOT(OnSaveCalibration())); connect(this, SIGNAL(NewConnectionSignal()), this, SLOT(OnNewConnection())); //Determine Spacing for Calibration of USVideoDevice connect(m_Controls.m_SpacingBtnFreeze, SIGNAL(clicked()), this, SLOT(OnFreezeClicked())); connect(m_Controls.m_SpacingAddPoint, SIGNAL(clicked()), this, SLOT(OnAddSpacingPoint())); connect(m_Controls.m_CalculateSpacing, SIGNAL(clicked()), this, SLOT(OnCalculateSpacing())); //connect( m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalCombinedModalitySelected(mitk::USCombinedModality::Pointer)), // this, SLOT(OnSelectDevice(mitk::USCombinedModality::Pointer)) ); connect(m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalReadyForNextStep()), this, SLOT(OnDeviceSelected())); connect(m_Controls.m_CombinedModalityManagerWidget, SIGNAL(SignalNoLongerReadyForNextStep()), this, SLOT(OnDeviceDeselected())); connect(m_Controls.m_StartCalibrationButton, SIGNAL(clicked()), this, SLOT(OnStartCalibrationProcess())); connect(m_Controls.m_StartPlusCalibrationButton, SIGNAL(clicked()), this, SLOT(OnStartPlusCalibration())); connect(m_Controls.m_CalibBtnRestartCalibration, SIGNAL(clicked()), this, SLOT(OnReset())); connect(m_Controls.m_CalibBtnStopCalibration, SIGNAL(clicked()), this, SLOT(OnStopCalibrationProcess())); connect(m_Controls.m_AddReferencePoints, SIGNAL(clicked()), this, SLOT(OnAddCurrentTipPositionToReferencePoints())); connect(m_Controls.m_AddCurrentPointerTipForVerification, SIGNAL(clicked()), this, SLOT(OnAddCurrentTipPositionForVerification())); connect(m_Controls.m_StartVerification, SIGNAL(clicked()), this, SLOT(OnStartVerification())); //initialize data storage combo box m_Controls.m_ReferencePointsComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.m_ReferencePointsComboBox->SetAutoSelectNewItems(true); m_Controls.m_ReferencePointsComboBox->SetPredicate(mitk::NodePredicateDataType::New("PointSet")); //initialize point list widget if (m_VerificationReferencePoints.IsNull()) { m_VerificationReferencePoints = mitk::PointSet::New(); } if (m_VerificationReferencePointsDataNode.IsNull()) { m_VerificationReferencePointsDataNode = mitk::DataNode::New(); m_VerificationReferencePointsDataNode->SetName("US Verification Reference Points"); m_VerificationReferencePointsDataNode->SetData(m_VerificationReferencePoints); this->GetDataStorage()->Add(m_VerificationReferencePointsDataNode); } m_Controls.m_ReferencePointsPointListWidget->SetPointSetNode(m_VerificationReferencePointsDataNode); m_Controls.m_ToolBox->setCurrentIndex(0); } void QmitkUltrasoundCalibration::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& /*nodes*/) { } void QmitkUltrasoundCalibration::OnTabSwitch(int index) { switch (index) { case 0: if (m_Controls.m_ToolBox->isItemEnabled(1) || m_Controls.m_ToolBox->isItemEnabled(2)) { this->OnStopCalibrationProcess(); } break; default: ; } } //void QmitkUltrasoundCalibration::OnSelectDevice(mitk::USCombinedModality::Pointer combinedModality) void QmitkUltrasoundCalibration::OnDeviceSelected() { mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { //m_Tracker = m_CombinedModality->GetNavigationDataSource(); // Construct Pipeline //this->m_NeedleProjectionFilter->SetInput(0, m_Tracker->GetOutput(0)); combinedModality->GetUltrasoundDevice()->AddPropertyChangedListener(m_USDeviceChanged); m_Controls.m_StartCalibrationButton->setEnabled(true); m_Controls.m_StartPlusCalibrationButton->setEnabled(true); m_Controls.m_ToolBox->setItemEnabled(1, true); m_Controls.m_ToolBox->setItemEnabled(2, true); } } void QmitkUltrasoundCalibration::OnDeviceDeselected() { mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality; combinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (combinedModality.IsNotNull()) { combinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_USDeviceChanged); } m_Controls.m_StartCalibrationButton->setEnabled(false); m_Controls.m_StartPlusCalibrationButton->setEnabled(false); m_Controls.m_ToolBox->setCurrentIndex(0); m_Controls.m_ToolBox->setItemEnabled(1, false); m_Controls.m_ToolBox->setItemEnabled(2, false); } void QmitkUltrasoundCalibration::OnAddCurrentTipPositionToReferencePoints() { if (m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource().IsNull() || (m_Controls.m_VerificationPointerChoser->GetSelectedToolID() == -1)) { MITK_WARN << "No tool selected, aborting"; return; } mitk::NavigationData::Pointer currentPointerData = m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_VerificationPointerChoser->GetSelectedToolID()); mitk::Point3D currentTipPosition = currentPointerData->GetPosition(); m_VerificationReferencePoints->InsertPoint(m_VerificationReferencePoints->GetSize(), currentTipPosition); } void QmitkUltrasoundCalibration::OnStartVerification() { m_currentPoint = 0; mitk::PointSet::Pointer selectedPointSet = dynamic_cast(m_Controls.m_ReferencePointsComboBox->GetSelectedNode()->GetData()); m_Controls.m_CurrentPointLabel->setText("Point " + QString::number(m_currentPoint) + " of " + QString::number(selectedPointSet->GetSize())); m_allErrors = std::vector(); m_allReferencePoints = std::vector(); for (int i = 0; i < selectedPointSet->GetSize(); i++) { m_allReferencePoints.push_back(selectedPointSet->GetPoint(i)); } } void QmitkUltrasoundCalibration::OnAddCurrentTipPositionForVerification() { if (m_currentPoint == -1) { MITK_WARN << "Cannot add point"; return; } if (m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource().IsNull() || (m_Controls.m_VerificationPointerChoser->GetSelectedToolID() == -1)) { MITK_WARN << "No tool selected, aborting"; return; } mitk::NavigationData::Pointer currentPointerData = m_Controls.m_VerificationPointerChoser->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_VerificationPointerChoser->GetSelectedToolID()); mitk::Point3D currentTipPosition = currentPointerData->GetPosition(); double currentError = m_allReferencePoints.at(m_currentPoint).EuclideanDistanceTo(currentTipPosition); MITK_INFO << "Current Error: " << currentError << " mm"; m_allErrors.push_back(currentError); if (++m_currentPoint < static_cast(m_allReferencePoints.size())) { m_Controls.m_CurrentPointLabel->setText("Point " + QString::number(m_currentPoint) + " of " + QString::number(m_allReferencePoints.size())); } else { m_currentPoint = -1; double meanError = 0; for (std::size_t i = 0; i < m_allErrors.size(); ++i) { meanError += m_allErrors[i]; } meanError /= m_allErrors.size(); QString result = "Finished verification! \n Verification of " + QString::number(m_allErrors.size()) + " points, mean error: " + QString::number(meanError) + " mm"; m_Controls.m_ResultsTextEdit->setText(result); MITK_INFO << result.toStdString(); } } void QmitkUltrasoundCalibration::OnStartCalibrationProcess() { // US Image Stream m_Node = mitk::DataNode::New(); m_Node->SetName("US Calibration Viewing Stream"); //create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); m_Node->SetData(dummyImage); this->GetDataStorage()->Add(m_Node); // data node for calibration point set m_CalibNode = mitk::DataNode::New(); m_CalibNode->SetName("Tool Calibration Points"); m_CalibNode->SetData(this->m_CalibPointsImage); this->GetDataStorage()->Add(m_CalibNode); // data node for world point set m_WorldNode = mitk::DataNode::New(); m_WorldNode->SetName("Image Calibration Points"); m_WorldNode->SetData(this->m_CalibPointsTool); this->GetDataStorage()->Add(m_WorldNode); m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (m_CombinedModality.IsNull()) { return; } m_Tracker = m_CombinedModality->GetNavigationDataSource(); //QString curDepth = service.getProperty(QString::fromStdString(mitk::USDevice::US_PROPKEY_BMODE_DEPTH)).toString(); // Construct Pipeline this->m_NeedleProjectionFilter->SetInput(0, m_Tracker->GetOutput(0)); QApplication::setOverrideCursor(Qt::WaitCursor); // make sure that the combined modality is in connected state before using it if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Connected) { m_CombinedModality->GetUltrasoundDevice()->Connect(); } if (m_CombinedModality->GetUltrasoundDevice()->GetDeviceState() < mitk::USDevice::State_Activated) { m_CombinedModality->GetUltrasoundDevice()->Activate(); } QApplication::restoreOverrideCursor(); this->SwitchFreeze(); // Todo: Maybe display this elsewhere this->ShowNeedlePath(); // Switch active tab to Calibration page m_Controls.m_ToolBox->setItemEnabled(1, true); m_Controls.m_ToolBox->setCurrentIndex(1); } void QmitkUltrasoundCalibration::OnStartPlusCalibration() { if (m_CombinedModality.IsNull()){ m_CombinedModality = m_Controls.m_CombinedModalityManagerWidget->GetSelectedCombinedModality(); if (m_CombinedModality.IsNull()) { return; } //something went wrong, there is no combined modality } //setup server to send UltrasoundImages to PLUS mitk::IGTLServer::Pointer m_USServer = mitk::IGTLServer::New(true); m_USServer->SetName("EchoTrack Image Source"); m_USServer->SetHostname("127.0.0.1"); m_USServer->SetPortNumber(18944); m_USMessageProvider = mitk::IGTLMessageProvider::New(); m_USMessageProvider->SetIGTLDevice(m_USServer); m_USMessageProvider->SetFPS(5); m_USImageToIGTLMessageFilter = mitk::ImageToIGTLMessageFilter::New(); m_USImageToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetUltrasoundDevice()); m_USImageToIGTLMessageFilter->SetName("USImage Filter"); //setup server to send TrackingData to PLUS m_TrackingServer = mitk::IGTLServer::New(true); m_TrackingServer->SetName("EchoTrack Tracking Source"); m_TrackingServer->SetHostname("127.0.0.1"); m_TrackingServer->SetPortNumber(18945); m_TrackingMessageProvider = mitk::IGTLMessageProvider::New(); m_TrackingMessageProvider->SetIGTLDevice(m_TrackingServer); m_TrackingMessageProvider->SetFPS(5); m_TrackingToIGTLMessageFilter = mitk::NavigationDataToIGTLMessageFilter::New(); m_TrackingToIGTLMessageFilter->ConnectTo(m_CombinedModality->GetTrackingDeviceDataSource()); m_TrackingToIGTLMessageFilter->SetName("Tracker Filter"); typedef itk::SimpleMemberCommand< QmitkUltrasoundCalibration > CurCommandType; CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkUltrasoundCalibration::OnPlusConnected); this->m_NewConnectionObserverTag = this->m_TrackingServer->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); //Open connections of both servers if (m_USServer->OpenConnection()) { MITK_INFO << "US Server opened its connection successfully"; m_USServer->StartCommunication(); } else { MITK_INFO << "US Server could not open its connection"; } if (m_TrackingServer->OpenConnection()) { MITK_INFO << "Tracking Server opened its connection successfully"; m_TrackingServer->StartCommunication(); } else { MITK_INFO << "Tracking Server could not open its connection"; } if (m_USMessageProvider->IsCommunicating() && m_TrackingMessageProvider->IsCommunicating()) { m_Controls.m_StartPlusCalibrationButton->setEnabled(false); m_Controls.m_GetCalibrationFromPLUS->setEnabled(true); m_Controls.m_StartStreaming->setEnabled(false); m_Controls.m_SavePlusCalibration->setEnabled(false); m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : green; }"); m_Controls.m_SetupStatus->setText("Setup successfull you can now connect PLUS"); } else { m_Controls.m_SetupStatus->setStyleSheet("QLabel { color : red; }"); m_Controls.m_SetupStatus->setText("Something went wrong. Please try again"); } } void QmitkUltrasoundCalibration::OnStopPlusCalibration() { //closing all server and clients when PlusCalibration is finished if (m_USMessageProvider.IsNotNull()) { if (m_USMessageProvider->IsStreaming()) { m_USMessageProvider->StopStreamingOfSource(m_USImageToIGTLMessageFilter); } } if (m_TrackingMessageProvider.IsNotNull()) { if (m_TrackingMessageProvider->IsStreaming()) { m_TrackingMessageProvider->StopStreamingOfSource(m_TrackingToIGTLMessageFilter); } } if (m_USServer.IsNotNull()) { m_USServer->CloseConnection(); } if (m_TrackingServer.IsNotNull()) { m_TrackingServer->CloseConnection(); } if (m_TransformClient.IsNotNull()) { m_TransformClient->CloseConnection(); } m_Controls.m_GotCalibrationLabel->setText(""); m_Controls.m_ConnectionStatus->setText(""); m_Controls.m_SetupStatus->setText(""); m_Controls.m_StartPlusCalibrationButton->setEnabled(true); m_StreamingTimer->stop(); delete m_StreamingTimer; } void QmitkUltrasoundCalibration::OnPlusConnected() { emit NewConnectionSignal(); } void QmitkUltrasoundCalibration::OnNewConnection() { m_Controls.m_StartStreaming->setEnabled(true); m_Controls.m_ConnectionStatus->setStyleSheet("QLabel { color : green; }"); m_Controls.m_ConnectionStatus->setText("Connection successfull you can now start streaming"); } void QmitkUltrasoundCalibration::OnStreamingTimerTimeout() { m_USMessageProvider->Update(); m_TrackingMessageProvider->Update(); } void QmitkUltrasoundCalibration::OnStartStreaming() { m_USMessageProvider->StartStreamingOfSource(m_USImageToIGTLMessageFilter, 5); m_TrackingMessageProvider->StartStreamingOfSource(m_TrackingToIGTLMessageFilter, 5); m_Controls.m_StartStreaming->setEnabled(false); m_Controls.m_ConnectionStatus->setText(""); m_StreamingTimer->start((1.0 / 5.0 * 1000.0)); } void QmitkUltrasoundCalibration::OnGetPlusCalibration() { m_TransformClient = mitk::IGTLClient::New(true); m_TransformClient->SetHostname("127.0.0.1"); m_TransformClient->SetPortNumber(18946); m_TransformDeviceSource = mitk::IGTLDeviceSource::New(); m_TransformDeviceSource->SetIGTLDevice(m_TransformClient); m_TransformDeviceSource->Connect(); if (m_TransformDeviceSource->IsConnected()) { MITK_INFO << "successfully connected"; m_TransformDeviceSource->StartCommunication(); if (m_TransformDeviceSource->IsCommunicating()) { MITK_INFO << "communication started"; mitk::IGTLMessage::Pointer receivedMessage; bool condition = false; igtl::Matrix4x4 transformPLUS; while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid())) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); m_TransformDeviceSource->Update(); receivedMessage = m_TransformDeviceSource->GetOutput(); igtl::TransformMessage::Pointer msg = dynamic_cast(m_TransformDeviceSource->GetOutput()->GetMessage().GetPointer()); if (msg == nullptr || msg.IsNull()) { MITK_INFO << "Received message could not be casted to TransformMessage. Skipping.."; continue; } else { if (std::strcmp(msg->GetDeviceName(), "ImageToTracker") != 0) { MITK_INFO << "Was not Image to Tracker Transform. Skipping..."; continue; } else { msg->GetMatrix(transformPLUS); condition = true; break; } } } if (condition) { this->ProcessPlusCalibration(transformPLUS); } else { m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } else { MITK_INFO << " no connection"; m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } else { m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : red; }"); m_Controls.m_GotCalibrationLabel->setText("Something went wrong. Please try again"); } } void QmitkUltrasoundCalibration::ProcessPlusCalibration(igtl::Matrix4x4& imageToTracker) { mitk::AffineTransform3D::Pointer imageToTrackerTransform = mitk::AffineTransform3D::New(); itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); rotationFloat[0][0] = imageToTracker[0][0]; rotationFloat[0][1] = imageToTracker[0][1]; rotationFloat[0][2] = imageToTracker[0][2]; rotationFloat[1][0] = imageToTracker[1][0]; rotationFloat[1][1] = imageToTracker[1][1]; rotationFloat[1][2] = imageToTracker[1][2]; rotationFloat[2][0] = imageToTracker[2][0]; rotationFloat[2][1] = imageToTracker[2][1]; rotationFloat[2][2] = imageToTracker[2][2]; translationFloat[0] = imageToTracker[0][3]; translationFloat[1] = imageToTracker[1][3]; translationFloat[2] = imageToTracker[2][3]; imageToTrackerTransform->SetTranslation(translationFloat); imageToTrackerTransform->SetMatrix(rotationFloat); m_CombinedModality->SetCalibration(imageToTrackerTransform); m_Controls.m_ToolBox->setItemEnabled(2, true); m_Controls.m_SavePlusCalibration->setEnabled(true); m_Controls.m_GotCalibrationLabel->setStyleSheet("QLabel { color : green; }"); m_Controls.m_GotCalibrationLabel->setText("Recieved Calibration from PLUS you can now save it"); } void QmitkUltrasoundCalibration::OnStopCalibrationProcess() { this->ClearTemporaryMembers(); m_Timer->stop(); this->GetDataStorage()->Remove(m_Node); m_Node = 0; this->GetDataStorage()->Remove(m_CalibNode); m_CalibNode = 0; this->GetDataStorage()->Remove(m_WorldNode); m_WorldNode = 0; m_Controls.m_ToolBox->setCurrentIndex(0); } void QmitkUltrasoundCalibration::OnDeviceServiceEvent(const ctkServiceEvent event) { if (m_CombinedModality.IsNull() || event.getType() != ctkServiceEvent::MODIFIED) { return; } ctkServiceReference service = event.getServiceReference(); QString curDepth = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH)).toString(); if (m_CurrentDepth != curDepth) { m_CurrentDepth = curDepth; this->OnReset(); } } void QmitkUltrasoundCalibration::OnAddCalibPoint() { mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_CalibPointsImage->InsertPoint(m_CalibPointsCount, world); this->m_CalibPointsTool->InsertPoint(m_CalibPointsCount, this->m_FreezePoint); QString text = text.number(m_CalibPointsCount + 1); text = "Point " + text; this->m_Controls.m_CalibPointList->addItem(text); m_CalibPointsCount++; SwitchFreeze(); } void QmitkUltrasoundCalibration::OnCalibration() { // Compute transformation vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetSourceLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsImage)->GetPoints()); transform->SetTargetLandmarks(this->ConvertPointSetToVtkPolyData(m_CalibPointsTool)->GetPoints()); if( !m_CombinedModality->GetIsTrackedUltrasoundActive() ) { if (m_Controls.m_ScaleTransform->isChecked()) { transform->SetModeToSimilarity(); } //use affine transform else { transform->SetModeToRigidBody(); } //use similarity transform: scaling is not touched MITK_INFO << "TEST"; } else { transform->SetModeToRigidBody();//use similarity transform: scaling is not touched } transform->Modified(); transform->Update(); // Convert from vtk to itk data types itk::Matrix rotationFloat = itk::Matrix(); itk::Vector translationFloat = itk::Vector(); vtkSmartPointer m = transform->GetMatrix(); rotationFloat[0][0] = m->GetElement(0, 0); rotationFloat[0][1] = m->GetElement(0, 1); rotationFloat[0][2] = m->GetElement(0, 2); rotationFloat[1][0] = m->GetElement(1, 0); rotationFloat[1][1] = m->GetElement(1, 1); rotationFloat[1][2] = m->GetElement(1, 2); rotationFloat[2][0] = m->GetElement(2, 0); rotationFloat[2][1] = m->GetElement(2, 1); rotationFloat[2][2] = m->GetElement(2, 2); translationFloat[0] = m->GetElement(0, 3); translationFloat[1] = m->GetElement(1, 3); translationFloat[2] = m->GetElement(2, 3); mitk::DataNode::Pointer CalibPointsImage = mitk::DataNode::New(); CalibPointsImage->SetName("Calibration Points Image"); CalibPointsImage->SetData(m_CalibPointsImage); this->GetDataStorage()->Add(CalibPointsImage); mitk::DataNode::Pointer CalibPointsTracking = mitk::DataNode::New(); CalibPointsTracking->SetName("Calibration Points Tracking"); CalibPointsTracking->SetData(m_CalibPointsTool); this->GetDataStorage()->Add(CalibPointsTracking); mitk::PointSet::Pointer ImagePointsTransformed = m_CalibPointsImage->Clone(); this->ApplyTransformToPointSet(ImagePointsTransformed, transform); mitk::DataNode::Pointer CalibPointsImageTransformed = mitk::DataNode::New(); CalibPointsImageTransformed->SetName("Calibration Points Image (Transformed)"); CalibPointsImageTransformed->SetData(ImagePointsTransformed); this->GetDataStorage()->Add(CalibPointsImageTransformed); // Set output variable mitk::AffineTransform3D::Pointer oldUSImageTransform = m_Image->GetGeometry()->GetIndexToWorldTransform(); //including spacing! MITK_INFO << "Old US Image transform: " << oldUSImageTransform; mitk::AffineTransform3D::Pointer calibTransform = mitk::AffineTransform3D::New(); calibTransform->SetTranslation(translationFloat); calibTransform->SetMatrix(rotationFloat); MITK_INFO << "Calibration transform: " << calibTransform; m_Transformation = mitk::AffineTransform3D::New(); if( !m_CombinedModality->GetIsTrackedUltrasoundActive() ) { if( !m_Controls.m_ScaleTransform->isChecked() ) { m_Transformation->Compose(oldUSImageTransform); } MITK_INFO << "Used old USImageTransform"; } m_Transformation->Compose(calibTransform); MITK_INFO << "New combined transform: " << m_Transformation; mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast (m_Node->GetData()->GetGeometry()); mitk::PlaneGeometry::Pointer plane = const_cast (sliced3d->GetPlaneGeometry(0)); plane->SetIndexToWorldTransform(m_Transformation); // Save to US-Device m_CombinedModality->SetCalibration(m_Transformation); m_Controls.m_ToolBox->setItemEnabled(2, true); // Save to NeedleProjectionFilter m_NeedleProjectionFilter->SetTargetPlane(m_Transformation); // Update Calibration FRE m_CalibrationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); mitk::PointSet::Pointer p1 = this->m_CalibPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems // Create point set with transformed image calibration points for // calculating the difference of image calibration and tool // calibration points in one geometry space mitk::PointSet::Pointer p2 = mitk::PointSet::New(); int n = 0; for (mitk::PointSet::PointsConstIterator it = m_CalibPointsImage->Begin(); it != m_CalibPointsImage->End(); ++it, ++n) { p2->InsertPoint(n, m_Transformation->TransformPoint(it->Value())); } m_CalibrationStatistics->SetPointSets(p1, p2); //QString text = text.number(m_CalibrationStatistics->GetRMS()); QString text = QString::number(ComputeFRE(m_CalibPointsImage, m_CalibPointsTool, transform)); MITK_INFO << "Calibration FRE: " << text.toStdString().c_str(); m_Controls.m_EvalLblCalibrationFRE->setText(text); m_Node->SetStringProperty("Calibration FRE", text.toStdString().c_str()); // Enable Button to save Calibration m_Controls.m_CalibBtnSaveCalibration->setEnabled(true); } void QmitkUltrasoundCalibration::OnAddEvalTargetPoint() { mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_EvalPointsImage->InsertPoint(m_EvalPointsImage->GetSize(), world); this->m_EvalPointsTool->InsertPoint(m_EvalPointsTool->GetSize(), this->m_FreezePoint); QString text = text.number(this->m_EvalPointsTool->GetSize()); this->m_Controls.m_EvalLblNumTargetPoints->setText(text); // Update FREs // Update Evaluation FRE, but only if it contains more than one point (will crash otherwise) if ((m_EvalPointsProjected->GetSize() > 1) && (m_EvalPointsTool->GetSize() > 1)) { m_EvaluationStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); m_ProjectionStatistics = mitk::PointSetDifferenceStatisticsCalculator::New(); mitk::PointSet::Pointer p1 = this->m_EvalPointsTool->Clone(); // We use clones to calculate statistics to avoid concurrency Problems mitk::PointSet::Pointer p2 = this->m_EvalPointsImage->Clone(); mitk::PointSet::Pointer p3 = this->m_EvalPointsProjected->Clone(); m_EvaluationStatistics->SetPointSets(p1, p2); m_ProjectionStatistics->SetPointSets(p1, p3); QString evalText = evalText.number(m_EvaluationStatistics->GetRMS()); QString projText = projText.number(m_ProjectionStatistics->GetRMS()); m_Controls.m_EvalLblEvaluationFRE->setText(evalText); m_Controls.m_EvalLblProjectionFRE->setText(projText); } SwitchFreeze(); } void QmitkUltrasoundCalibration::OnAddEvalProjectedPoint() { MITK_WARN << "Projection Evaluation may currently be inaccurate."; // TODO: Verify correct Evaluation. Is the Point that is added really current? mitk::Point3D projection = this->m_NeedleProjectionFilter->GetProjection()->GetPoint(1); m_EvalPointsProjected->InsertPoint(m_EvalPointsProjected->GetSize(), projection); QString text = text.number(this->m_EvalPointsProjected->GetSize()); this->m_Controls.m_EvalLblNumProjectionPoints->setText(text); } void QmitkUltrasoundCalibration::OnSaveEvaluation() { //Filename without suffix QString filename = m_Controls.m_EvalFilePath->text() + "//" + m_Controls.m_EvalFilePrefix->text(); MITK_WARN << "CANNOT SAVE, ABORTING!"; /* not working any more TODO! mitk::PointSetWriter::Pointer psWriter = mitk::PointSetWriter::New(); psWriter->SetInput(0, m_CalibPointsImage); psWriter->SetInput(1, m_CalibPointsTool); psWriter->SetInput(2, m_EvalPointsImage); psWriter->SetInput(3, m_EvalPointsTool); psWriter->SetInput(4, m_EvalPointsProjected); psWriter->SetFileName(filename.toStdString() + ".xml"); psWriter->Write(); */ // TODO: New writer for transformations must be implemented. /* mitk::TransformationFileWriter::Pointer tWriter = mitk::TransformationFileWriter::New(); tWriter->SetInput(0, m_CalibPointsImage); tWriter->SetInput(1, m_CalibPointsTool); tWriter->SetInput(2, m_EvalPointsImage); tWriter->SetInput(3, m_EvalPointsTool); tWriter->SetInput(4, m_EvalPointsProjected); tWriter->SetOutputFilename(filename.toStdString() + ".txt"); tWriter->DoWrite(this->m_Transformation); */ } void QmitkUltrasoundCalibration::OnSaveCalibration() { m_Controls.m_GotCalibrationLabel->setText(""); QString filename = QFileDialog::getSaveFileName(QApplication::activeWindow(), "Save Calibration", "", "Calibration files *.cal"); QFile file(filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { MITK_WARN << "Cannot open file '" << filename.toStdString() << "' for writing."; return; } std::string calibrationSerialization = m_CombinedModality->SerializeCalibration(); QTextStream outStream(&file); outStream << QString::fromStdString(calibrationSerialization); //save additional information if (m_Controls.m_saveAdditionalCalibrationLog->isChecked()) { mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); QString filenameScene = filename + "_mitkScene.mitk"; mitk::NodePredicateNot::Pointer isNotHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = this->GetDataStorage()->GetSubset(isNotHelperObject); mySceneIO->SaveScene(nodesToBeSaved, this->GetDataStorage(), filenameScene.toStdString().c_str()); } } void QmitkUltrasoundCalibration::OnReset() { this->ClearTemporaryMembers(); if (m_Transformation.IsNull()) { m_Transformation = mitk::AffineTransform3D::New(); } m_Transformation->SetIdentity(); if (m_Node.IsNotNull() && (m_Node->GetData() != nullptr) && (m_Node->GetData()->GetGeometry() != nullptr)) { mitk::SlicedGeometry3D::Pointer sliced3d = dynamic_cast (m_Node->GetData()->GetGeometry()); mitk::PlaneGeometry::Pointer plane = const_cast (sliced3d->GetPlaneGeometry(0)); plane->SetIndexToWorldTransform(m_Transformation); } QString text1 = text1.number(this->m_EvalPointsTool->GetSize()); this->m_Controls.m_EvalLblNumTargetPoints->setText(text1); QString text2 = text2.number(this->m_EvalPointsProjected->GetSize()); this->m_Controls.m_EvalLblNumProjectionPoints->setText(text2); } void QmitkUltrasoundCalibration::Update() { //QList nodes = this->GetDataManagerSelection(); // if (nodes.empty()) return; // Update Tracking Data std::vector* datas = new std::vector(); datas->push_back(m_Tracker->GetOutput()); m_Controls.m_CalibTrackingStatus->SetNavigationDatas(datas); m_Controls.m_CalibTrackingStatus->Refresh(); m_Controls.m_EvalTrackingStatus->SetNavigationDatas(datas); m_Controls.m_EvalTrackingStatus->Refresh(); // Update US Image if (m_Image.IsNotNull() && m_Image->IsInitialized()) { m_Node->SetData(m_Image); } else { mitk::Image::Pointer m_Image = m_CombinedModality->GetUltrasoundDevice()->GetOutput(); m_Node->SetData(m_Image); //Workaround because image is not initalized, maybe problem of the Ultrasound view? } m_CombinedModality->Modified(); m_CombinedModality->Update(); // Update Needle Projection m_NeedleProjectionFilter->Update(); //only update 2d window because it is faster this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } void QmitkUltrasoundCalibration::SwitchFreeze() { m_Controls.m_CalibBtnAddPoint->setEnabled(false); // generally deactivate // We use the activity state of the timer to determine whether we are currently viewing images if (!m_Timer->isActive()) // Activate Imaging { // if (m_Node) m_Node->ReleaseData(); if (m_CombinedModality.IsNull()){ m_Timer->stop(); return; } m_CombinedModality->Update(); m_Image = m_CombinedModality->GetOutput(); if (m_Image.IsNotNull() && m_Image->IsInitialized()) { m_Node->SetData(m_Image); } std::vector datas; datas.push_back(m_Tracker->GetOutput()); m_Controls.m_CalibTrackingStatus->SetNavigationDatas(&datas); m_Controls.m_CalibTrackingStatus->ShowStatusLabels(); m_Controls.m_CalibTrackingStatus->Refresh(); m_Controls.m_EvalTrackingStatus->SetNavigationDatas(&datas); m_Controls.m_EvalTrackingStatus->ShowStatusLabels(); m_Controls.m_EvalTrackingStatus->Refresh(); int interval = 40; m_Timer->setInterval(interval); m_Timer->start(); - m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); + m_CombinedModality->SetIsFreezed(false); } else if (this->m_Tracker->GetOutput(0)->IsDataValid()) { //deactivate Imaging m_Timer->stop(); // Remember last tracking coordinates m_FreezePoint = this->m_Tracker->GetOutput(0)->GetPosition(); m_Controls.m_CalibBtnAddPoint->setEnabled(true); // activate only, if valid point is set - m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(true); + m_CombinedModality->SetIsFreezed(true); } } void QmitkUltrasoundCalibration::ShowNeedlePath() { // Init Filter this->m_NeedleProjectionFilter->SelectInput(0); // Create Node for Pointset mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode("Needle Path"); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetName("Needle Path"); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); this->GetDataStorage()->Add(node); } } void QmitkUltrasoundCalibration::ClearTemporaryMembers() { m_CalibPointsTool->Clear(); m_CalibPointsImage->Clear(); m_CalibPointsCount = 0; m_EvalPointsImage->Clear(); m_EvalPointsTool->Clear(); m_EvalPointsProjected->Clear(); this->m_Controls.m_CalibPointList->clear(); m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; } vtkSmartPointer QmitkUltrasoundCalibration::ConvertPointSetToVtkPolyData(mitk::PointSet::Pointer PointSet) { vtkSmartPointer returnValue = vtkSmartPointer::New(); vtkSmartPointer points = vtkSmartPointer::New(); for (int i = 0; i < PointSet->GetSize(); i++) { double point[3] = { PointSet->GetPoint(i)[0], PointSet->GetPoint(i)[1], PointSet->GetPoint(i)[2] }; points->InsertNextPoint(point); } vtkSmartPointer temp = vtkSmartPointer::New(); temp->SetPoints(points); vtkSmartPointer vertexFilter = vtkSmartPointer::New(); vertexFilter->SetInputData(temp); vertexFilter->Update(); returnValue->ShallowCopy(vertexFilter->GetOutput()); return returnValue; } double QmitkUltrasoundCalibration::ComputeFRE(mitk::PointSet::Pointer imageFiducials, mitk::PointSet::Pointer realWorldFiducials, vtkSmartPointer transform) { if (imageFiducials->GetSize() != realWorldFiducials->GetSize()) return -1; double FRE = 0; for (int i = 0; i < imageFiducials->GetSize(); ++i) { itk::Point current_image_fiducial_point = imageFiducials->GetPoint(i); if (transform != nullptr) { current_image_fiducial_point = transform->TransformPoint(imageFiducials->GetPoint(i)[0], imageFiducials->GetPoint(i)[1], imageFiducials->GetPoint(i)[2]); } double cur_error_squared = current_image_fiducial_point.SquaredEuclideanDistanceTo(realWorldFiducials->GetPoint(i)); FRE += cur_error_squared; } FRE = sqrt(FRE / (double)imageFiducials->GetSize()); return FRE; } void QmitkUltrasoundCalibration::ApplyTransformToPointSet(mitk::PointSet::Pointer pointSet, vtkSmartPointer transform) { for (int i = 0; i < pointSet->GetSize(); ++i) { itk::Point current_point_transformed = itk::Point(); current_point_transformed = transform->TransformPoint(pointSet->GetPoint(i)[0], pointSet->GetPoint(i)[1], pointSet->GetPoint(i)[2]); pointSet->SetPoint(i, current_point_transformed); } } void QmitkUltrasoundCalibration::OnFreezeClicked() { if (m_CombinedModality->GetUltrasoundDevice()->GetIsFreezed()) { if (!m_Timer->isActive()) // Activate Imaging { // if (m_Node) m_Node->ReleaseData(); if (m_CombinedModality.IsNull()) { m_Timer->stop(); return; } m_Timer->start(); } //device was already frozen so we need to delete all Spacing points because they need to be collected all at once // no need to check if all four points are already collected, because if thats the case you can no longer click the Freeze Button m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; m_Controls.m_SpacingAddPoint->setEnabled(false); - m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); + m_CombinedModality->SetIsFreezed(false); } else { //deactivate Imaging m_Timer->stop(); - m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(true); + m_CombinedModality->SetIsFreezed(true); m_Controls.m_SpacingAddPoint->setEnabled(true); } //SwitchFreeze(); } void QmitkUltrasoundCalibration::OnAddSpacingPoint() { mitk::Point3D point = this->GetRenderWindowPart()->GetSelectedPosition(); this->m_SpacingPoints->InsertPoint(m_SpacingPointsCount, point); QString text = text.number(m_SpacingPointsCount + 1); text = "Point " + text; this->m_Controls.m_SpacingPointsList->addItem(text); m_SpacingPointsCount++; if (m_SpacingPointsCount == 4) //now we have all 4 points needed { m_Controls.m_SpacingAddPoint->setEnabled(false); m_Controls.m_CalculateSpacing->setEnabled(true); m_Controls.m_SpacingBtnFreeze->setEnabled(false); } } void QmitkUltrasoundCalibration::OnCalculateSpacing() { mitk::Point3D horizontalOne = m_SpacingPoints->GetPoint(0); mitk::Point3D horizontalTwo = m_SpacingPoints->GetPoint(1); mitk::Point3D verticalOne = m_SpacingPoints->GetPoint(2); mitk::Point3D verticalTwo = m_SpacingPoints->GetPoint(3); //Get the distances between the points in the image double xDistance = horizontalOne.EuclideanDistanceTo(horizontalTwo); double yDistance = verticalOne.EuclideanDistanceTo(verticalTwo); //Calculate the spacing of the image and fill a vector with it double xSpacing = 30 / xDistance; double ySpacing = 20 / yDistance; m_CombinedModality->GetUltrasoundDevice()->SetSpacing(xSpacing, ySpacing); //Now that the spacing is set clear all stuff and return to Calibration m_SpacingPoints->Clear(); m_Controls.m_SpacingPointsList->clear(); m_SpacingPointsCount = 0; - m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); + m_CombinedModality->SetIsFreezed(false); } void QmitkUltrasoundCalibration::OnUSDepthChanged(const std::string& key, const std::string&) { //whenever depth of USImage is changed the spacing should no longer be overwritten if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { } } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp index fdf97175d2..0d90347697 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/Widgets/QmitkUSNavigationFreezeButton.cpp @@ -1,136 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkUSNavigationFreezeButton.h" #include QmitkUSNavigationFreezeButton::QmitkUSNavigationFreezeButton(QWidget* parent) : QPushButton(parent), m_OutputIndex(-1), m_FreezeButtonToggle(true) { this->setText("Freeze Imaging"); this->setIcon(QIcon(":/USNavigation/system-lock-screen.png")); this->setCheckable(true); //set shortcuts QShortcut *shortcut = new QShortcut(QKeySequence("F12"), parent); connect(shortcut, SIGNAL(activated()), this, SLOT(OnFreezeButtonToggle())); connect(this, SIGNAL(clicked(bool)), this, SLOT(OnButtonClicked(bool))); } QmitkUSNavigationFreezeButton::~QmitkUSNavigationFreezeButton() { } void QmitkUSNavigationFreezeButton::SetCombinedModality(mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality, int outputIndex) { m_CombinedModality = combinedModality; m_OutputIndex = outputIndex; } void QmitkUSNavigationFreezeButton::Freeze() { if ( ! this->isChecked() ) { this->setChecked(true); this->OnButtonClicked(true); } } void QmitkUSNavigationFreezeButton::Unfreeze() { if ( this->isChecked() ) { this->setChecked(false); this->OnButtonClicked(false); } } void QmitkUSNavigationFreezeButton::OnFreezeButtonToggle() { if(this->isVisible()) { this->setChecked(m_FreezeButtonToggle); OnButtonClicked(m_FreezeButtonToggle); } } void QmitkUSNavigationFreezeButton::OnButtonClicked(bool checked) { // cannot do anything without a combined modality if ( m_CombinedModality.IsNull() ) { MITK_WARN("QmitkUSNavigationFreezeButton") << "Cannot freeze the device as the device is null."; this->setChecked(false); m_FreezeButtonToggle = true; return; } m_FreezeButtonToggle = !checked; // cannot do anything without a navigation data source mitk::NavigationDataSource::Pointer navigationDataSource = m_CombinedModality->GetNavigationDataSource(); if ( navigationDataSource.IsNull() ) { MITK_WARN("QmitkUSNavigationFreezeButton") << "Cannot freeze the device as the NavigationDataSource is null."; this->setChecked(false); return; } if (checked) //freezing { MITK_INFO << "Freezing"; // freeze the imaging and the tracking - m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(true); + m_CombinedModality->SetIsFreezed(true); if ( m_OutputIndex >= 0 ) { // make sure that the navigation data is up to date navigationDataSource->Update(); // unfreeze if the navigation data got invalid during the time between // the button click and the actual freeze if ( checked && ! navigationDataSource->GetOutput(m_OutputIndex)->IsDataValid() ) { MITK_WARN("QmitkUSNavigationStepZoneMarking")("QmitkUSNavigationStepTumourSelection") << "Unfreezing device as the last tracking data of the reference sensor wasn't valid."; - m_CombinedModality->GetUltrasoundDevice()->SetIsFreezed(false); + m_CombinedModality->SetIsFreezed(false); this->setChecked(false); return; } } emit SignalFreezed(true); } else //unfreezing { MITK_INFO << "Unfreezing"; emit SignalFreezed(false); //m_CombinedModality->SetIsFreezed(false);//commented out to workaround bug: may only be unfreezed after critical structure was added } }