diff --git a/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp b/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp index 1d5280b178..de79cda569 100644 --- a/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp +++ b/Modules/PhotoacousticsHardware/mitkOphirPyro.cpp @@ -1,316 +1,314 @@ /*=================================================================== 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() { // 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 MakeFolder = "mkdir \"c:/DiPhASTimeStamps/" + currentDate + "\""; - system(MakeFolder.c_str()); - std::string pathTS = "c:\\DiPhASTimeStamps\\" + currentDate + " Timestamps" + ".csv"; + std::string pathTS = "c:\\ImageData\\" + currentDate + " pyro-ts" + ".csv"; 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() { SaveCsvData(); } bool mitk::OphirPyro::StopDataAcquisition() { if (ophirAPI.StopStream(m_DeviceHandle)) m_Streaming = false; 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 (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) { while (!m_PulseTime.size()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } 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 = ophirAPI.ScanUSB(); if (m_SerialNumber != 0) { 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/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp index f6ffd5ca7f..51e003dc0c 100644 --- a/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp +++ b/Modules/US/USControlInterfaces/mitkUSDiPhASDeviceCustomControls.cpp @@ -1,205 +1,206 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSDiPhASDeviceCustomControls.h" mitk::USDiPhASDeviceCustomControls::USDiPhASDeviceCustomControls(itk::SmartPointer device) : mitk::USAbstractControlInterface(device.GetPointer()), m_IsActive(false), silentUpdate(false) { } mitk::USDiPhASDeviceCustomControls::~USDiPhASDeviceCustomControls() { } void mitk::USDiPhASDeviceCustomControls::SetIsActive(bool isActive) { m_IsActive = isActive; } bool mitk::USDiPhASDeviceCustomControls::GetIsActive() { return m_IsActive; } void mitk::USDiPhASDeviceCustomControls::passGUIOut(std::function callback) {} void mitk::USDiPhASDeviceCustomControls::SetSilentUpdate(bool silent) { silentUpdate = silent; } bool mitk::USDiPhASDeviceCustomControls::GetSilentUpdate() { return silentUpdate; } //Set Functions void mitk::USDiPhASDeviceCustomControls::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) { this->OnSetTGCMin(min); } void mitk::USDiPhASDeviceCustomControls::SetTGCMax(int max) { this->OnSetTGCMax(max); + } 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) {} //Transmit void mitk::USDiPhASDeviceCustomControls::OnSetTransmitPhaseLength(double ms) {} void mitk::USDiPhASDeviceCustomControls::OnSetExcitationFrequency(double MHz) {} void mitk::USDiPhASDeviceCustomControls::OnSetTransmitEvents(int events) {} void mitk::USDiPhASDeviceCustomControls::OnSetVoltage(int voltage) {} void mitk::USDiPhASDeviceCustomControls::OnSetMode(bool interleaved) {} //Receive void mitk::USDiPhASDeviceCustomControls::OnSetScanDepth(double mm) {} void mitk::USDiPhASDeviceCustomControls::OnSetAveragingCount(int count) {} void mitk::USDiPhASDeviceCustomControls::OnSetTGCMin(int min) {} void mitk::USDiPhASDeviceCustomControls::OnSetTGCMax(int max) {} void mitk::USDiPhASDeviceCustomControls::OnSetDataType(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/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp index b4294741dd..04c01ba907 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp @@ -1,839 +1,839 @@ /*=================================================================== 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_UseGUIOutPut(false), m_DataType(DataType::Image_uChar), m_GUIOutput(nullptr), m_UseBModeFilter(false), m_CurrentlyRecording(false), m_DataTypeModified(true), m_DataTypeNext(DataType::Image_uChar), m_CurrentImageTimestamp(0), m_PyroConnected(false), m_ImageTimestampBuffer(), 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_BufferSize = 100; m_ImageTimestampBuffer.insert(m_ImageTimestampBuffer.begin(), m_BufferSize, 0); m_LastWrittenImage = m_BufferSize - 1; m_ImageBuffer.insert(m_ImageBuffer.begin(), m_BufferSize, 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::GetNextRawImage( mitk::Image::Pointer& image) { // 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; } // make sure image is nullptr image = nullptr; float ImageEnergyValue = 0; for (int i = 100; i > 90 && ImageEnergyValue <= 0; --i) { if (m_ImageTimestampBuffer[(m_LastWrittenImage + i) % 100] != 0) { ImageEnergyValue = m_Pyro->GetClosestEnergyInmJ(m_ImageTimestampBuffer[(m_LastWrittenImage + i) % 100]); if (ImageEnergyValue > 0) { image = &(*m_ImageBuffer[(m_LastWrittenImage + i) % 100]); } } } // if we did not get any usable Energy value, compensate using this default value if (image == nullptr) { image = &(*m_ImageBuffer[m_LastWrittenImage]); ImageEnergyValue = 40; if (image == nullptr) return; } // do image processing before displaying it if (image.IsNotNull()) { // now apply filters to the image, if the options have been selected. if ((m_CompensateForScattering || m_UseBModeFilter) && m_DataType == DataType::Beamformed_Short) { if (m_Device->GetScanMode().beamformingAlgorithm == Beamforming::PlaneWaveCompound) { if(m_UseBModeFilter) image = ApplyBmodeFilter(image, true, m_VerticalSpacing); } // this is for ultrasound only mode else { Image::Pointer imagePA = Image::New(); unsigned int dim[] = { image->GetDimension(0),image->GetDimension(1),1}; imagePA->Initialize(image->GetPixelType(), 3, dim); imagePA->SetGeometry(image->GetGeometry()); mitk::ImageReadAccessor inputReadAccessorCopy(image, image->GetSliceData(0)); imagePA->SetSlice(inputReadAccessorCopy.GetData(), 0); // first, seperate the PA image from the USImages // then, we compensate the PAImage using our ImageEnergyValue if(m_CompensateEnergy) imagePA = MultiplyImage(imagePA, 1/ImageEnergyValue); // TODO: add the correct prefactor here!!!! // now we apply the BModeFilter if (m_UseBModeFilter) { image = ApplyBmodeFilter(image, true, m_VerticalSpacing); // the US Images get a logarithmic filter imagePA = ApplyBmodeFilter(imagePA, false, m_VerticalSpacing); } // and finally the scattering corrections if (m_CompensateForScattering) { auto curResizeImage = m_FluenceCompResized.at(m_ScatteringCoefficient); // just for convenience // update the fluence reference images! bool doResampling = image->GetDimension(0) != curResizeImage->GetDimension(0) || image->GetDimension(1) != curResizeImage->GetDimension(1) || image->GetGeometry()->GetSpacing()[0] != curResizeImage->GetGeometry()->GetSpacing()[0] || image->GetGeometry()->GetSpacing()[1] != curResizeImage->GetGeometry()->GetSpacing()[1]; if (doResampling) { curResizeImage = ApplyResampling(m_FluenceCompOriginal.at(m_ScatteringCoefficient), image->GetGeometry()->GetSpacing(), image->GetDimensions()); double* rawOutputData = new double[image->GetDimension(0)*image->GetDimension(1)]; double* rawScatteringData = (double*)curResizeImage->GetData(); int sizeRawScatteringData = curResizeImage->GetDimension(0) * curResizeImage->GetDimension(1); int imageSize = image->GetDimension(0)*image->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; int lowerBound = std::round(upperCutoffmm / image->GetGeometry()->GetSpacing()[1])*image->GetDimension(0); int upperBound = lowerBound + sizeRawScatteringData; for (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 (int i = lowerBound; i < upperBound && i < imageSize; ++i) { rawOutputData[i] = 1 / rawScatteringData[i-lowerBound]; } for (int i = upperBound; i < imageSize; ++i) { rawOutputData[i] = 0; // everything than cannot be compensated shall be treated as garbage } unsigned int dim[] = { image->GetDimension(0), image->GetDimension(1), 1 }; curResizeImage->Initialize(mitk::MakeScalarPixelType(), 3, dim); curResizeImage->SetGeometry(image->GetGeometry()); curResizeImage->SetSlice(rawOutputData,0); delete[] 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."; } // actually apply the scattering compensation imagePA = ApplyScatteringCompensation(imagePA, m_ScatteringCoefficient); } mitk::ImageReadAccessor inputReadAccessor(imagePA, imagePA->GetSliceData(0)); image->SetSlice(inputReadAccessor.GetData(), 0); } } } } mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyBmodeFilter(mitk::Image::Pointer inputImage, bool useLogFilter, float resampleSpacing) { // 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::Image< float, 3 > itkFloatImageType; 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 typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::Pointer bmode; if (useLogFilter) { bModeFilter->SetInput(itkImage); bModeFilter->SetDirection(1); bmode = bModeFilter->GetOutput(); } else { photoacousticBModeFilter->SetInput(itkImage); photoacousticBModeFilter->SetDirection(1); bmode = photoacousticBModeFilter->GetOutput(); } // resampleSpacing == 0 means: do no resampling if (resampleSpacing == 0) { return mitk::GrabItkImageMemory(bmode); } itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSize[0] = inputSize[0]; // don't do any resampling in x-direction! outputSpacing[0] = itkImage->GetSpacing()[0] * (static_cast(inputSize[0]) / static_cast(outputSize[0])); outputSpacing[1] = resampleSpacing; outputSpacing[2] = 0.6; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(bmode); 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::Image< float, 3 > itkFloatImageType; 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::Image< double, 3 > itkFloatImageType; 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::Image< float, 3 > itkFloatImageType; 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 might save later on m_CurrentImageTimestamp = std::chrono::high_resolution_clock::now().time_since_epoch().count(); // create a new image and initialize it mitk::Image::Pointer image = mitk::Image::New(); switch (m_DataType) { case DataType::Image_uChar: { m_ImageDimensions[0] = imageWidth; m_ImageDimensions[1] = imageHeight; m_ImageDimensions[2] = imageSetsTotal; image->Initialize(mitk::MakeScalarPixelType(), 3, m_ImageDimensions); break; } case DataType::Beamformed_Short: { m_ImageDimensions[0] = beamformedLines; m_ImageDimensions[1] = beamformedSamples; m_ImageDimensions[2] = beamformedTotalDatasets; image->Initialize(mitk::MakeScalarPixelType(), 3, m_ImageDimensions); break; } } image->GetGeometry()->SetSpacing(m_ImageSpacing); image->GetGeometry()->Modified(); // write the given buffer into the image switch (m_DataType) { case DataType::Image_uChar: { for (unsigned char i = 0; i < imageSetsTotal; i++) { image->SetSlice(&imageData[i*imageHeight*imageWidth], i); } 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]; } } // the beamformed pa image is flipped by 90 degrees; we need to flip it manually } for (unsigned char i = 0; i < beamformedTotalDatasets; i++) { image->SetSlice(&flipme[i*beamformedLines*beamformedSamples], i); // set every image to a different slice } delete[] flipme; break; } } if (m_SavingSettings.saveRaw && m_CurrentlyRecording && rfDataChannelData != nullptr) { unsigned int dim[3]; dim[0] = channelDataChannelsPerDataset; dim[1] = channelDataSamplesPerChannel; dim[2] = 1; short offset = m_Device->GetScanMode().accumulation * 2048; short* noOffset = new short[channelDataChannelsPerDataset*channelDataSamplesPerChannel*channelDataTotalDatasets]; for (unsigned char set = 0; 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... } } } // save the raw images when recording for (unsigned char i = 0; i < channelDataTotalDatasets; ++i) { mitk::Image::Pointer rawImage = mitk::Image::New(); rawImage->Initialize(mitk::MakeScalarPixelType(), 3, dim); rawImage->SetSlice(&noOffset[i*channelDataChannelsPerDataset*channelDataSamplesPerChannel]); float& recordTime = m_Device->GetScanMode().receivePhaseLengthSeconds; int& speedOfSound = m_Device->GetScanMode().averageSpeedOfSound; mitk::Vector3D rawSpacing; rawSpacing[0] = m_Device->GetScanMode().reconstructedLinePitchMmOrAngleDegree; - rawSpacing[1] = recordTime * speedOfSound / 2 * 1000 / channelDataSamplesPerChannel; + rawSpacing[1] = recordTime / channelDataSamplesPerChannel / 2; rawSpacing[2] = 0.6; rawImage->GetGeometry()->SetSpacing(rawSpacing); rawImage->GetGeometry()->Modified(); m_RawRecordedImages.push_back(rawImage); } delete[] noOffset; } itk::Index<3> pixel = { { (image->GetDimension(0) / 2), 22.0/532.0*m_Device->GetScanMode().reconstructionSamplesPerLine, 0 } }; //22/532*2048 = 84 if (!m_Pyro->IsSyncDelaySet() &&(image->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] = image; m_LastWrittenImage = (m_LastWrittenImage + 1) % m_BufferSize; // if the user decides to start recording, we feed the vector the generated images if (m_CurrentlyRecording) { for (unsigned char index = 0; index < image->GetDimension(2); ++index) { if (image->IsSliceSet(index)) { m_RecordedImages.push_back(Image::New()); unsigned int dim[] = { image ->GetDimension(0), image->GetDimension(1), 1}; m_RecordedImages.back()->Initialize(image->GetPixelType(), 3, dim); m_RecordedImages.back()->SetGeometry(image->GetGeometry()); mitk::ImageReadAccessor inputReadAccessor(image, image->GetSliceData(index)); m_RecordedImages.back()->SetSlice(inputReadAccessor.GetData(),0); } } m_ImageTimestampRecord.push_back(m_CurrentImageTimestamp); // save timestamps for each laser image! } } } 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] = 0.6; 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::SetGUIOutput(std::function out) { USDiPhASImageSource::m_GUIOutput = out; m_StartTime = ((float)std::clock()) / CLOCKS_PER_SEC; //wait till the callback is available again m_UseGUIOutPut = false; } 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; } // 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 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(); // 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 MakeFolder = "mkdir \"c:/DiPhASImageData/" + currentDate + "\""; - system(MakeFolder.c_str()); + //std::string MakeFolder = "mkdir \"c:/DiPhASImageData/" + currentDate + "\""; + //system(MakeFolder.c_str()); // initialize file paths and the images Image::Pointer PAImage = Image::New(); Image::Pointer USImage = Image::New(); - std::string pathPA = "c:\\DiPhASImageData\\" + currentDate + "\\" + "PAImages" + ".nrrd"; - std::string pathUS = "c:\\DiPhASImageData\\" + currentDate + "\\" + "USImages" + ".nrrd"; - std::string pathTS = "c:\\DiPhASImageData\\" + currentDate + "\\" + "TimestampsImages" + ".csv"; + std::string pathPA = "c:\\ImageData\\" + currentDate + "-" + "PAbeamformed" + ".nrrd"; + std::string pathUS = "c:\\ImageData\\" + currentDate + "\\" + "USImages" + ".nrrd"; + std::string pathTS = "c:\\ImageData\\" + currentDate + "-" + "ts" + ".csv"; // idon't forget the raw Images (if chosen to be saved) Image::Pointer PAImageRaw = Image::New(); Image::Pointer USImageRaw = Image::New(); - std::string pathPARaw = "c:\\DiPhASImageData\\" + currentDate + "\\" + "PAImagesRaw" + ".nrrd"; - std::string pathUSRaw = "c:\\DiPhASImageData\\" + currentDate + "\\" + "USImagesRaw" + ".nrrd"; + std::string pathPARaw = "c:\\ImageData\\" + currentDate + "-" + "PAraw" + ".nrrd"; + std::string pathUSRaw = "c:\\ImageData\\" + currentDate + "\\" + "USImagesRaw" + ".nrrd"; if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) // save a PAImage if we used interleaved mode { // first, save the data, so the pyro does not aquire more unneccessary timestamps m_Pyro->SaveData(); // now order the images and save them // the beamformed ones... if (m_SavingSettings.saveBeamformed) { OrderImagesInterleaved(PAImage, USImage, m_RecordedImages, false); - mitk::IOUtil::Save(USImage, pathUS); + //mitk::IOUtil::Save(USImage, pathUS); mitk::IOUtil::Save(PAImage, pathPA); } // ...and the raw images if (m_SavingSettings.saveRaw) { OrderImagesInterleaved(PAImageRaw, USImageRaw, m_RawRecordedImages, true); - mitk::IOUtil::Save(USImageRaw, pathUSRaw); + //mitk::IOUtil::Save(USImageRaw, pathUSRaw); mitk::IOUtil::Save(PAImageRaw, pathPARaw); } // read the pixelvalues of the enveloped images at this position itk::Index<3> pixel = { { m_RecordedImages.at(1)->GetDimension(0) / 2, 22.0/532.0*m_Device->GetScanMode().reconstructionSamplesPerLine, 0 } }; //22/532*2048 = 84 GetPixelValues(pixel); // save the timestamps! ofstream timestampFile; timestampFile.open(pathTS); timestampFile << ",timestamp,pixelvalue"; // write the header for (int index = 0; index < m_ImageTimestampRecord.size(); ++index) { timestampFile << "\n" << index << "," << m_ImageTimestampRecord.at(index) << "," << m_PixelValues.at(index); } timestampFile.close(); } else if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::PlaneWaveCompound) // save no PAImage if we used US only mode { OrderImagesUltrasound(USImage, m_RecordedImages); mitk::IOUtil::Save(USImage, pathUS); } m_PixelValues.clear(); m_RawRecordedImages.clear(); // clean up the pixel values m_RecordedImages.clear(); // clean up the images m_ImageTimestampRecord.clear(); // clean up the timestamps } } void mitk::USDiPhASImageSource::GetPixelValues(itk::Index<3> pixel) { unsigned int events = m_Device->GetScanMode().transmitEventsCount + 1; // the PA event is not included in the transmitEvents, so we add 1 here for (int index = 0; index < m_RecordedImages.size(); index += events) // omit sound images { Image::Pointer image = ApplyBmodeFilter(m_RecordedImages.at(index)); m_PixelValues.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 + 1; // the PA event is not included in the transmitEvents, so we add 1 here if (raw) { width = recordedList.at(0)->GetDimension(0); height = recordedList.at(0)->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, recordedList.size() / events}; unsigned int dimSound[] = { width, height, recordedList.size() / events * (events-1)}; PAImage->Initialize(recordedList.back()->GetPixelType(), 3, dimLaser); PAImage->SetGeometry(recordedList.back()->GetGeometry()); USImage->Initialize(recordedList.back()->GetPixelType(), 3, dimSound); USImage->SetGeometry(recordedList.back()->GetGeometry()); for (int index = 0; index < recordedList.size(); ++index) { mitk::ImageReadAccessor inputReadAccessor(recordedList.at(index)); if (index % events == 0) { PAImage->SetSlice(inputReadAccessor.GetData(), index / events); } else { USImage->SetSlice(inputReadAccessor.GetData(), ((index - (index % events)) / events) + (index % events)-1); } } } 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 = 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 dimSound[] = { width, height, recordedList.size()}; USImage->Initialize(recordedList.back()->GetPixelType(), 3, dimSound); USImage->SetGeometry(recordedList.back()->GetGeometry()); for (int index = 0; index < recordedList.size(); ++index) { mitk::ImageReadAccessor inputReadAccessor(recordedList.at(index)); USImage->SetSlice(inputReadAccessor.GetData(), index); } } \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp index de736b03e8..4ff0b46a69 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.cpp @@ -1,419 +1,421 @@ /*=================================================================== 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()); if (m_ControlInterface.IsNotNull()) { m_ControlInterface->passGUIOut([](QString str)->void {} ); } delete ui; } std::string QmitkUSControlsCustomDiPhASDeviceWidget::GetDeviceClass() const { return "org.mitk.modules.us.USDiPhASDevice"; } QmitkUSAbstractCustomWidget* QmitkUSControlsCustomDiPhASDeviceWidget::Clone(QWidget* parent) const { QmitkUSAbstractCustomWidget* clonedWidget = new QmitkUSControlsCustomDiPhASDeviceWidget(parent); clonedWidget->SetDevice(this->GetDevice()); return clonedWidget; } void QmitkUSControlsCustomDiPhASDeviceWidget::OnDeviceSet() { m_ControlInterface = dynamic_cast (this->GetDevice()->GetControlInterfaceCustom().GetPointer()); if ( m_ControlInterface.IsNotNull() ) { m_ControlInterface->passGUIOut([this](QString str)->void{ if (this && this->ui) { this->ui->CurrentState->setText(str); } }); } else { MITK_WARN("QmitkUSAbstractCustomWidget")("QmitkUSControlsCustomDiPhASDeviceWidget") << "Did not get a custom device control interface."; } //now pass the default values m_OldReconstructionLines = 0; m_ControlInterface->SetSilentUpdate(true); // don't update the scanmode everytime OnTransmitPhaseLengthChanged(); OnExcitationFrequencyChanged(); OnTransmitEventsChanged(); OnVoltageChanged(); OnScanDepthChanged(); // HERE OnAveragingCountChanged(); OnTGCMinChanged(); OnTGCMaxChanged(); OnDataTypeChanged(); OnPitchChanged(); OnReconstructedSamplesChanged(); OnReconstructedLinesChanged(); OnSpeedOfSoundChanged(); OnBandpassEnabledChanged(); OnLowCutChanged(); OnHighCutChanged(); OnUseBModeFilterChanged(); // HERE OnVerticalSpacingChanged(); OnScatteringCoefficientChanged(); OnCompensateScatteringChanged(); OnChangedSavingSettings(); OnCompensateEnergyChanged(); 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->DataType, SIGNAL(currentTextChanged(QString)), this, SLOT(OnDataTypeChanged())); //Beamforming connect(ui->PitchOfTransducer, SIGNAL(valueChanged(double)), this, SLOT(OnPitchChanged())); connect(ui->ReconstructedSamplesPerLine, SIGNAL(valueChanged(int)), this, SLOT(OnReconstructedSamplesChanged())); connect(ui->ReconstructedLines, SIGNAL(valueChanged(int)), this, SLOT(OnReconstructedLinesChanged())); connect(ui->SpeedOfSound, SIGNAL(valueChanged(int)), this, SLOT(OnSpeedOfSoundChanged())); //Bandpass connect(ui->BandpassEnabled, SIGNAL(currentTextChanged(QString)), this, SLOT(OnBandpassEnabledChanged())); connect(ui->LowCut, SIGNAL(valueChanged(double)), this, SLOT(OnLowCutChanged())); connect(ui->HighCut, SIGNAL(valueChanged(double)), this, SLOT(OnHighCutChanged())); } //slots void QmitkUSControlsCustomDiPhASDeviceWidget::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::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->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 { 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->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() { 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()); } 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.ui b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui index fffb5b2e76..580f079648 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui @@ -1,661 +1,648 @@ QmitkUSControlsCustomDiPhASDeviceWidget 0 0 - 311 + 351 903 Form 0 25 16777215 25 QFrame::WinPanel QFrame::Raised Started Qt::AlignCenter - <html><head/><body><p><span style=" font-weight:600;">Recording Settings</span></p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Record Images</span></p></body></html> - - - - Qt::Horizontal - - - - 40 - 20 - - - - - Save Beamformed Images + Save Beamformed - Save Raw Images + Save Raw 100 25 Start Recording Qt::Horizontal 40 20 <html><head/><body><p><span style=" font-weight:600;">Receive Parameters</span></p></body></html> 0 0 0 0 - 200 - 200 + 16777215 + 16777215 42 Qt::Horizontal 42 Qt::Horizontal 0 Scan Depth [mm] 1 100 1 Averaging Count false Beamformed Data Image Data 2.000000000000000 1000.000000000000000 45.000000000000000 DataType TGC Min - + TGC Max Compensate Fluence For Scattering 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 2048 0.010000000000000 0.050000000000000 0.300000000000000 Qt::PreventContextMenu 128 1024 128 128 Samples per Line Reconstructed Lines 1000 1000000 1540 Speed of Sound [m/s] Pitch of Transducer [mm] <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 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 1 Transmit Events true false 1 1.000000000000000 10000.000000000000000 1.000000000000000 Transmit Phase Length [us] Excitation Frequency [MHz] false Interleaved Ultrasound only false 5 75 75 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.lasercontrol/src/internal/QmitkLaserControlControls.ui b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControlControls.ui index a2d9b4f66b..2854825c4f 100644 --- a/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControlControls.ui +++ b/Plugins/org.mitk.gui.qt.lasercontrol/src/internal/QmitkLaserControlControls.ui @@ -1,770 +1,775 @@ OPOLaserControlControls 0 0 343 528 0 0 + + + 9 + + QmitkTemplate 9 OPOTEK Phocus Control 10 20 301 431 true 10 Trigger Externally true 10 Init Laser false 10 Start Lamp false 10 Start Laser 11 75 true Laser Status Current Wavelength 10 75 true PreferDefault true 750.0 nm Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Pulse Energy false 10 75 true PreferDefault true 0 mJ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 6900 9500 5 100 7500 Qt::Horizontal QSlider::NoTicks 10000 1 690.000000000000000 950.000000000000000 0.500000000000000 750.000000000000000 nm false Tune 10 50 false Fast Tuning Wavelengths 0 75 16777215 75 10 true Qt::SolidLine 42 50 - 20 + 30 - 20 + 30 λ/nm 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 690 690 690 690 690 800 800 800 800 800 800 800 800 800 800 false Start Fast Tuning Qt::Vertical 20 40 calibrate OPO 50000 400 24400 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 68acb02ac9..62b3d292fe 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp @@ -1,123 +1,159 @@ /*=================================================================== 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" const std::string QmitkPAUSViewerView::VIEW_ID = "org.mitk.views.photoacoustics.pausviewer"; QmitkPAUSViewerView::QmitkPAUSViewerView() : m_PADataStorage(mitk::StandaloneDataStorage::New()), m_USDataStorage(mitk::StandaloneDataStorage::New()), m_UltrasoundReference(nullptr) { } QmitkPAUSViewerView::~QmitkPAUSViewerView() { if(m_UltrasoundReference != nullptr) *m_UltrasoundReference = nullptr; } void QmitkPAUSViewerView::InitWindows() { AddOverlays(); } void QmitkPAUSViewerView::SetFocus() { } void QmitkPAUSViewerView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes) { } void QmitkPAUSViewerView::CreateQtPartControl(QWidget *parent) { m_Controls = new Ui::QmitkPAUSViewerViewControls; m_Controls->setupUi(parent); m_Controls->m_PARenderWindow->GetRenderer()->SetDataStorage(m_PADataStorage); m_Controls->m_USRenderWindow->GetRenderer()->SetDataStorage(m_USDataStorage); } 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*/) - { + //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_INFO << "1111111111111111111111"; mitk::ScaleLegendAnnotation::Pointer scaleAnnotation = mitk::ScaleLegendAnnotation::New(); - scaleAnnotation->SetLeftAxisVisibility(true); - scaleAnnotation->SetRightAxisVisibility(false); - scaleAnnotation->SetRightAxisVisibility(false); - scaleAnnotation->SetTopAxisVisibility(false); - scaleAnnotation->SetCornerOffsetFactor(0); - mitk::LayoutAnnotationRenderer::AddAnnotation(scaleAnnotation.GetPointer(), m_PARenderer, mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); + //scaleAnnotation->SetLeftAxisVisibility(true); + //scaleAnnotation->SetRightAxisVisibility(false); + //scaleAnnotation->SetRightAxisVisibility(false); + //scaleAnnotation->SetTopAxisVisibility(false); + //scaleAnnotation->SetCornerOffsetFactor(0); + MITK_INFO << "1111111111111111111111"; + + // 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); + MITK_INFO << "1111111111111111111111"; + + // 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); + MITK_INFO << "1111111111111111111111"; + + 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_INFO << "1111111111111111111111"; + + + 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); + MITK_INFO << "1111111111111111111111"; + } void QmitkPAUSViewerView::RemoveOverlays() { // m_PAOverlayManager->RemoveAllOverlays(); } void QmitkPAUSViewerView::SetUltrasoundReference(QmitkPAUSViewerView** ultrasoundReference) { m_UltrasoundReference = ultrasoundReference; } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp index 30a6d8f06d..9780ed231b 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp @@ -1,694 +1,694 @@ /*=================================================================== 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 //Mitk #include #include #include #include #include #include #include #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include #include // Qmitk #include "UltrasoundSupport.h" // Qt #include #include #include // Ultrasound #include "mitkUSDevice.h" #include "QmitkUSAbstractCustomWidget.h" #include #include #include "usServiceReference.h" #include "internal/org_mitk_gui_qt_ultrasound_Activator.h" #include "mitkNodePredicateDataType.h" #include const std::string UltrasoundSupport::VIEW_ID = "org.mitk.views.ultrasoundsupport"; void UltrasoundSupport::SetFocus() { } void UltrasoundSupport::CreateQtPartControl(QWidget *parent) { //initialize timers m_UpdateTimer = new QTimer(this); m_RenderingTimer2d = new QTimer(this); m_RenderingTimer3d = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); //load persistence data before connecting slots (so no slots are called in this phase...) LoadUISettings(); //connect signals and slots... connect(m_Controls.m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this, SLOT(OnClickedAddNewDevice())); // Change Widget Visibilities connect(m_Controls.m_DeviceManagerWidget, SIGNAL(NewDeviceButtonClicked()), this->m_Controls.m_NewVideoDeviceWidget, SLOT(CreateNewDevice())); // Init NewDeviceWidget connect(m_Controls.m_ActiveVideoDevices, SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_RunImageTimer, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_ShowImageStream, SIGNAL(clicked()), this, SLOT(OnChangedActiveDevice())); connect(m_Controls.m_NewVideoDeviceWidget, SIGNAL(Finished()), this, SLOT(OnNewDeviceWidgetDone())); // After NewDeviceWidget finished editing connect(m_Controls.m_FrameRatePipeline, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FrameRate2d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FrameRate3d, SIGNAL(valueChanged(int)), this, SLOT(OnChangedFramerateLimit())); connect(m_Controls.m_FreezeButton, SIGNAL(clicked()), this, SLOT(OnClickedFreezeButton())); connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(UpdateImage())); connect(m_RenderingTimer2d, SIGNAL(timeout()), this, SLOT(RenderImage2d())); connect(m_RenderingTimer3d, SIGNAL(timeout()), this, SLOT(RenderImage3d())); connect(m_Controls.m_Update2DView, SIGNAL(clicked()), this, SLOT(StartTimers())); connect(m_Controls.m_Update3DView, SIGNAL(clicked()), this, SLOT(StartTimers())); connect(m_Controls.m_DeviceManagerWidget, SIGNAL(EditDeviceButtonClicked(mitk::USDevice::Pointer)), this, SLOT(OnClickedEditDevice())); //Change Widget Visibilities connect(m_Controls.m_DeviceManagerWidget, SIGNAL(EditDeviceButtonClicked(mitk::USDevice::Pointer)), this->m_Controls.m_NewVideoDeviceWidget, SLOT(EditDevice(mitk::USDevice::Pointer))); // Initializations m_Controls.m_NewVideoDeviceWidget->setVisible(false); std::string filter = "(&(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.UltrasoundDevice)(" + mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE + "=true))"; m_Controls.m_ActiveVideoDevices->Initialize( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, filter); m_Controls.m_ActiveVideoDevices->SetAutomaticallySelectFirstEntry(true); m_FrameCounterPipeline = 0; m_FrameCounter2d = 0; m_FrameCounter3d = 0; m_Controls.tabWidget->setTabEnabled(1, false); } void UltrasoundSupport::CreateWindows() { auto pausViewer = GetSite()->GetWorkbenchWindow()->GetActivePage()->FindView("org.mitk.views.photoacoustics.pausviewer"); if (pausViewer != nullptr) { m_PausViewerView = dynamic_cast(pausViewer.GetPointer()); m_PausViewerView->SetPADataStorage(m_PADataStorage); m_PausViewerView->SetUSDataStorage(m_USDataStorage); m_PausViewerView->InitWindows(); m_PausViewerView->SetUltrasoundReference(&m_PausViewerView); UpdateLevelWindows(); m_ForceRequestUpdateAll = true; } } void UltrasoundSupport::InitNewNode() { m_Node.push_back(nullptr); auto& Node = m_Node.back(); Node = mitk::DataNode::New(); Node->SetName("No Data received yet ..."); //create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); Node->SetData(dummyImage); m_OldGeometry = dynamic_cast(dummyImage->GetGeometry()); // Add to Control Datastorage this->GetDataStorage()->Add(Node); // Add to Display Datastorage if (m_Node.size() > 1) m_USDataStorage->Add(Node); else if (m_Node.size() == 1) m_PADataStorage->Add(Node); } void UltrasoundSupport::DestroyLastNode() { auto& Node = m_Node.back(); // Remove from Control Datastorage this->GetDataStorage()->Remove(Node); // Remove from Display Datastorage if (m_Node.size() > 1) m_USDataStorage->Remove(Node); else if (m_Node.size() == 1) m_PADataStorage->Remove(Node); // clean up Node->ReleaseData(); m_Node.pop_back(); } void UltrasoundSupport::UpdateLevelWindows() { mitk::LevelWindow levelWindow; if (m_Node.size() > 1) { for (int index = 0; index < m_AmountOfOutputs; ++index) { m_Node.at(index)->GetLevelWindow(levelWindow); if (!m_curOutput.at(index)->IsEmpty()) - levelWindow.SetWindowBounds(0, 4 * (index+1)); - //levelWindow.SetAuto(m_curOutput.at(index), true, true); + //levelWindow.SetWindowBounds(0, 4 * (index+1)); + levelWindow.SetToImageRange(m_curOutput.at(index)); m_Node.at(index)->SetLevelWindow(levelWindow); } } else if (m_Node.size() == 1) { m_Node.back()->GetLevelWindow(levelWindow); if (!m_curOutput.at(0)->IsEmpty()) - levelWindow.SetAuto(m_curOutput.at(0), true, true); + levelWindow.SetToImageRange(m_curOutput.at(0)); m_Node.back()->SetLevelWindow(levelWindow); } } void UltrasoundSupport::SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type) { // consider removing this, unused for now, and probably forever mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); mitk::LookupTableProperty::Pointer lookupTableProperty = mitk::LookupTableProperty::New(); lookupTable->SetType(type); lookupTableProperty->SetLookupTable(lookupTable); node->SetProperty("LookupTable", lookupTableProperty); mitk::RenderingModeProperty::Pointer renderingMode = dynamic_cast(node->GetProperty("Image Rendering.Mode")); renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); } void UltrasoundSupport::OnClickedAddNewDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_Headline->setText("Add New Video Device:"); m_Controls.m_WidgetActiveDevices->setVisible(false); } void UltrasoundSupport::OnClickedEditDevice() { m_Controls.m_NewVideoDeviceWidget->setVisible(true); m_Controls.m_DeviceManagerWidget->setVisible(false); m_Controls.m_WidgetActiveDevices->setVisible(false); m_Controls.m_Headline->setText("Edit Video Device:"); } void UltrasoundSupport::UpdateAmountOfOutputs() { // Update the amount of Nodes; there should be one Node for every slide that is set. Note that we must check whether the slices are set, // just using the m_Image->dimension(3) will produce nullpointers on slices of the image that were not set bool isSet = true; m_AmountOfOutputs = 0; while (isSet) { isSet = m_Image->IsSliceSet(m_AmountOfOutputs); if (isSet) ++m_AmountOfOutputs; } // correct the amount of Nodes to display data while (m_Node.size() < m_AmountOfOutputs) { InitNewNode(); } while (m_Node.size() > m_AmountOfOutputs) { DestroyLastNode(); } // correct the amount of image outputs that we feed the nodes with while (m_curOutput.size() < m_AmountOfOutputs) { m_curOutput.push_back(mitk::Image::New()); // initialize the slice images as 2d images with the size of m_Images unsigned int* dimOld = m_Image->GetDimensions(); unsigned int dim[2] = { dimOld[0], dimOld[1] }; m_curOutput.back()->Initialize(m_Image->GetPixelType(), 2, dim); } while (m_curOutput.size() > m_AmountOfOutputs) { m_curOutput.pop_back(); } } void UltrasoundSupport::UpdateImage() { if(m_Controls.m_ShowImageStream->isChecked()) { m_Device->Modified(); m_Device->Update(); // Update device m_Image = m_Device->GetOutput(); // get the Image data to display UpdateAmountOfOutputs(); // create as many Nodes and Outputs as there are slices in m_Image if (m_AmountOfOutputs == 0) return; // if there is no image to be displayed, skip the rest of this method for (int index = 0; index < m_AmountOfOutputs; ++index) { if (m_curOutput.at(index)->GetDimension(0) != m_Image->GetDimension(0) || m_curOutput.at(index)->GetDimension(1) != m_Image->GetDimension(1) || m_curOutput.at(index)->GetDimension(2) != m_Image->GetDimension(2) || m_curOutput.at(index)->GetPixelType() != m_Image->GetPixelType()) { unsigned int* dimOld = m_Image->GetDimensions(); unsigned int dim[2] = { dimOld[0], dimOld[1]}; m_curOutput.at(index)->Initialize(m_Image->GetPixelType(), 2, dim); // if we switched image resolution or type the outputs must be reinitialized! } if (!m_Image->IsEmpty()) { mitk::ImageReadAccessor inputReadAccessor(m_Image, m_Image->GetSliceData(index,0,0,nullptr,mitk::Image::ReferenceMemory)); // just reference the slices, to get a small performance gain m_curOutput.at(index)->SetSlice(inputReadAccessor.GetData()); m_curOutput.at(index)->GetGeometry()->SetIndexToWorldTransform(m_Image->GetSlicedGeometry()->GetIndexToWorldTransform()); // Update the image Output with seperate slices } if (m_curOutput.at(index)->IsEmpty()) { m_Node.at(index)->SetName("No Data received yet ..."); // create a noise image for correct initialization of level window, etc. mitk::Image::Pointer randomImage = mitk::ImageGenerator::GenerateRandomImage(32, 32, 1, 1, 1, 1, 1, 255, 0); m_Node.at(index)->SetData(randomImage); m_curOutput.at(index)->SetGeometry(randomImage->GetGeometry()); } else { char name[30]; sprintf(name, "US Viewing Stream - Image %d", index); m_Node.at(index)->SetName(name); m_Node.at(index)->SetData(m_curOutput.at(index)); // set the name of the Output } } // if the geometry changed: reinitialize the ultrasound image. we use the m_curOutput.at(0) to readjust the geometry if ((m_OldGeometry.IsNotNull()) && (m_curOutput.at(0)->GetGeometry() != NULL) && (!mitk::Equal(m_OldGeometry.GetPointer(), m_curOutput.at(0)->GetGeometry(), 0.0001, false)) || m_ForceRequestUpdateAll) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if ((renderWindow != NULL) && (m_curOutput.at(0)->GetTimeGeometry()->IsValid()) && (m_Controls.m_ShowImageStream->isChecked())) { renderWindow->GetRenderingManager()->InitializeViews( m_curOutput.at(0)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); renderWindow->GetRenderingManager()->RequestUpdateAll(); } m_CurrentImageWidth = m_curOutput.at(0)->GetDimension(0); m_CurrentImageHeight = m_curOutput.at(0)->GetDimension(1); m_OldGeometry = dynamic_cast(m_curOutput.at(0)->GetGeometry()); UpdateLevelWindows(); m_ForceRequestUpdateAll = false; } } //Update frame counter m_FrameCounterPipeline++; if (m_FrameCounterPipeline >= 10) { // compute framerate of pipeline update int nMilliseconds = m_Clock.restart(); int fps = 10000.0f / (nMilliseconds); m_FPSPipeline = fps; m_FrameCounterPipeline = 0; // display lowest framerate in UI int lowestFPS = m_FPSPipeline; if (m_Controls.m_Update2DView->isChecked() && (m_FPS2d < lowestFPS)) { lowestFPS = m_FPS2d; } if (m_Controls.m_Update3DView->isChecked() && (m_FPS3d < lowestFPS)) { lowestFPS = m_FPS3d; } m_Controls.m_FramerateLabel->setText("Current Framerate: " + QString::number(lowestFPS) + " FPS"); } } void UltrasoundSupport::RenderImage2d() { if (!m_Controls.m_Update2DView->isChecked()) return; if (m_PausViewerView != nullptr) { auto renderingManager = mitk::RenderingManager::GetInstance(); renderingManager->RequestUpdate(m_PausViewerView->GetPARenderWindow()); renderingManager->RequestUpdate(m_PausViewerView->GetUSRenderWindow()); } else { CreateWindows(); // try to check whether the PausViwer has been opened by now } //mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); //renderWindow->GetRenderingManager()->RequestUpdate(mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))->GetRenderWindow()); // TODO: figure out how to proceed with the standard display //this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); m_FrameCounter2d++; if (m_FrameCounter2d >= 10) { // compute framerate of 2d render window update int nMilliseconds = m_Clock2d.restart(); int fps = 10000.0f / (nMilliseconds); m_FPS2d = fps; m_FrameCounter2d = 0; } } void UltrasoundSupport::RenderImage3d() { if (!m_Controls.m_Update3DView->isChecked()) return; this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); m_FrameCounter3d++; if (m_FrameCounter3d >= 10) { // compute framerate of 2d render window update int nMilliseconds = m_Clock3d.restart(); int fps = 10000.0f / (nMilliseconds); m_FPS3d = fps; m_FrameCounter3d = 0; } } void UltrasoundSupport::OnChangedFramerateLimit() { StopTimers(); int intervalPipeline = (1000 / m_Controls.m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls.m_FrameRate2d->value()); int interval3D = (1000 / m_Controls.m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline, interval2D, interval3D); StartTimers(); } void UltrasoundSupport::OnClickedFreezeButton() { if (m_Device.IsNull()) { MITK_WARN("UltrasoundSupport") << "Freeze button clicked though no device is selected."; return; } if (m_Device->GetIsFreezed()) { m_Device->SetIsFreezed(false); m_Controls.m_FreezeButton->setText("Freeze"); } else { m_Device->SetIsFreezed(true); m_Controls.m_FreezeButton->setText("Start Viewing Again"); } } void UltrasoundSupport::OnChangedActiveDevice() { //clean up, delete nodes and stop timer StopTimers(); this->RemoveControlWidgets(); for (auto& Node : m_Node) { this->GetDataStorage()->Remove(Node); Node->ReleaseData(); } m_Node.clear(); // disconnect from the PausViewer m_PausViewerView = nullptr; //get current device, abort if it is invalid m_Device = m_Controls.m_ActiveVideoDevices->GetSelectedService(); if (m_Device.IsNull()) { m_Controls.tabWidget->setTabEnabled(1, false); return; } //create the widgets for this device and enable the widget tab this->CreateControlWidgets(); m_Controls.tabWidget->setTabEnabled(1, true); //start timer if (m_Controls.m_RunImageTimer->isChecked()) { int intervalPipeline = (1000 / m_Controls.m_FrameRatePipeline->value()); int interval2D = (1000 / m_Controls.m_FrameRate2d->value()); int interval3D = (1000 / m_Controls.m_FrameRate3d->value()); SetTimerIntervals(intervalPipeline, interval2D, interval3D); StartTimers(); m_Controls.m_TimerWidget->setEnabled(true); } else { m_Controls.m_TimerWidget->setEnabled(false); } // connect to PausViewer and Set it up CreateWindows(); } void UltrasoundSupport::OnNewDeviceWidgetDone() { m_Controls.m_NewVideoDeviceWidget->setVisible(false); m_Controls.m_DeviceManagerWidget->setVisible(true); m_Controls.m_Headline->setText("Ultrasound Devices:"); m_Controls.m_WidgetActiveDevices->setVisible(true); } void UltrasoundSupport::CreateControlWidgets() { m_ControlProbesWidget = new QmitkUSControlsProbesWidget(m_Device->GetControlInterfaceProbes(), m_Controls.m_ToolBoxControlWidgets); m_Controls.probesWidgetContainer->addWidget(m_ControlProbesWidget); // create b mode widget for current device m_ControlBModeWidget = new QmitkUSControlsBModeWidget(m_Device->GetControlInterfaceBMode(), m_Controls.m_ToolBoxControlWidgets); if (m_Device->GetControlInterfaceBMode()) { m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlBModeWidget, "B Mode Controls"); //m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } // create doppler widget for current device m_ControlDopplerWidget = new QmitkUSControlsDopplerWidget(m_Device->GetControlInterfaceDoppler(), m_Controls.m_ToolBoxControlWidgets); if (m_Device->GetControlInterfaceDoppler()) { m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlDopplerWidget, "Doppler Controls"); //m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { std::string filter = "(ork.mitk.services.UltrasoundCustomWidget.deviceClass=" + m_Device->GetDeviceClass() + ")"; QString interfaceName = QString::fromStdString(us_service_interface_iid()); m_CustomWidgetServiceReference = pluginContext->getServiceReferences(interfaceName, QString::fromStdString(filter)); if (m_CustomWidgetServiceReference.size() > 0) { m_ControlCustomWidget = pluginContext->getService (m_CustomWidgetServiceReference.at(0))->CloneForQt(m_Controls.tab2); m_ControlCustomWidget->SetDevice(m_Device); m_Controls.m_ToolBoxControlWidgets->addItem(m_ControlCustomWidget, "Custom Controls"); } else { m_Controls.m_ToolBoxControlWidgets->addItem(new QWidget(m_Controls.m_ToolBoxControlWidgets), "Custom Controls"); m_Controls.m_ToolBoxControlWidgets->setItemEnabled(m_Controls.m_ToolBoxControlWidgets->count() - 1, false); } } // select first enabled control widget for (int n = 0; n < m_Controls.m_ToolBoxControlWidgets->count(); ++n) { if (m_Controls.m_ToolBoxControlWidgets->isItemEnabled(n)) { m_Controls.m_ToolBoxControlWidgets->setCurrentIndex(n); break; } } } void UltrasoundSupport::RemoveControlWidgets() { if (!m_ControlProbesWidget) { return; } //widgets do not exist... nothing to do // remove all control widgets from the tool box widget while (m_Controls.m_ToolBoxControlWidgets->count() > 0) { m_Controls.m_ToolBoxControlWidgets->removeItem(0); } // remove probes widget (which is not part of the tool box widget) m_Controls.probesWidgetContainer->removeWidget(m_ControlProbesWidget); delete m_ControlProbesWidget; m_ControlProbesWidget = 0; delete m_ControlBModeWidget; m_ControlBModeWidget = 0; delete m_ControlDopplerWidget; m_ControlDopplerWidget = 0; // delete custom widget if it is present if (m_ControlCustomWidget) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); delete m_ControlCustomWidget; m_ControlCustomWidget = 0; if (m_CustomWidgetServiceReference.size() > 0) { pluginContext->ungetService(m_CustomWidgetServiceReference.at(0)); } } } void UltrasoundSupport::OnDeciveServiceEvent(const ctkServiceEvent event) { if (m_Device.IsNull() || event.getType() != us::ServiceEvent::MODIFIED) { return; } ctkServiceReference service = event.getServiceReference(); if (m_Device->GetManufacturer() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER)).toString().toStdString() && m_Device->GetName() != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME)).toString().toStdString()) { return; } if (!m_Device->GetIsActive() && m_UpdateTimer->isActive()) { StopTimers(); } if (m_CurrentDynamicRange != service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble()) { m_CurrentDynamicRange = service.getProperty(QString::fromStdString(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DYNAMIC_RANGE)).toDouble(); // update level window for the current dynamic range mitk::LevelWindow levelWindow; for (auto& Node : m_Node) { Node->GetLevelWindow(levelWindow); levelWindow.SetAuto(m_Image, true, true); levelWindow.SetWindowBounds(55, 125,true); Node->SetLevelWindow(levelWindow); } } } UltrasoundSupport::UltrasoundSupport() : m_ControlCustomWidget(0), m_ControlBModeWidget(0), m_ControlProbesWidget(0), m_ImageAlreadySetToNode(false), m_CurrentImageWidth(0), m_CurrentImageHeight(0), m_AmountOfOutputs(0), m_PADataStorage(mitk::StandaloneDataStorage::New()), m_USDataStorage(mitk::StandaloneDataStorage::New()), m_ForceRequestUpdateAll(false) { ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { // to be notified about service event of an USDevice pluginContext->connectServiceListener(this, "OnDeciveServiceEvent", QString::fromStdString("(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")")); } } UltrasoundSupport::~UltrasoundSupport() { try { StopTimers(); // Get all active devicesand deactivate them to prevent freeze std::vector devices = this->m_Controls.m_ActiveVideoDevices->GetAllServices(); for (int i = 0; i < devices.size(); i++) { mitk::USDevice::Pointer device = devices[i]; if (device.IsNotNull() && device->GetIsActive()) { device->Deactivate(); device->Disconnect(); } } StoreUISettings(); } catch (std::exception &e) { MITK_ERROR << "Exception during call of destructor! Message: " << e.what(); } } void UltrasoundSupport::StoreUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); settings.setValue("DisplayImage", QVariant(m_Controls.m_ShowImageStream->isChecked())); settings.setValue("RunImageTimer", QVariant(m_Controls.m_RunImageTimer->isChecked())); settings.setValue("Update2DView", QVariant(m_Controls.m_Update2DView->isChecked())); settings.setValue("Update3DView", QVariant(m_Controls.m_Update3DView->isChecked())); settings.setValue("UpdateRatePipeline", QVariant(m_Controls.m_FrameRatePipeline->value())); settings.setValue("UpdateRate2d", QVariant(m_Controls.m_FrameRate2d->value())); settings.setValue("UpdateRate3d", QVariant(m_Controls.m_FrameRate3d->value())); settings.endGroup(); } void UltrasoundSupport::LoadUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); m_Controls.m_ShowImageStream->setChecked(settings.value("DisplayImage", true).toBool()); m_Controls.m_RunImageTimer->setChecked(settings.value("RunImageTimer", true).toBool()); m_Controls.m_Update2DView->setChecked(settings.value("Update2DView", true).toBool()); m_Controls.m_Update3DView->setChecked(settings.value("Update3DView", true).toBool()); m_Controls.m_FrameRatePipeline->setValue(settings.value("UpdateRatePipeline", 50).toInt()); m_Controls.m_FrameRate2d->setValue(settings.value("UpdateRate2d", 20).toInt()); m_Controls.m_FrameRate3d->setValue(settings.value("UpdateRate3d", 5).toInt()); settings.endGroup(); } void UltrasoundSupport::StartTimers() { m_UpdateTimer->start(); if (m_Controls.m_Update2DView->isChecked()) { m_RenderingTimer2d->start(); } if (m_Controls.m_Update3DView->isChecked()) { m_RenderingTimer3d->start(); } } void UltrasoundSupport::StopTimers() { m_UpdateTimer->stop(); m_RenderingTimer2d->stop(); m_RenderingTimer3d->stop(); } void UltrasoundSupport::SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D) { m_UpdateTimer->setInterval(intervalPipeline); m_RenderingTimer2d->setInterval(interval2D); m_RenderingTimer3d->setInterval(interval3D); }