diff --git a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp index 3e626d91ab..d37db56419 100644 --- a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp +++ b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp @@ -1,176 +1,182 @@ /*=================================================================== 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 "mitkUSDiPhASDeviceCustomControls.h" mitk::USDiPhASDeviceCustomControls::USDiPhASDeviceCustomControls(itk::SmartPointer device) : mitk::USAbstractControlInterface(device.GetPointer()), m_IsActive(false), silentUpdate(false) { } mitk::USDiPhASDeviceCustomControls::~USDiPhASDeviceCustomControls() { } void mitk::USDiPhASDeviceCustomControls::SetIsActive(bool isActive) { m_IsActive = isActive; } bool mitk::USDiPhASDeviceCustomControls::GetIsActive() { return m_IsActive; } void mitk::USDiPhASDeviceCustomControls::passGUIOut(std::function callback) {} void mitk::USDiPhASDeviceCustomControls::SetSilentUpdate(bool silent) { silentUpdate = silent; } bool mitk::USDiPhASDeviceCustomControls::GetSilentUpdate() { return silentUpdate; } //Set Functions void mitk::USDiPhASDeviceCustomControls::SetUseBModeFilter(bool isSet) { this->OnSetUseBModeFilter(isSet); } void mitk::USDiPhASDeviceCustomControls::SetEventDisplay(int event) { this->OnSetEventDisplay(event); } +void mitk::USDiPhASDeviceCustomControls::SetRecord(bool record) +{ + this->OnSetRecord(record); +} + //Transmit void mitk::USDiPhASDeviceCustomControls::SetTransmitPhaseLength(double us) { this->OnSetTransmitPhaseLength(us); } void mitk::USDiPhASDeviceCustomControls::SetExcitationFrequency(double MHz) { this->OnSetExcitationFrequency(MHz); } void mitk::USDiPhASDeviceCustomControls::SetTransmitEvents(int events) { this->OnSetTransmitEvents(events); } void mitk::USDiPhASDeviceCustomControls::SetVoltage(int voltage) { this->OnSetVoltage(voltage); } void mitk::USDiPhASDeviceCustomControls::SetMode(bool interleaved) { this->OnSetMode(interleaved); } //Receive void mitk::USDiPhASDeviceCustomControls::SetScanDepth(double mm) { this->OnSetScanDepth(mm); } void mitk::USDiPhASDeviceCustomControls::SetAveragingCount(int count) { this->OnSetAveragingCount(count); } void mitk::USDiPhASDeviceCustomControls::SetTGCMin(int min) { this->OnSetTGCMin(min); } void mitk::USDiPhASDeviceCustomControls::SetTGCMax(int max) { this->OnSetTGCMax(max); } void mitk::USDiPhASDeviceCustomControls::SetDataType(int type) { this->OnSetDataType(type); } // 0= image; 1= beamformed; //Beamforming void mitk::USDiPhASDeviceCustomControls::SetPitch(double mm) { this->OnSetPitch(mm); } void mitk::USDiPhASDeviceCustomControls::SetReconstructedSamples(int samples) { this->OnSetReconstructedSamples(samples); } void mitk::USDiPhASDeviceCustomControls::SetReconstructedLines(int lines) { this->OnSetReconstructedLines(lines); } void mitk::USDiPhASDeviceCustomControls::SetSpeedOfSound(int mps) { this->OnSetSpeedOfSound(mps); } //Bandpass void mitk::USDiPhASDeviceCustomControls::SetBandpassEnabled(bool bandpass) { this->OnSetBandpassEnabled(bandpass); } void mitk::USDiPhASDeviceCustomControls::SetLowCut(double MHz) { this->OnSetLowCut(MHz); } void mitk::USDiPhASDeviceCustomControls::SetHighCut(double MHz) { this->OnSetHighCut(MHz); } //OnSetDummies void mitk::USDiPhASDeviceCustomControls::OnSetEventDisplay(int event) {} void mitk::USDiPhASDeviceCustomControls::OnSetUseBModeFilter(bool isSet) {} +void mitk::USDiPhASDeviceCustomControls::OnSetRecord(bool record) {} //Transmit void mitk::USDiPhASDeviceCustomControls::OnSetTransmitPhaseLength(double ms) {} void mitk::USDiPhASDeviceCustomControls::OnSetExcitationFrequency(double MHz) {} void mitk::USDiPhASDeviceCustomControls::OnSetTransmitEvents(int events) {} void mitk::USDiPhASDeviceCustomControls::OnSetVoltage(int voltage) {} void mitk::USDiPhASDeviceCustomControls::OnSetMode(bool interleaved) {} //Receive void mitk::USDiPhASDeviceCustomControls::OnSetScanDepth(double mm) {} void mitk::USDiPhASDeviceCustomControls::OnSetAveragingCount(int count) {} void mitk::USDiPhASDeviceCustomControls::OnSetTGCMin(int min) {} void mitk::USDiPhASDeviceCustomControls::OnSetTGCMax(int max) {} void mitk::USDiPhASDeviceCustomControls::OnSetDataType(int type) {} //Beamforming void mitk::USDiPhASDeviceCustomControls::OnSetPitch(double mm) {} void mitk::USDiPhASDeviceCustomControls::OnSetReconstructedSamples(int samples) {} void mitk::USDiPhASDeviceCustomControls::OnSetReconstructedLines(int lines) {} void mitk::USDiPhASDeviceCustomControls::OnSetSpeedOfSound(int mps) {} //Bandpass void mitk::USDiPhASDeviceCustomControls::OnSetBandpassEnabled(bool bandpass) {} void mitk::USDiPhASDeviceCustomControls::OnSetLowCut(double MHz) {} void mitk::USDiPhASDeviceCustomControls::OnSetHighCut(double MHz) {} diff --git a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h index 0d39dc736a..9e96fe435a 100644 --- a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h +++ b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h @@ -1,127 +1,129 @@ /*=================================================================== 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 MITKUSDiPhASDeviceCustomControls_H_HEADER_INCLUDED_ #define MITKUSDiPhASDeviceCustomControls_H_HEADER_INCLUDED_ #include "mitkUSAbstractControlInterface.h" #include "mitkUSImageVideoSource.h" #include "mitkUSDevice.h" #include #include #include namespace mitk { /** * \brief Custom controls for mitk::USDiPhASDevice. */ class MITKUS_EXPORT USDiPhASDeviceCustomControls : public USAbstractControlInterface { public: mitkClassMacro(USDiPhASDeviceCustomControls, USAbstractControlInterface); mitkNewMacro1Param(Self, itk::SmartPointer); /** * Activate or deactivate the custom controls. This is just for handling * widget visibility in a GUI for example. */ virtual void SetIsActive( bool isActive ) override; /** * \return if this custom controls are currently activated */ virtual bool GetIsActive( ) override; virtual void SetEventDisplay(int event); virtual void SetUseBModeFilter(bool isSet); + virtual void SetRecord(bool record); //Transmit virtual void SetTransmitPhaseLength(double us); virtual void SetExcitationFrequency(double MHz); virtual void SetTransmitEvents(int events); virtual void SetVoltage(int voltage); virtual void SetMode(bool interleaved); //Receive virtual void SetScanDepth(double mm); virtual void SetAveragingCount(int count); virtual void SetTGCMin(int min); virtual void SetTGCMax(int max); virtual void SetDataType(int type); // 0= image; 1= beamformed; //Beamforming virtual void SetPitch(double mm); virtual void SetReconstructedSamples(int samples); virtual void SetReconstructedLines(int lines); virtual void SetSpeedOfSound(int mps); //Bandpass virtual void SetBandpassEnabled(bool bandpass); virtual void SetLowCut(double MHz); virtual void SetHighCut(double MHz); virtual void passGUIOut(std::function callback); virtual void SetSilentUpdate(bool silent); virtual bool GetSilentUpdate(); protected: /** * Class needs an mitk::USDevice object for beeing constructed. */ USDiPhASDeviceCustomControls( itk::SmartPointer device ); virtual ~USDiPhASDeviceCustomControls( ); bool m_IsActive; USImageVideoSource::Pointer m_ImageSource; bool silentUpdate; /** virtual handlers implemented in Device Controls */ virtual void OnSetEventDisplay(int event); virtual void OnSetUseBModeFilter(bool isSet); + virtual void OnSetRecord(bool record); //Transmit virtual void OnSetTransmitPhaseLength(double us); virtual void OnSetExcitationFrequency(double MHz); virtual void OnSetTransmitEvents(int events); virtual void OnSetVoltage(int voltage); virtual void OnSetMode(bool interleaved); //Receive virtual void OnSetScanDepth(double mm); virtual void OnSetAveragingCount(int count); virtual void OnSetTGCMin(int min); virtual void OnSetTGCMax(int max); virtual void OnSetDataType(int type); // 0= image; 1= beamformed; //Beamforming virtual void OnSetPitch(double mm); virtual void OnSetReconstructedSamples(int samples); virtual void OnSetReconstructedLines(int lines); virtual void OnSetSpeedOfSound(int mps); //Bandpass virtual void OnSetBandpassEnabled(bool bandpass); virtual void OnSetLowCut(double MHz); virtual void OnSetHighCut(double MHz); }; } // namespace mitk #endif // MITKUSDiPhASDeviceCustomControls_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp index 7db5dd1dac..bad9cde14c 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp @@ -1,210 +1,216 @@ /*=================================================================== 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 "mitkUSDiPhASCustomControls.h" #include mitk::USDiPhASCustomControls::USDiPhASCustomControls(USDiPhASDevice* device) : mitk::USDiPhASDeviceCustomControls(device), m_IsActive(false), m_device(device), currentBeamformingAlgorithm((int)Beamforming::PlaneWaveCompound) { } mitk::USDiPhASCustomControls::~USDiPhASCustomControls() { } void mitk::USDiPhASCustomControls::SetIsActive(bool isActive) { m_IsActive = isActive; } bool mitk::USDiPhASCustomControls::GetIsActive() { return m_IsActive; } void mitk::USDiPhASCustomControls::passGUIOut(std::function callback) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); callback("initializing"); imageSource->SetGUIOutput(callback); } // OnSet methods void mitk::USDiPhASCustomControls::OnSetUseBModeFilter(bool isSet) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->SetUseBModeFilter(isSet); } void mitk::USDiPhASCustomControls::OnSetEventDisplay(int event) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->SetDisplayedEvent(event); } +void mitk::USDiPhASCustomControls::OnSetRecord(bool record) +{ + mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); + imageSource->SetRecordingStatus(record); +} + //Transmit void mitk::USDiPhASCustomControls::OnSetTransmitPhaseLength(double us) { m_device->GetScanMode().transmitPhaseLengthSeconds = us*1000*1000; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetExcitationFrequency(double MHz) { m_device->GetScanMode().BurstHalfwaveClockCountAllChannels = round(((120 / MHz) - 2) / 2); m_device->UpdateScanmode(); // b = (c/f - 2) * 1/2, where c is the internal clock, f the wanted frequency, b the burst count } void mitk::USDiPhASCustomControls::OnSetTransmitEvents(int events) { m_device->GetScanMode().transmitEventsCount = events; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetVoltage(int voltage) { m_device->GetScanMode().voltageV = voltage; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetMode(bool interleaved) { auto& scanMode = m_device->GetScanMode(); if (interleaved) { currentBeamformingAlgorithm = (int)Beamforming::Interleaved_OA_US; parametersPW.SpeedOfSoundMeterPerSecond = scanMode.averageSpeedOfSound; parametersPW.angleSkipFactor = 1; scanMode.beamformingAlgorithmParameters = (void*)¶metersPW; } else { currentBeamformingAlgorithm = (int)Beamforming::PlaneWaveCompound; parametersOSUS.SpeedOfSoundMeterPerSecond = scanMode.averageSpeedOfSound; parametersOSUS.angleSkipFactor = 1; scanMode.beamformingAlgorithmParameters = (void*)¶metersOSUS; } scanMode.beamformingAlgorithm = currentBeamformingAlgorithm; m_device->UpdateScanmode(); } //Receive void mitk::USDiPhASCustomControls::OnSetScanDepth(double mm) { auto& scanMode = m_device->GetScanMode(); float time = 2 * (0.001 * mm) / scanMode.averageSpeedOfSound; m_device->GetScanMode().receivePhaseLengthSeconds = time; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetAveragingCount(int count) { m_device->GetScanMode().averagingCount = count; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetTGCMin(int min) { auto& scanMode = m_device->GetScanMode(); char range = scanMode.tgcdB[7] - min; for (int tgc = 0; tgc < 7; ++tgc) scanMode.tgcdB[tgc] = round(tgc*range / 7 + min); m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetTGCMax(int max) { auto& scanMode = m_device->GetScanMode(); char range = max - scanMode.tgcdB[0]; for (int tgc = 1; tgc < 8; ++tgc) scanMode.tgcdB[tgc] = round(tgc*range / 7 + scanMode.tgcdB[0]); m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetDataType(int type) { auto& scanMode = m_device->GetScanMode(); auto imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); switch (type) { case 0: { scanMode.transferBeamformedData = false; scanMode.transferImageData = true; m_device->UpdateScanmode(); imageSource->SetDataType(0); break; } case 1: { scanMode.transferBeamformedData = true; scanMode.transferImageData = false; m_device->UpdateScanmode(); imageSource->SetDataType(1); break; } default: MITK_INFO << "Unknown Data Type requested"; break; } } // 0= image; 1= beamformed //Beamforming void mitk::USDiPhASCustomControls::OnSetPitch(double mm) { m_device->GetScanMode().reconstructedLinePitchMmOrAngleDegree = mm; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetReconstructedSamples(int samples) { m_device->GetScanMode().reconstructionSamplesPerLine = samples; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetReconstructedLines(int lines) { m_device->GetScanMode().reconstructionLines = lines; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetSpeedOfSound(int mps) { m_device->GetScanMode().averageSpeedOfSound = mps; m_device->UpdateScanmode(); } //Bandpass void mitk::USDiPhASCustomControls::OnSetBandpassEnabled(bool bandpass) { m_device->GetScanMode().bandpassApply = bandpass; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetLowCut(double MHz) { m_device->GetScanMode().bandpassFrequencyLowHz = MHz*1000*1000; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetHighCut(double MHz) { m_device->GetScanMode().bandpassFrequencyHighHz = MHz*1000*1000; m_device->UpdateScanmode(); } \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h index e57040b17b..28791ad493 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h @@ -1,99 +1,100 @@ /*=================================================================== 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 MITKUSDiPhASCustomControls_H_HEADER_INCLUDED_ #define MITKUSDiPhASCustomControls_H_HEADER_INCLUDED_ #include "mitkUSDevice.h" #include "mitkUSDiPhASDeviceCustomControls.h" #include "mitkUSDiPhASDevice.h" #include namespace mitk { /** * \brief Custom controls for mitk::USDiPhASDevice. */ class USDiPhASDevice; class USDiPhASCustomControls : public USDiPhASDeviceCustomControls { public: mitkClassMacro(USDiPhASCustomControls, USAbstractControlInterface); mitkNewMacro1Param(Self, mitk::USDiPhASDevice*); /** * Activate or deactivate the custom controls. This is just for handling * widget visibility in a GUI for example. */ virtual void SetIsActive( bool isActive ) override; /** * \return if this custom controls are currently activated */ virtual bool GetIsActive( ) override; virtual void passGUIOut(std::function callback) override; BeamformingParametersPlaneWaveCompound parametersPW; BeamformingParametersInterleaved_OA_US parametersOSUS; protected: /** * Class needs an mitk::USDiPhASDevice object for beeing constructed. * This object's ScanMode will be manipulated by the custom controls methods. */ USDiPhASCustomControls(USDiPhASDevice* device); virtual ~USDiPhASCustomControls( ); bool m_IsActive; USImageVideoSource::Pointer m_ImageSource; USDiPhASDevice* m_device; int currentBeamformingAlgorithm; /** handlers for value changes */ virtual void OnSetEventDisplay(int event) override; virtual void OnSetUseBModeFilter(bool isSet) override; + virtual void OnSetRecord(bool record) override; //Transmit virtual void OnSetTransmitPhaseLength(double us) override; virtual void OnSetExcitationFrequency(double MHz) override; virtual void OnSetTransmitEvents(int events) override; virtual void OnSetVoltage(int voltage) override; virtual void OnSetMode(bool interleaved) override; //Receive virtual void OnSetScanDepth(double mm) override; virtual void OnSetAveragingCount(int count) override; virtual void OnSetTGCMin(int min) override; virtual void OnSetTGCMax(int max) override; virtual void OnSetDataType(int type) override; // 0= image; 1= beamformed; //Beamforming virtual void OnSetPitch(double mm) override; virtual void OnSetReconstructedSamples(int samples) override; virtual void OnSetReconstructedLines(int lines) override; virtual void OnSetSpeedOfSound(int mps) override; //Bandpass virtual void OnSetBandpassEnabled(bool bandpass) override; virtual void OnSetLowCut(double MHz) override; virtual void OnSetHighCut(double MHz) override; }; } // namespace mitk #endif // MITKUSDiPhASCustomControls_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.h index ec8fda44d4..a885d4b3fc 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.h +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASDevice.h @@ -1,162 +1,162 @@ /*=================================================================== 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 MITKUSDiPhASDevice_H_HEADER_INCLUDED_ #define MITKUSDiPhASDevice_H_HEADER_INCLUDED_ #include #include "mitkUSDevice.h" #include "mitkUSDiPhASImageSource.h" #include "mitkUSDiPhASProbesControls.h" #include "mitkUSDiPhASCustomControls.h" #include "Framework.IBMT.US.CWrapper.h" #include #include #include #include #include #include namespace mitk { /** * \brief Implementation of mitk::USDevice for DiPhAS API devices. * Connects to a DiPhAS API device through its COM library interface. * * This class handles all API communications and creates interfaces for * b mode, doppler and probes controls. * Images given by the device are put into an object of * mitk::USDiPhASImageSource. */ class USDiPhASDevice : public USDevice { public: mitkClassMacro(USDiPhASDevice, mitk::USDevice); mitkNewMacro2Param(Self, std::string, std::string); /** * \brief Returns the class of the device. */ virtual std::string GetDeviceClass(); virtual USControlInterfaceProbes::Pointer GetControlInterfaceProbes(); virtual itk::SmartPointer GetControlInterfaceCustom(); /** * \brief Is called during the initialization process. * There is nothing done on the initialization of a mik::USDiPhASDevive object. * * \return always true */ virtual bool OnInitialization(); /** * \brief Is called during the connection process. * Connect to the DiPhAS API. * * \return true if successfull, false if no device is connected to the pc * \throws mitk::Exception if something goes wrong at the API calls */ virtual bool OnConnection(); /** * \brief Is called during the disconnection process. * Deactivate and remove all DiPhAS API controls. A disconnect from the * DiPhAS API is not possible for which reason the hardware stays in connected * state even after calling this method. * * \return always true * \throws mitk::Exception if something goes wrong at the API calls */ virtual bool OnDisconnection(); /** * \brief Is called during the activation process. * After this method is finished, the device is generating images in b mode. * Changing scanning mode is possible afterwards by using the appropriate * control interfaces. * * \return always true * \throws mitk::Exception if something goes wrong at the API calls */ virtual bool OnActivation(); /** * \brief Is called during the deactivation process. * After a call to this method the device is connected, but not producing images anymore. * * \return always true * \throws mitk::Exception if something goes wrong at the API calls */ virtual bool OnDeactivation(); /** * \brief Changes scan state of the device if freeze is toggeled in mitk::USDevice. */ virtual void OnFreeze(bool freeze); /** @return Returns the current image source of this device. */ USImageSource::Pointer GetUSImageSource( ); /** @return Returns the currently used scanmode of this device*/ ScanModeNative& GetScanMode(); - /** Updates the Scanmode + /** Updates the Scanmode and feeds it to the hardware */ void UpdateScanmode(); - + /** This method forwards messages from the API to the user*/ void MessageCallback(const char* message); protected: /** * Constructs a mitk::USDiPhASDevice object by given manufacturer * and model string. These strings are just for labeling the device * in the micro service. * * Control interfaces and image source are available directly after * construction. Registration at the micro service happens not before * initialization method was called. */ USDiPhASDevice(std::string manufacturer, std::string model); virtual ~USDiPhASDevice(); /** * The DiPhAS API expects callback functions to pass * both status messages and the processed images to the user. * The message callback is here, the data itself is given directly to the image source. */ /** * This method sets up the scanmode at the begining */ void InitializeScanMode(); USDiPhASProbesControls::Pointer m_ControlsProbes; itk::SmartPointer m_ControlInterfaceCustom; USDiPhASImageSource::Pointer m_ImageSource; bool m_IsRunning; ScanModeNative m_ScanMode; }; } // namespace mitk #endif // MITKUSDiPhASDevice_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp index bb7d9d4c0c..a41ff11628 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp @@ -1,286 +1,337 @@ /*=================================================================== 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 "mitkUSDiPhASImageSource.h" #include "mitkUSDiPhASDevice.h" - +#include mitk::USDiPhASImageSource::USDiPhASImageSource(mitk::USDiPhASDevice* device) : m_Image(mitk::Image::New()), m_ImageMutex(itk::FastMutexLock::New()), m_device(device), startTime(((float)std::clock()) / CLOCKS_PER_SEC), useGUIOutPut(false), DataType(0), displayedEvent(0), m_GUIOutput(nullptr), - useBModeFilter(false) + useBModeFilter(false), + currentlyRecording(false) { } mitk::USDiPhASImageSource::~USDiPhASImageSource( ) { } #include "mitkUSDiPhASBModeImageFilter.h" #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCropImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include "itkIntensityWindowingImageFilter.h" #include "mitkImageCast.h" #include "mitkITKImageImport.h" void mitk::USDiPhASImageSource::GetNextRawImage( mitk::Image::Pointer& image) { m_ImageMutex->Lock(); if (m_Image->IsInitialized()) { //initialize the image the first time if (image.IsNull()) { image = mitk::Image::New(); image->Initialize(m_Image->GetPixelType(), m_Image->GetDimension(), m_Image->GetDimensions()); } // write the data of m_Image to image if it changed if (image->GetPixelType() != m_Image->GetPixelType() || image->GetDimensions() != m_Image->GetDimensions()) { image = mitk::Image::New(); image->Initialize(m_Image->GetPixelType(), m_Image->GetDimension(), m_Image->GetDimensions()); } - if (!useBModeFilter) + // if DataType == 0 : just bypass the filter here, if imageData is given, as imageData is already enveloped.. + if (!useBModeFilter || DataType == 0) { // copy contents of the given image into the member variable, slice after slice for (int sliceNumber = 0; sliceNumber < m_Image->GetDimension(2); ++sliceNumber) { if (m_Image->IsSliceSet(sliceNumber)) { mitk::ImageReadAccessor inputReadAccessor(m_Image, m_Image->GetSliceData(sliceNumber, 0, 0)); image->SetSlice(inputReadAccessor.GetData(), sliceNumber); } } } else { // feed the m_image to the BMode filter and grab it back; - // input type has to be a floating point number, thus we have a little bit more performance loss, - // as the image needs to be casted and copied into a float image, in addition to being fitted with the envelope filter - if (DataType == 0) - { - typedef itk::Image< float, 3 > itkInputImageType; - typedef itk::Image< unsigned char, 3 > itkOutputImageType; - typedef itk::PhotoacousticBModeImageFilter < itkInputImageType, itkOutputImageType > PhotoacousticBModeImageFilter; - - PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); - itkInputImageType::Pointer itkImage; - - mitk::CastToItkImage(m_Image, itkImage); - photoacousticBModeFilter->SetInput(itkImage); - photoacousticBModeFilter->SetDirection(0); - image = mitk::GrabItkImageMemory(photoacousticBModeFilter->GetOutput()); - } // DataType == 0 : imageData -> uchar output type - else if (DataType == 1) - { - typedef itk::Image< float, 3 > itkInputImageType; - typedef itk::Image< short, 3 > itkOutputImageType; - typedef itk::PhotoacousticBModeImageFilter < itkInputImageType, itkOutputImageType > PhotoacousticBModeImageFilter; - - PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); - itkInputImageType::Pointer itkImage; - - mitk::CastToItkImage(m_Image, itkImage); - photoacousticBModeFilter->SetInput(itkImage); - photoacousticBModeFilter->SetDirection(0); - image = mitk::GrabItkImageMemory(photoacousticBModeFilter->GetOutput()); - } // DataType == 1 : beamformed -> short output type + if (DataType==1) + image = ApplyBmodeFilter(m_Image); } // always copy the geometry from the m_Image image->SetGeometry(m_Image->GetGeometry()); } m_ImageMutex->Unlock(); if (!useGUIOutPut && m_GUIOutput) { // Need to do this because the program initializes the GUI twice // this is probably a bug in UltrasoundSupport, if it's fixed the timing becomes unneccesary float timePassed = ((float)std::clock()) / CLOCKS_PER_SEC - startTime; if (timePassed > 10) { useGUIOutPut = true; } } if (useGUIOutPut) { // pass some beamformer state infos to the GUI getSystemInfo(&BeamformerInfos); std::ostringstream s; s << "state info: PRF:" << BeamformerInfos.systemPRF << "Hz, datarate: " << BeamformerInfos.dataTransferRateMBit << "MBit/s"; m_GUIOutput(QString::fromStdString(s.str())); } } +mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyBmodeFilter2d(mitk::Image::Pointer inputImage) +{ + // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage + typedef itk::Image< float, 2 > itkInputImageType; + typedef itk::Image< short, 2 > itkOutputImageType; + typedef itk::PhotoacousticBModeImageFilter < itkInputImageType, itkOutputImageType > PhotoacousticBModeImageFilter; + + PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); + itkInputImageType::Pointer itkImage; + + mitk::CastToItkImage(inputImage, itkImage); + photoacousticBModeFilter->SetInput(itkImage); + photoacousticBModeFilter->SetDirection(0); + return mitk::GrabItkImageMemory(photoacousticBModeFilter->GetOutput()); +} + +mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyBmodeFilter(mitk::Image::Pointer inputImage) +{ + // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage + typedef itk::Image< float, 3 > itkInputImageType; + typedef itk::Image< short, 3 > itkOutputImageType; + typedef itk::PhotoacousticBModeImageFilter < itkInputImageType, itkOutputImageType > PhotoacousticBModeImageFilter; + + PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); + itkInputImageType::Pointer itkImage; + + mitk::CastToItkImage(inputImage, itkImage); + photoacousticBModeFilter->SetInput(itkImage); + photoacousticBModeFilter->SetDirection(0); + return mitk::GrabItkImageMemory(photoacousticBModeFilter->GetOutput()); +} + void mitk::USDiPhASImageSource::ImageDataCallback( short* rfDataChannelData, int& channelDataChannelsPerDataset, int& channelDataSamplesPerChannel, int& channelDataTotalDatasets, short* rfDataArrayBeamformed, int& beamformedLines, int& beamformedSamples, int& beamformedTotalDatasets, unsigned char* imageData, int& imageWidth, int& imageHeight, int& imageBytesPerPixel, int& imageSetsTotal, double& timeStamp) { - bool writeImage = ((DataType == 0) && (imageData != nullptr)) || ((DataType == 1) && (rfDataArrayBeamformed != nullptr)); - if (!m_Image.IsNull() && writeImage) + bool writeImage = ((DataType == 0) && (imageData != nullptr)) || ((DataType == 1) && (rfDataArrayBeamformed != nullptr)) && !m_Image.IsNull(); + if (writeImage) { + if ( m_ImageMutex.IsNotNull() ) { m_ImageMutex->Lock(); } // initialize mitk::Image with given image size on the first time if ( ! m_Image->IsInitialized() ) { UpdateImageDataType(imageHeight, imageWidth); // update data type and image pixel dimensions } // lock the image for writing an copy the given buffer into the image then switch (DataType) { case 0: { for (int i = 0; i < imageSetsTotal; i++) { m_Image->SetSlice(&imageData[i*imageHeight*imageWidth], i); } break; } case 1: { short* flipme = new short[beamformedLines*beamformedSamples*beamformedTotalDatasets]; int pixelsPerImage = beamformedLines*beamformedSamples; for (char currentSet = 0; currentSet < beamformedTotalDatasets; currentSet++) { for (unsigned int sample = 0; sample < beamformedSamples; sample++) { for (short line = 0; line < beamformedLines; line++) { flipme[sample*beamformedLines + line + pixelsPerImage*currentSet] = rfDataArrayBeamformed[line*beamformedSamples + sample + pixelsPerImage*currentSet]; } } // the beamformed image is flipped by 90 degrees; we need to flip it manually } for (int i = 0; i < beamformedTotalDatasets; i++) { m_Image->SetSlice(&flipme[i*beamformedLines*beamformedSamples], i); // set every image to a different slice } delete flipme; break; } } - if ( m_ImageMutex.IsNotNull() ) { m_ImageMutex->Unlock(); } + if (m_ImageMutex.IsNotNull()) { m_ImageMutex->Unlock(); } + } + // if the user decides to start recording, we feed the vector the generated images + if (currentlyRecording) { + Image::Pointer savedImage = Image::New(); + bool sliceSet = true; + int index = 0; + for (int index = 0; index < m_Image->GetDimension(2); ++index) + { + if (m_Image->IsSliceSet(index)) + { + savedImage->Initialize(m_Image->GetPixelType(), 2, m_Image->GetDimensions()); + savedImage->SetGeometry(m_Image->GetGeometry()); + + mitk::ImageReadAccessor inputReadAccessor(m_Image, m_Image->GetSliceData(index)); + savedImage->SetSlice(inputReadAccessor.GetData()); + + m_recordedImages.push_back(savedImage); + } + } } } void mitk::USDiPhASImageSource::UpdateImageDataType(int imageHeight, int imageWidth) { unsigned int dim[] = { imageWidth, imageHeight, displayedEvent+1 }; // image dimensions; every image needs a seperate slice! m_ImageMutex->Lock(); m_Image = mitk::Image::New(); switch (DataType) { case 0: { m_Image->Initialize(mitk::MakeScalarPixelType(), 3, dim); break; } case 1: { m_Image->Initialize(mitk::MakeScalarPixelType(), 3, dim); break; } } // 0:imageData 1:beamformed m_ImageMutex->Unlock(); UpdateImageGeometry(); // update the image geometry startTime = ((float)std::clock()) / CLOCKS_PER_SEC; //wait till the callback is available again useGUIOutPut = false; } void mitk::USDiPhASImageSource::UpdateImageGeometry() { mitk::Vector3D spacing; float& recordTime = m_device->GetScanMode().receivePhaseLengthSeconds; int& speedOfSound = m_device->GetScanMode().averageSpeedOfSound; int& imageWidth = m_device->GetScanMode().imageWidth; int& imageHeight = m_device->GetScanMode().imageHeight; float& pitch = m_device->GetScanMode().reconstructedLinePitchMmOrAngleDegree; int& reconstructionLines = m_device->GetScanMode().reconstructionLines; spacing[0] = (pitch*reconstructionLines)/imageWidth; spacing[1] = ((recordTime*speedOfSound/2)*1000)/imageHeight; spacing[2] = 1; //recalculate correct spacing m_ImageMutex->Lock(); if (m_Image.IsNotNull() && (m_Image->GetGeometry() != NULL)) { m_Image->GetGeometry()->SetSpacing(spacing); m_Image->GetGeometry()->Modified(); } else { MITK_WARN << "image or geometry was NULL, can't adapt geometry"; } m_ImageMutex->Unlock(); MITK_INFO << "UpdateImageGeometry called!"; MITK_INFO << "depth in mm: " << (recordTime*speedOfSound / 2); MITK_INFO << "new spacing: " << spacing; } void mitk::USDiPhASImageSource::SetDataType(int DataT) { if (DataT != DataType) { DataType = DataT; UpdateImageDataType(m_device->GetScanMode().imageHeight, m_device->GetScanMode().imageWidth); } } void mitk::USDiPhASImageSource::SetDisplayedEvent(int event) { displayedEvent = event; auto& ScanMode = m_device->GetScanMode(); UpdateImageDataType(ScanMode.imageHeight, ScanMode.imageWidth); } void mitk::USDiPhASImageSource::SetGUIOutput(std::function out) { USDiPhASImageSource::m_GUIOutput = out; } void mitk::USDiPhASImageSource::SetUseBModeFilter(bool isSet) { useBModeFilter = isSet; +} + +void mitk::USDiPhASImageSource::SetRecordingStatus(bool record) +{ + // start the recording process + if (record) + { + currentlyRecording = true; + m_recordedImages.clear(); // we make sure there are no leftovers + } + // save images, end recording, and clean up + else + { + currentlyRecording = false; + for (int index = 0; index < m_recordedImages.size(); ++index) + { + // add the Bmode filter here + if (DataType == 1 && useBModeFilter) + m_recordedImages.at(index) = ApplyBmodeFilter2d(m_recordedImages.at(index)); + + std::string path = "d:\\temporaryyy\\" + std::to_string(index) + ".nrrd"; + mitk::IOUtil::Save(m_recordedImages.at(index), path); + } + m_recordedImages.clear(); // clean up the images + } } \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h index 7e46d0aa13..096724d412 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h @@ -1,115 +1,128 @@ /*=================================================================== 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 MITKUSDiPhASImageSource_H_HEADER_INCLUDED_ #define MITKUSDiPhASImageSource_H_HEADER_INCLUDED_ #include "mitkUSImageSource.h" #include "Framework.IBMT.US.CWrapper.h" #include "mitkImageReadAccessor.h" #include "itkFastMutexLock.h" #include #include #include #include namespace mitk { class USDiPhASDevice; /** * \brief Implementation of mitk::USImageSource for DiPhAS API devices. * The method mitk::USImageSource::GetNextRawImage() is implemented for * getting images from the DiPhAS API. * * The image data is given to this class from the DiPhAS API by calling * a callback method that writes the image data to an mitk::image */ class USDiPhASImageSource : public USImageSource { public: mitkClassMacro(USDiPhASImageSource, USImageSource); mitkNewMacro1Param(Self, mitk::USDiPhASDevice*); itkCloneMacro(Self); /** * Implementation of the superclass method. Returns the pointer * to the mitk::Image filled by DiPhAS API callback. */ virtual void GetNextRawImage( mitk::Image::Pointer& ); /** * The API calls this function to pass the image data to the * user; here the m_Image is updated */ void mitk::USDiPhASImageSource::ImageDataCallback( short* rfDataChannelData, int& channelDataChannelsPerDataset, int& channelDataSamplesPerChannel, int& channelDataTotalDatasets, short* rfDataArrayBeamformed, int& beamformedLines, int& beamformedSamples, int& beamformedTotalDatasets, unsigned char* imageData, int& imageWidth, int& imageHeight, int& imagePixelFormat, int& imageSetsTotal, double& timeStamp); /** * Sets the spacing used in the image based on the informations of the ScanMode in USDiPhAS Device */ void UpdateImageGeometry(); void SetGUIOutput(std::function out); - void SetDataType(int DataT); void SetDisplayedEvent(int event); void SetUseBModeFilter(bool isSet); + /** REinitializes the image according to the DataType set. */ void UpdateImageDataType(int imageHeight, int imageWidth); - + + /** This starts or ends the recording session*/ + void SetRecordingStatus(bool record); protected: USDiPhASImageSource(mitk::USDiPhASDevice* device); virtual ~USDiPhASImageSource( ); + /** This vector holds all the images we record, if recording is set to active. */ + std::vector m_recordedImages; + + mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage); + mitk::Image::Pointer ApplyBmodeFilter2d(mitk::Image::Pointer inputImage); + + /** This image holds the image to be displayed right now*/ + mitk::Image::Pointer m_Image; + + itk::FastMutexLock::Pointer m_ImageMutex; + mitk::USDiPhASDevice* m_device; + + /** This is a callback to pass text data to the GUI. */ + std::function m_GUIOutput; - mitk::Image::Pointer m_Image; - itk::FastMutexLock::Pointer m_ImageMutex; - mitk::USDiPhASDevice* m_device; - std::function m_GUIOutput; /** - * variables for management of current state + * Variables for management of current state. */ float startTime; bool useGUIOutPut; int displayedEvent; BeamformerStateInfoNative BeamformerInfos; int DataType; // 0: Use image data; 1: Use beamformed data bool useBModeFilter; + bool currentlyRecording; }; } // namespace mitk #endif // MITKUSDiPhASImageSource_H diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp index 76abf4d354..f5401c404a 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp @@ -1,300 +1,315 @@ /*=================================================================== 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 "QmitkUSControlsCustomDiPhASDeviceWidget.h" #include "ui_QmitkUSControlsCustomDiPhASDeviceWidget.h" #include #include QmitkUSControlsCustomDiPhASDeviceWidget::QmitkUSControlsCustomDiPhASDeviceWidget(QWidget *parent) : QmitkUSAbstractCustomWidget(parent), ui(new Ui::QmitkUSControlsCustomDiPhASDeviceWidget) { } QmitkUSControlsCustomDiPhASDeviceWidget::~QmitkUSControlsCustomDiPhASDeviceWidget() { delete ui; } std::string QmitkUSControlsCustomDiPhASDeviceWidget::GetDeviceClass() const { return "org.mitk.modules.us.USDiPhASDevice"; } QmitkUSAbstractCustomWidget* QmitkUSControlsCustomDiPhASDeviceWidget::Clone(QWidget* parent) const { QmitkUSAbstractCustomWidget* clonedWidget = new QmitkUSControlsCustomDiPhASDeviceWidget(parent); clonedWidget->SetDevice(this->GetDevice()); return clonedWidget; } void QmitkUSControlsCustomDiPhASDeviceWidget::OnDeviceSet() { m_ControlInterface = dynamic_cast (this->GetDevice()->GetControlInterfaceCustom().GetPointer()); if ( m_ControlInterface.IsNotNull() ) { m_ControlInterface->passGUIOut([this](QString str)->void{ if (this && this->ui) { this->ui->CurrentState->setText(str); } }); } else { MITK_WARN("QmitkUSAbstractCustomWidget")("QmitkUSControlsCustomDiPhASDeviceWidget") << "Did not get a custom device control interface."; } //now pass the default values m_ControlInterface->SetSilentUpdate(true); // don't update the scanmode everytime OnTransmitPhaseLengthChanged(); OnExcitationFrequencyChanged(); OnTransmitEventsChanged(); OnVoltageChanged(); OnScanDepthChanged(); OnAveragingCountChanged(); OnTGCMinChanged(); OnTGCMaxChanged(); OnDataTypeChanged(); OnPitchChanged(); OnReconstructedSamplesChanged(); OnReconstructedLinesChanged(); OnSpeedOfSoundChanged(); OnBandpassEnabledChanged(); OnLowCutChanged(); OnHighCutChanged(); OnEventDisplayChanged(); OnUseBModeFilterChanged(); m_ControlInterface->SetSilentUpdate(false); // on the last update pass the scanmode and geometry! OnModeChanged(); } void QmitkUSControlsCustomDiPhASDeviceWidget::Initialize() { ui->setupUi(this); connect(ui->UseBModeFilter, SIGNAL(stateChanged(int)), this, SLOT(OnUseBModeFilterChanged())); connect(ui->EventDisplay, SIGNAL(valueChanged(int)), this, SLOT(OnEventDisplayChanged())); + connect(ui->StartStopRecord, SIGNAL(clicked()), this, SLOT(OnRecordChanged())); //transmit connect(ui->TransmitPhaseLength, SIGNAL(valueChanged(double)), this, SLOT(OnTransmitPhaseLengthChanged())); connect(ui->ExcitationFrequency, SIGNAL(valueChanged(double)), this, SLOT(OnExcitationFrequencyChanged())); connect(ui->TransmitEvents, SIGNAL(valueChanged(int)), this, SLOT(OnTransmitEventsChanged())); connect(ui->Voltage, SIGNAL(valueChanged(int)), this, SLOT(OnVoltageChanged())); connect(ui->Mode, SIGNAL(currentTextChanged(QString)), this, SLOT(OnModeChanged())); //Receive connect(ui->ScanDepth, SIGNAL(valueChanged(double)), this, SLOT(OnScanDepthChanged())); connect(ui->AveragingCount, SIGNAL(valueChanged(int)), this, SLOT(OnAveragingCountChanged())); connect(ui->TimeGainCompensationMin, SIGNAL(valueChanged(int)), this, SLOT(OnTGCMinChanged())); connect(ui->TimeGainCompensationMax, SIGNAL(valueChanged(int)), this, SLOT(OnTGCMaxChanged())); connect(ui->DataType, SIGNAL(currentTextChanged(QString)), this, SLOT(OnDataTypeChanged())); //Beamforming connect(ui->PitchOfTransducer, SIGNAL(valueChanged(double)), this, SLOT(OnPitchChanged())); connect(ui->ReconstructedSamplesPerLine, SIGNAL(valueChanged(int)), this, SLOT(OnReconstructedSamplesChanged())); connect(ui->ReconstructedLines, SIGNAL(valueChanged(int)), this, SLOT(OnReconstructedLinesChanged())); connect(ui->SpeedOfSound, SIGNAL(valueChanged(int)), this, SLOT(OnSpeedOfSoundChanged())); //Bandpass connect(ui->BandpassEnabled, SIGNAL(currentTextChanged(QString)), this, SLOT(OnBandpassEnabledChanged())); connect(ui->LowCut, SIGNAL(valueChanged(double)), this, SLOT(OnLowCutChanged())); connect(ui->HighCut, SIGNAL(valueChanged(double)), this, SLOT(OnHighCutChanged())); } //slots void QmitkUSControlsCustomDiPhASDeviceWidget::OnUseBModeFilterChanged() { if (m_ControlInterface.IsNull()) { return; } bool UseBModeFilter = ui->UseBModeFilter->isChecked(); m_ControlInterface->SetUseBModeFilter(UseBModeFilter); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnEventDisplayChanged() { if (m_ControlInterface.IsNull()) { return; } int max = ui->TransmitEvents->value(); int current = ui->EventDisplay->value(); if (current > max-1) { ui->EventDisplay->setValue(max - 1); MITK_INFO << "User tried to set displayed event higher than amount of created events."; } m_ControlInterface->SetEventDisplay(ui->EventDisplay->value()); } +void QmitkUSControlsCustomDiPhASDeviceWidget::OnRecordChanged() +{ + if (ui->StartStopRecord->text() == "Start Recording") + { + ui->StartStopRecord->setText("Stop Recording"); + m_ControlInterface->SetRecord(true); + } + else + { + ui->StartStopRecord->setText("Start Recording"); + m_ControlInterface->SetRecord(false); + } +} + //Transmit void QmitkUSControlsCustomDiPhASDeviceWidget::OnTransmitPhaseLengthChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetTransmitPhaseLength(ui->TransmitPhaseLength->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnExcitationFrequencyChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetExcitationFrequency(ui->ExcitationFrequency->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnTransmitEventsChanged() { if (m_ControlInterface.IsNull()) { return; } OnEventDisplayChanged(); //correct the displayed event m_ControlInterface->SetTransmitEvents(ui->TransmitEvents->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnVoltageChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetVoltage(ui->Voltage->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnModeChanged() { if (m_ControlInterface.IsNull()) { return; } QString Mode = ui->Mode->currentText(); bool silent = m_ControlInterface->GetSilentUpdate(); m_ControlInterface->SetSilentUpdate(true); if (Mode == "Ultrasound only") { m_ControlInterface->SetMode(false); ui->TransmitEvents->setValue(1); } else if (Mode == "Interleaved") { m_ControlInterface->SetMode(true); ui->TransmitEvents->setValue(2); } if (!silent) { m_ControlInterface->SetSilentUpdate(false); } OnTransmitEventsChanged(); } //Receive void QmitkUSControlsCustomDiPhASDeviceWidget::OnScanDepthChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetScanDepth(ui->ScanDepth->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnAveragingCountChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetAveragingCount(ui->AveragingCount->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnTGCMinChanged() { if (m_ControlInterface.IsNull()) { return; } int tgcMin = ui->TimeGainCompensationMin->value(); int tgcMax = ui->TimeGainCompensationMax->value(); if (tgcMin > tgcMax) { ui->TimeGainCompensationMin->setValue(tgcMax); MITK_INFO << "User tried to set tgcMin>tgcMax."; } m_ControlInterface->SetTGCMin(ui->TimeGainCompensationMin->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnTGCMaxChanged() { if (m_ControlInterface.IsNull()) { return; } int tgcMin = ui->TimeGainCompensationMin->value(); int tgcMax = ui->TimeGainCompensationMax->value(); if (tgcMin > tgcMax) { ui->TimeGainCompensationMax->setValue(tgcMin); MITK_INFO << "User tried to set tgcMin>tgcMax."; } m_ControlInterface->SetTGCMax(ui->TimeGainCompensationMax->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnDataTypeChanged() { if (m_ControlInterface.IsNull()) { return; } QString DataType = ui->DataType->currentText(); if (DataType == "Image Data") { m_ControlInterface->SetDataType(0); } else if (DataType == "Beamformed Data") { m_ControlInterface->SetDataType(1); } } // 0= image; 1= beamformed; //Beamforming void QmitkUSControlsCustomDiPhASDeviceWidget::OnPitchChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetPitch(ui->PitchOfTransducer->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnReconstructedSamplesChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetReconstructedSamples(ui->ReconstructedSamplesPerLine->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnReconstructedLinesChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetReconstructedLines(ui->ReconstructedLines->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnSpeedOfSoundChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetSpeedOfSound(ui->SpeedOfSound->value()); } //Bandpass void QmitkUSControlsCustomDiPhASDeviceWidget::OnBandpassEnabledChanged() { if (m_ControlInterface.IsNull()) { return; } if (ui->BandpassEnabled->currentText() == "On") { m_ControlInterface->SetBandpassEnabled(true); } else { m_ControlInterface->SetBandpassEnabled(false); } } void QmitkUSControlsCustomDiPhASDeviceWidget::OnLowCutChanged() { if (m_ControlInterface.IsNull()) { return; } unsigned int Low = ui->LowCut->value(); unsigned int High = ui->HighCut->value(); if (Low > High) { ui->LowCut->setValue(High); MITK_INFO << "User tried to set LowCut>HighCut."; } m_ControlInterface->SetLowCut(ui->LowCut->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnHighCutChanged() { if (m_ControlInterface.IsNull()) { return; } unsigned int Low = ui->LowCut->value(); unsigned int High = ui->HighCut->value(); if (Low > High) { ui->HighCut->setValue(Low); MITK_INFO << "User tried to set LowCut>HighCut."; } m_ControlInterface->SetHighCut(ui->HighCut->value()); } diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h index 596909d74d..5824a41400 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h @@ -1,110 +1,111 @@ /*=================================================================== 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 QmitkUSControlsCustomDiPhASDeviceWidget_H #define QmitkUSControlsCustomDiPhASDeviceWidget_H #include "QmitkUSAbstractCustomWidget.h" #include "mitkUSDiPhASDeviceCustomControls.h" #include "mitkUSDevice.h" #include namespace Ui { class QmitkUSControlsCustomDiPhASDeviceWidget; } /** \brief Widget for custom controls of mitk::USDiPhASDevice. * This class handles the itk::USDiPhASDeviceCustomControls of video device * objects. */ class QmitkUSControlsCustomDiPhASDeviceWidget : public QmitkUSAbstractCustomWidget { Q_OBJECT private slots: virtual void OnEventDisplayChanged(); virtual void OnUseBModeFilterChanged(); + virtual void OnRecordChanged(); //Transmit virtual void OnTransmitPhaseLengthChanged(); virtual void OnExcitationFrequencyChanged(); virtual void OnTransmitEventsChanged(); virtual void OnVoltageChanged(); virtual void OnModeChanged(); //Receive virtual void OnScanDepthChanged(); virtual void OnAveragingCountChanged(); virtual void OnTGCMinChanged(); virtual void OnTGCMaxChanged(); virtual void OnDataTypeChanged(); // 0= image; 1= beamformed; //Beamforming virtual void OnPitchChanged(); virtual void OnReconstructedSamplesChanged(); virtual void OnReconstructedLinesChanged(); virtual void OnSpeedOfSoundChanged(); //Bandpass virtual void OnBandpassEnabledChanged(); virtual void OnLowCutChanged(); virtual void OnHighCutChanged(); public: /** * Constructs widget object. All gui control elements will be disabled until * QmitkUSAbstractCustomWidget::SetDevice() was called. */ explicit QmitkUSControlsCustomDiPhASDeviceWidget(QWidget *parent = 0); ~QmitkUSControlsCustomDiPhASDeviceWidget(); /** * Getter for the device class of mitk:USDiPhASDevice. */ virtual std::string GetDeviceClass() const override; /** * Creates new QmitkUSAbstractCustomWidget with the same mitk::USDiPhASDevice * and the same mitk::USDiPhASDeviceCustomControls which were set on the * original object. * * This method is just for being calles by the factory. Use * QmitkUSAbstractCustomWidget::CloneForQt() instead, if you want a clone of * an object. */ virtual QmitkUSAbstractCustomWidget* Clone(QWidget* parent = 0) const override; /** * Gets control interface from the device which was currently set. Control * elements are according to current crop area of the device. If custom * control interface is null, the control elements stay disabled. */ virtual void OnDeviceSet() override; virtual void Initialize() override; protected: void BlockSignalAndSetValue(QSpinBox* target, int value); private: Ui::QmitkUSControlsCustomDiPhASDeviceWidget* ui; mitk::USDiPhASDeviceCustomControls::Pointer m_ControlInterface; }; #endif // QmitkUSControlsCustomDiPhASDeviceWidget_H \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui index d20766945c..14b70b080f 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui @@ -1,480 +1,486 @@ QmitkUSControlsCustomDiPhASDeviceWidget 0 0 579 903 Form + + + 0 + 25 + + QFrame::WinPanel QFrame::Raised Started Qt::AlignCenter <html><head/><body><p><span style=" font-weight:600;">General Settings</span></p></body></html> - - - - Qt::Horizontal - - - - 40 - 20 - - - - Use BMode Envelope Filter Qt::Horizontal 40 20 Display Events 0 1 Qt::Horizontal 40 20 + + + + + 100 + 50 + + + + Start Recording + + + <html><head/><body><p><span style=" font-weight:600;">Transmit Parameters</span></p></body></html> 15.000000000000000 0.100000000000000 5.000000000000000 1 2 Transmit Events 1 0.100000000000000 10000.000000000000000 1.000000000000000 Transmit Phase Length [us] Excitation Frequency [MHz] Interleaved Ultrasound only 5 75 70 Voltage [V] Mode <html><head/><body><p><span style=" font-weight:600;">Receive Parameters</span></p></body></html> Scan Depth [mm] 1 10000 1 Averaging Count 42 10 TimeGainCompensationMin 42 24 TimeGainCompensationMax false Image Data Beamformed Data DataType 1000.000000000000000 50.000000000000000 <html><head/><body><p><span style=" font-weight:600;">Beamforming Parameters</span></p></body></html> 256 4096 256 2048 Pitch of Transducer [mm] 128 1024 128 128 Reconstructed Samples per Line 0.100000000000000 0.300000000000000 Speed of Sound [m/s] 1000000 1540 Reconstructed Lines <html><head/><body><p><span style=" font-weight:600;">Bandpass Parameters</span></p></body></html> High Cut [MHz] Low Cut [MHz] Bandpass Enabled 5.000000000000000 Off On 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 fa63ba034e..58ae5d9d07 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp @@ -1,575 +1,607 @@ /*=================================================================== 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 #include #include #include +#include // Qmitk #include "UltrasoundSupport.h" // Qt #include #include #include // Ultrasound #include "mitkUSDevice.h" #include "QmitkUSAbstractCustomWidget.h" #include #include #include "usServiceReference.h" #include "internal/org_mitk_gui_qt_ultrasound_Activator.h" const std::string UltrasoundSupport::VIEW_ID = "org.mitk.views.ultrasoundsupport"; void UltrasoundSupport::SetFocus() { } void UltrasoundSupport::CreateQtPartControl( QWidget *parent ) { //initialize timers m_UpdateTimer = new QTimer(this); m_RenderingTimer2d = new QTimer(this); m_RenderingTimer3d = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); //load persistence data before connecting slots (so no slots are called in this phase...) LoadUISettings(); //connect signals and slots... connect( m_Controls.m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this, SLOT(OnClickedAddNewDevice()) ); // Change Widget Visibilities connect( m_Controls.m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this->m_Controls.m_NewVideoDeviceWidget, SLOT(CreateNewDevice()) ); // Init NewDeviceWidget connect( m_Controls.m_ActiveVideoDevices, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnChangedActiveDevice()) ); connect( m_Controls.m_RunImageTimer, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice()) ); connect( m_Controls.m_ShowImageStream, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice()) ); connect( m_Controls.m_NewVideoDeviceWidget, SIGNAL(Finished()), this, SLOT(OnNewDeviceWidgetDone()) ); // After NewDeviceWidget finished editing connect( m_Controls.m_FrameRatePipeline, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit()) ); connect( m_Controls.m_FrameRate2d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit()) ); connect( m_Controls.m_FrameRate3d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit()) ); connect( m_Controls.m_FreezeButton, SIGNAL(clicked()), this, SLOT(OnClickedFreezeButton()) ); connect( m_UpdateTimer, SIGNAL(timeout()), this, SLOT(UpdateImage())); connect( m_RenderingTimer2d, SIGNAL(timeout()), this, SLOT(RenderImage2d())); connect( m_RenderingTimer3d, SIGNAL(timeout()), this, SLOT(RenderImage3d())); connect( m_Controls.m_Update2DView, SIGNAL(clicked()), this, SLOT(StartTimers()) ); connect( m_Controls.m_Update3DView, SIGNAL(clicked()), this, SLOT(StartTimers()) ); // Initializations m_Controls.m_NewVideoDeviceWidget->setVisible(false); std::string filter = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE + "=true))"; m_Controls.m_ActiveVideoDevices->Initialize( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL ,filter); m_Controls.m_ActiveVideoDevices->SetAutomaticallySelectFirstEntry(true); m_FrameCounterPipeline = 0; m_FrameCounter2d = 0; m_FrameCounter3d = 0; m_Controls.tabWidget->setTabEnabled(1, false); } #include -void UltrasoundSupport::InitNewNode(const char* name) +void UltrasoundSupport::InitNewNode() { m_Node.push_back(nullptr); auto& Node = m_Node.back(); Node = mitk::DataNode::New(); - Node->SetName(name); + Node->SetName("No Data received yet ..."); //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); Node->SetData(dummyImage); m_OldGeometry = dynamic_cast(dummyImage->GetGeometry()); + UpdateColormaps(); + this->GetDataStorage()->Add(Node); } +void UltrasoundSupport::UpdateColormaps() +{ + if (m_Node.size() > 1) + { + for (int index = 0; index < m_AmountOfOutputs - 1; ++index) + { + SetColormap(m_Node.at(index), mitk::LookupTable::LookupTableType::GRAYSCALE); + } + SetColormap(m_Node.back(), mitk::LookupTable::LookupTableType::JET_TRANSPARENT); + } + else + SetColormap(m_Node.back(), mitk::LookupTable::LookupTableType::GRAYSCALE); +} + +void UltrasoundSupport::SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type) +{ + mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); + mitk::LookupTableProperty::Pointer lookupTableProperty = mitk::LookupTableProperty::New(); + lookupTable->SetType(type); + lookupTableProperty->SetLookupTable(lookupTable); + node->SetProperty("LookupTable", lookupTableProperty); + + mitk::RenderingModeProperty::Pointer renderingMode = + dynamic_cast(node->GetProperty("Image Rendering.Mode")); + renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); +} + void UltrasoundSupport::DestroyLastNode() { auto& Node = m_Node.back(); this->GetDataStorage()->Remove(Node); Node->ReleaseData(); m_Node.pop_back(); } void UltrasoundSupport::OnClickedAddNewDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_Headline->setText("Add New Video Device:"); m_Controls.m_WidgetActiveDevices->setVisible(false); } void UltrasoundSupport::UpdateAmountOfOutputs() { - //Update the amount of Nodes; there should be one Node for every slide - m_AmountOfOutputs = AllImagesOutput->GetDimension(2); + // Update the amount of Nodes; there should be one Node for every slide that is set. Note that we must check whether the slices are set, + // just using the m_Image->dimension(3) will produce nulltpointers on slices of the image that were not set + bool isSet = true; + m_AmountOfOutputs = 0; + while (isSet) { + isSet = m_Image->IsSliceSet(m_AmountOfOutputs); + if (isSet) + ++m_AmountOfOutputs; + } // correct the amount of Nodes to display data while (m_Node.size() < m_AmountOfOutputs) { - InitNewNode("No Data received yet ..."); + InitNewNode(); } while (m_Node.size() > m_AmountOfOutputs) { DestroyLastNode(); } // correct the amount of image outputs that we feed the nodes with - while (curOutput.size() < m_AmountOfOutputs) { - curOutput.push_back(mitk::Image::New()); - unsigned int* dimOld = AllImagesOutput->GetDimensions(); + while (m_curOutput.size() < m_AmountOfOutputs) { + m_curOutput.push_back(mitk::Image::New()); + + // initialize the slice images as 2d images with the size of m_Images + unsigned int* dimOld = m_Image->GetDimensions(); unsigned int dim[2] = { dimOld[0], dimOld[1]}; - curOutput.back()->Initialize(AllImagesOutput->GetPixelType(), 2, dim); + m_curOutput.back()->Initialize(m_Image->GetPixelType(), 2, dim); } - while (curOutput.size() > m_AmountOfOutputs) { - curOutput.pop_back(); + while (m_curOutput.size() > m_AmountOfOutputs) { + m_curOutput.pop_back(); } } void UltrasoundSupport::UpdateImage() { - m_Device->Modified(); - m_Device->Update(); - //Update device - - AllImagesOutput = m_Device->GetOutput(); - UpdateAmountOfOutputs(); - // create as many Nodes and Outputs as there are slices in AllImagesOutput - - if (m_AmountOfOutputs == 0) - return; - //if there is no image to be displayed, skip the rest of this method - - //Only update the view if the image is shown if(m_Controls.m_ShowImageStream->isChecked()) { + m_Device->Modified(); + m_Device->Update(); + // Update device + + m_Image = m_Device->GetOutput(); + // get the Image data to display + UpdateAmountOfOutputs(); + // create as many Nodes and Outputs as there are slices in m_Image + + if (m_AmountOfOutputs == 0) + return; + // if there is no image to be displayed, skip the rest of this method + for (int index = 0; index < m_AmountOfOutputs; ++index) { - if (curOutput.at(index)->GetDimension(0) != AllImagesOutput->GetDimension(0) || - curOutput.at(index)->GetDimension(1) != AllImagesOutput->GetDimension(1) || - curOutput.at(index)->GetDimension(2) != AllImagesOutput->GetDimension(2) || - curOutput.at(index)->GetPixelType() != AllImagesOutput->GetPixelType()) + if (m_curOutput.at(index)->GetDimension(0) != m_Image->GetDimension(0) || + m_curOutput.at(index)->GetDimension(1) != m_Image->GetDimension(1) || + m_curOutput.at(index)->GetDimension(2) != m_Image->GetDimension(2) || + m_curOutput.at(index)->GetPixelType() != m_Image->GetPixelType()) { - unsigned int* dimOld = AllImagesOutput->GetDimensions(); + unsigned int* dimOld = m_Image->GetDimensions(); unsigned int dim[2] = { dimOld[0], dimOld[1]}; - curOutput.at(index)->Initialize(AllImagesOutput->GetPixelType(), 2, dim); + m_curOutput.at(index)->Initialize(m_Image->GetPixelType(), 2, dim); // if we switched image resolution or type the outputs must be reinitialized! } - if (!AllImagesOutput->IsEmpty()) + if (!m_Image->IsEmpty()) { - mitk::ImageReadAccessor inputReadAccessor(AllImagesOutput, AllImagesOutput->GetSliceData(index)); - curOutput.at(index)->SetSlice(inputReadAccessor.GetData()); - curOutput.at(index)->SetGeometry(AllImagesOutput->GetGeometry()); - //Update the image Output with seperate slices + mitk::ImageReadAccessor inputReadAccessor(m_Image, m_Image->GetSliceData(m_AmountOfOutputs-index-1,0,0,nullptr,mitk::Image::ReferenceMemory)); + //we'll switch here the order of the images to get the laser image as the top image; also just reference the slices, to get a small performance gain + m_curOutput.at(index)->SetSlice(inputReadAccessor.GetData()); + m_curOutput.at(index)->SetGeometry(m_Image->GetGeometry()); + // Update the image Output with seperate slices } - if (curOutput.at(index)->IsEmpty()) + if (m_curOutput.at(index)->IsEmpty()) { m_Node.at(index)->SetName("No Data received yet ..."); - //create a noise image for correct initialization of level window, etc. + // create a noise image for correct initialization of level window, etc. mitk::Image::Pointer randomImage = mitk::ImageGenerator::GenerateRandomImage(32, 32, 1, 1, 1, 1, 1, 255, 0); m_Node.at(index)->SetData(randomImage); - curOutput.at(index)->SetGeometry(randomImage->GetGeometry()); + m_curOutput.at(index)->SetGeometry(randomImage->GetGeometry()); } else { char name[30]; sprintf(name, "US Viewing Stream - Image %d", index); m_Node.at(index)->SetName(name); - m_Node.at(index)->SetData(curOutput.at(index)); + m_Node.at(index)->SetData(m_curOutput.at(index)); // set the name of the Output } } - // if the geometry changed: reinitialize the ultrasound image. we use the first image in the vector to readjust the geometry + // if the geometry changed: reinitialize the ultrasound image. we use the m_Image to readjust the geometry if ((m_OldGeometry.IsNotNull()) && - (curOutput.at(0)->GetGeometry() != NULL) && - (!mitk::Equal(m_OldGeometry.GetPointer(), curOutput.at(0)->GetGeometry(), 0.0001, false)) + (m_Image->GetGeometry() != NULL) && + (!mitk::Equal(m_OldGeometry.GetPointer(), m_Image->GetGeometry(), 0.0001, false)) ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); - if ((renderWindow != NULL) && (curOutput.at(0)->GetTimeGeometry()->IsValid()) && (m_Controls.m_ShowImageStream->isChecked())) + if ((renderWindow != NULL) && (m_Image->GetTimeGeometry()->IsValid()) && (m_Controls.m_ShowImageStream->isChecked())) { renderWindow->GetRenderingManager()->InitializeViews( - curOutput.at(0)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); + m_Image->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); renderWindow->GetRenderingManager()->RequestUpdateAll(); } - m_CurrentImageWidth = curOutput.at(0)->GetDimension(0); - m_CurrentImageHeight = curOutput.at(0)->GetDimension(1); - m_OldGeometry = dynamic_cast(curOutput.at(0)->GetGeometry()); + m_CurrentImageWidth = m_Image->GetDimension(0); + m_CurrentImageHeight = m_Image->GetDimension(1); + m_OldGeometry = dynamic_cast(m_Image->GetGeometry()); } } //Update frame counter m_FrameCounterPipeline ++; if (m_FrameCounterPipeline >= 10) { - //compute framerate of pipeline update + // compute framerate of pipeline update int nMilliseconds = m_Clock.restart(); int fps = 10000.0f / (nMilliseconds ); m_FPSPipeline = fps; m_FrameCounterPipeline = 0; - //display lowest framerate in UI + // display lowest framerate in UI int lowestFPS=m_FPSPipeline; if (m_Controls.m_Update2DView->isChecked() && (m_FPS2disChecked() && (m_FPS3dsetText("Current Framerate: "+ QString::number(lowestFPS) +" FPS"); } } void UltrasoundSupport::RenderImage2d() { this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); m_FrameCounter2d ++; if (m_FrameCounter2d >= 10) { - //compute framerate of 2d render window update + // compute framerate of 2d render window update int nMilliseconds = m_Clock2d.restart(); int fps = 10000.0f / (nMilliseconds ); m_FPS2d = fps; m_FrameCounter2d = 0; } } void UltrasoundSupport::RenderImage3d() { this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); m_FrameCounter3d ++; if (m_FrameCounter3d >= 10) { - //compute framerate of 2d render window update + // compute framerate of 2d render window update int nMilliseconds = m_Clock3d.restart(); int fps = 10000.0f / (nMilliseconds ); m_FPS3d = fps; m_FrameCounter3d = 0; } } void UltrasoundSupport::OnChangedFramerateLimit() { StopTimers(); int intervalPipeline = (1000 / m_Controls.m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls.m_FrameRate2d->value()); int interval3D = (1000 / m_Controls.m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline,interval2D,interval3D); StartTimers(); } void UltrasoundSupport::OnClickedFreezeButton() { if ( m_Device.IsNull() ) { MITK_WARN("UltrasoundSupport") << "Freeze button clicked though no device is selected."; return; } if ( m_Device->GetIsFreezed() ) { m_Device->SetIsFreezed(false); m_Controls.m_FreezeButton->setText("Freeze"); } else { m_Device->SetIsFreezed(true); m_Controls.m_FreezeButton->setText("Start Viewing Again"); } } void UltrasoundSupport::OnChangedActiveDevice() { - //clean up and stop timer + //clean up, delete nodes and stop timer StopTimers(); this->RemoveControlWidgets(); for (auto& Node : m_Node) { this->GetDataStorage()->Remove(Node); Node->ReleaseData(); } + m_Node.clear(); //get current device, abort if it is invalid m_Device = m_Controls.m_ActiveVideoDevices->GetSelectedService(); if (m_Device.IsNull()) { m_Controls.tabWidget->setTabEnabled(1, false); return; } //create the widgets for this device and enable the widget tab this->CreateControlWidgets(); m_Controls.tabWidget->setTabEnabled(1, true); - //show node if the option is enabled - if (m_Controls.m_ShowImageStream->isChecked()) - { - for (auto& Node : m_Node) - { - this->GetDataStorage()->Add(Node); - } - } - //start timer if(m_Controls.m_RunImageTimer->isChecked()) { int intervalPipeline = (1000 / m_Controls.m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls.m_FrameRate2d->value()); int interval3D = (1000 / m_Controls.m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline,interval2D,interval3D); StartTimers(); m_Controls.m_TimerWidget->setEnabled(true); } else { m_Controls.m_TimerWidget->setEnabled(false); } } void UltrasoundSupport::OnNewDeviceWidgetDone() { m_Controls.m_NewVideoDeviceWidget->setVisible(false); m_Controls.m_DeviceManagerWidget->setVisible(true); m_Controls.m_Headline->setText("Ultrasound Devices:"); m_Controls.m_WidgetActiveDevices->setVisible(true); } void UltrasoundSupport::CreateControlWidgets() { m_ControlProbesWidget = new QmitkUSControlsProbesWidget(m_Device->GetControlInterfaceProbes(), m_Controls.m_ToolBoxControlWidgets); m_Controls.probesWidgetContainer->addWidget(m_ControlProbesWidget); // create b mode widget for current device m_ControlBModeWidget = new QmitkUSControlsBModeWidget(m_Device->GetControlInterfaceBMode(), m_Controls.m_ToolBoxControlWidgets); m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlBModeWidget, "B Mode Controls"); if ( ! m_Device->GetControlInterfaceBMode() ) { m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count()-1, false); } // create doppler widget for current device m_ControlDopplerWidget = new QmitkUSControlsDopplerWidget(m_Device->GetControlInterfaceDoppler(), m_Controls.m_ToolBoxControlWidgets); m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlDopplerWidget, "Doppler Controls"); if ( ! m_Device->GetControlInterfaceDoppler() ) { m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count()-1, false); } ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if ( pluginContext ) { std::string filter = "(ork.mitk.services.UltrasoundCustomWidget.deviceClass=" + m_Device->GetDeviceClass() + ")"; QString interfaceName = QString::fromStdString(us_service_interface_iid() ); m_CustomWidgetServiceReference = pluginContext->getServiceReferences(interfaceName, QString::fromStdString(filter)); if (m_CustomWidgetServiceReference.size() > 0) { m_ControlCustomWidget = pluginContext->getService (m_CustomWidgetServiceReference.at(0))->CloneForQt(m_Controls.tab2); m_ControlCustomWidget->SetDevice(m_Device); m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlCustomWidget, "Custom Controls"); } else { m_Controls.m_ToolBoxControlWidgets->addItem(new QWidget(m_Controls.m_ToolBoxControlWidgets), "Custom Controls"); m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count()-1, false); } } // select first enabled control widget for ( int n = 0; n < m_Controls.m_ToolBoxControlWidgets->count(); ++n) { if ( m_Controls.m_ToolBoxControlWidgets->isItemEnabled(n) ) { m_Controls.m_ToolBoxControlWidgets->setCurrentIndex(n); break; } } } void UltrasoundSupport::RemoveControlWidgets() { if(!m_ControlProbesWidget) {return;} //widgets do not exist... nothing to do // remove all control widgets from the tool box widget while (m_Controls.m_ToolBoxControlWidgets->count() > 0) { m_Controls.m_ToolBoxControlWidgets->removeItem(0); } // remove probes widget (which is not part of the tool box widget) m_Controls.probesWidgetContainer->removeWidget(m_ControlProbesWidget); delete m_ControlProbesWidget; m_ControlProbesWidget = 0; delete m_ControlBModeWidget; m_ControlBModeWidget = 0; delete m_ControlDopplerWidget; m_ControlDopplerWidget = 0; // delete custom widget if it is present if ( m_ControlCustomWidget ) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); delete m_ControlCustomWidget; m_ControlCustomWidget = 0; if ( m_CustomWidgetServiceReference.size() > 0 ) { pluginContext->ungetService(m_CustomWidgetServiceReference.at(0)); } } } void UltrasoundSupport::OnDeciveServiceEvent(const ctkServiceEvent event) { if ( m_Device.IsNull() || event.getType() != us::ServiceEvent::MODIFIED ) { return; } ctkServiceReference service = event.getServiceReference(); if ( m_Device->GetManufacturer() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER)).toString().toStdString() && m_Device->GetName() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME)).toString().toStdString() ) { return; } if ( ! m_Device->GetIsActive() && m_UpdateTimer->isActive() ) { StopTimers(); } if ( m_CurrentDynamicRange != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble() ) { m_CurrentDynamicRange = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble(); // update level window for the current dynamic range mitk::LevelWindow levelWindow; for (auto& Node : m_Node) { Node->GetLevelWindow(levelWindow); levelWindow.SetAuto(m_Image, true, true); Node->SetLevelWindow(levelWindow); } } } UltrasoundSupport::UltrasoundSupport() : m_ControlCustomWidget(0), m_ControlBModeWidget(0), m_ControlProbesWidget(0), m_ImageAlreadySetToNode(false), m_CurrentImageWidth(0), m_CurrentImageHeight(0), m_AmountOfOutputs(0) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if ( pluginContext ) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeciveServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } UltrasoundSupport::~UltrasoundSupport() { try { StopTimers(); // Get all active devicesand deactivate them to prevent freeze std::vector devices = this->m_Controls.m_ActiveVideoDevices->GetAllServices(); for (int i = 0; i < devices.size(); i ++) { mitk::USDevice::Pointer device = devices[i]; if (device.IsNotNull() && device->GetIsActive()) { device->Deactivate(); device->Disconnect(); } } StoreUISettings(); } catch(std::exception &e) { MITK_ERROR << "Exception during call of destructor! Message: " << e.what(); } } void UltrasoundSupport::StoreUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); settings.setValue("DisplayImage", QVariant(m_Controls.m_ShowImageStream->isChecked())); settings.setValue("RunImageTimer", QVariant(m_Controls.m_RunImageTimer->isChecked())); settings.setValue("Update2DView", QVariant(m_Controls.m_Update2DView->isChecked())); settings.setValue("Update3DView", QVariant(m_Controls.m_Update3DView->isChecked())); settings.setValue("UpdateRatePipeline", QVariant(m_Controls.m_FrameRatePipeline->value())); settings.setValue("UpdateRate2d", QVariant(m_Controls.m_FrameRate2d->value())); settings.setValue("UpdateRate3d", QVariant(m_Controls.m_FrameRate3d->value())); settings.endGroup(); } void UltrasoundSupport::LoadUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); m_Controls.m_ShowImageStream->setChecked(settings.value("DisplayImage", true).toBool()); m_Controls.m_RunImageTimer->setChecked(settings.value("RunImageTimer", true).toBool()); m_Controls.m_Update2DView->setChecked(settings.value("Update2DView", true).toBool()); m_Controls.m_Update3DView->setChecked(settings.value("Update3DView", true).toBool()); m_Controls.m_FrameRatePipeline->setValue(settings.value("UpdateRatePipeline", 50).toInt()); m_Controls.m_FrameRate2d->setValue(settings.value("UpdateRate2d", 20).toInt()); m_Controls.m_FrameRate3d->setValue(settings.value("UpdateRate3d", 5).toInt()); settings.endGroup(); } void UltrasoundSupport::StartTimers() { m_UpdateTimer->start(); if (m_Controls.m_Update2DView->isChecked()) {m_RenderingTimer2d->start();} if (m_Controls.m_Update3DView->isChecked()) {m_RenderingTimer3d->start();} } void UltrasoundSupport::StopTimers() { m_UpdateTimer->stop(); m_RenderingTimer2d->stop(); m_RenderingTimer3d->stop(); } void UltrasoundSupport::SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D) { m_UpdateTimer->setInterval(intervalPipeline); m_RenderingTimer2d->setInterval(interval2D); m_RenderingTimer3d->setInterval(interval3D); } diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h index 6aaa9b8379..559bfdc397 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h @@ -1,155 +1,166 @@ /*=================================================================== 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 UltrasoundSupport_h #define UltrasoundSupport_h +#include +#include + #include #include #include "ui_UltrasoundSupportControls.h" #include "QmitkUSAbstractCustomWidget.h" #include "QmitkUSControlsBModeWidget.h" #include "QmitkUSControlsDopplerWidget.h" #include "QmitkUSControlsProbesWidget.h" #include #include /*! \brief UltrasoundSupport This plugin provides functionality to manage Ultrasound devices, create video devices and to view device images. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class UltrasoundSupport : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: virtual void SetFocus() override; static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent) override; UltrasoundSupport(); virtual ~UltrasoundSupport(); public slots: /* * \brief This is called when the newDeviceWidget is closed */ void OnNewDeviceWidgetDone(); protected slots: void OnClickedAddNewDevice(); void OnChangedFramerateLimit(); /* *\brief Called, when the selection in the list of the active devices changes. */ void OnChangedActiveDevice(); void OnClickedFreezeButton(); void OnDeciveServiceEvent(const ctkServiceEvent event); /* * \brief This is the main imaging loop that updates the image and is called regularily during the imaging process */ void UpdateImage(); void RenderImage2d(); void RenderImage3d(); void StartTimers(); void StopTimers(); protected: void CreateControlWidgets(); void RemoveControlWidgets(); /** The device that is currently used to aquire images */ mitk::USDevice::Pointer m_Device; void SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D); /** This timer triggers periodic updates to the pipeline */ QTimer* m_UpdateTimer; QTimer* m_RenderingTimer2d; QTimer* m_RenderingTimer3d; /** These clocks are used to compute the framerate in the methods DisplayImage(),RenderImage2d() and RenderImage3d(). */ QTime m_Clock; QTime m_Clock2d; QTime m_Clock3d; /** A counter to comute the framerate. */ int m_FrameCounterPipeline; int m_FrameCounter2d; int m_FrameCounter3d; int m_FPSPipeline, m_FPS2d, m_FPS3d; /** Stores the properties of some QWidgets (and the tool storage file name) to QSettings.*/ void StoreUISettings(); /** Loads the properties of some QWidgets (and the tool storage file name) from QSettings.*/ void LoadUISettings(); /** The nodes that we feed images into.*/ std::vector m_Node; - void InitNewNode(const char* name); + /** Adds a new node to the m_Nodes vector*/ + void InitNewNode(); + /** Destroys the last node in the m_Nodes vector */ void DestroyLastNode(); + /** Checks the amount of slices in the image from the USDevice and creates as many Nodes as there are slices */ void UpdateAmountOfOutputs(); - /** The image that is hold by the node above.*/ - mitk::Image::Pointer m_Image; - mitk::Image::Pointer AllImagesOutput; - std::vector curOutput; + /** This function just checks how many nodes there are currently and sets the laser image to a jet transparent colormap. */ + void UpdateColormaps(); + void SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type); + + /** The image that holds all data given by the USDevice.*/ + mitk::Image::Pointer m_Image; + /** The seperated slices from m_Image */ + std::vector m_curOutput; + /** Keeps track of the amount of output Nodes*/ int m_AmountOfOutputs; /** The old geometry of m_Image. It is needed to check if the geometry changed (e.g. because * the zoom factor was modified) and the image needs to be reinitialized. */ mitk::SlicedGeometry3D::Pointer m_OldGeometry; Ui::UltrasoundSupportControls m_Controls; QmitkUSAbstractCustomWidget* m_ControlCustomWidget; QmitkUSControlsBModeWidget* m_ControlBModeWidget; QmitkUSControlsDopplerWidget* m_ControlDopplerWidget; QmitkUSControlsProbesWidget* m_ControlProbesWidget; QList m_CustomWidgetServiceReference; bool m_ImageAlreadySetToNode; unsigned int m_CurrentImageWidth; unsigned int m_CurrentImageHeight; double m_CurrentDynamicRange; }; #endif // UltrasoundSupport_h