diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index 1e55c31253..00caba5b25 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,293 +1,312 @@ /*=================================================================== 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" //Microservices #include #include #include #include "mitkModuleContext.h" const std::string mitk::USDevice::US_INTERFACE_NAME = "org.mitk.services.UltrasoundDevice"; const std::string mitk::USDevice::US_PROPKEY_LABEL = US_INTERFACE_NAME + ".label"; const std::string mitk::USDevice::US_PROPKEY_ISACTIVE = US_INTERFACE_NAME + ".isActive"; const std::string mitk::USDevice::US_PROPKEY_CLASS = US_INTERFACE_NAME + ".class"; +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; +} mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource() { // Initialize Members m_Metadata = mitk::USImageMetadata::New(); m_Metadata->SetDeviceManufacturer(manufacturer); m_Metadata->SetDeviceModel(model); m_IsActive = false; + USImageCropArea empty; + empty.cropBottom = 0; + empty.cropTop = 0; + empty.cropLeft = 0; + empty.cropRight = 0; + this->m_CropArea = empty; + m_IsConnected = false; //set number of outputs this->SetNumberOfOutputs(1); //create a new output mitk::USImage::Pointer newOutput = mitk::USImage::New(); this->SetNthOutput(0,newOutput); } mitk::USDevice::USDevice(mitk::USImageMetadata::Pointer metadata) : mitk::ImageSource() { m_Metadata = metadata; m_IsActive = false; + m_IsConnected = false; //set number of outputs this->SetNumberOfOutputs(1); //create a new output mitk::USImage::Pointer newOutput = mitk::USImage::New(); this->SetNthOutput(0,newOutput); } mitk::USDevice::~USDevice() { } mitk::ServiceProperties mitk::USDevice::ConstructServiceProperties() { ServiceProperties props; std::string yes = "true"; std::string no = "false"; if(this->GetIsActive()) props[mitk::USDevice::US_PROPKEY_ISACTIVE] = yes; else props[mitk::USDevice::US_PROPKEY_ISACTIVE] = no; std::string isActive; if (GetIsActive()) isActive = " (Active)"; else isActive = " (Inactive)"; // e.g.: Zonare MyLab5 (Active) props[ mitk::USDevice::US_PROPKEY_LABEL] = m_Metadata->GetDeviceManufacturer() + " " + m_Metadata->GetDeviceModel() + isActive; if( m_Calibration.IsNotNull() ) props[ mitk::USImageMetadata::PROP_DEV_ISCALIBRATED ] = yes; else props[ mitk::USImageMetadata::PROP_DEV_ISCALIBRATED ] = no; props[ mitk::USDevice::US_PROPKEY_CLASS ] = GetDeviceClass(); props[ mitk::USImageMetadata::PROP_DEV_MANUFACTURER ] = m_Metadata->GetDeviceManufacturer(); props[ mitk::USImageMetadata::PROP_DEV_MODEL ] = m_Metadata->GetDeviceModel(); props[ mitk::USImageMetadata::PROP_DEV_COMMENT ] = m_Metadata->GetDeviceComment(); props[ mitk::USImageMetadata::PROP_PROBE_NAME ] = m_Metadata->GetProbeName(); props[ mitk::USImageMetadata::PROP_PROBE_FREQUENCY ] = m_Metadata->GetProbeFrequency(); props[ mitk::USImageMetadata::PROP_ZOOM ] = m_Metadata->GetZoom(); return props; } bool mitk::USDevice::Connect() { if (GetIsConnected()) { MITK_WARN << "Tried to connect an ultrasound device that was already connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (! this->OnConnection()) return false; + // Update state + m_IsConnected = true; + // Get Context and Module mitk::ModuleContext* context = GetModuleContext(); ServiceProperties props = ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); // This makes sure that the SmartPointer to this device does not invalidate while the device is connected this->Register(); return true; } 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_IsConnected = false; + // Unregister m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; // Undo the manual registration done in Connect(). Pointer will invalidte, if no one holds a reference to this object anymore. this->UnRegister(); return true; } bool mitk::USDevice::Activate() { if (! this->GetIsConnected()) return false; m_IsActive = true; // <- Necessary to safely allow Subclasses to start threading based on activity state m_IsActive = OnActivation(); ServiceProperties props = ConstructServiceProperties(); this->m_ServiceRegistration.SetProperties(props); return m_IsActive; } void mitk::USDevice::Deactivate() { m_IsActive= false; ServiceProperties props = ConstructServiceProperties(); this->m_ServiceRegistration.SetProperties(props); OnDeactivation(); } void mitk::USDevice::AddProbe(mitk::USProbe::Pointer probe) { for(int i = 0; i < m_ConnectedProbes.size(); i++) { if (m_ConnectedProbes[i]->IsEqualToProbe(probe)) return; } this->m_ConnectedProbes.push_back(probe); } void mitk::USDevice::ActivateProbe(mitk::USProbe::Pointer probe){ // currently, we may just add the probe. This behaviour should be changed, should more complicated SDK applications emerge AddProbe(probe); int index = -1; for(int i = 0; i < m_ConnectedProbes.size(); i++) { if (m_ConnectedProbes[i]->IsEqualToProbe(probe)) index = i; } // index now contains the position of the original instance of this probe m_ActiveProbe = m_ConnectedProbes[index]; } void mitk::USDevice::DeactivateProbe(){ m_ActiveProbe = 0; } mitk::USImage* mitk::USDevice::GetOutput() { if (this->GetNumberOfOutputs() < 1) return NULL; return static_cast(this->ProcessObject::GetOutput(0)); } mitk::USImage* mitk::USDevice::GetOutput(unsigned int idx) { if (this->GetNumberOfOutputs() < 1) return NULL; 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 NULL pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a NULL pointer" ); } // Call Graft on USImage to copy member data output->Graft( graft ); } itk::ProcessObject::DataObjectPointer mitk::USDevice::MakeOutput( unsigned int /*idx */) { mitk::USImage::Pointer p = mitk::USImage::New(); return static_cast(p.GetPointer()); } bool mitk::USDevice::ApplyCalibration(mitk::USImage::Pointer image){ if ( m_Calibration.IsNull() ) return false; image->GetGeometry()->SetIndexToWorldTransform(m_Calibration); return true; } //########### GETTER & SETTER ##################// void mitk::USDevice::setCalibration (mitk::AffineTransform3D::Pointer calibration){ if (calibration.IsNull()) { MITK_ERROR << "Null pointer passed to SetCalibration of mitk::USDevice. Ignoring call."; return; } m_Calibration = calibration; m_Metadata->SetDeviceIsCalibrated(true); if (m_ServiceRegistration != 0) { ServiceProperties props = ConstructServiceProperties(); this->m_ServiceRegistration.SetProperties(props); } } bool mitk::USDevice::GetIsActive() { return m_IsActive; } bool mitk::USDevice::GetIsConnected() { // a device is connected if it is registered with the Microservice Registry return (m_ServiceRegistration != 0); } std::string mitk::USDevice::GetDeviceManufacturer(){ return this->m_Metadata->GetDeviceManufacturer(); } std::string mitk::USDevice::GetDeviceModel(){ return this->m_Metadata->GetDeviceModel(); } std::string mitk::USDevice::GetDeviceComment(){ return this->m_Metadata->GetDeviceComment(); } std::vector mitk::USDevice::GetConnectedProbes() { return m_ConnectedProbes; } diff --git a/Modules/US/USModel/mitkUSDevice.h b/Modules/US/USModel/mitkUSDevice.h index c982eadca9..ffb9aa1501 100644 --- a/Modules/US/USModel/mitkUSDevice.h +++ b/Modules/US/USModel/mitkUSDevice.h @@ -1,298 +1,313 @@ /*=================================================================== 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 MITKUSDevice_H_HEADER_INCLUDED_ #define MITKUSDevice_H_HEADER_INCLUDED_ // STL #include // MitkUS #include "mitkUSProbe.h" #include "mitkUSImageMetadata.h" #include "mitkUSImage.h" #include // MITK #include #include // ITK #include // Microservices #include #include #include namespace mitk { /**Documentation * \brief A device holds information about it's model, make and the connected probes. It is the * common super class for all devices and acts as an image source for mitkUSImages. It is the base class * for all US Devices, and every new device should extend it. * * US Devices support output of calibrated images, i.e. images that include a specific geometry. * To achieve this, call SetCalibration, and make sure that the subclass also calls apply * transformation at some point (The USDevice does not automatically apply the transformation to the image) * * Note that SmartPointers to USDevices will not invalidate while the device is still connected. * \ingroup US */ class MitkUS_EXPORT USDevice : public mitk::ImageSource { public: mitkClassMacro(USDevice, mitk::ImageSource); + struct USImageCropArea + { + int cropLeft; + int cropRight; + int cropBottom; + int cropTop; + }; + /** *\brief These constants are used in conjunction with Microservices */ static const std::string US_INTERFACE_NAME; // Common Interface name of all US Devices. Used to refer to this device via Microservices static const std::string US_PROPKEY_LABEL; // Human readable text represntation of this device static const std::string US_PROPKEY_ISACTIVE; // Whether this Device is active or not. static const std::string US_PROPKEY_CLASS; // Class Name of this Object /** * \brief Connects this device. A connected device is ready to deliver images (i.e. be Activated). A Connected Device can be active. A disconnected Device cannot be active. * Internally calls onConnect and then registers the device with the service. A device usually should * override the OnConnection() method, but never the Connect() method, since this will possibly exclude the device * from normal service management. The exact flow of events is: * 0. Check if the device is already connected. If yes, return true anyway, but don't do anything. * 1. Call OnConnection() Here, a device should establish it's connection with the hardware Afterwards, it should be ready to start transmitting images at any time. * 2. If OnConnection() returns true ("successful"), then the device is registered with the service. * 3. if not, it the method itself returns false or may throw an expection, depeneding on the device implementation. * */ bool Connect(); /** * \brief Works analogously to mitk::USDevice::Connect(). Don't override this Method, but onDisconnection instead. */ bool Disconnect(); /** * \brief Activates this device. After the activation process, the device will start to produce images. This Method will fail, if the device is not connected. */ bool Activate(); /** * \brief Deactivates this device. After the deactivation process, the device will no longer produce images, but still be connected. */ void Deactivate(); /** * \brief Add a probe to the device without connecting to it. * This should usually be done before connecting to the probe. */ virtual void AddProbe(mitk::USProbe::Pointer probe); /** * \brief Connect to a probe and activate it. The probe should be added first. * Usually, a VideoDevice will simply add a probe it wants to connect to, * but an SDK Device might require adding a probe first. */ virtual void ActivateProbe(mitk::USProbe::Pointer probe); /** * \brief Deactivates the currently active probe. */ virtual void DeactivateProbe(); /** * \brief Removes a probe from the ist of currently added probes. */ //virtual void removeProbe(mitk::USProbe::Pointer probe); /** * \brief Returns a vector containing all connected probes. */ std::vector GetConnectedProbes(); /** *\brief return the output (output with id 0) of the filter */ USImage* GetOutput(void); /** *\brief return the output with id idx of the filter */ USImage* GetOutput(unsigned int idx); /** *\brief Graft the specified DataObject onto this ProcessObject's output. * * See itk::ImageSource::GraftNthOutput for details */ virtual void GraftNthOutput(unsigned int idx, itk::DataObject *graft); /** * \brief Graft the specified DataObject onto this ProcessObject's output. * * See itk::ImageSource::Graft Output for details */ virtual void GraftOutput(itk::DataObject *graft); /** * \brief Make a DataObject of the correct type to used as the specified output. * * This method is automatically called when DataObject::DisconnectPipeline() * is called. DataObject::DisconnectPipeline, disconnects a data object * from being an output of its current source. When the data object * is disconnected, the ProcessObject needs to construct a replacement * output data object so that the ProcessObject is in a valid state. * Subclasses of USImageVideoSource that have outputs of different * data types must overwrite this method so that proper output objects * are created. */ virtual DataObjectPointer MakeOutput(unsigned int idx); //########### GETTER & SETTER ##################// /** * \brief Returns the Class of the Device. This Method must be reimplemented by every Inheriting Class. */ virtual std::string GetDeviceClass() = 0; /** * \brief True, if the device is currently generating image data, false otherwise. */ bool GetIsActive(); /** * \brief True, if the device is currently ready to start transmitting image data or is already * transmitting image data. A disconnected device cannot be activated. */ bool GetIsConnected(); /** * \brief Sets a transformation as Calibration data. It also marks the device as Calibrated. This data is not automatically applied to the image. Subclasses must call ApplyTransformation * to achieve this. */ void setCalibration (mitk::AffineTransform3D::Pointer calibration); /** * \brief Returns the current Calibration */ itkGetMacro(Calibration, mitk::AffineTransform3D::Pointer); /** * \brief Returns the currently active probe or null, if none is active */ itkGetMacro(ActiveProbe, mitk::USProbe::Pointer); + /* @return Returns the area that will be cropped from the US image. Is disabled / [0,0,0,0] by default. */ + mitk::USDevice::USImageCropArea GetCropArea(); + std::string GetDeviceManufacturer(); std::string GetDeviceModel(); std::string GetDeviceComment(); protected: mitk::USProbe::Pointer m_ActiveProbe; std::vector m_ConnectedProbes; bool m_IsActive; + bool m_IsConnected; + + /* @brief defines the area that should be cropped from the US image */ + USImageCropArea m_CropArea; /* * \brief This Method constructs the service properties which can later be used to * register the object with the Microservices * Return service properties */ mitk::ServiceProperties ConstructServiceProperties(); /** * \brief Is called during the connection process. Override this method in your subclass to handle the actual connection. * Return true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ virtual bool OnConnection() = 0; /** * \brief Is called during the disconnection process. Override this method in your subclass to handle the actual disconnection. * Return true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ virtual bool OnDisconnection() = 0; /** * \brief Is called during the activation process. After this method is finished, the device should be generating images */ virtual bool OnActivation() = 0; /** * \brief Is called during the deactivation process. After a call to this method the device should still be connected, but not producing images anymore. */ virtual void OnDeactivation() = 0; /** * \brief This metadata set is privately used to imprint USImages with Metadata later. * At instantiation time, it only contains Information about the Device, * At scan time, it integrates this data with the probe information and imprints it on * the produced images. This field is intentionally hidden from outside interference. */ mitk::USImageMetadata::Pointer m_Metadata; /** * \brief Enforces minimal Metadata to be set. */ USDevice(std::string manufacturer, std::string model); /** * \brief Constructs a device with the given Metadata. Make sure the Metadata contains meaningful content! */ USDevice(mitk::USImageMetadata::Pointer metadata); virtual ~USDevice(); /** * \brief Grabs the next frame from the Video input. This method is called internally, whenever Update() is invoked by an Output. */ void GenerateData() = 0; /** * \brief The Calibration Transformation of this US-Device. This will automatically be written into the image once */ mitk::AffineTransform3D::Pointer m_Calibration; /** * \brief Convenience method that can be used by subclasses to apply the Calibration Data to the image. A subclass has to call * this method or set the transformation itself for the output to be calibrated! Returns true if a Calibration was set and false otherwise * (Usually happens when no transformation was set yet). */ bool ApplyCalibration(mitk::USImage::Pointer image); private: /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ mitk::ServiceRegistration m_ServiceRegistration; }; } // namespace mitk // This is the microservice declaration. Do not meddle! US_DECLARE_SERVICE_INTERFACE(mitk::USDevice, "org.mitk.services.UltrasoundDevice") #endif \ No newline at end of file diff --git a/Modules/US/USModel/mitkUSVideoDevice.cpp b/Modules/US/USModel/mitkUSVideoDevice.cpp index 0140d714eb..7cbe2e126b 100644 --- a/Modules/US/USModel/mitkUSVideoDevice.cpp +++ b/Modules/US/USModel/mitkUSVideoDevice.cpp @@ -1,137 +1,170 @@ /*=================================================================== 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 "mitkUSVideoDevice.h" mitk::USVideoDevice::USVideoDevice(int videoDeviceNumber, std::string manufacturer, std::string model) : mitk::USDevice(manufacturer, model) { Init(); m_SourceIsFile = false; m_DeviceID = videoDeviceNumber; m_FilePath = ""; } mitk::USVideoDevice::USVideoDevice(std::string videoFilePath, std::string manufacturer, std::string model) : mitk::USDevice(manufacturer, model) { Init(); m_SourceIsFile = true; m_FilePath = videoFilePath; } mitk::USVideoDevice::USVideoDevice(int videoDeviceNumber, mitk::USImageMetadata::Pointer metadata) : mitk::USDevice(metadata) { Init(); m_SourceIsFile = false; m_DeviceID = videoDeviceNumber; m_FilePath = ""; } mitk::USVideoDevice::USVideoDevice(std::string videoFilePath, mitk::USImageMetadata::Pointer metadata) : mitk::USDevice(metadata) { Init(); m_SourceIsFile = true; m_FilePath = videoFilePath; } mitk::USVideoDevice::~USVideoDevice() { } void mitk::USVideoDevice::Init() { m_Source = mitk::USImageVideoSource::New(); //this->SetNumberOfInputs(1); this->SetNumberOfOutputs(1); // mitk::USImage::Pointer output = mitk::USImage::New(); // output->Initialize(); this->SetNthOutput(0, this->MakeOutput(0)); this->m_MultiThreader = itk::MultiThreader::New(); this->m_ImageMutex = itk::FastMutexLock::New(); this->m_CameraActiveMutex= itk::FastMutexLock::New(); m_IsActive = false; } std::string mitk::USVideoDevice::GetDeviceClass(){ return "org.mitk.modules.us.USVideoDevice"; } bool mitk::USVideoDevice::OnConnection() { if (m_SourceIsFile){ m_Source->SetVideoFileInput(m_FilePath); } else { m_Source->SetCameraInput(m_DeviceID); } + SetSourceCropArea(); return true; } bool mitk::USVideoDevice::OnDisconnection() { if (m_IsActive) this->Deactivate(); return true; } bool mitk::USVideoDevice::OnActivation() { MITK_INFO << "Activated UsVideoDevice!"; this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); return true; } void mitk::USVideoDevice::OnDeactivation() { // happens automatically when m_Active is set to false } void mitk::USVideoDevice::GenerateData() { mitk::USImage::Pointer result; result = m_Image; // Set Metadata result->SetMetadata(this->m_Metadata); //Apply Transformation this->ApplyCalibration(result); // Set Output this->SetNthOutput(0, result); } void mitk::USVideoDevice::GrabImage() { m_Image = m_Source->GetNextImage(); //this->SetNthOutput(0, m_Image); //this->Modified(); } +void mitk::USVideoDevice::SetSourceCropArea() +{ +if (this->m_Source.IsNotNull()) + { + if((m_CropArea.cropBottom==0)&& + (m_CropArea.cropTop==0)&& + (m_CropArea.cropLeft==0)&& + (m_CropArea.cropRight==0)) + {this->m_Source->RemoveRegionOfInterest();} + else + { + int right = m_Source->GetImageWidth() - m_CropArea.cropRight; + int bottom = m_Source->GetImageHeight() - m_CropArea.cropBottom; + this->m_Source->SetRegionOfInterest(m_CropArea.cropLeft, + m_CropArea.cropTop, + right, + bottom); + } + + } +else + {MITK_WARN << "Cannot set crop are, source is not initialized!";} + +} + +void mitk::USVideoDevice::SetCropArea(mitk::USDevice::USImageCropArea newArea) +{ +m_CropArea = newArea; +MITK_INFO << "Set Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; +if (m_IsConnected) SetSourceCropArea(); +} + ITK_THREAD_RETURN_TYPE mitk::USVideoDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USVideoDevice * device = (mitk::USVideoDevice *) pInfo->UserData; while (device->GetIsActive()) { device->GrabImage(); } return ITK_THREAD_RETURN_VALUE; } diff --git a/Modules/US/USModel/mitkUSVideoDevice.h b/Modules/US/USModel/mitkUSVideoDevice.h index 1d76f092e6..fa7ef2f703 100644 --- a/Modules/US/USModel/mitkUSVideoDevice.h +++ b/Modules/US/USModel/mitkUSVideoDevice.h @@ -1,150 +1,154 @@ /*=================================================================== 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 MITKUSVideoDevice_H_HEADER_INCLUDED_ #define MITKUSVideoDevice_H_HEADER_INCLUDED_ #include #include #include "mitkUSDevice.h" #include #include "mitkUSImageVideoSource.h" namespace mitk { /**Documentation * \brief A VideoDevice is the common class for video only devices. They capture Video Input either from * a file or from a device, and transform the output into an mitkUSImage with attached Metadata. * This simple implementation does only capture and display 2D Images without cropping or registration. * One can simply inherit from this class and overwrite the handle2D and handle 3Dmethods to get full access to the data * \ingroup US */ class MitkUS_EXPORT USVideoDevice : public mitk::USDevice { public: mitkClassMacro(USVideoDevice, mitk::USDevice); // To open a device (DeviceID, Manufacturer, Model) mitkNewMacro3Param(Self, int, std::string, std::string); // To open A VideoFile (Path, Manufacturer, Model) mitkNewMacro3Param(Self, std::string, std::string, std::string); // To open a device (DeviceID, Metadata) mitkNewMacro2Param(Self, int, mitk::USImageMetadata::Pointer); // To open A VideoFile (Path, Metadata) mitkNewMacro2Param(Self, std::string, mitk::USImageMetadata::Pointer); + /*@brief Sets the area that will be cropped from the US image. Set [0,0,0,0] to disable it, which is also default. */ + void SetCropArea(mitk::USDevice::USImageCropArea newArea); /** * \brief Returns the qualified name of this class. Be sure to override this when inheriting from VideoDevice! */ virtual std::string GetDeviceClass(); void GenerateData(); itkGetMacro(Source, mitk::USImageVideoSource::Pointer); itkGetMacro(Image, mitk::USImage::Pointer); itkGetMacro(DeviceID,int); itkGetMacro(FilePath,std::string); void GrabImage(); protected: static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); /** * \brief Creates a new device that will deliver USImages taken from a video device. * under windows, try -1 for device number, which will grab the first available one * (Open CV functionality) */ USVideoDevice(int videoDeviceNumber, std::string manufacturer, std::string model); /** * \brief Creates a new device that will deliver USImages taken from a video file. */ USVideoDevice(std::string videoFilePath, std::string manufacturer, std::string model); /** * \brief Creates a new device that will deliver USImages taken from a video device. * under windows, try -1 for device number, which will grab the first available one * (Open CV functionality) */ USVideoDevice(int videoDeviceNumber, mitk::USImageMetadata::Pointer metadata); /** * \brief Creates a new device that will deliver USImages taken from a video file. */ USVideoDevice(std::string videoFilePath, mitk::USImageMetadata::Pointer metadata); virtual ~USVideoDevice(); /** * \brief Initializes common properties for all constructors. */ void Init(); /** * \brief Is called during the connection process. * Returns true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ virtual bool OnConnection(); /** * \brief Is called during the disconnection process. * Returns true if successful and false if unsuccessful. Additionally, you may throw an exception to clarify what went wrong. */ virtual bool OnDisconnection(); /** * \brief Is called during the activation process. After this method is finsihed, the device should be generating images */ virtual bool OnActivation(); /** * \brief Is called during the deactivation process. After a call to this method the device should still be connected, but not producing images anymore. */ virtual void OnDeactivation(); /** * \brief The image source that we use to aquire data */ mitk::USImageVideoSource::Pointer m_Source; /** * \brief True, if this source plays back a file, false if it recieves data from a device */ bool m_SourceIsFile; /** * \brief The device id to connect to. Undefined, if m_SourceIsFile == true; */ int m_DeviceID; /** * \brief The Filepath id to connect to. Undefined, if m_SourceIsFile == false; */ std::string m_FilePath; + void SetSourceCropArea(); + // Threading-Related itk::MultiThreader::Pointer m_MultiThreader; ///< itk::MultiThreader used for thread handling itk::FastMutexLock::Pointer m_ImageMutex; ///< mutex for images provided by the range camera itk::FastMutexLock::Pointer m_CameraActiveMutex; ///< mutex for the cameraActive flag int m_ThreadID; ///< ID of the started thread mitk::USImage::Pointer m_Image; }; } // namespace mitk #endif diff --git a/Modules/USUI/Qmitk/mitkUSDevicePersistence.cpp b/Modules/USUI/Qmitk/mitkUSDevicePersistence.cpp index dbd488f7cf..e80db1e4c3 100644 --- a/Modules/USUI/Qmitk/mitkUSDevicePersistence.cpp +++ b/Modules/USUI/Qmitk/mitkUSDevicePersistence.cpp @@ -1,168 +1,185 @@ /*=================================================================== 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 "mitkUSDevicePersistence.h" //Microservices #include "usServiceReference.h" #include "usModuleContext.h" #include #include mitk::USDevicePersistence::USDevicePersistence() : m_devices("MITK US","Device Settings") { } void mitk::USDevicePersistence::StoreCurrentDevices() { mitk::ModuleContext* thisContext = mitk::GetModuleContext(); std::list services = thisContext->GetServiceReferences(); MITK_INFO << "Trying to save " << services.size() << " US devices."; int numberOfSavedDevices = 0; for(std::list::iterator it = services.begin(); it != services.end(); ++it) { mitk::USDevice::Pointer currentDevice = thisContext->GetService(*it); //check if it is a USVideoDevice if (currentDevice->GetDeviceClass()=="org.mitk.modules.us.USVideoDevice") { mitk::USVideoDevice::Pointer currentVideoDevice = dynamic_cast(currentDevice.GetPointer()); QString identifier = "device" + QString::number(numberOfSavedDevices); m_devices.setValue(identifier,USVideoDeviceToString(currentVideoDevice)); numberOfSavedDevices++; } else { MITK_WARN << "Saving of US devices of the type " << currentDevice->GetDeviceClass() << " is not supported at the moment. Skipping device."; } } m_devices.setValue("numberOfSavedDevices",numberOfSavedDevices); MITK_INFO << "Successfully saved " << numberOfSavedDevices << " US devices."; } void mitk::USDevicePersistence::RestoreLastDevices() { int numberOfSavedDevices = m_devices.value("numberOfSavedDevices").toInt(); for(int i=0; iConnect(); } MITK_INFO << "Restoring " << numberOfSavedDevices << " US devices."; } QString mitk::USDevicePersistence::USVideoDeviceToString(mitk::USVideoDevice::Pointer d) { QString manufacturer = d->GetDeviceManufacturer().c_str(); QString model = d->GetDeviceModel().c_str(); QString comment = d->GetDeviceComment().c_str(); int source = d->GetDeviceID(); std::string file = d->GetFilePath(); if (file == "") file = "none"; int greyscale = d->GetSource()->GetIsGreyscale(); int resOverride = d->GetSource()->GetResolutionOverride(); int resWidth = d->GetSource()->GetResolutionOverrideWidth(); int resHight = d->GetSource()->GetResolutionOverrideHeight(); +int cropRight = d->GetCropArea().cropRight; +int cropLeft = d->GetCropArea().cropLeft; +int cropBottom = d->GetCropArea().cropBottom; +int cropTop = d->GetCropArea().cropTop; char seperator = '|'; QString returnValue = manufacturer + seperator + model + seperator + comment + seperator + QString::number(source) + seperator + file.c_str() + seperator + QString::number(greyscale) + seperator + QString::number(resOverride) + seperator + QString::number(resWidth) + seperator - + QString::number(resHight); - -//DEBUG: MITK_INFO << "Output String: " << returnValue.toStdString(); + + QString::number(resHight) + seperator + + QString::number(cropRight) + seperator + + QString::number(cropLeft) + seperator + + QString::number(cropBottom) + seperator + + QString::number(cropTop) + ; + +MITK_INFO << "Output String: " << returnValue.toStdString(); return returnValue; } mitk::USVideoDevice::Pointer mitk::USDevicePersistence::StringToUSVideoDevice(QString s) { -//DEBUG: MITK_INFO << "Input String: " << s.toStdString(); +MITK_INFO << "Input String: " << s.toStdString(); std::vector data; std::string seperators = "|"; split(s.toStdString(),seperators,data); -if(data.size() != 9) +if(data.size() != 13) { MITK_ERROR << "Cannot parse US device! (Size: " << data.size() << ")"; return mitk::USVideoDevice::New("INVALID","INVALID","INVALID"); } std::string manufacturer = data.at(0); std::string model = data.at(1); std::string comment = data.at(2); int source = (QString(data.at(3).c_str())).toInt(); std::string file = data.at(4); bool greyscale = (QString(data.at(5).c_str())).toInt(); bool resOverride = (QString(data.at(6).c_str())).toInt(); int resWidth = (QString(data.at(7).c_str())).toInt(); int resHight = (QString(data.at(8).c_str())).toInt(); +mitk::USDevice::USImageCropArea cropArea; +cropArea.cropRight = (QString(data.at(9).c_str())).toInt(); +cropArea.cropLeft = (QString(data.at(10).c_str())).toInt(); +cropArea.cropBottom = (QString(data.at(11).c_str())).toInt(); +cropArea.cropTop = (QString(data.at(12).c_str())).toInt(); // Assemble Metadata mitk::USImageMetadata::Pointer metadata = mitk::USImageMetadata::New(); metadata->SetDeviceManufacturer(manufacturer); metadata->SetDeviceComment(comment); metadata->SetDeviceModel(model); metadata->SetProbeName(""); metadata->SetZoom(""); // Create Device mitk::USVideoDevice::Pointer returnValue; if (file == "none") { returnValue = mitk::USVideoDevice::New(source, metadata); } else { returnValue = mitk::USVideoDevice::New(file, metadata); } // Set Video Options returnValue->GetSource()->SetColorOutput(!greyscale); // If Resolution override is activated, apply it if (resOverride) { returnValue->GetSource()->OverrideResolution(resWidth, resHight); returnValue->GetSource()->SetResolutionOverride(true); } +// Set Crop Area +returnValue->SetCropArea(cropArea); + return returnValue; } void mitk::USDevicePersistence::split(std::string& text, std::string& separators, std::vector& words) { int n = text.length(); int start, stop; start = text.find_first_not_of(separators); while ((start >= 0) && (start < n)) { stop = text.find_first_of(separators, start); if ((stop < 0) || (stop > n)) stop = n; words.push_back(text.substr(start, stop - start)); start = text.find_first_not_of(separators, stop+1); } } diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp index debbff51d3..5a696f73a5 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp @@ -1,198 +1,214 @@ /*=================================================================== 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 //Mitk #include #include #include // Qmitk #include "UltrasoundSupport.h" #include // Qt #include // Ultrasound #include "mitkUSDevice.h" const std::string UltrasoundSupport::VIEW_ID = "org.mitk.views.ultrasoundsupport"; void UltrasoundSupport::SetFocus() { m_Controls.m_AddDevice->setFocus(); } void UltrasoundSupport::CreateQtPartControl( QWidget *parent ) { m_Timer = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); connect( m_Controls.m_AddDevice, SIGNAL(clicked()), this, SLOT(OnClickedAddNewDevice()) ); // Change Widget Visibilities connect( m_Controls.m_AddDevice, SIGNAL(clicked()), this->m_Controls.m_NewVideoDeviceWidget, SLOT(CreateNewDevice()) ); // Init NewDeviceWidget connect( m_Controls.m_NewVideoDeviceWidget, SIGNAL(Finished()), this, SLOT(OnNewDeviceWidgetDone()) ); // After NewDeviceWidget finished editing connect( m_Controls.m_BtnView, SIGNAL(clicked()), this, SLOT(OnClickedViewDevice()) ); connect( m_Timer, SIGNAL(timeout()), this, SLOT(DisplayImage())); connect( m_Controls.crop_left, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged()) ); connect( m_Controls.crop_right, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged()) ); connect( m_Controls.crop_top, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged()) ); connect( m_Controls.crop_bot, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged()) ); //connect (m_Controls.m_ActiveVideoDevices, SIGNAL()) // Initializations m_Controls.m_NewVideoDeviceWidget->setVisible(false); std::string filter = "(&(" + mitk::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::US_PROPKEY_ISACTIVE + "=true))"; m_Controls.m_ActiveVideoDevices->Initialize(mitk::USDevice::US_PROPKEY_LABEL ,filter); + //UI initializations + m_Controls.crop_left->setEnabled(false); + m_Controls.crop_right->setEnabled(false); + m_Controls.crop_bot->setEnabled(false); + m_Controls.crop_top->setEnabled(false); + m_Node = mitk::DataNode::New(); m_Node->SetName("US Image Stream"); this->GetDataStorage()->Add(m_Node); } void UltrasoundSupport::OnClickedAddNewDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_AddDevice->setVisible(false); m_Controls.m_Headline->setText("Add New Device:"); } void UltrasoundSupport::DisplayImage() { m_Device->UpdateOutputData(0); m_Node->SetData(m_Device->GetOutput()); this->RequestRenderWindowUpdate(); m_FrameCounter ++; if (m_FrameCounter == 10) { int nMilliseconds = m_Clock.restart(); int fps = 10000.0f / (nMilliseconds ); m_Controls.m_FramerateLabel->setText("Current Framerate: "+ QString::number(fps) +" FPS"); m_FrameCounter = 0; } } void UltrasoundSupport::OnCropAreaChanged() { if (m_Device->GetDeviceClass()=="org.mitk.modules.us.USVideoDevice") { mitk::USVideoDevice::Pointer currentVideoDevice = dynamic_cast(m_Device.GetPointer()); - if ((m_Controls.crop_left->value() == 0) && - (m_Controls.crop_top->value() == 0) && - (m_Controls.crop_right->value() == 0) && - (m_Controls.crop_bot->value() == 0)) - currentVideoDevice->GetSource()->RemoveRegionOfInterest(); - - int left = m_Controls.crop_left->value(); - int top = m_Controls.crop_top->value(); - int right = currentVideoDevice->GetSource()->GetImageWidth() - m_Controls.crop_right->value(); - int bottom = currentVideoDevice->GetSource()->GetImageHeight() - m_Controls.crop_bot->value(); - currentVideoDevice->GetSource()->SetRegionOfInterest(left,top,right,bottom); - MITK_INFO << "Image H:" << currentVideoDevice->GetSource()->GetImageHeight() << " W:" <GetSource()->GetImageWidth(); - MITK_INFO << "Crop L:"<value(); + newArea.cropTop = m_Controls.crop_top->value(); + newArea.cropRight = m_Controls.crop_right->value(); + newArea.cropBottom = m_Controls.crop_bot->value(); + + //check enabled: if not we are in the initializing step and don't need to do anything + //otherwise: update crop area + if (m_Controls.crop_right->isEnabled()) + currentVideoDevice->SetCropArea(newArea); + GlobalReinit(); } else { MITK_WARN << "No USVideoDevice: Cannot Crop!"; } } void UltrasoundSupport::OnClickedViewDevice() { m_FrameCounter = 0; // We use the activity state of the timer to determine whether we are currently viewing images if ( ! m_Timer->isActive() ) // Activate Imaging { //get device & set data node m_Device = m_Controls.m_ActiveVideoDevices->GetSelectedService(); if (m_Device.IsNull()){ m_Timer->stop(); return; } m_Device->Update(); m_Node->SetData(m_Device->GetOutput()); //start timer int interval = (1000 / m_Controls.m_FrameRate->value()); m_Timer->setInterval(interval); m_Timer->start(); //reinit view GlobalReinit(); //change UI elements m_Controls.m_BtnView->setText("Stop Viewing"); m_Controls.m_FrameRate->setEnabled(false); + m_Controls.crop_left->setValue(m_Device->GetCropArea().cropLeft); + m_Controls.crop_right->setValue(m_Device->GetCropArea().cropRight); + m_Controls.crop_bot->setValue(m_Device->GetCropArea().cropBottom); + m_Controls.crop_top->setValue(m_Device->GetCropArea().cropTop); + m_Controls.crop_left->setEnabled(true); + m_Controls.crop_right->setEnabled(true); + m_Controls.crop_bot->setEnabled(true); + m_Controls.crop_top->setEnabled(true); } else //deactivate imaging { //stop timer & release data m_Timer->stop(); m_Node->ReleaseData(); this->RequestRenderWindowUpdate(); //change UI elements m_Controls.m_BtnView->setText("Start Viewing"); m_Controls.m_FrameRate->setEnabled(true); + m_Controls.crop_left->setEnabled(false); + m_Controls.crop_right->setEnabled(false); + m_Controls.crop_bot->setEnabled(false); + m_Controls.crop_top->setEnabled(false); } } void UltrasoundSupport::OnNewDeviceWidgetDone() { m_Controls.m_NewVideoDeviceWidget->setVisible(false); m_Controls.m_DeviceManagerWidget->setVisible(true); m_Controls.m_AddDevice->setVisible(true); m_Controls.m_Headline->setText("Connected Devices:"); } void UltrasoundSupport::GlobalReinit() { // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); // calculate bounding geometry of these nodes mitk::TimeSlicedGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } UltrasoundSupport::UltrasoundSupport() { m_DevicePersistence = mitk::USDevicePersistence::New(); m_DevicePersistence->RestoreLastDevices(); } UltrasoundSupport::~UltrasoundSupport() { m_DevicePersistence->StoreCurrentDevices(); m_Controls.m_DeviceManagerWidget->DisconnectAllDevices(); } \ No newline at end of file