diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp index 253f6b6cd2..fe303273c1 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp @@ -1,824 +1,824 @@ /*=================================================================== 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_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; } // 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 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[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"; + 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::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()); // 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"; // 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"; 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(PAImage, pathPA); } // ...and the raw images if (m_SavingSettings.saveRaw) { OrderImagesInterleaved(PAImageRaw, USImageRaw, m_RawRecordedImages, true); 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/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/files.cmake b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/files.cmake index d1ea1b0bd4..a9177ae3a3 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/files.cmake +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/files.cmake @@ -1,26 +1,29 @@ -set(INTERNAL_CPP_FILES +set(SRC_CPP_FILES QmitkPAUSViewerView.cpp +) + +set(INTERNAL_CPP_FILES org_mitk_gui_qt_photoacoustics_pausviewer_Activator.cpp ) set(UI_FILES src/internal/QmitkPAUSViewerViewControls.ui ) set(MOC_H_FILES - src/internal/QmitkPAUSViewerView.h + src/QmitkPAUSViewerView.h src/internal/org_mitk_gui_qt_photoacoustics_pausviewer_Activator.h ) set(CACHED_RESOURCE_FILES resources/PAUSViewer.png plugin.xml ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp new file mode 100644 index 0000000000..15ad7b8610 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp @@ -0,0 +1,123 @@ +/*=================================================================== + +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 "mitkScaleLegendOverlay.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()) +{ +} + +QmitkPAUSViewerView::~QmitkPAUSViewerView() +{ +} + +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_PAOverlayManager == nullptr || m_USRenderer == nullptr || m_USOverlayManager == nullptr) + { + //setup an overlay manager + mitk::OverlayManager::Pointer OverlayManagerInstancePA = mitk::OverlayManager::New(); + m_PARenderer = mitk::BaseRenderer::GetInstance(GetPARenderWindow()); + m_PARenderer->SetOverlayManager(OverlayManagerInstancePA); + m_PAOverlayManager = m_PARenderer->GetOverlayManager(); + + mitk::OverlayManager::Pointer OverlayManagerInstanceUS = mitk::OverlayManager::New(); + m_USRenderer = mitk::BaseRenderer::GetInstance(GetUSRenderWindow()); + m_USRenderer->SetOverlayManager(OverlayManagerInstanceUS); + m_USOverlayManager = m_USRenderer->GetOverlayManager(); + } + + mitk::ScaleLegendOverlay::Pointer scaleOverlay = mitk::ScaleLegendOverlay::New(); + scaleOverlay->SetLeftAxisVisibility(true); + scaleOverlay->SetRightAxisVisibility(false); + scaleOverlay->SetRightAxisVisibility(false); + scaleOverlay->SetTopAxisVisibility(false); + scaleOverlay->SetCornerOffsetFactor(0); + m_PAOverlayManager->AddOverlay(scaleOverlay.GetPointer()); + m_USOverlayManager->AddOverlay(scaleOverlay.GetPointer()); +} + +void QmitkPAUSViewerView::RemoveOverlays() +{ + m_PAOverlayManager->RemoveAllOverlays(); +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerView.h b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.h similarity index 56% rename from Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerView.h rename to Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.h index b994cdba12..69a9ec52ca 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerView.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.h @@ -1,54 +1,76 @@ /*=================================================================== 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 QMITKPAUSVIEWERVIEW_H_INCLUDED #define QMITKPAUSVIEWERVIEW_H_INCLUDED #include #include +#include +#include +#include "QmitkRenderWindow.h" +#include #include "ui_QmitkPAUSViewerViewControls.h" +#include "org_mitk_gui_qt_photoacoustics_pausviewer_Export.h" #include "mitkCommon.h" -class QmitkPAUSViewerView : public QmitkAbstractView +class PHOTOACOUSTICS_PAUSVIEWER_EXPORTS QmitkPAUSViewerView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkPAUSViewerView(); virtual ~QmitkPAUSViewerView(); - virtual void CreateQtPartControl(QWidget *parent); + virtual void CreateQtPartControl(QWidget *parent) override; void InitWindows(); + void SetPADataStorage(mitk::StandaloneDataStorage::Pointer paStore); + void SetUSDataStorage(mitk::StandaloneDataStorage::Pointer usStore); + + vtkRenderWindow* GetPARenderWindow(); + vtkRenderWindow* GetUSRenderWindow(); + protected: + void AddOverlays(); + void RemoveOverlays(); + + mitk::StandaloneDataStorage::Pointer m_PADataStorage; + mitk::StandaloneDataStorage::Pointer m_USDataStorage; + + mitk::OverlayManager::Pointer m_PAOverlayManager; + mitk::OverlayManager::Pointer m_USOverlayManager; + mitk::BaseRenderer::Pointer m_PARenderer; + mitk::BaseRenderer::Pointer m_USRenderer; + virtual void SetFocus() override; virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& nodes) override; - Ui::QmitkPAUSViewerViewControls m_Controls; + Ui::QmitkPAUSViewerViewControls* m_Controls; }; #endif // QMITKPAUSVIEWERVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerView.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerView.cpp deleted file mode 100644 index 67af788781..0000000000 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerView.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/*=================================================================== - -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 "QmitkPAUSViewerView.h" - -const std::string QmitkPAUSViewerView::VIEW_ID = "org.mitk.views.photoacoustics.pausviewer"; - -QmitkPAUSViewerView::QmitkPAUSViewerView() -{ -} - -QmitkPAUSViewerView::~QmitkPAUSViewerView() -{ -} - -void QmitkPAUSViewerView::InitWindows() -{ -} - -void QmitkPAUSViewerView::SetFocus() -{ -} - -void QmitkPAUSViewerView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, - const QList& nodes) -{ -} - -void QmitkPAUSViewerView::CreateQtPartControl(QWidget *parent) -{ - m_Controls.setupUi(parent); -} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerViewControls.ui b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerViewControls.ui index dda546f9e0..8d192e8de4 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerViewControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/internal/QmitkPAUSViewerViewControls.ui @@ -1,91 +1,129 @@ QmitkPAUSViewerViewControls 0 0 1086 744 0 0 QmitkTemplate false 0 0 - - - - - 0 - 0 - - - - 75 true Ultrasound - + + + + + 0 + 0 + + + + + 75 true Photoacoustics + + + + + 0 + 0 + + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + QmitkRenderWindow QListView
QmitkRenderWindow.h
+ + QmitkLevelWindowWidget + QWidget +
QmitkLevelWindowWidget.h
+ 1 +
QmitkDataStorageComboBox.h
diff --git a/Plugins/org.mitk.gui.qt.ultrasound/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.ultrasound/manifest_headers.cmake index 182113f62b..ef169719cb 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.ultrasound/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "Ultrasound") set(Plugin-Version "0.1") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "") -set(Require-Plugin org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.qt.common org.mitk.gui.qt.photoacoustics.pausviewer) 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 9904cbd530..31b569d45c 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.cpp @@ -1,732 +1,677 @@ /*=================================================================== 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 #include #include #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" -#include "mitkScaleLegendOverlay.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); - - CreateWindows(); } void UltrasoundSupport::CreateWindows() { - auto renderingManager = mitk::RenderingManager::GetInstance(); - - m_PARenderWidget = new QmitkSliceWidget(); - m_PARenderWidget->SetLevelWindowEnabled(true); - m_PARenderWidget->levelWindow->SetDataStorage(m_PADataStorage); - m_PARenderWidget->SetDataStorage(m_PADataStorage); - m_PARenderWidget->hide(); - m_PARenderWidget->m_NavigatorWidget->hide(); - - m_USRenderWidget = new QmitkSliceWidget(); - m_USRenderWidget->SetLevelWindowEnabled(true); - m_USRenderWidget->levelWindow->SetDataStorage(m_USDataStorage); - m_USRenderWidget->SetDataStorage(m_USDataStorage); - m_USRenderWidget->hide(); - m_USRenderWidget->m_NavigatorWidget->hide(); + m_PausViewerView = dynamic_cast((GetSite()->GetWorkbenchWindow()->GetActivePage()->FindView("org.mitk.views.photoacoustics.pausviewer")).GetPointer()); + if (m_PausViewerView == nullptr) + MITK_INFO << "failed"; + m_PausViewerView->SetPADataStorage(m_PADataStorage); + m_PausViewerView->SetUSDataStorage(m_USDataStorage); } 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()); - UpdateColormaps(); this->GetDataStorage()->Add(Node); 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(); this->GetDataStorage()->Remove(Node); if (m_Node.size() > 1) m_USDataStorage->Remove(Node); else if (m_Node.size() == 1) m_PADataStorage->Remove(Node); Node->ReleaseData(); m_Node.pop_back(); - UpdateColormaps(); -} - -void UltrasoundSupport::AddOverlays() -{ - mitk::ScaleLegendOverlay::Pointer scaleOverlay = mitk::ScaleLegendOverlay::New(); - scaleOverlay->SetLeftAxisVisibility(true); - scaleOverlay->SetRightAxisVisibility(false); - scaleOverlay->SetRightAxisVisibility(false); - scaleOverlay->SetTopAxisVisibility(false); - scaleOverlay->SetCornerOffsetFactor(0); - m_PAOverlayManager->AddOverlay(scaleOverlay.GetPointer()); - m_USOverlayManager->AddOverlay(scaleOverlay.GetPointer()); -} - -void UltrasoundSupport::RemoveOverlays() -{ - m_PAOverlayManager->RemoveAllOverlays(); } -void UltrasoundSupport::UpdateColormaps() +void UltrasoundSupport::UpdateLevelWindows() { - //return; // TODO: review the colormap functionality - - // we update here both the colormaps of the nodes, as well as the - // level window for the current dynamic range mitk::LevelWindow levelWindow; if (m_Node.size() > 1) { - for (int index = 0; index < m_AmountOfOutputs - 1; ++index) + for (int index = 0; index < m_AmountOfOutputs; ++index) { - SetColormap(m_Node.at(index), mitk::LookupTable::LookupTableType::GRAYSCALE); m_Node.at(index)->GetLevelWindow(levelWindow); - if (!m_Image->IsEmpty()) - levelWindow.SetAuto(m_Image, true, true); + if (!m_curOutput.at(index)->IsEmpty()) + levelWindow.SetWindowBounds(0, 4 * (index+1)); + //levelWindow.SetAuto(m_curOutput.at(index), true, true); m_Node.at(index)->SetLevelWindow(levelWindow); } - SetColormap(m_Node.back(), mitk::LookupTable::LookupTableType::GRAYSCALE); - m_Node.back()->GetLevelWindow(levelWindow); - levelWindow.SetWindowBounds(10, 150, true); - m_Node.back()->SetLevelWindow(levelWindow); } else if (m_Node.size() == 1) { - SetColormap(m_Node.back(), mitk::LookupTable::LookupTableType::GRAYSCALE); m_Node.back()->GetLevelWindow(levelWindow); - if (!m_Image->IsEmpty()) - levelWindow.SetAuto(m_Image, true, true); + if (!m_curOutput.at(0)->IsEmpty()) + levelWindow.SetAuto(m_curOutput.at(0), true, true); m_Node.back()->SetLevelWindow(levelWindow); } } void UltrasoundSupport::SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type) { mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); mitk::LookupTableProperty::Pointer lookupTableProperty = mitk::LookupTableProperty::New(); lookupTable->SetType(type); lookupTableProperty->SetLookupTable(lookupTable); node->SetProperty("LookupTable", lookupTableProperty); mitk::RenderingModeProperty::Pointer renderingMode = dynamic_cast(node->GetProperty("Image Rendering.Mode")); renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); } void UltrasoundSupport::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()) { - if (m_PARenderer == nullptr || m_PAOverlayManager == nullptr || m_USRenderer == nullptr || m_USOverlayManager == nullptr) - { - //setup an overlay manager - mitk::OverlayManager::Pointer OverlayManagerInstancePA = mitk::OverlayManager::New(); - m_PARenderer = mitk::BaseRenderer::GetInstance(m_PARenderWidget->GetRenderWindow()->GetVtkRenderWindow()); - m_PARenderer->SetOverlayManager(OverlayManagerInstancePA); - m_PAOverlayManager = m_PARenderer->GetOverlayManager(); - - mitk::OverlayManager::Pointer OverlayManagerInstanceUS = mitk::OverlayManager::New(); - m_USRenderer = mitk::BaseRenderer::GetInstance(m_USRenderWidget->GetRenderWindow()->GetVtkRenderWindow()); - m_USRenderer->SetOverlayManager(OverlayManagerInstanceUS); - m_USOverlayManager = m_USRenderer->GetOverlayManager(); - - AddOverlays(); - - m_PARenderWidget->show(); - m_USRenderWidget->show(); - } - 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(m_AmountOfOutputs-index-1,0,0,nullptr,mitk::Image::ReferenceMemory)); + 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 { + if (!firstTimeLevelWindowInit) + { + UpdateLevelWindows(); + firstTimeLevelWindowInit = true; + } 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)) ) { 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()); } } //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; //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 auto renderingManager = mitk::RenderingManager::GetInstance(); - renderingManager->RequestUpdate(m_PARenderWidget->GetRenderWindow()->GetRenderWindow()); - renderingManager->RequestUpdate(m_USRenderWidget->GetRenderWindow()->GetRenderWindow()); + renderingManager->RequestUpdate(m_PausViewerView->GetPARenderWindow()); + renderingManager->RequestUpdate(m_PausViewerView->GetUSRenderWindow()); + + if (m_PausViewerView->GetPARenderWindow() == nullptr) + MITK_INFO << "nullptr at renderwindow"; + //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(); - m_PARenderWidget->hide(); - m_USRenderWidget->hide(); + + 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); } - m_PARenderWidget->show(); - m_USRenderWidget->show(); + CreateWindows(); + m_PausViewerView->InitWindows(); } 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_PARenderer(nullptr), m_PAOverlayManager(nullptr), m_USRenderer(nullptr), m_USOverlayManager(nullptr), - m_PADataStorage(mitk::StandaloneDataStorage::New()), m_USDataStorage(mitk::StandaloneDataStorage::New()) + m_CurrentImageWidth(0), m_CurrentImageHeight(0), m_AmountOfOutputs(0), + m_PADataStorage(mitk::StandaloneDataStorage::New()), m_USDataStorage(mitk::StandaloneDataStorage::New()), firstTimeLevelWindowInit(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(); } - - delete m_PARenderWidget; - delete m_USRenderWidget; } void UltrasoundSupport::StoreUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); settings.setValue("DisplayImage", QVariant(m_Controls.m_ShowImageStream->isChecked())); settings.setValue("RunImageTimer", QVariant(m_Controls.m_RunImageTimer->isChecked())); settings.setValue("Update2DView", QVariant(m_Controls.m_Update2DView->isChecked())); settings.setValue("Update3DView", QVariant(m_Controls.m_Update3DView->isChecked())); settings.setValue("UpdateRatePipeline", QVariant(m_Controls.m_FrameRatePipeline->value())); settings.setValue("UpdateRate2d", QVariant(m_Controls.m_FrameRate2d->value())); settings.setValue("UpdateRate3d", QVariant(m_Controls.m_FrameRate3d->value())); settings.endGroup(); } void UltrasoundSupport::LoadUISettings() { QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); m_Controls.m_ShowImageStream->setChecked(settings.value("DisplayImage", true).toBool()); m_Controls.m_RunImageTimer->setChecked(settings.value("RunImageTimer", true).toBool()); m_Controls.m_Update2DView->setChecked(settings.value("Update2DView", true).toBool()); m_Controls.m_Update3DView->setChecked(settings.value("Update3DView", true).toBool()); m_Controls.m_FrameRatePipeline->setValue(settings.value("UpdateRatePipeline", 50).toInt()); m_Controls.m_FrameRate2d->setValue(settings.value("UpdateRate2d", 20).toInt()); m_Controls.m_FrameRate3d->setValue(settings.value("UpdateRate3d", 5).toInt()); settings.endGroup(); } void UltrasoundSupport::StartTimers() { m_UpdateTimer->start(); if (m_Controls.m_Update2DView->isChecked()) { m_RenderingTimer2d->start(); } if (m_Controls.m_Update3DView->isChecked()) { m_RenderingTimer3d->start(); } } void UltrasoundSupport::StopTimers() { m_UpdateTimer->stop(); m_RenderingTimer2d->stop(); m_RenderingTimer3d->stop(); } void UltrasoundSupport::SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D) { m_UpdateTimer->setInterval(intervalPipeline); m_RenderingTimer2d->setInterval(interval2D); m_RenderingTimer3d->setInterval(interval3D); } diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h index 4349fd4032..715c5f3970 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/UltrasoundSupport.h @@ -1,189 +1,183 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef UltrasoundSupport_h #define UltrasoundSupport_h #include #include #include #include #include #include "ui_UltrasoundSupportControls.h" #include "QmitkUSAbstractCustomWidget.h" #include "QmitkUSControlsBModeWidget.h" #include "QmitkUSControlsDopplerWidget.h" #include "QmitkUSControlsProbesWidget.h" #include #include "QmitkRenderWindow.h" #include #include #include +#include #include #include /*! \brief UltrasoundSupport This plugin provides functionality to manage Ultrasound devices, create video devices and to view device images. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class UltrasoundSupport : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: virtual void SetFocus() override; static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent) override; UltrasoundSupport(); virtual ~UltrasoundSupport(); public slots: /* * \brief This is called when the newDeviceWidget is closed */ void OnNewDeviceWidgetDone(); protected slots: void OnClickedAddNewDevice(); void OnChangedFramerateLimit(); void OnClickedEditDevice(); /* *\brief Called, when the selection in the list of the active devices changes. */ void OnChangedActiveDevice(); void OnClickedFreezeButton(); void OnDeciveServiceEvent(const ctkServiceEvent event); /* * \brief This is the main imaging loop that updates the image and is called regularily during the imaging process */ void UpdateImage(); void RenderImage2d(); void RenderImage3d(); void StartTimers(); void StopTimers(); protected: void CreateControlWidgets(); void RemoveControlWidgets(); - void AddOverlays(); - void RemoveOverlays(); - void CreateWindows(); - QmitkSliceWidget* m_PARenderWidget; - QmitkSliceWidget* m_USRenderWidget; + QmitkPAUSViewerView* m_PausViewerView; mitk::StandaloneDataStorage::Pointer m_PADataStorage; mitk::StandaloneDataStorage::Pointer m_USDataStorage; - mitk::OverlayManager::Pointer m_PAOverlayManager; - mitk::OverlayManager::Pointer m_USOverlayManager; - mitk::BaseRenderer::Pointer m_PARenderer; - mitk::BaseRenderer::Pointer m_USRenderer; - /** The device that is currently used to aquire images */ mitk::USDevice::Pointer m_Device; void SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D); /** This timer triggers periodic updates to the pipeline */ QTimer* m_UpdateTimer; QTimer* m_RenderingTimer2d; QTimer* m_RenderingTimer3d; /** These clocks are used to compute the framerate in the methods DisplayImage(),RenderImage2d() and RenderImage3d(). */ QTime m_Clock; QTime m_Clock2d; QTime m_Clock3d; /** A counter to comute the framerate. */ int m_FrameCounterPipeline; int m_FrameCounter2d; int m_FrameCounter3d; int m_FPSPipeline, m_FPS2d, m_FPS3d; /** Stores the properties of some QWidgets (and the tool storage file name) to QSettings.*/ void StoreUISettings(); /** Loads the properties of some QWidgets (and the tool storage file name) from QSettings.*/ void LoadUISettings(); /** The nodes that we feed images into.*/ std::vector m_Node; /** Adds a new node to the m_Nodes vector*/ void InitNewNode(); /** Destroys the last node in the m_Nodes vector */ void DestroyLastNode(); /** Checks the amount of slices in the image from the USDevice and creates as many Nodes as there are slices */ void UpdateAmountOfOutputs(); /** This function just checks how many nodes there are currently and sets the laser image to a jet transparent colormap. */ - void UpdateColormaps(); + void UpdateLevelWindows(); + bool firstTimeLevelWindowInit; + void SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type); /** The image that holds all data given by the USDevice.*/ mitk::Image::Pointer m_Image; /** The seperated slices from m_Image */ std::vector m_curOutput; /** Keeps track of the amount of output Nodes*/ int m_AmountOfOutputs; /** The old geometry of m_Image. It is needed to check if the geometry changed (e.g. because * the zoom factor was modified) and the image needs to be reinitialized. */ mitk::SlicedGeometry3D::Pointer m_OldGeometry; Ui::UltrasoundSupportControls m_Controls; QmitkUSAbstractCustomWidget* m_ControlCustomWidget; QmitkUSControlsBModeWidget* m_ControlBModeWidget; QmitkUSControlsDopplerWidget* m_ControlDopplerWidget; QmitkUSControlsProbesWidget* m_ControlProbesWidget; QList m_CustomWidgetServiceReference; bool m_ImageAlreadySetToNode; unsigned int m_CurrentImageWidth; unsigned int m_CurrentImageHeight; double m_CurrentDynamicRange; }; #endif // UltrasoundSupport_h