diff --git a/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp b/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp index c4d76224e1..f075bc276c 100644 --- a/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp +++ b/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp @@ -1,337 +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 "mitkOphirPyro.h" #include #include #include #include mitk::OphirPyro::OphirPyro() : m_CurrentWavelength(0), m_DeviceHandle(0), m_Connected(false), m_Streaming(false), m_SerialNumber(nullptr), m_GetDataThread(), m_ImagePyroDelay(0), m_EnergyMultiplicator(60000) { m_PulseEnergy.clear(); m_PulseTime.clear(); m_PulseStatus.clear(); m_TimeStamps.clear(); } mitk::OphirPyro::~OphirPyro() { if (m_Connected) { this->CloseConnection(); if (m_GetDataThread.joinable()) { m_GetDataThread.join(); MITK_INFO << "[OphirPyro Debug] joined data thread"; } } MITK_INFO << "[OphirPyro Debug] destroying that Pyro"; /* cleanup thread */ } bool mitk::OphirPyro::StartDataAcquisition() { if (ophirAPI.StartStream(m_DeviceHandle)) { m_Streaming = true; m_GetDataThread = std::thread(&mitk::OphirPyro::GetDataFromSensorThread, this); } return m_Streaming; } // this is just a little function to set the filenames below right inline void replaceAll(std::string& str, const std::string& from, const std::string& to) { if (from.empty()) return; size_t start_pos = 0; while ((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' } } -void mitk::OphirPyro::SaveCsvData() +void mitk::OphirPyro::SaveCsvData(std::string filename) { - // get the time and date, put them into a nice string and create a folder for the images - time_t time = std::time(nullptr); - time_t* timeptr = &time; - std::string currentDate = std::ctime(timeptr); - replaceAll(currentDate, ":", "-"); - currentDate.pop_back(); - - std::string pathTS = "c:\\ImageData\\" + currentDate + " pyro-ts" + ".csv"; + std::string pathTS = filename; std::ofstream timestampFile; timestampFile.open(pathTS); timestampFile << ",timestamp,PulseEnergy,PulseTime"; int currentSize = m_TimeStamps.size(); for (int index = 0; index < currentSize; ++index) { timestampFile << "\n" << index << "," << m_TimeStamps.at(index) << ","<< m_PulseEnergySaved.at(index) << "," << (long)m_PulseTimeSaved.at(index); } timestampFile.close(); } -void mitk::OphirPyro::SaveData() +void mitk::OphirPyro::SaveData(std::string filename) { - SaveCsvData(); + SaveCsvData(filename); } bool mitk::OphirPyro::StopDataAcquisition() { if (ophirAPI.StopStream(m_DeviceHandle)) m_Streaming = false; - SaveCsvData(); + //SaveCsvData(); MITK_INFO << "[OphirPyro Debug] m_Streaming = "<< m_Streaming; std::this_thread::sleep_for(std::chrono::milliseconds(50)); if (m_GetDataThread.joinable()) { m_GetDataThread.join(); } return !m_Streaming; } unsigned int mitk::OphirPyro::GetDataFromSensor() { if (m_Streaming) { std::vector newEnergy; std::vector newTimestamp; std::vector newStatus; unsigned int noPackages = 0; try { noPackages = ophirAPI.GetData(m_DeviceHandle, &newEnergy, &newTimestamp, &newStatus); if (noPackages > 0) { m_PulseEnergy.insert(m_PulseEnergy.end(), newEnergy.begin(), newEnergy.end()); for (unsigned int i=0; iGetDataFromSensor(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } return; } double mitk::OphirPyro::LookupCurrentPulseEnergy() { if (m_Connected && !m_PulseEnergy.empty()) { MITK_INFO << m_PulseEnergy.size(); return m_PulseEnergy.back(); } return 0; } double mitk::OphirPyro::GetClosestEnergyInmJ(long long ImageTimeStamp, double interval) { if (m_PulseTime.size() == 0) return 0; long long searchTime = (ImageTimeStamp/1000000) - m_ImagePyroDelay; // conversion from ns to ms //MITK_INFO << "searchTime = " << searchTime; int foundIndex = -1; long long shortestDifference = 250*interval; // search the list for a fitting energy value time for (int index = 0; index < m_PulseTime.size();++index) { long long newDifference = abs(((int)m_PulseTime[index]) - searchTime); //MITK_INFO << "newDifference[" << index << "] = " << newDifference; if (newDifference < shortestDifference) { shortestDifference = newDifference; foundIndex = index; //MITK_INFO << "foundIndex = " << foundIndex; } } if (abs(shortestDifference) < interval) { // delete all elements before the one found m_PulseEnergy.erase(m_PulseEnergy.begin(), m_PulseEnergy.begin() + foundIndex); m_PulseTime.erase(m_PulseTime.begin(), m_PulseTime.begin() + foundIndex); m_PulseStatus.erase(m_PulseStatus.begin(), m_PulseStatus.begin() + foundIndex); // multipy with m_EnergyMultiplicator, because the Pyro gives just a fraction of the actual Laser Energy return (GetNextPulseEnergy()*m_EnergyMultiplicator); } //MITK_INFO << "No matching energy value for image found in interval of " << interval << "ms. sd: " << shortestDifference; return -1; } double mitk::OphirPyro::GetNextEnergyInmJ(long long ImageTimeStamp, double interval) { if (m_Connected && !(m_PulseTime.size() > 0)) return 0; long long searchTime = (ImageTimeStamp / 1000000) - m_ImagePyroDelay; // conversion from ns to ms if (abs(searchTime - m_PulseTime.front()) < interval) { return (GetNextPulseEnergy()*m_EnergyMultiplicator); // multipy with m_EnergyMultiplicator, because the Pyro gives just a fraction of the actual Laser Energy } MITK_INFO << "Image aquisition and energy measurement ran out of sync"; return -1; } void mitk::OphirPyro::SetSyncDelay(long long FirstImageTimeStamp) { + unsigned int i = 0; while (!m_PulseTime.size()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); + ++i; + if (i > 100) + { + MITK_ERROR << "Pyro was not active for synchronization. Please turn on the laser before setting tgc higher (WIP)!"; + return; + } } m_ImagePyroDelay = (FirstImageTimeStamp / 1000000) - m_PulseTime.at(0); MITK_INFO << "m_ImagePyroDelay = " << m_ImagePyroDelay; return; } bool mitk::OphirPyro::IsSyncDelaySet() { return (m_ImagePyroDelay != 0); } double mitk::OphirPyro::GetNextPulseEnergy() { if (m_Connected && m_PulseEnergy.size()>=1) { double out = m_PulseEnergy.front(); m_PulseEnergy.erase(m_PulseEnergy.begin()); m_PulseTime.erase(m_PulseTime.begin()); m_PulseStatus.erase(m_PulseStatus.begin()); return out; } return 0; } double mitk::OphirPyro::LookupCurrentPulseEnergy(double* timestamp, int* status) { if (m_Connected) { *timestamp = m_PulseTime.back(); *status = m_PulseStatus.back(); return m_PulseEnergy.back(); } return 0; } double mitk::OphirPyro::GetNextPulseEnergy(double* timestamp, int* status) { if (m_Connected) { double out = m_PulseEnergy.front(); *timestamp = m_PulseTime.front(); *status = m_PulseStatus.front(); m_PulseEnergy.erase(m_PulseEnergy.begin()); m_PulseTime.erase(m_PulseTime.begin()); m_PulseStatus.erase(m_PulseStatus.begin()); return out; } return 0; } bool mitk::OphirPyro::OpenConnection() { if (!m_Connected) { char* m_SerialNumber; try { MITK_INFO << "Scanning for Ophir connection"; m_SerialNumber = ophirAPI.ScanUSB(); } catch (...) { MITK_INFO << "Scanning failed, trying again in 2 seconds..."; std::this_thread::sleep_for(std::chrono::seconds(2)); MITK_INFO << "Scanning for Ophir connection"; m_SerialNumber = ophirAPI.ScanUSB(); } if (m_SerialNumber != 0) { try { MITK_INFO << "Opening Ophir connection"; m_DeviceHandle = ophirAPI.OpenDevice(m_SerialNumber); } catch (...) { MITK_INFO << "Ophir connection failed, trying again in 2 seconds..."; std::this_thread::sleep_for(std::chrono::seconds(2)); MITK_INFO << "Opening Ophir connection"; m_DeviceHandle = ophirAPI.OpenDevice(m_SerialNumber); } if (m_DeviceHandle != 0) { m_Connected = true; return true; } } } return false; } bool mitk::OphirPyro::CloseConnection() { if (m_Connected) { bool closed = ophirAPI.CloseDevice(m_DeviceHandle); if (closed) m_DeviceHandle = 0; m_Connected = !closed; return closed; } return false; } \ No newline at end of file diff --git a/Modules/PhotoacousticsHardware/mitkOphirPyro.h b/Modules/PhotoacousticsHardware/mitkOphirPyro.h index b1d9f886d6..aa34f061fa 100644 --- a/Modules/PhotoacousticsHardware/mitkOphirPyro.h +++ b/Modules/PhotoacousticsHardware/mitkOphirPyro.h @@ -1,94 +1,94 @@ /*=================================================================== 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 MITKOPHIRPYRO_H_HEADER_INCLUDED #define MITKOPHIRPYRO_H_HEADER_INCLUDED #include "itkObject.h" #include "mitkCommon.h" #include "vector" #include "MitkPhotoacousticsHardwareExports.h" #include "OphirPyroWrapper.h" #include #include #include #include #include #include #include #include #include namespace mitk { class MITKPHOTOACOUSTICSHARDWARE_EXPORT OphirPyro : public itk::Object { public: mitkClassMacroItkParent(mitk::OphirPyro, itk::Object); itkFactorylessNewMacro(Self); virtual bool OpenConnection(); virtual bool CloseConnection(); virtual bool StartDataAcquisition(); virtual bool StopDataAcquisition(); unsigned int GetDataFromSensor(); void GetDataFromSensorThread(); - void SaveData(); + void SaveData(std::string filename); virtual double LookupCurrentPulseEnergy(); virtual double GetNextPulseEnergy(); virtual double LookupCurrentPulseEnergy(double* timestamp, int* status); virtual double GetNextPulseEnergy(double* timestamp, int* status); virtual double GetClosestEnergyInmJ(long long ImageTimeStamp, double interval=20); virtual double GetNextEnergyInmJ(long long ImageTimeStamp, double interval = 20); virtual void SetSyncDelay(long long FirstImageTimeStamp); virtual bool IsSyncDelaySet(); protected: OphirPyro(); virtual ~OphirPyro(); - void SaveCsvData(); + void SaveCsvData(std::string filename); OphirPyroWrapper ophirAPI; char* m_SerialNumber; int m_DeviceHandle; bool m_Connected; bool m_Streaming; std::vector m_PulseEnergy; std::vector m_PulseTime; std::vector m_PulseStatus; std::vector m_TimeStamps; std::vector m_PulseEnergySaved; std::vector m_PulseTimeSaved; std::vector m_PulseStatusSaved; std::vector m_TimeStampsSaved; double m_CurrentWavelength; double m_CurrentEnergyRange; long long m_ImagePyroDelay; float m_EnergyMultiplicator; std::thread m_GetDataThread; }; } // namespace mitk #endif /* MITKOPHIRPYRO_H_HEADER_INCLUDED */ diff --git a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp index 52d028d7db..09948886cd 100644 --- a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp +++ b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp @@ -1,210 +1,203 @@ /*=================================================================== 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::SetSilentUpdate(bool silent) { silentUpdate = silent; } bool mitk::USDiPhASDeviceCustomControls::GetSilentUpdate() { return silentUpdate; } void mitk::USDiPhASDeviceCustomControls::SetSavingName(std::string name) { this->OnSetSavingName(name); } //Set Functions void mitk::USDiPhASDeviceCustomControls::SetCompensateEnergy(bool compensate) { this->OnSetCompensateEnergy(compensate); } void mitk::USDiPhASDeviceCustomControls::SetUseBModeFilter(bool isSet) { this->OnSetUseBModeFilter(isSet); } void mitk::USDiPhASDeviceCustomControls::SetRecord(bool record) { this->OnSetRecord(record); } void mitk::USDiPhASDeviceCustomControls::SetVerticalSpacing(float mm) { this->OnSetVerticalSpacing(mm); } void mitk::USDiPhASDeviceCustomControls::SetScatteringCoefficient(float coeff) { this->OnSetScatteringCoefficient(coeff); } void mitk::USDiPhASDeviceCustomControls::SetCompensateScattering(bool compensate) { this->OnSetCompensateScattering(compensate); } void mitk::USDiPhASDeviceCustomControls::SetSavingSettings(SavingSettings settings) { this->OnSetSavingSettings(settings); } //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) +void mitk::USDiPhASDeviceCustomControls::SetTGC(int* tgc) { - this->OnSetTGCMin(min); -} - -void mitk::USDiPhASDeviceCustomControls::SetTGCMax(int max) -{ - this->OnSetTGCMax(max); - + this->OnSetTGC(tgc); } void mitk::USDiPhASDeviceCustomControls::SetDataType(DataType type) { this->OnSetDataType(type); } //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::OnSetCompensateEnergy(bool /*compensate*/) {} void mitk::USDiPhASDeviceCustomControls::OnSetUseBModeFilter(bool /*isSet*/) {} void mitk::USDiPhASDeviceCustomControls::OnSetRecord(bool /*record*/) {} void mitk::USDiPhASDeviceCustomControls::OnSetVerticalSpacing(float /*mm*/) {} void mitk::USDiPhASDeviceCustomControls::OnSetScatteringCoefficient(float /*coeff*/) {} void mitk::USDiPhASDeviceCustomControls::OnSetCompensateScattering(bool /*compensate*/) {} void mitk::USDiPhASDeviceCustomControls::OnSetSavingSettings(SavingSettings /*settings*/) {} void mitk::USDiPhASDeviceCustomControls::OnSetSavingName(std::string name) {} //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::OnSetTGC(int* /*tgc*/) {} void mitk::USDiPhASDeviceCustomControls::OnSetDataType(DataType /*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 1285380944..608963cdfb 100644 --- a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h +++ b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.h @@ -1,145 +1,143 @@ /*=================================================================== 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; enum DataType { Image_uChar, Beamformed_Short }; struct SavingSettings { bool saveRaw; bool saveBeamformed; }; /** * \return if this custom controls are currently activated */ virtual bool GetIsActive( ) override; virtual void SetCompensateEnergy(bool compensate); virtual void SetUseBModeFilter(bool isSet); virtual void SetVerticalSpacing(float mm); virtual void SetRecord(bool record); virtual void SetScatteringCoefficient(float coeff); virtual void SetCompensateScattering(bool compensate); virtual void SetSavingSettings(SavingSettings settings); virtual void SetSavingName(std::string name); //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 SetTGC(int* tgc); virtual void SetDataType(DataType type); //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 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 OnSetCompensateEnergy(bool /*compensate*/); virtual void OnSetSavingSettings(SavingSettings /*settings*/); virtual void OnSetUseBModeFilter(bool /*isSet*/); virtual void OnSetRecord(bool /*record*/); virtual void OnSetVerticalSpacing(float /*mm*/); virtual void OnSetScatteringCoefficient(float /*coeff*/); virtual void OnSetCompensateScattering(bool /*compensate*/); virtual void OnSetSavingName(std::string name); //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 OnSetTGC(int* /*tgc*/); virtual void OnSetDataType(DataType /*type*/); //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_ diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp index 5ca9ecc8df..19f4dbb583 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.cpp @@ -1,226 +1,215 @@ /*=================================================================== 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; } // OnSet methods void mitk::USDiPhASCustomControls::OnSetCompensateEnergy(bool compensate) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->ModifyEnergyCompensation(compensate); } void mitk::USDiPhASCustomControls::OnSetUseBModeFilter(bool isSet) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->ModifyUseBModeFilter(isSet); } void mitk::USDiPhASCustomControls::OnSetRecord(bool record) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->SetRecordingStatus(record); } void mitk::USDiPhASCustomControls::OnSetVerticalSpacing(float mm) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->SetVerticalSpacing(mm); } void mitk::USDiPhASCustomControls::OnSetScatteringCoefficient(float coeff) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->ModifyScatteringCoefficient(coeff); } void mitk::USDiPhASCustomControls::OnSetCompensateScattering(bool compensate) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->ModifyCompensateForScattering(compensate); } void mitk::USDiPhASCustomControls::OnSetSavingSettings(SavingSettings settings) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->SetSavingSettings(settings); } void mitk::USDiPhASCustomControls::OnSetSavingName(std::string name) { mitk::USDiPhASImageSource* imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); imageSource->SetSavingName(name); } //Transmit void mitk::USDiPhASCustomControls::OnSetTransmitPhaseLength(double us) { m_device->GetScanMode().transmitPhaseLengthSeconds = us/1000000; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetExcitationFrequency(double MHz) { m_device->SetBursts(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) { m_device->SetInterleaved(interleaved); m_device->UpdateScanmode(); } //Receive void mitk::USDiPhASCustomControls::OnSetScanDepth(double mm) { auto& scanMode = m_device->GetScanMode(); float time = 2 * (0.001 * (mm)) / scanMode.averageSpeedOfSound; float timeInMicroSeconds = floor(time *1e6); // this is necessary because sub-microsecond accuracy causes undefined behaviour m_device->GetScanMode().receivePhaseLengthSeconds = timeInMicroSeconds*1e-6; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetAveragingCount(int count) { m_device->GetScanMode().averagingCount = count; m_device->UpdateScanmode(); } -void mitk::USDiPhASCustomControls::OnSetTGCMin(int min) +void mitk::USDiPhASCustomControls::OnSetTGC(int* tgc) { 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]); + for (int i = 0; i < 8; ++i) + scanMode.tgcdB[i] = tgc[i]; m_device->UpdateScanmode(); } void mitk::USDiPhASCustomControls::OnSetDataType(DataType type) { auto& scanMode = m_device->GetScanMode(); auto imageSource = dynamic_cast(m_device->GetUSImageSource().GetPointer()); switch (type) { case DataType::Image_uChar : { scanMode.transferBeamformedData = false; scanMode.transferImageData = true; m_device->UpdateScanmode(); imageSource->ModifyDataType(DataType::Image_uChar); break; } case DataType::Beamformed_Short : { scanMode.transferBeamformedData = true; scanMode.transferImageData = false; m_device->UpdateScanmode(); imageSource->ModifyDataType(DataType::Beamformed_Short); 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->SetInterleaved(m_device->IsInterleaved()); //update transmit parameters 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 35237fc40c..e9d8e6fb01 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASCustomControls.h @@ -1,105 +1,104 @@ /*=================================================================== 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 "mitkUSDiPhASDeviceCustomControls.h" #include "mitkUSDevice.h" #include "mitkUSDiPhASDevice.h" #include "Framework.IBMT.US.CWrapper.h" #include namespace mitk { /** * \brief Custom controls for mitk::USDiPhASDevice. */ class USDiPhASDevice; class USDiPhASCustomControls : public USDiPhASDeviceCustomControls { public: mitkClassMacro(USDiPhASCustomControls, USAbstractControlInterface); mitkNewMacro1Param(Self, mitk::USDiPhASDevice*); typedef USDiPhASDeviceCustomControls::DataType DataType; typedef USDiPhASDeviceCustomControls::SavingSettings SavingSettings; /** * 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; 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 OnSetCompensateEnergy(bool compensate) override; virtual void OnSetUseBModeFilter(bool isSet) override; virtual void OnSetRecord(bool record) override; virtual void OnSetVerticalSpacing(float mm) override; virtual void OnSetScatteringCoefficient(float coeff) override; virtual void OnSetCompensateScattering(bool compensate) override; virtual void OnSetSavingSettings(SavingSettings settings) override; virtual void OnSetSavingName(std::string name) 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 OnSetTGC(int* tgc) override; virtual void OnSetDataType(DataType type) override; //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/mitkUSDiPhASImageSource.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp index 95c02857e4..b177f779eb 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp @@ -1,979 +1,980 @@ /*=================================================================== 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. ===================================================================*/ // std dependencies #include #include #include // mitk dependencies #include "mitkUSDiPhASDevice.h" #include "mitkUSDiPhASImageSource.h" #include #include "mitkUSDiPhASBModeImageFilter.h" #include "ITKUltrasound/itkBModeImageFilter.h" #include "mitkImageCast.h" #include "mitkITKImageImport.h" // itk dependencies #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCropImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include "itkIntensityWindowingImageFilter.h" #include #include "itkMultiplyImageFilter.h" mitk::USDiPhASImageSource::USDiPhASImageSource(mitk::USDiPhASDevice* device) : m_Device(device), m_StartTime(((float)std::clock()) / CLOCKS_PER_SEC), m_DataType(DataType::Image_uChar), m_UseBModeFilter(false), m_CurrentlyRecording(false), m_DataTypeModified(true), m_DataTypeNext(DataType::Image_uChar), m_CurrentImageTimestamp(0), m_PyroConnected(false), m_VerticalSpacing(0), m_UseBModeFilterModified(false), m_UseBModeFilterNext(false), m_ScatteringCoefficientModified(false), m_CompensateForScatteringModified(false), m_VerticalSpacingModified(false), m_ScatteringCoefficient(15), m_CompensateForScattering(false), m_CompensateEnergy(false), m_CompensateEnergyNext(false), m_CompensateEnergyModified(false), m_SaveInterval(500), m_SavingName("-replace") { m_BufferSize = 100; m_ImageTimestampBuffer.insert(m_ImageTimestampBuffer.begin(), m_BufferSize, 0); m_LastWrittenImage = m_BufferSize - 1; m_ImageBuffer.insert(m_ImageBuffer.begin(), m_BufferSize, std::pair(nullptr, nullptr)); us::ModuleResource resourceFile; std::string name; m_FluenceCompOriginal.insert(m_FluenceCompOriginal.begin(), 5, Image::New()); for (int i = 5; i <= 25; ++i) { name = "c:\\HomogeneousScatteringAssumptions\\Scattering" + std::to_string(i) + ".nrrd"; m_FluenceCompOriginal.push_back(mitk::IOUtil::LoadImage(name)); } m_FluenceCompResized.insert(m_FluenceCompResized.begin(), 26, Image::New()); m_FluenceCompResizedItk.insert(m_FluenceCompResizedItk.begin(), 26, itk::Image::New()); } mitk::USDiPhASImageSource::~USDiPhASImageSource() { // close the pyro MITK_INFO("Pyro Debug") << "StopDataAcquisition: " << m_Pyro->StopDataAcquisition(); MITK_INFO("Pyro Debug") << "CloseConnection: " << m_Pyro->CloseConnection(); m_PyroConnected = false; m_Pyro = nullptr; } void mitk::USDiPhASImageSource::CheckModifiedVariables() { // modify all settings that have been changed here, so we don't get multithreading issues if (m_DataTypeModified) { SetDataType(m_DataTypeNext); m_DataTypeModified = false; UpdateImageGeometry(); } if (m_UseBModeFilterModified) { SetUseBModeFilter(m_UseBModeFilterNext); m_UseBModeFilterModified = false; } if (m_VerticalSpacingModified) { m_VerticalSpacing = m_VerticalSpacingNext; m_VerticalSpacingModified = false; } if (m_ScatteringCoefficientModified) { m_ScatteringCoefficient = m_ScatteringCoefficientNext; m_ScatteringCoefficientModified = false; } if (m_CompensateForScatteringModified) { m_CompensateForScattering = m_CompensateForScatteringNext; m_CompensateForScatteringModified = false; } if (m_CompensateEnergyModified) { m_CompensateEnergy = m_CompensateEnergyNext; m_CompensateEnergyModified = false; } } void mitk::USDiPhASImageSource::ResizeFluenceImage(mitk::Vector3D spacing, unsigned int* dimensions) { auto curResizeImage = ApplyResampling(m_FluenceCompOriginal.at(m_ScatteringCoefficient), spacing, dimensions); unsigned int imageSize = dimensions[0] * dimensions[1]; double* rawOutputData = new double[imageSize]; double* rawScatteringData = (double*)curResizeImage->GetData(); unsigned int sizeRawScatteringData = curResizeImage->GetDimension(0) * curResizeImage->GetDimension(1); //everything above 1.5mm is still inside the transducer; therefore the fluence compensation image has to be positioned a little lower float upperCutoffmm = 1.5; unsigned int lowerBound = std::round(upperCutoffmm / spacing[1])*dimensions[0]; unsigned int upperBound = lowerBound + sizeRawScatteringData; for (unsigned int i = 0; i < lowerBound && i < imageSize; ++i) { rawOutputData[i] = 0; // everything than cannot be compensated shall be treated as garbage, here the upper 0.15mm } for (unsigned int i = lowerBound; i < upperBound && i < imageSize; ++i) { rawOutputData[i] = 1 / rawScatteringData[i - lowerBound]; } for (unsigned int i = upperBound; i < imageSize; ++i) { rawOutputData[i] = 0; // everything than cannot be compensated shall be treated as garbage } unsigned int dim[] = { dimensions[0], dimensions[1], 1 }; curResizeImage->Initialize(mitk::MakeScalarPixelType(), 3, dim); curResizeImage->SetSpacing(spacing); curResizeImage->SetSlice(rawOutputData); mitk::CastToItkImage(curResizeImage, m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); m_FluenceCompResized.at(m_ScatteringCoefficient) = mitk::GrabItkImageMemory(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); MITK_INFO << "Resized a fluence image."; delete[] rawOutputData; } void mitk::USDiPhASImageSource::GetNextRawImage(std::vector& imageVector) { CheckModifiedVariables(); if (imageVector.size() != 2) { imageVector.resize(2); } // make sure image is nullptr mitk::Image::Pointer imageUS = nullptr; mitk::Image::Pointer imagePA = nullptr; float ImageEnergyValue = 0; for (int i = 100; i > 0 && ImageEnergyValue <= 0; --i) { if (m_ImageTimestampBuffer[(m_LastWrittenImage + i) % 100] != 0) { ImageEnergyValue = m_Pyro->GetClosestEnergyInmJ(m_ImageTimestampBuffer[(m_LastWrittenImage + i) % 100]); if (ImageEnergyValue > 0) { imagePA = m_ImageBuffer[(m_LastWrittenImage + i) % 100].first; imageUS = m_ImageBuffer[(m_LastWrittenImage + i) % 100].second; } } } // if we did not get any usable Energy value, compensate using this default value if (imagePA == nullptr || imageUS == nullptr) { imagePA = m_ImageBuffer[m_LastWrittenImage].first; imageUS = m_ImageBuffer[m_LastWrittenImage].second; ImageEnergyValue = 1; if (imagePA == nullptr || imageUS == nullptr) return; } // do image processing before displaying it if(imagePA.IsNotNull() && m_DataType == DataType::Beamformed_Short) { itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(imagePA, itkImage); imagePA = mitk::GrabItkImageMemory(itkImage); //thereby using float images imagePA = CutOffTop(imagePA, 165); if (m_CompensateEnergy) imagePA = MultiplyImage(imagePA, 1 / ImageEnergyValue); // TODO: add the correct prefactor here if (m_UseBModeFilter) imagePA = ApplyBmodeFilter(imagePA, false); if (m_VerticalSpacing) imagePA = ResampleOutputVertical(imagePA, m_VerticalSpacing); if (m_CompensateForScattering) { auto curResizeImage = m_FluenceCompResized.at(m_ScatteringCoefficient); bool doResampling = imagePA->GetDimension(0) != curResizeImage->GetDimension(0) || imagePA->GetDimension(1) != curResizeImage->GetDimension(1) || imagePA->GetGeometry()->GetSpacing()[0] != curResizeImage->GetGeometry()->GetSpacing()[0] || imagePA->GetGeometry()->GetSpacing()[1] != curResizeImage->GetGeometry()->GetSpacing()[1]; if (doResampling) ResizeFluenceImage(imagePA->GetGeometry()->GetSpacing(), imagePA->GetDimensions()); imagePA = ApplyScatteringCompensation(imagePA, m_ScatteringCoefficient); } } if(imageUS.IsNotNull() && m_DataType == DataType::Beamformed_Short) { itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(imageUS, itkImage); imageUS = mitk::GrabItkImageMemory(itkImage); //thereby using float images imageUS = CutOffTop(imageUS, 165); if (m_UseBModeFilter) imageUS = ApplyBmodeFilter(imageUS, true); // the US Images get a logarithmic filter if (m_VerticalSpacing) imageUS = ResampleOutputVertical(imageUS, m_VerticalSpacing); } imageVector[0] = imagePA; imageVector[1] = imageUS; } mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyBmodeFilter(mitk::Image::Pointer image, bool useLogFilter) { // we use this seperate ApplyBmodeFilter Method for processing of two-dimensional images // 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::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter itkFloatImageType::Pointer itkImage; itkFloatImageType::Pointer bmode; mitk::CastToItkImage(image, itkImage); if (useLogFilter) { bModeFilter->SetInput(itkImage); bModeFilter->SetDirection(1); bmode = bModeFilter->GetOutput(); } else { photoacousticBModeFilter->SetInput(itkImage); photoacousticBModeFilter->SetDirection(1); bmode = photoacousticBModeFilter->GetOutput(); } return mitk::GrabItkImageMemory(bmode); } mitk::Image::Pointer mitk::USDiPhASImageSource::CutOffTop(mitk::Image::Pointer image, int cutOffSize) { typedef itk::CropImageFilter < itkFloatImageType, itkFloatImageType > CutImageFilter; itkFloatImageType::SizeType cropSize; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(image, itkImage); cropSize[0] = 0; if(itkImage->GetLargestPossibleRegion().GetSize()[1] == 2048) cropSize[1] = cutOffSize; else cropSize[1] = 0; cropSize[2] = 0; CutImageFilter::Pointer cutOffFilter = CutImageFilter::New(); cutOffFilter->SetInput(itkImage); cutOffFilter->SetLowerBoundaryCropSize(cropSize); cutOffFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(cutOffFilter->GetOutput()); } mitk::Image::Pointer mitk::USDiPhASImageSource::ResampleOutputVertical(mitk::Image::Pointer image, float verticalSpacing) { typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(image, itkImage); itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0] * (static_cast(inputSize[0]) / static_cast(outputSize[0])); outputSpacing[1] = verticalSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) { typedef itk::MultiplyImageFilter MultiplyImageFilterType; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); multiplyFilter->SetInput1(itkImage); multiplyFilter->SetInput2(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); return mitk::GrabItkImageMemory(multiplyFilter->GetOutput()); } mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyResampling(mitk::Image::Pointer inputImage, mitk::Vector3D outputSpacing, unsigned int outputSize[3]) { typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::SpacingType outputSpacingItk; itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSizeItk = inputSizeItk; itkFloatImageType::SpacingType inputSpacing = itkImage->GetSpacing(); outputSizeItk[0] = outputSize[0]; outputSizeItk[1] = 10 * (inputSpacing[1] * inputSizeItk[1]) / (outputSpacing[1]); outputSizeItk[2] = 1; outputSpacingItk[0] = 0.996 * inputSpacing[0] * (static_cast(inputSizeItk[0]) / static_cast(outputSizeItk[0])); // TODO: find out why the spacing is not correct, so we need that factor; ?!?! outputSpacingItk[1] = inputSpacing[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); outputSpacingItk[2] = outputSpacing[2]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSizeItk); resampleImageFilter->SetOutputSpacing(outputSpacingItk); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::USDiPhASImageSource::MultiplyImage(mitk::Image::Pointer inputImage, double value) { typedef itk::MultiplyImageFilter MultiplyImageFilterType; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); multiplyFilter->SetInput1(itkImage); multiplyFilter->SetConstant(value); return mitk::GrabItkImageMemory(multiplyFilter->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) { if (m_DataTypeModified) return; if (!m_PyroConnected) { m_Pyro = mitk::OphirPyro::New(); MITK_INFO << "[Pyro Debug] OpenConnection: " << m_Pyro->OpenConnection(); MITK_INFO << "[Pyro Debug] StartDataAcquisition: " << m_Pyro->StartDataAcquisition(); m_PyroConnected = true; } bool writeImage = ((m_DataType == DataType::Image_uChar) && (imageData != nullptr)) || ((m_DataType == DataType::Beamformed_Short) && (rfDataArrayBeamformed != nullptr)); if (writeImage) { //get the timestamp we will save later on m_CurrentImageTimestamp = std::chrono::high_resolution_clock::now().time_since_epoch().count(); // create new images and initialize them mitk::Image::Pointer imageUS = mitk::Image::New(); mitk::Image::Pointer imagePA = mitk::Image::New(); switch (m_DataType) { case DataType::Image_uChar: { unsigned int imageDimensions[3]; imageDimensions[0] = imageWidth; imageDimensions[1] = imageHeight; imageDimensions[2] = 1; imagePA->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensions); imageUS->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensions); imagePA->SetSpacing(m_ImageSpacing); imageUS->SetSpacing(m_ImageSpacing); break; } case DataType::Beamformed_Short: { unsigned int imageDimensions[3]; imageDimensions[0] = beamformedLines; imageDimensions[1] = beamformedSamples; imageDimensions[2] = 1; imagePA->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensions); imageUS->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensions); imagePA->SetSpacing(m_ImageSpacing); imageUS->SetSpacing(m_ImageSpacing); break; } } // write the given buffer into the image switch (m_DataType) { case DataType::Image_uChar: { if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) { imagePA->SetSlice(imageData); imageUS->SetVolume(&imageData[imageHeight*imageWidth]); } else { imageUS->SetVolume(imageData); } break; } case DataType::Beamformed_Short: { short* flipme = new short[beamformedLines*beamformedSamples*beamformedTotalDatasets]; int pixelsPerImage = beamformedLines*beamformedSamples; for (unsigned char currentSet = 0; currentSet < beamformedTotalDatasets; currentSet++) { for (unsigned short sample = 0; sample < beamformedSamples; sample++) { for (unsigned short line = 0; line < beamformedLines; line++) { flipme[sample*beamformedLines + line + pixelsPerImage*currentSet] = rfDataArrayBeamformed[line*beamformedSamples + sample + pixelsPerImage*currentSet]; } } } if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) { imagePA->SetImportVolume(flipme, 0, 0, mitk::Image::RtlCopyMemory); imageUS->SetImportVolume(&(flipme[beamformedLines*beamformedSamples]), 0, 0, mitk::Image::RtlCopyMemory); } else { imageUS->SetImportVolume(flipme, 0, 0, mitk::Image::RtlCopyMemory); } delete[] flipme; break; } } if (m_SavingSettings.saveRaw && m_CurrentlyRecording && rfDataChannelData != nullptr) { short offset = m_Device->GetScanMode().accumulation * 2048; short* noOffset = new short[channelDataChannelsPerDataset*channelDataSamplesPerChannel];// *channelDataTotalDatasets]; for (unsigned char set = 0; set < 1; ++set)// channelDataTotalDatasets; ++set) { for (unsigned short sam = 0; sam < channelDataSamplesPerChannel; ++sam) { for (unsigned short chan = 0; chan < channelDataChannelsPerDataset; ++chan) { noOffset[set*channelDataSamplesPerChannel*channelDataChannelsPerDataset + sam * channelDataChannelsPerDataset + chan] = rfDataChannelData[set*channelDataSamplesPerChannel*channelDataChannelsPerDataset + sam * channelDataChannelsPerDataset + chan] - offset; // this offset in the raw Images is given by the API... } } } mitk::Image::Pointer rawImageUS = mitk::Image::New(); mitk::Image::Pointer rawImagePA = mitk::Image::New(); unsigned int dim[3]; dim[0] = channelDataChannelsPerDataset; dim[1] = channelDataSamplesPerChannel; dim[2] = 1; mitk::Vector3D rawSpacing; rawSpacing[0] = m_Device->GetScanMode().transducerPitchMeter * 1000; // save in mm rawSpacing[1] = m_Device->GetScanMode().receivePhaseLengthSeconds / channelDataSamplesPerChannel * 1000000; // save in us rawSpacing[2] = 1; rawImagePA->Initialize(mitk::MakeScalarPixelType(), 3, dim); dim[2] = channelDataTotalDatasets - 1; rawImageUS->Initialize(mitk::MakeScalarPixelType(), 3, dim); rawImagePA->SetSpacing(rawSpacing); rawImageUS->SetSpacing(rawSpacing); if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) { rawImagePA->SetImportVolume(noOffset, 0, 0, mitk::Image::RtlCopyMemory); //rawImageUS->SetImportVolume(&noOffset[channelDataChannelsPerDataset*channelDataSamplesPerChannel], 0, 0, mitk::Image::RtlCopyMemory); } else { //rawImageUS->SetImportVolume(noOffset, 0, 0, mitk::Image::RtlCopyMemory); } // save the raw images when recording m_RawRecordedImages.push_back(std::pair(rawImagePA, rawImageUS)); delete[] noOffset; } if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) { itk::Index<3> pixel = { { (itk::Index<3>::IndexValueType)(imagePA->GetDimension(0) / 2), (itk::Index<3>::IndexValueType)(22.0 / 532.0*m_Device->GetScanMode().reconstructionSamplesPerLine), 0 } }; //22/532*2048 = 84 if (!m_Pyro->IsSyncDelaySet() && (imagePA->GetPixelValueByIndex(pixel) < -30)) // #MagicNumber { MITK_INFO << "Setting SyncDelay now"; m_Pyro->SetSyncDelay(m_CurrentImageTimestamp); } } m_ImageTimestampBuffer[(m_LastWrittenImage + 1) % m_BufferSize] = m_CurrentImageTimestamp; m_ImageBuffer[(m_LastWrittenImage + 1) % m_BufferSize] = std::pair(imagePA, imageUS); m_LastWrittenImage = (m_LastWrittenImage + 1) % m_BufferSize; // if the user decides to start recording, we feed the vector the generated images if (m_CurrentlyRecording) { m_RecordedImages.push_back(std::pair(imagePA, imageUS)); m_ImageTimestampRecord.push_back(m_CurrentImageTimestamp); // save timestamps for each PA image! if (m_RecordedImages.size() % m_SaveInterval == 0 && m_RecordedImages.size() != 0) { m_SaveThreads.push_back(std::thread(&USDiPhASImageSource::saveDataThread, this, m_RecordedImages.size() - (size_t)m_SaveInterval, m_RecordedImages.size())); } } } } void mitk::USDiPhASImageSource::UpdateImageGeometry() { MITK_INFO << "Retreaving Image Geometry Information for Spacing..."; float& recordTime = m_Device->GetScanMode().receivePhaseLengthSeconds; int& speedOfSound = m_Device->GetScanMode().averageSpeedOfSound; float& pitch = m_Device->GetScanMode().reconstructedLinePitchMmOrAngleDegree; int& reconstructionLines = m_Device->GetScanMode().reconstructionLines; switch (m_DataType) { case DataType::Image_uChar : { int& imageWidth = m_Device->GetScanMode().imageWidth; int& imageHeight = m_Device->GetScanMode().imageHeight; m_ImageSpacing[0] = pitch * reconstructionLines / imageWidth; m_ImageSpacing[1] = recordTime * speedOfSound / 2 * 1000 / imageHeight; break; } case DataType::Beamformed_Short : { int& imageWidth = reconstructionLines; int& imageHeight = m_Device->GetScanMode().reconstructionSamplesPerLine; m_ImageSpacing[0] = pitch; m_ImageSpacing[1] = recordTime * speedOfSound / 2 * 1000 / imageHeight; break; } } m_ImageSpacing[2] = 1; MITK_INFO << "Retreaving Image Geometry Information for Spacing " << m_ImageSpacing[0] << " ... " << m_ImageSpacing[1] << " ... " << m_ImageSpacing[2] << " ...[DONE]"; } void mitk::USDiPhASImageSource::ModifyDataType(DataType dataT) { m_DataTypeModified = true; m_DataTypeNext = dataT; } void mitk::USDiPhASImageSource::ModifyUseBModeFilter(bool isSet) { m_UseBModeFilterModified = true; m_UseBModeFilterNext = isSet; } void mitk::USDiPhASImageSource::ModifyScatteringCoefficient(int coeff) { m_ScatteringCoefficientNext = coeff; m_ScatteringCoefficientModified = true; } void mitk::USDiPhASImageSource::ModifyCompensateForScattering(bool useIt) { m_CompensateForScatteringNext = useIt; m_CompensateForScatteringModified = true; } void mitk::USDiPhASImageSource::ModifyEnergyCompensation(bool compensate) { m_CompensateEnergyNext = compensate; m_CompensateEnergyModified = true; } void mitk::USDiPhASImageSource::SetDataType(DataType dataT) { if (dataT != m_DataType) { m_DataType = dataT; MITK_INFO << "Setting new DataType..." << dataT; switch (m_DataType) { case DataType::Image_uChar : MITK_INFO << "height: " << m_Device->GetScanMode().imageHeight << " width: " << m_Device->GetScanMode().imageWidth; break; case DataType::Beamformed_Short : MITK_INFO << "samples: " << m_Device->GetScanMode().reconstructionSamplesPerLine << " lines: " << m_Device->GetScanMode().reconstructionLines; break; } } } void mitk::USDiPhASImageSource::SetUseBModeFilter(bool isSet) { m_UseBModeFilter = isSet; } void mitk::USDiPhASImageSource::SetVerticalSpacing(float mm) { m_VerticalSpacingNext = mm; m_VerticalSpacingModified = true; } void mitk::USDiPhASImageSource::SetSavingSettings(SavingSettings settings) { m_SavingSettings = settings; } void mitk::USDiPhASImageSource::SetSavingName(std::string name) { if (name == "") { m_SavingName = "-replace"; } else { m_SavingName = name; } } // this is just a little function to set the filenames below right inline void replaceAll(std::string& str, const std::string& from, const std::string& to) { if (from.empty()) return; size_t start_pos = 0; while ((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' } } void mitk::USDiPhASImageSource::SetRecordingStatus(bool record) { // start the recording process if (record) { m_RecordedImages.clear(); m_RawRecordedImages.clear(); // we make sure there are no leftovers m_ImageTimestampRecord.clear(); // also for the timestamps m_PixelValues.clear(); // aaaand for the pixel values if (m_SavingSettings.saveRaw) { m_Device->GetScanMode().transferChannelData = true; m_Device->UpdateScanmode(); // set the raw Data to be transfered } // tell the callback to start recording images m_CurrentlyRecording = true; //save the settings! // get the time and date time_t time = std::time(nullptr); time_t* timeptr = &time; std::string currentDate = std::ctime(timeptr); replaceAll(currentDate, ":", "-"); currentDate.pop_back(); if (m_SavingName == "-replace") { - m_SavingName = currentDate; + m_SavingName = "c:\\ImageData\\" + currentDate; } - std::string pathS = "d:\\ImageData\\" + m_SavingName + ".settings" + ".txt"; + std::string pathS = m_SavingName + ".settings" + ".txt"; ofstream settingsFile; settingsFile.open(pathS); auto& sM = m_Device->GetScanMode(); settingsFile << "[General Parameters]\n"; settingsFile << "Scan Depth [mm] = " << sM.receivePhaseLengthSeconds * sM.averageSpeedOfSound / 2 * 1000 << "\n"; settingsFile << "Speed of Sound [m/s] = " << sM.averageSpeedOfSound << "\n"; settingsFile << "Excitation Frequency [MHz] = " << sM.transducerFrequencyHz / 1000000 << "\n"; settingsFile << "Voltage [V] = " << sM.voltageV << "\n"; settingsFile << "TGC min = " << (int)sM.tgcdB[0] << " max = " << (int)sM.tgcdB[7] << "\n"; settingsFile << "[Beamforming Parameters]\n"; settingsFile << "Reconstructed Lines = " << sM.reconstructionLines << "\n"; settingsFile << "Samples per Line = " << sM.reconstructionSamplesPerLine << "\n"; settingsFile.close(); } // save images, end recording, and clean up else { m_CurrentlyRecording = false; m_Device->GetScanMode().transferChannelData = false; // make sure raw Channel Data is not transferred anymore! m_Device->UpdateScanmode(); if (m_SaveThreads.size() * m_SaveInterval != m_RecordedImages.size()) { m_SaveThreads.push_back(std::thread(&USDiPhASImageSource::saveDataThread, this, m_SaveThreads.size() * m_SaveInterval, m_RecordedImages.size())); } // wait for all saving Threads to finish for (size_t i = 0; i < m_SaveThreads.size(); ++i) { m_SaveThreads[i].join(); } m_PixelValues.clear(); // clean up the pixel values m_RawRecordedImages.clear(); m_RecordedImages.clear(); // clean up the images m_ImageTimestampRecord.clear(); // clean up the timestamps m_SaveThreads.clear(); // clean up all threads m_SavingName = "-replace"; } } void mitk::USDiPhASImageSource::GetPixelValues(itk::Index<3> pixel, std::vector& values, unsigned int pos1, unsigned int pos2) { unsigned int events = 2; for (unsigned int index = pos1; index < pos2; ++index) // omit sound images { Image::Pointer image = m_RecordedImages[index].first; if (image != nullptr && image.IsNotNull()) { image = ApplyBmodeFilter(image); values.push_back(image.GetPointer()->GetPixelValueByIndex(pixel)); } } } void mitk::USDiPhASImageSource::OrderImagesInterleaved(Image::Pointer PAImage, Image::Pointer USImage, std::vector> recordedList, bool raw) { unsigned int width = 32; unsigned int height = 32; unsigned int events = m_Device->GetScanMode().transmitEventsCount; if (!raw) events = 1; // the beamformed image array contains only the resulting image of multiple events if (raw) { width = recordedList.at(0).first->GetDimension(0); height = recordedList.at(0).first->GetDimension(1); } else if (m_DataType == DataType::Beamformed_Short) { width = m_Device->GetScanMode().reconstructionLines; height = m_Device->GetScanMode().reconstructionSamplesPerLine; } else if (m_DataType == DataType::Image_uChar) { width = m_Device->GetScanMode().imageWidth; height = m_Device->GetScanMode().imageHeight; } unsigned int dimLaser[] = { width, height, (unsigned int)recordedList.size()}; unsigned int dimSound[] = { width, height, (unsigned int)(recordedList.size() * events)}; PAImage->Initialize(recordedList.back().first->GetPixelType(), 3, dimLaser); PAImage->SetSpacing(recordedList.back().first->GetGeometry()->GetSpacing()); USImage->Initialize(recordedList.back().first->GetPixelType(), 3, dimSound); USImage->SetSpacing(recordedList.back().first->GetGeometry()->GetSpacing()); for (int index = 0; index < recordedList.size(); ++index) { mitk::ImageReadAccessor inputReadAccessorPA(recordedList.at(index).first); PAImage->SetSlice(inputReadAccessorPA.GetData(), index); for (unsigned int i = 0; i < events; ++i) { mitk::ImageReadAccessor inputReadAccessorUS(recordedList.at(index).second, recordedList.at(index).second->GetSliceData(i)); USImage->SetSlice(inputReadAccessorUS.GetData(), index + i); } } } void mitk::USDiPhASImageSource::OrderImagesUltrasound(Image::Pointer USImage, std::vector> recordedList) { unsigned int width = 32; unsigned int height = 32; unsigned int events = m_Device->GetScanMode().transmitEventsCount; if (m_DataType == DataType::Beamformed_Short) { width = (unsigned int)m_Device->GetScanMode().reconstructionLines; height = (unsigned int)m_Device->GetScanMode().reconstructionSamplesPerLine; } else if (m_DataType == DataType::Image_uChar) { width = (unsigned int)m_Device->GetScanMode().imageWidth; height = (unsigned int)m_Device->GetScanMode().imageHeight; } unsigned int dimSound[] = { width, height, (unsigned int)(recordedList.size() * events) }; USImage->Initialize(recordedList.back().second->GetPixelType(), 3, dimSound); USImage->SetSpacing(recordedList.back().second->GetGeometry()->GetSpacing()); for (int index = 0; index < recordedList.size(); ++index) { for (unsigned int i = 0; i < events; ++i) { mitk::ImageReadAccessor inputReadAccessorUS(recordedList.at(index).second, recordedList.at(index).second->GetSliceData(i)); USImage->SetSlice(inputReadAccessorUS.GetData(), index + i); } } } void mitk::USDiPhASImageSource::saveDataThread(size_t pos1, size_t pos2) { char postfix[25]; if(pos2 % m_SaveInterval == 0) sprintf(postfix, "%03d", (int)(pos2 / m_SaveInterval)); else { int am = pos1 / m_SaveInterval + 1; sprintf(postfix, "%03d", am); } // initialize file paths and the images Image::Pointer PAImage = Image::New(); Image::Pointer USImage = Image::New(); - std::string pathPA = "d:\\ImageData\\" + m_SavingName + ".PA.bf." + postfix + ".nrrd"; - std::string pathUS = "d:\\ImageData\\" + m_SavingName + ".US.bf." + postfix + ".nrrd"; - std::string pathTS = "d:\\ImageData\\" + m_SavingName + ".ts." + postfix + ".csv"; + std::string pathPA = m_SavingName + ".PA.bf." + postfix + ".nrrd"; + std::string pathUS = m_SavingName + ".US.bf." + postfix + ".nrrd"; + std::string pathTS = m_SavingName + ".ts." + postfix + ".csv"; // raw Images (if chosen to be saved) Image::Pointer PAImageRaw = Image::New(); Image::Pointer USImageRaw = Image::New(); - std::string pathPARaw = "d:\\ImageData\\" + m_SavingName + ".PA.rf." + postfix + ".nrrd"; - std::string pathUSRaw = "d:\\ImageData\\" + m_SavingName + ".US.rf." + postfix + ".nrrd"; + std::string pathPARaw = m_SavingName + ".PA.rf." + postfix + ".nrrd"; + std::string pathUSRaw = m_SavingName + ".US.rf." + postfix + ".nrrd"; if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) // save a PAImage if we used interleaved mode { - // first, save the timestamp data - m_Pyro->SaveData(); + // first, save the pyro data + m_Pyro->SaveData(m_SavingName + ".pyro." + postfix + ".csv"); // create subvectors std::vector>::const_iterator first = m_RecordedImages.begin() + pos1; std::vector>::const_iterator last = m_RecordedImages.begin() + pos2; std::vector> subRecordedImages(first, last); std::vector>::const_iterator firstRaw = m_RawRecordedImages.begin() + pos1; std::vector>::const_iterator lastRaw = m_RawRecordedImages.begin() + pos2; - std::vector> subRawRecordedImages(first, last); + std::vector> subRawRecordedImages(firstRaw, lastRaw); // now order the images and save them // the beamformed ones... + + OrderImagesInterleaved(PAImage, USImage, subRecordedImages, false); + mitk::IOUtil::Save(USImage, pathUS); if (m_SavingSettings.saveBeamformed) { - OrderImagesInterleaved(PAImage, USImage, subRecordedImages, false); - mitk::IOUtil::Save(USImage, pathUS); mitk::IOUtil::Save(PAImage, pathPA); } // ...and the raw images if (m_SavingSettings.saveRaw) { OrderImagesInterleaved(PAImageRaw, USImageRaw, subRawRecordedImages, true); // mitk::IOUtil::Save(USImageRaw, pathUSRaw); mitk::IOUtil::Save(PAImageRaw, pathPARaw); } std::vector pixelValues; // read the pixelvalues of the enveloped images at this position if (subRecordedImages[0].first != nullptr && subRecordedImages[0].first.IsNotNull()) { itk::Index<3> pixel = { { (itk::Index<3>::IndexValueType)(subRecordedImages[0].first->GetDimension(0) / 2), (itk::Index<3>::IndexValueType)(22.0 / 532.0*m_Device->GetScanMode().reconstructionSamplesPerLine), 0 } }; //22/532*2048 = 84 GetPixelValues(pixel, pixelValues, pos1, pos2); // write the Pixelvalues to m_PixelValues } // save the timestamps! ofstream timestampFile; timestampFile.open(pathTS); timestampFile << ",timestamp,pixelvalue"; // write the header for (size_t index = pos1; index < pos2; ++index) { timestampFile << "\n" << index << "," << m_ImageTimestampRecord[index] << "," << pixelValues[index - pos1]; } timestampFile.close(); } else if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::PlaneWaveCompound) // save no PAImage if we used US only mode { std::vector>::const_iterator first = m_RecordedImages.begin() + pos1; std::vector>::const_iterator last = m_RecordedImages.begin() + pos2; std::vector> subRecordedImages(first, last); OrderImagesUltrasound(USImage, subRecordedImages); mitk::IOUtil::Save(USImage, pathUS); } // remove the images from the vectors for (size_t i = pos1; i < pos2; ++i) { m_RecordedImages[i] = std::pair(nullptr, nullptr); } if (m_SavingSettings.saveRaw) { for (size_t i = pos1; i < pos2; ++i) { m_RawRecordedImages[i] = std::pair(nullptr, nullptr); } } MITK_INFO << "The saving Thread from " << pos1 << " to " << pos2 << " has finished."; } \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp index 41ec92d56d..92bf7221f2 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp @@ -1,417 +1,454 @@ /*=================================================================== 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() { m_ControlInterface = dynamic_cast (this->GetDevice()->GetControlInterfaceCustom().GetPointer()); 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.IsNull() ) { MITK_WARN("QmitkUSAbstractCustomWidget")("QmitkUSControlsCustomDiPhASDeviceWidget") << "Did not get a custom device control interface."; } //now pass the default values m_OldReconstructionLines = 0; m_ControlInterface->SetSilentUpdate(true); // don't update the scanmode everytime OnTransmitPhaseLengthChanged(); OnExcitationFrequencyChanged(); OnTransmitEventsChanged(); OnVoltageChanged(); OnScanDepthChanged(); // HERE OnAveragingCountChanged(); - OnTGCMinChanged(); - OnTGCMaxChanged(); + OnTGCChanged(); OnDataTypeChanged(); OnPitchChanged(); OnReconstructedSamplesChanged(); OnReconstructedLinesChanged(); OnSpeedOfSoundChanged(); OnBandpassEnabledChanged(); OnLowCutChanged(); OnHighCutChanged(); OnUseBModeFilterChanged(); // HERE OnVerticalSpacingChanged(); OnScatteringCoefficientChanged(); OnCompensateScatteringChanged(); OnChangedSavingSettings(); OnCompensateEnergyChanged(); + OnSaveNameChanged(); m_ControlInterface->SetSilentUpdate(false); // on the last update pass the scanmode and geometry! OnModeChanged(); // HERE } void QmitkUSControlsCustomDiPhASDeviceWidget::Initialize() { ui->setupUi(this); connect(ui->CompensateEnergy, SIGNAL(stateChanged(int)), this, SLOT(OnCompensateEnergyChanged())); connect(ui->UseBModeFilter, SIGNAL(stateChanged(int)), this, SLOT(OnUseBModeFilterChanged())); connect(ui->StartStopRecord, SIGNAL(clicked()), this, SLOT(OnRecordChanged())); connect(ui->ScatteringCoefficient, SIGNAL(valueChanged(int)), this, SLOT(OnScatteringCoefficientChanged())); connect(ui->CompensateScattering, SIGNAL(stateChanged(int)), this, SLOT(OnCompensateScatteringChanged())); connect(ui->VerticalSpacing, SIGNAL(valueChanged(double)), this, SLOT(OnVerticalSpacingChanged())); connect(ui->SaveBeamformed, SIGNAL(stateChanged(int)), this, SLOT(OnChangedSavingSettings())); connect(ui->SaveRaw, SIGNAL(stateChanged(int)), this, SLOT(OnChangedSavingSettings())); //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->TimeGainCompensationMinSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCMinChanged())); - connect(ui->TimeGainCompensationMaxSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCMaxChanged())); + connect(ui->TimeGainCompensation0Slider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCChanged())); + connect(ui->TimeGainCompensation1Slider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCChanged())); + connect(ui->TimeGainCompensation2Slider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCChanged())); + connect(ui->TimeGainCompensation3Slider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCChanged())); + connect(ui->TimeGainCompensation4Slider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCChanged())); + connect(ui->TimeGainCompensation5Slider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCChanged())); + connect(ui->TimeGainCompensation6Slider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCChanged())); + connect(ui->TimeGainCompensation7Slider, SIGNAL(valueChanged(int)), this, SLOT(OnTGCChanged())); 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())); connect(ui->RecordingName, SIGNAL(textChanged()), this, SLOT(OnSaveNameChanged())); } //slots void QmitkUSControlsCustomDiPhASDeviceWidget::OnCompensateEnergyChanged() { if (m_ControlInterface.IsNull()) { return; } bool CompensateEnergy = ui->CompensateEnergy->isChecked(); m_ControlInterface->SetCompensateEnergy(CompensateEnergy); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnUseBModeFilterChanged() { if (m_ControlInterface.IsNull()) { return; } bool UseBModeFilter = ui->UseBModeFilter->isChecked(); m_ControlInterface->SetUseBModeFilter(UseBModeFilter); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnSaveNameChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetSavingName(ui->RecordingName->toPlainText().toStdString()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnRecordChanged() { if (m_ControlInterface.IsNull()) { return; } if (ui->StartStopRecord->text() == "Start Recording") { ui->StartStopRecord->setText("Stop Recording"); ui->UseBModeFilter->setEnabled(false); ui->ScatteringCoefficient->setEnabled(false); ui->CompensateScattering->setEnabled(false); ui->VerticalSpacing->setEnabled(false); ui->SaveBeamformed->setEnabled(false); ui->SaveRaw->setEnabled(false); ui->TransmitPhaseLength->setEnabled(false); ui->ExcitationFrequency->setEnabled(false); ui->TransmitEvents->setEnabled(false); ui->Voltage->setEnabled(false); ui->Mode->setEnabled(false); ui->ScanDepth->setEnabled(false); ui->AveragingCount->setEnabled(false); - ui->TimeGainCompensationMinSlider->setEnabled(false); - ui->TimeGainCompensationMaxSlider->setEnabled(false); + ui->TimeGainCompensation0Slider->setEnabled(false); + ui->TimeGainCompensation1Slider->setEnabled(false); + ui->TimeGainCompensation2Slider->setEnabled(false); + ui->TimeGainCompensation3Slider->setEnabled(false); + ui->TimeGainCompensation4Slider->setEnabled(false); + ui->TimeGainCompensation5Slider->setEnabled(false); + ui->TimeGainCompensation6Slider->setEnabled(false); + ui->TimeGainCompensation7Slider->setEnabled(false); ui->DataType->setEnabled(false); ui->PitchOfTransducer->setEnabled(false); ui->ReconstructedSamplesPerLine->setEnabled(false); ui->ReconstructedLines->setEnabled(false); ui->SpeedOfSound->setEnabled(false); ui->BandpassEnabled->setEnabled(false); ui->LowCut->setEnabled(false); ui->HighCut->setEnabled(false); ui->CompensateEnergy->setEnabled(false); m_ControlInterface->SetRecord(true); } else { + size_t index_ = ui->RecordingName->toPlainText().toStdString().find_last_of('_'); + if(std::string::npos == index_) + ui->RecordingName->setPlainText(ui->RecordingName->toPlainText() + "_1"); + else + { + std::string oldName = ui->RecordingName->toPlainText().toStdString(); + int number = std::stoi(oldName.substr(index_ + 1, oldName.length() - index_)) + 1; + std::string newName = oldName.substr(0, index_ + 1) + std::to_string(number); + ui->RecordingName->setPlainText(QString::fromStdString(newName)); + } + + ui->StartStopRecord->setText("Start Recording"); ui->UseBModeFilter->setEnabled(true); ui->CompensateScattering->setEnabled(true); if(ui->CompensateScattering->isChecked()) ui->ScatteringCoefficient->setEnabled(true); ui->VerticalSpacing->setEnabled(true); ui->SaveBeamformed->setEnabled(true); ui->SaveRaw->setEnabled(true); ui->TransmitPhaseLength->setEnabled(true); ui->ExcitationFrequency->setEnabled(true); ui->TransmitEvents->setEnabled(true); ui->Voltage->setEnabled(true); ui->Mode->setEnabled(true); ui->ScanDepth->setEnabled(true); ui->AveragingCount->setEnabled(true); - ui->TimeGainCompensationMinSlider->setEnabled(true); - ui->TimeGainCompensationMaxSlider->setEnabled(true); + ui->TimeGainCompensation0Slider->setEnabled(true); + ui->TimeGainCompensation1Slider->setEnabled(true); + ui->TimeGainCompensation2Slider->setEnabled(true); + ui->TimeGainCompensation3Slider->setEnabled(true); + ui->TimeGainCompensation4Slider->setEnabled(true); + ui->TimeGainCompensation5Slider->setEnabled(true); + ui->TimeGainCompensation6Slider->setEnabled(true); + ui->TimeGainCompensation7Slider->setEnabled(true); ui->DataType->setEnabled(true); ui->PitchOfTransducer->setEnabled(true); ui->ReconstructedSamplesPerLine->setEnabled(true); ui->ReconstructedLines->setEnabled(true); ui->SpeedOfSound->setEnabled(true); ui->BandpassEnabled->setEnabled(true); ui->LowCut->setEnabled(true); ui->HighCut->setEnabled(true); ui->CompensateEnergy->setEnabled(true); m_ControlInterface->SetRecord(false); } } void QmitkUSControlsCustomDiPhASDeviceWidget::OnVerticalSpacingChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetVerticalSpacing(ui->VerticalSpacing->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnScatteringCoefficientChanged() { if (m_ControlInterface.IsNull()) { return; } m_ControlInterface->SetScatteringCoefficient(ui->ScatteringCoefficient->value()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnCompensateScatteringChanged() { if (m_ControlInterface.IsNull()) { return; } if (ui->CompensateScattering->isChecked()) ui->ScatteringCoefficient->setEnabled(true); else ui->ScatteringCoefficient->setEnabled(false); m_ControlInterface->SetCompensateScattering(ui->CompensateScattering->isChecked()); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnChangedSavingSettings() { if (m_ControlInterface.IsNull()) { return; } mitk::USDiPhASDeviceCustomControls::SavingSettings settings; settings.saveBeamformed = ui->SaveBeamformed->isChecked(); settings.saveRaw = ui->SaveRaw->isChecked(); m_ControlInterface->SetSavingSettings(settings); } //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; } 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(1); } 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->TimeGainCompensationMinSlider->value(); - int tgcMax = ui->TimeGainCompensationMaxSlider->value(); - if (tgcMin > tgcMax) { - ui->TimeGainCompensationMinSlider->setValue(tgcMax); - MITK_INFO << "User tried to set tgcMin>tgcMax."; - } - QString text("TGC min = " + QString::fromStdString(std::to_string(ui->TimeGainCompensationMinSlider->value()))); - ui->TimeGainCompensationMinLabel->setText(text); - m_ControlInterface->SetTGCMin(ui->TimeGainCompensationMinSlider->value()); -} -void QmitkUSControlsCustomDiPhASDeviceWidget::OnTGCMaxChanged() +void QmitkUSControlsCustomDiPhASDeviceWidget::OnTGCChanged() { if (m_ControlInterface.IsNull()) { return; } - int tgcMin = ui->TimeGainCompensationMinSlider->value(); - int tgcMax = ui->TimeGainCompensationMaxSlider->value(); - if (tgcMin > tgcMax) { - ui->TimeGainCompensationMaxSlider->setValue(tgcMin); - MITK_INFO << "User tried to set tgcMin>tgcMax."; - } - QString text("TGC max = "+QString::fromStdString(std::to_string(ui->TimeGainCompensationMaxSlider->value()))); - ui->TimeGainCompensationMaxLabel->setText(text); - m_ControlInterface->SetTGCMax(ui->TimeGainCompensationMaxSlider->value()); + int tgc[8]; + + tgc[0] = ui->TimeGainCompensation0Slider->value(); + tgc[1] = ui->TimeGainCompensation1Slider->value(); + tgc[2] = ui->TimeGainCompensation2Slider->value(); + tgc[3] = ui->TimeGainCompensation3Slider->value(); + tgc[4] = ui->TimeGainCompensation4Slider->value(); + tgc[5] = ui->TimeGainCompensation5Slider->value(); + tgc[6] = ui->TimeGainCompensation6Slider->value(); + tgc[7] = ui->TimeGainCompensation7Slider->value(); + + QString label[8]; + + label[0] = QString::fromStdString(std::to_string(ui->TimeGainCompensation0Slider->value())); + label[1] = QString::fromStdString(std::to_string(ui->TimeGainCompensation1Slider->value())); + label[2] = QString::fromStdString(std::to_string(ui->TimeGainCompensation2Slider->value())); + label[3] = QString::fromStdString(std::to_string(ui->TimeGainCompensation3Slider->value())); + label[4] = QString::fromStdString(std::to_string(ui->TimeGainCompensation4Slider->value())); + label[5] = QString::fromStdString(std::to_string(ui->TimeGainCompensation5Slider->value())); + label[6] = QString::fromStdString(std::to_string(ui->TimeGainCompensation6Slider->value())); + label[7] = QString::fromStdString(std::to_string(ui->TimeGainCompensation7Slider->value())); + ui->TimeGainCompensation0Label->setText(label[0]); + ui->TimeGainCompensation1Label->setText(label[1]); + ui->TimeGainCompensation2Label->setText(label[2]); + ui->TimeGainCompensation3Label->setText(label[3]); + ui->TimeGainCompensation4Label->setText(label[4]); + ui->TimeGainCompensation5Label->setText(label[5]); + ui->TimeGainCompensation6Label->setText(label[6]); + ui->TimeGainCompensation7Label->setText(label[7]); + m_ControlInterface->SetTGC(tgc); } void QmitkUSControlsCustomDiPhASDeviceWidget::OnDataTypeChanged() { if (m_ControlInterface.IsNull()) { return; } QString DataType = ui->DataType->currentText(); if (DataType == "Image Data") { m_ControlInterface->SetDataType(mitk::USDiPhASDeviceCustomControls::DataType::Image_uChar); } else if (DataType == "Beamformed Data") { m_ControlInterface->SetDataType(mitk::USDiPhASDeviceCustomControls::DataType::Beamformed_Short); } } //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; } if (m_OldReconstructionLines == 0) m_OldReconstructionLines = ui->ReconstructedLines->value(); m_ControlInterface->SetReconstructedLines(ui->ReconstructedLines->value()); ui->PitchOfTransducer->setValue(ui->PitchOfTransducer->value()*((double)m_OldReconstructionLines / (double)ui->ReconstructedLines->value())); m_OldReconstructionLines = 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 9283bb1ade..b81a0431d7 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.h @@ -1,117 +1,116 @@ /*=================================================================== 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 OnCompensateEnergyChanged(); virtual void OnUseBModeFilterChanged(); virtual void OnVerticalSpacingChanged(); virtual void OnRecordChanged(); virtual void OnScatteringCoefficientChanged(); virtual void OnCompensateScatteringChanged(); virtual void OnChangedSavingSettings(); virtual void OnSaveNameChanged(); //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 OnTGCChanged(); virtual void OnDataTypeChanged(); //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; int m_OldReconstructionLines; }; #endif // QmitkUSControlsCustomDiPhASDeviceWidget_H \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui index 7e9ba5d394..23fc8bc311 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui @@ -1,649 +1,784 @@ QmitkUSControlsCustomDiPhASDeviceWidget 0 0 351 - 903 + 974 Form <html><head/><body><p><span style=" font-weight:600;">Record Images</span></p></body></html> Save Beamformed + + true + Save Raw + + true + 250 50 + + E:/ImageData/recordingName + 100 25 Start Recording Qt::Horizontal 40 20 - + - <html><head/><body><p><span style=" font-weight:600;">Receive Parameters</span></p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Beamforming Parameters</span></p></body></html> - + + + + + 256 + + + 4096 + + + 256 + + + 2048 + + + + + + + 3 + + + 0.005000000000000 + + + 10.000000000000000 + + + 0.005000000000000 + + + 0.150000000000000 + + + + + + + Qt::PreventContextMenu + + + 128 + + + 1024 + + + 128 + + + 256 + + + + + + + Samples per Line + + + + + + + Reconstructed Lines + + + + + + + 1000 + + + 1000000 + + + 5 + + + 1480 + + + - + - Averaging Count + Speed of Sound [m/s] + + + + + + + Pitch of Transducer [mm] + + + + + + <html><head/><body><p><span style=" font-weight:600;">Receive Parameters</span></p></body></html> + + + + + 1 100 1 - - - - false + + + + Averaging Count - - - Beamformed Data - - - - - Image Data - - - + 0 0 0 0 16777215 16777215 42 - 10 + 0 Qt::Horizontal - - + + + + Scan Depth [mm] + + + + + 42 - 20 + 42 Qt::Horizontal 0 - - + + - Scan Depth [mm] + DataType - - - - DataType + + + + false + + + Beamformed Data + + + + + Image Data + + 3.000000000000000 200.000000000000000 - 50.000000000000000 + 40.000000000000000 - - + + TGC Max - + TGC Min - - - - - - - - Compensate Fluence For Scattering + + + + 42 + + + 38 + + + Qt::Horizontal - - - - - - false - - - 5 - - - 25 - - - 15 - - - - - - - false - - - Avg. μs' [1/cm] - - - - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Beamforming Parameters</span></p></body></html> - - - - - - - - - 256 - + + - 4096 - - - 256 + 42 - 2048 + 34 + + + Qt::Horizontal - - - - 0.010000000000000 - - - 0.050000000000000 + + + + 42 - 0.300000000000000 + 36 + + + Qt::Horizontal - - - - Qt::PreventContextMenu + + + + 42 - - 128 + + 42 + + Qt::Horizontal + + + + + - 1024 + 42 - - 128 + + 40 + + + Qt::Horizontal + + + + + + + 42 - 128 + 42 + + + Qt::Horizontal - - + + - Samples per Line + TextLabel - - + + - Reconstructed Lines + TextLabel - - - - 1000 - - - 1000000 + + + + TextLabel - - 5 + + + + + + TextLabel - - 1480 + + + + + + TextLabel - - + + - Speed of Sound [m/s] + TextLabel - - + + + + + + - Pitch of Transducer [mm] + Compensate Fluence For Scattering + + + + + + false + + + 5 + + + 25 + + + 15 + + + + + + + false + + + Avg. μs' [1/cm] + + + + + <html><head/><body><p><span style=" font-weight:600;">Display Parameters</span></p></body></html> Envelope Filter true Compensate Energy Values 0.010000000000000 1.200000000000000 0.050000000000000 - 0.300000000000000 + 0.100000000000000 Vertical Spacing <html><head/><body><p><span style=" font-weight:600;">Transmit Parameters</span></p></body></html> 1.000000000000000 15.000000000000000 0.100000000000000 7.500000000000000 1 11 - 2 + 1 - 1 + 3 Transmit Events true false 1 1.000000000000000 10000.000000000000000 4.000000000000000 Transmit Phase Length [us] Excitation Frequency [MHz] false Interleaved Ultrasound only false - 6 + 0 75 - 70 + 5 Voltage [V] Mode false <html><head/><body><p><span style=" font-weight:600;">Bandpass Parameters</span></p></body></html> false High Cut [MHz] false Low Cut [MHz] false Bandpass Enabled false false 5.000000000000000 false Off On Qt::Vertical 20 40 diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp index 7fd7f0345e..33fec65be1 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp @@ -1,208 +1,208 @@ /*=================================================================== 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 #include "mitkScaleLegendAnnotation.h" #include "mitkLayoutAnnotationRenderer.h" #include "mitkManualPlacementAnnotationRenderer.h" #include "mitkTextAnnotation2D.h" #include "QmitkPAUSViewerView.h" #include #include const std::string QmitkPAUSViewerView::VIEW_ID = "org.mitk.views.photoacoustics.pausviewer"; QmitkPAUSViewerView::QmitkPAUSViewerView() : m_PADataStorage(mitk::StandaloneDataStorage::New()), m_USDataStorage(mitk::StandaloneDataStorage::New()) { } QmitkPAUSViewerView::~QmitkPAUSViewerView() { this->GetDataStorage()->AddNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); this->GetDataStorage()->AddNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::RemovedNodeFromStorage)); this->GetDataStorage()->ChangedNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); } void QmitkPAUSViewerView::InitWindows() { AddOverlays(); } void QmitkPAUSViewerView::SetFocus() { } void QmitkPAUSViewerView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& /*nodes*/) { } void QmitkPAUSViewerView::CreateQtPartControl(QWidget *parent) { MITK_INFO << "in here"; m_Controls = new Ui::QmitkPAUSViewerViewControls; m_Controls->setupUi(parent); SetPADataStorage(m_PADataStorage); SetUSDataStorage(m_USDataStorage); //create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); m_USData = mitk::DataNode::New(); std::stringstream USnodeName; USnodeName << "US Image Stream"; m_USData->SetName(USnodeName.str()); m_USData->SetData(dummyImage); m_USDataStorage->Add(m_USData); m_PAData = mitk::DataNode::New(); std::stringstream PAnodeName; PAnodeName << "PA Image Stream"; m_PAData->SetName(PAnodeName.str()); m_PAData->SetData(dummyImage); m_PADataStorage->Add(m_PAData); InitWindows(); this->GetDataStorage()->AddNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); this->GetDataStorage()->RemoveNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::RemovedNodeFromStorage)); this->GetDataStorage()->ChangedNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); ScanDataStorage(nullptr); } void QmitkPAUSViewerView::SetPADataStorage(mitk::StandaloneDataStorage::Pointer paStore) { if (m_Controls == nullptr) return; m_PADataStorage = paStore; m_Controls->m_PARenderWindow->GetRenderer()->SetDataStorage(m_PADataStorage); m_Controls->m_PALevelWindow->SetDataStorage(m_PADataStorage); } void QmitkPAUSViewerView::SetUSDataStorage(mitk::StandaloneDataStorage::Pointer usStore) { if (m_Controls == nullptr) return; m_USDataStorage = usStore; m_Controls->m_USRenderWindow->GetRenderer()->SetDataStorage(m_USDataStorage); m_Controls->m_USLevelWindow->SetDataStorage(m_USDataStorage); } vtkRenderWindow* QmitkPAUSViewerView::GetPARenderWindow() { if (m_Controls == nullptr) return nullptr; return m_Controls->m_PARenderWindow->GetRenderWindow(); } vtkRenderWindow* QmitkPAUSViewerView::GetUSRenderWindow() { if (m_Controls == nullptr) return nullptr; return m_Controls->m_USRenderWindow->GetRenderWindow(); } void QmitkPAUSViewerView::AddOverlays() { //if (m_PARenderer == nullptr || /*m_PAOverlayController == nullptr||*/ m_USRenderer == nullptr /*|| m_USOverlayController == nullptr*/) //{ m_PARenderer = mitk::BaseRenderer::GetInstance(GetPARenderWindow()); m_USRenderer = mitk::BaseRenderer::GetInstance(GetUSRenderWindow()); //} mitk::ScaleLegendAnnotation::Pointer scaleAnnotation = mitk::ScaleLegendAnnotation::New(); //scaleAnnotation->SetLeftAxisVisibility(true); //scaleAnnotation->SetRightAxisVisibility(false); //scaleAnnotation->SetRightAxisVisibility(false); //scaleAnnotation->SetTopAxisVisibility(false); //scaleAnnotation->SetCornerOffsetFactor(0); // Add Overlays //![TextAnnotation2D] // Create a textAnnotation2D mitk::TextAnnotation2D::Pointer textAnnotation = mitk::TextAnnotation2D::New(); textAnnotation->SetText("Test!"); // set UTF-8 encoded text to render textAnnotation->SetFontSize(40); textAnnotation->SetColor(1, 0, 0); // Set text color to red textAnnotation->SetOpacity(0.5); // The position of the Annotation can be set to a fixed coordinate on the display. mitk::Point2D pos; pos[0] = 10; pos[1] = 20; textAnnotation->SetPosition2D(pos); std::string rendererID = m_PARenderer->GetName(); // The LayoutAnnotationRenderer can place the TextAnnotation2D at some defined corner positions mitk::LayoutAnnotationRenderer::AddAnnotation( textAnnotation, rendererID, mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); mitk::LayoutAnnotationRenderer::AddAnnotation( textAnnotation, m_PARenderer.GetPointer(), mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); mitk::ManualPlacementAnnotationRenderer::AddAnnotation( textAnnotation, m_PARenderer.GetPointer()); mitk::LayoutAnnotationRenderer::AddAnnotation(scaleAnnotation.GetPointer(), m_PARenderer->GetName(), mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); mitk::LayoutAnnotationRenderer::AddAnnotation(scaleAnnotation.GetPointer(), m_USRenderer, mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); } void QmitkPAUSViewerView::RemoveOverlays() { // m_PAOverlayManager->RemoveAllOverlays(); } void QmitkPAUSViewerView::ScanDataStorage(const mitk::DataNode* dataNode) { auto storage = this->GetDataStorage(); - auto nodeUS = storage->GetNamedNode("US Viewing Stream - Image 0"); - auto nodePA = storage->GetNamedNode("US Viewing Stream - Image 1"); + auto nodeUS = storage->GetNamedNode("US Viewing Stream - Image 1"); + auto nodePA = storage->GetNamedNode("US Viewing Stream - Image 0"); if (nodeUS != nullptr) { m_USData->SetData(dynamic_cast(nodeUS->GetData())); } if (nodePA != nullptr) { m_PAData->SetData(dynamic_cast(nodePA->GetData())); } auto renderingManager = mitk::RenderingManager::GetInstance(); renderingManager->RequestUpdate(GetPARenderWindow()); renderingManager->RequestUpdate(GetUSRenderWindow()); } void QmitkPAUSViewerView::RemovedNodeFromStorage(const mitk::DataNode* dataNode) { auto nodeUS = m_USDataStorage->GetNamedNode(dataNode->GetName()); auto nodePA = m_PADataStorage->GetNamedNode(dataNode->GetName()); //create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); m_USData->SetData(dummyImage); m_PAData->SetData(dummyImage); } \ No newline at end of file