diff --git a/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.cpp b/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.cpp index e9a7426e10..3a5211068f 100644 --- a/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.cpp +++ b/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.cpp @@ -1,262 +1,269 @@ /*=================================================================== 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 "mitkImageToIGTLMessageFilter.h" #include "mitkImageReadAccessor.h" #include "itkByteSwapper.h" #include "igtlImageMessage.h" mitk::ImageToIGTLMessageFilter::ImageToIGTLMessageFilter() { mitk::IGTLMessage::Pointer output = mitk::IGTLMessage::New(); this->SetNumberOfRequiredOutputs(1); this->SetNthOutput(0, output.GetPointer()); this->SetNumberOfRequiredInputs(1); } void mitk::ImageToIGTLMessageFilter::GenerateData() { // MITK_INFO << "ImageToIGTLMessageFilter.GenerateData()"; for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); ++i) { mitk::IGTLMessage* output = this->GetOutput(i); assert(output); const mitk::Image* img = this->GetInput(i); int dims = img->GetDimension(); int chn = img->GetNumberOfChannels(); if (dims < 1) { MITK_ERROR << "Can not handle dimensionless images"; } if (dims > 3) { MITK_ERROR << "Can not handle more than three dimensions"; continue; } if (chn != 1) { MITK_ERROR << "Can not handle anything but one channel. Image contained " << chn; continue; } igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New(); // TODO: Which kind of coordinate system does MITK really use? imgMsg->SetCoordinateSystem(igtl::ImageMessage::COORDINATE_RAS); // We could do this based on the host endiannes, but that's weird. // We instead use little endian, as most modern systems are little endian, // so there will probably not be an endian swap involved. imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_LITTLE); // Set number of components. mitk::PixelType type = img->GetPixelType(); imgMsg->SetNumComponents(type.GetNumberOfComponents()); // Set scalar type. switch (type.GetComponentType()) { case itk::ImageIOBase::CHAR: imgMsg->SetScalarTypeToInt8(); break; case itk::ImageIOBase::UCHAR: imgMsg->SetScalarTypeToUint8(); break; case itk::ImageIOBase::SHORT: imgMsg->SetScalarTypeToInt16(); break; case itk::ImageIOBase::USHORT: imgMsg->SetScalarTypeToUint16(); break; case itk::ImageIOBase::INT: imgMsg->SetScalarTypeToInt32(); break; case itk::ImageIOBase::UINT: imgMsg->SetScalarTypeToUint32(); break; case itk::ImageIOBase::LONG: // OIGTL doesn't formally support 64bit int scalars, but if they are // ever added, // they will have the identifier 8 assigned. imgMsg->SetScalarType(8); break; case itk::ImageIOBase::ULONG: // OIGTL doesn't formally support 64bit uint scalars, but if they are // ever added, // they will have the identifier 9 assigned. imgMsg->SetScalarType(9); break; case itk::ImageIOBase::FLOAT: // The igtl library has no method for this. Correct type is 10. imgMsg->SetScalarType(10); break; case itk::ImageIOBase::DOUBLE: // The igtl library has no method for this. Correct type is 11. imgMsg->SetScalarType(11); break; default: MITK_ERROR << "Can not handle pixel component type " << type.GetComponentType(); return; } // Set transformation matrix. vtkMatrix4x4* matrix = img->GetGeometry()->GetVtkMatrix(); float matF[4][4]; for (size_t i = 0; i < 4; ++i) { for (size_t j = 0; j < 4; ++j) { matF[i][j] = matrix->GetElement(i, j); } } imgMsg->SetMatrix(matF); float spacing[3]; auto spacingImg = img->GetGeometry()->GetSpacing(); for (int i = 0; i < 3; ++i) spacing[i] = spacingImg[i]; imgMsg->SetSpacing(spacing); // Set dimensions. int sizes[3]; for (size_t j = 0; j < 3; ++j) { sizes[j] = img->GetDimension(j); } imgMsg->SetDimensions(sizes); // Allocate and copy data. imgMsg->AllocatePack(); imgMsg->AllocateScalars(); size_t num_pixel = sizes[0] * sizes[1] * sizes[2]; void* out = imgMsg->GetScalarPointer(); { // Scoped, so that readAccess will be released ASAP. mitk::ImageReadAccessor readAccess(img, img->GetChannelData(0)); const void* in = readAccess.GetData(); memcpy(out, in, num_pixel * type.GetSize()); } // We want to byte swap to little endian. We would like to just // swap by number of bytes for each component, but itk::ByteSwapper // is templated over element type, not over element size. So we need to // switch on the size and use types of the same size. size_t num_scalars = num_pixel * type.GetNumberOfComponents(); switch (type.GetComponentType()) { case itk::ImageIOBase::CHAR: case itk::ImageIOBase::UCHAR: // No endian conversion necessary, because a char is exactly one byte! break; case itk::ImageIOBase::SHORT: case itk::ImageIOBase::USHORT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((short*)out, num_scalars); break; case itk::ImageIOBase::INT: case itk::ImageIOBase::UINT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((int*)out, num_scalars); break; case itk::ImageIOBase::LONG: case itk::ImageIOBase::ULONG: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((long*)out, num_scalars); break; case itk::ImageIOBase::FLOAT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((float*)out, num_scalars); break; case itk::ImageIOBase::DOUBLE: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian( (double*)out, num_scalars); break; } //copy timestamp of mitk image igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); timestamp->SetTime(img->GetMTime() / 1000, (int)(img->GetMTime()) % 1000); imgMsg->SetTimeStamp(timestamp); imgMsg->Pack(); output->SetMessage(imgMsg.GetPointer()); } } void mitk::ImageToIGTLMessageFilter::SetInput(const mitk::Image* img) { this->ProcessObject::SetNthInput(0, const_cast(img)); this->CreateOutputsForAllInputs(); } void mitk::ImageToIGTLMessageFilter::SetInput(unsigned int idx, const Image* img) { this->ProcessObject::SetNthInput(idx, const_cast(img)); this->CreateOutputsForAllInputs(); } const mitk::Image* mitk::ImageToIGTLMessageFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::Image* mitk::ImageToIGTLMessageFilter::GetInput(unsigned int idx) { if (this->GetNumberOfInputs() < idx + 1) { return nullptr; } return static_cast(this->ProcessObject::GetInput(idx)); } void mitk::ImageToIGTLMessageFilter::ConnectTo(mitk::ImageSource* upstream) { MITK_INFO << "Image source for this (" << this << ") mitkImageToIGTLMessageFilter is " << upstream; - for (DataObjectPointerArraySizeType i = 0; i < upstream->GetNumberOfOutputs(); + for (DataObjectPointerArraySizeType i = 0; upstream->GetNumberOfOutputs(); i++) { this->SetInput(i, upstream->GetOutput(i)); } } +void mitk::ImageToIGTLMessageFilter::ConnectTo(mitk::ImageSource *upstream, unsigned int output, unsigned int input) +{ + MITK_INFO << "Image source for this (" << this << ") mitkImageToIGTLMessageFilter is " << upstream; + MITK_INFO << "Connected output " << output << " to input " << input; + this->SetInput(input, upstream->GetOutput(output)); +} + void mitk::ImageToIGTLMessageFilter::CreateOutputsForAllInputs() { // create one message output for all image inputs this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); for (size_t idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx) { if (this->GetOutput(idx) == nullptr) { this->SetNthOutput(idx, this->MakeOutput(idx)); } this->Modified(); } } diff --git a/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.h b/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.h index e9f840245b..c758a70161 100644 --- a/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.h +++ b/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.h @@ -1,98 +1,107 @@ /*=================================================================== 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 _MITKIMAGEToIGTLMessageFILTER_H__ #define _MITKIMAGEToIGTLMessageFILTER_H__ #include #include #include #include namespace mitk { /**Documentation * * \brief This filter creates IGTL messages from mitk::Image objects * * \ingroup OpenIGTLink * */ class MITKOPENIGTLINK_EXPORT ImageToIGTLMessageFilter : public IGTLMessageSource { public: mitkClassMacro(ImageToIGTLMessageFilter, IGTLMessageSource); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** * \brief filter execute method */ void GenerateData() override; using Superclass::SetInput; /** * \brief Sets one input Image */ virtual void SetInput(const mitk::Image* img); /** * \brief Sets the input Image at a specific index */ virtual void SetInput(unsigned int idx, const Image* img); /** * \brief Returns the input of this filter */ const mitk::Image* GetInput(); /** * \brief Returns the input of this filter */ const mitk::Image* GetInput(unsigned int idx); /** * empty implementation to prevent calling of the superclass method that * would try to copy information from the input Image to the output * PointSet, which makes no sense! */ void GenerateOutputInformation() override{}; /** * \brief Connects the input of this filter to the outputs of the given *ImageSource * * This method does not support smartpointer. use FilterX.GetPointer() to * retrieve a dumbpointer. */ virtual void ConnectTo(mitk::ImageSource* UpstreamFilter); + /** + * \brief Connects the input of index "input" of this filter to the output of index "output" of the given + *ImageSource + * + * This method does not support smartpointer. use FilterX.GetPointer() to + * retrieve a dumbpointer. + */ + virtual void ConnectTo(mitk::ImageSource *upstream, unsigned int output, unsigned int input); + protected: ImageToIGTLMessageFilter(); ~ImageToIGTLMessageFilter() override {}; /** * \brief create output objects for all inputs */ virtual void CreateOutputsForAllInputs(); mitk::ImageSource* m_Upstream; }; } // namespace mitk #endif // _MITKIMAGEToIGTLMessageFILTER_H__ diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp index 5b565556d4..38b3a3b86b 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.cpp @@ -1,1035 +1,1128 @@ /*=================================================================== 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 +#include +#include // mitk dependencies +#include "ITKUltrasound/itkBModeImageFilter.h" +#include "mitkITKImageImport.h" +#include "mitkImageCast.h" +#include "mitkUSDiPhASBModeImageFilter.h" #include "mitkUSDiPhASDevice.h" #include "mitkUSDiPhASImageSource.h" #include -#include "mitkUSDiPhASBModeImageFilter.h" -#include "ITKUltrasound/itkBModeImageFilter.h" -#include "mitkImageCast.h" -#include "mitkITKImageImport.h" +#include #include // itk dependencies -#include "itkImage.h" -#include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCropImageFilter.h" -#include "itkRescaleIntensityImageFilter.h" +#include "itkImage.h" #include "itkIntensityWindowingImageFilter.h" -#include #include "itkMultiplyImageFilter.h" +#include "itkResampleImageFilter.h" +#include "itkRescaleIntensityImageFilter.h" +#include -mitk::USDiPhASImageSource::USDiPhASImageSource(mitk::USDiPhASDevice* device) +mitk::USDiPhASImageSource::USDiPhASImageSource(mitk::USDiPhASDevice *device) : m_Device(device), - m_StartTime(((float)std::clock()) / CLOCKS_PER_SEC), - m_DataType(DataType::Image_uChar), - m_UseBModeFilter(false), - m_CurrentlyRecording(false), - m_DataTypeModified(true), - m_DataTypeNext(DataType::Image_uChar), - m_RecordedImageCounter(0), - m_PyroConnected(false), - m_VerticalSpacing(0), - m_UseBModeFilterModified(false), - m_UseBModeFilterNext(false), - m_ScatteringCoefficientModified(false), - m_CompensateForScatteringModified(false), - m_VerticalSpacingModified(false), - m_ScatteringCoefficient(15), - m_CompensateForScattering(false), - m_CompensateEnergy(false), - m_CompensateEnergyNext(false), - m_CompensateEnergyModified(false), - m_BatchSize(24), // why? because magic number, thats why! - m_SavingName("-replace"), - m_BufferBatches(12), // we like magic numbers - m_LastImage(0) + m_StartTime(((float)std::clock()) / CLOCKS_PER_SEC), + m_DataType(DataType::Image_uChar), + m_UseBModeFilter(false), + m_CurrentlyRecording(false), + m_DataTypeModified(true), + m_DataTypeNext(DataType::Image_uChar), + m_RecordedImageCounter(0), + m_PyroConnected(false), + m_VerticalSpacing(0), + m_UseBModeFilterModified(false), + m_UseBModeFilterNext(false), + m_ScatteringCoefficientModified(false), + m_CompensateForScatteringModified(false), + m_VerticalSpacingModified(false), + m_ScatteringCoefficient(15), + m_CompensateForScattering(false), + m_CompensateEnergy(false), + m_CompensateEnergyNext(false), + m_CompensateEnergyModified(false), + m_BatchSize(24), // why? because magic number, thats why! + m_SavingName("-replace"), + m_BufferBatches(12), // we like magic numbers + m_LastImage(0) { - // fill the Recording Buffers with empty images - m_ImagesBuffer.insert(m_ImagesBuffer.begin(),m_BufferBatches, std::vector>()); - m_RawImagesBuffer.insert(m_RawImagesBuffer.begin(),m_BufferBatches, std::vector>()); - m_ImageTimestampsBuffer.insert(m_ImageTimestampsBuffer.begin(),m_BufferBatches, std::vector()); + m_ImagesBuffer.insert( + m_ImagesBuffer.begin(), m_BufferBatches, std::vector>()); + m_RawImagesBuffer.insert( + m_RawImagesBuffer.begin(), m_BufferBatches, std::vector>()); + m_ImageTimestampsBuffer.insert(m_ImageTimestampsBuffer.begin(), m_BufferBatches, std::vector()); - for (int i = 0; i (mitk::Image::New(), mitk::Image::New())); - m_RawImagesBuffer[i].insert(m_RawImagesBuffer[i].begin(), m_BatchSize, std::pair(mitk::Image::New(), mitk::Image::New())); + m_ImagesBuffer[i].insert( + m_ImagesBuffer[i].begin(), + m_BatchSize, + std::pair(mitk::Image::New(), mitk::Image::New())); + m_RawImagesBuffer[i].insert( + m_RawImagesBuffer[i].begin(), + m_BatchSize, + std::pair(mitk::Image::New(), mitk::Image::New())); m_ImageTimestampsBuffer[i].insert(m_ImageTimestampsBuffer[i].begin(), m_BatchSize, 0); } m_LastBatch = 0; m_LastImage = -1; 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::Load(name)); } m_FluenceCompResized.insert(m_FluenceCompResized.begin(), 26, Image::New()); - m_FluenceCompResizedItk.insert(m_FluenceCompResizedItk.begin(), 26, itk::Image::New()); + m_FluenceCompResizedItk.insert(m_FluenceCompResizedItk.begin(), 26, itk::Image::New()); } mitk::USDiPhASImageSource::~USDiPhASImageSource() { // close the pyro MITK_INFO("Pyro Debug") << "StopDataAcquisition: " << m_Pyro->StopDataAcquisition(); MITK_INFO("Pyro Debug") << "CloseConnection: " << m_Pyro->CloseConnection(); m_PyroConnected = false; m_Pyro = nullptr; } void mitk::USDiPhASImageSource::CheckModifiedVariables() { // modify all settings that have been changed here, so we don't get multithreading issues if (m_DataTypeModified) { SetDataType(m_DataTypeNext); m_DataTypeModified = false; UpdateImageGeometry(); } if (m_UseBModeFilterModified) { SetUseBModeFilter(m_UseBModeFilterNext); m_UseBModeFilterModified = false; } if (m_VerticalSpacingModified) { m_VerticalSpacing = m_VerticalSpacingNext; m_VerticalSpacingModified = false; } if (m_ScatteringCoefficientModified) { m_ScatteringCoefficient = m_ScatteringCoefficientNext; m_ScatteringCoefficientModified = false; } if (m_CompensateForScatteringModified) { m_CompensateForScattering = m_CompensateForScatteringNext; m_CompensateForScatteringModified = false; } if (m_CompensateEnergyModified) { m_CompensateEnergy = m_CompensateEnergyNext; m_CompensateEnergyModified = false; } } -void mitk::USDiPhASImageSource::ResizeFluenceImage(mitk::Vector3D spacing, unsigned int* dimensions) +void mitk::USDiPhASImageSource::ResizeFluenceImage(mitk::Vector3D spacing, unsigned int *dimensions) { auto curResizeImage = ApplyResampling(m_FluenceCompOriginal.at(m_ScatteringCoefficient), spacing, dimensions); unsigned int imageSize = dimensions[0] * dimensions[1]; - double* rawOutputData = new double[imageSize]; - double* rawScatteringData = (double*)curResizeImage->GetData(); + double *rawOutputData = new double[imageSize]; + double *rawScatteringData = (double *)curResizeImage->GetData(); unsigned int sizeRawScatteringData = curResizeImage->GetDimension(0) * curResizeImage->GetDimension(1); - //everything above 1.5mm is still inside the transducer; therefore the fluence compensation image has to be positioned a little lower + // everything above 1.5mm is still inside the transducer; therefore the fluence compensation image has to be + // positioned a little lower float upperCutoffmm = 1.5; - unsigned int lowerBound = std::round(upperCutoffmm / spacing[1])*dimensions[0]; + unsigned int lowerBound = std::round(upperCutoffmm / spacing[1]) * dimensions[0]; unsigned int upperBound = lowerBound + sizeRawScatteringData; for (unsigned int i = 0; i < lowerBound && i < imageSize; ++i) { rawOutputData[i] = 0; // everything than cannot be compensated shall be treated as garbage, here the upper 0.15mm } for (unsigned int i = lowerBound; i < upperBound && i < imageSize; ++i) { rawOutputData[i] = 1 / rawScatteringData[i - lowerBound]; } for (unsigned int i = upperBound; i < imageSize; ++i) { rawOutputData[i] = 0; // everything than cannot be compensated shall be treated as garbage } - unsigned int dim[] = { dimensions[0], dimensions[1], 1 }; + unsigned int dim[] = {dimensions[0], dimensions[1], 1}; curResizeImage->Initialize(mitk::MakeScalarPixelType(), 3, dim); curResizeImage->SetSpacing(spacing); curResizeImage->SetSlice(rawOutputData); mitk::CastToItkImage(curResizeImage, m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); - m_FluenceCompResized.at(m_ScatteringCoefficient) = mitk::GrabItkImageMemory(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); + m_FluenceCompResized.at(m_ScatteringCoefficient) = + mitk::GrabItkImageMemory(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); MITK_INFO << "Resized a fluence image."; delete[] rawOutputData; } -void mitk::USDiPhASImageSource::GetNextRawImage(std::vector& imageVector) +void mitk::USDiPhASImageSource::GetNextRawImage(std::vector &imageVector) { CheckModifiedVariables(); if (imageVector.size() != 2) { imageVector.resize(2); } if (m_LastImage == -1) return; // make sure image is nullptr mitk::Image::Pointer imageUS = nullptr; mitk::Image::Pointer imagePA = nullptr; float ImageEnergyValue = 0; imagePA = m_ImagesBuffer[m_LastBatch][m_LastImage].first; imageUS = m_ImagesBuffer[m_LastBatch][m_LastImage].second; ImageEnergyValue = 1; if (imagePA == nullptr || imageUS == nullptr || !imagePA->IsInitialized() || !imageUS->IsInitialized()) return; // do image processing before displaying it - if(imagePA.IsNotNull() && m_DataType == DataType::Beamformed_Short) + if (imagePA.IsNotNull() && m_DataType == DataType::Beamformed_Short) { itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(imagePA, itkImage); - imagePA = mitk::GrabItkImageMemory(itkImage); //thereby using float images + imagePA = mitk::GrabItkImageMemory(itkImage); // thereby using float images imagePA = CutOffTop(imagePA, 165); if (m_CompensateEnergy && ImageEnergyValue != 1) imagePA = MultiplyImage(imagePA, 1 / ImageEnergyValue); // TODO: add the correct prefactor here if (m_UseBModeFilter) imagePA = ApplyBmodeFilter(imagePA, false); if (m_VerticalSpacing) imagePA = ResampleOutputVertical(imagePA, m_VerticalSpacing); if (m_CompensateForScattering) { auto curResizeImage = m_FluenceCompResized.at(m_ScatteringCoefficient); - bool doResampling = imagePA->GetDimension(0) != curResizeImage->GetDimension(0) || imagePA->GetDimension(1) != curResizeImage->GetDimension(1) - || imagePA->GetGeometry()->GetSpacing()[0] != curResizeImage->GetGeometry()->GetSpacing()[0] || imagePA->GetGeometry()->GetSpacing()[1] != curResizeImage->GetGeometry()->GetSpacing()[1]; + bool doResampling = imagePA->GetDimension(0) != curResizeImage->GetDimension(0) || + imagePA->GetDimension(1) != curResizeImage->GetDimension(1) || + imagePA->GetGeometry()->GetSpacing()[0] != curResizeImage->GetGeometry()->GetSpacing()[0] || + imagePA->GetGeometry()->GetSpacing()[1] != curResizeImage->GetGeometry()->GetSpacing()[1]; if (doResampling) ResizeFluenceImage(imagePA->GetGeometry()->GetSpacing(), imagePA->GetDimensions()); imagePA = ApplyScatteringCompensation(imagePA, m_ScatteringCoefficient); } } - if(imageUS.IsNotNull() && m_DataType == DataType::Beamformed_Short) + if (imageUS.IsNotNull() && m_DataType == DataType::Beamformed_Short) { itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(imageUS, itkImage); - imageUS = mitk::GrabItkImageMemory(itkImage); //thereby using float images + imageUS = mitk::GrabItkImageMemory(itkImage); // thereby using float images imageUS = CutOffTop(imageUS, 165); if (m_UseBModeFilter) imageUS = ApplyBmodeFilter(imageUS, true); // the US Images get a logarithmic filter if (m_VerticalSpacing) imageUS = ResampleOutputVertical(imageUS, m_VerticalSpacing); + } + itkUCharImageType::Pointer itkImage = nullptr; + if (imageUS != nullptr && imageUS->IsInitialized()) + { + //NormalizeImage(imageUS, 10); + //itkImage = nullptr; + //mitk::CastToItkImage(imageUS, itkImage); + //imageUS = mitk::GrabItkImageMemory(itkImage); } + + if (imagePA != nullptr && imagePA->IsInitialized()) + { + NormalizeImage(imagePA, 10); + itkImage = nullptr; + mitk::CastToItkImage(imagePA, itkImage); + imagePA = mitk::GrabItkImageMemory(itkImage); + } + imageVector[0] = imagePA; imageVector[1] = imageUS; } +void mitk::USDiPhASImageSource::NormalizeImage(mitk::Image::Pointer image, double rescale) +{ + auto imageStat = image->GetStatistics(); + float max = imageStat->GetScalarValueMax(); + float min = imageStat->GetScalarValueMin(); + float offset = (max + min) / 2.; + float scale = std::max(abs(min - offset), abs(max - offset)); + + mitk::ImageWriteAccessor write(image); + float *data = (float *)write.GetData(); + + for (size_t i = 0; i < image->GetDimension(0) * image->GetDimension(1) * image->GetDimension(2); ++i) + { + if (data[i] > 255) + data[i] = 255; + else if (data[i] < 0) + data[i] = 0; + } +} + mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyBmodeFilter(mitk::Image::Pointer image, bool useLogFilter) { // we use this seperate ApplyBmodeFilter Method for processing of two-dimensional images - // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage + // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by + // the CastToItkImage - typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; - BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter + typedef itk::BModeImageFilter BModeFilterType; + BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter - typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; - PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter + typedef itk::PhotoacousticBModeImageFilter PhotoacousticBModeImageFilter; + PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = + PhotoacousticBModeImageFilter::New(); // No LogFilter itkFloatImageType::Pointer itkImage; itkFloatImageType::Pointer bmode; mitk::CastToItkImage(image, itkImage); if (useLogFilter) { bModeFilter->SetInput(itkImage); bModeFilter->SetDirection(1); bmode = bModeFilter->GetOutput(); } else { photoacousticBModeFilter->SetInput(itkImage); photoacousticBModeFilter->SetDirection(1); bmode = photoacousticBModeFilter->GetOutput(); } return mitk::GrabItkImageMemory(bmode); } mitk::Image::Pointer mitk::USDiPhASImageSource::CutOffTop(mitk::Image::Pointer image, int cutOffSize) { - typedef itk::CropImageFilter < itkFloatImageType, itkFloatImageType > CutImageFilter; + typedef itk::CropImageFilter CutImageFilter; itkFloatImageType::SizeType cropSize; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(image, itkImage); cropSize[0] = 0; - if(itkImage->GetLargestPossibleRegion().GetSize()[1] == 2048) + if (itkImage->GetLargestPossibleRegion().GetSize()[1] == 2048) cropSize[1] = cutOffSize; else cropSize[1] = 0; cropSize[2] = 0; CutImageFilter::Pointer cutOffFilter = CutImageFilter::New(); cutOffFilter->SetInput(itkImage); cutOffFilter->SetLowerBoundaryCropSize(cropSize); cutOffFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(cutOffFilter->GetOutput()); } -mitk::Image::Pointer mitk::USDiPhASImageSource::ResampleOutputVertical(mitk::Image::Pointer image, float verticalSpacing) +mitk::Image::Pointer mitk::USDiPhASImageSource::ResampleOutputVertical(mitk::Image::Pointer image, + float verticalSpacing) { - typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + typedef itk::ResampleImageFilter ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(image, itkImage); itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; - outputSpacing[0] = itkImage->GetSpacing()[0] * (static_cast(inputSize[0]) / static_cast(outputSize[0])); + outputSpacing[0] = + itkImage->GetSpacing()[0] * (static_cast(inputSize[0]) / static_cast(outputSize[0])); outputSpacing[1] = verticalSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } -mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) +mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, + int scattering) { - typedef itk::MultiplyImageFilter MultiplyImageFilterType; + 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]) +mitk::Image::Pointer mitk::USDiPhASImageSource::ApplyResampling(mitk::Image::Pointer inputImage, + mitk::Vector3D outputSpacing, + unsigned int outputSize[3]) { - typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + typedef itk::ResampleImageFilter 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[0] = + 0.996 * inputSpacing[0] * + (static_cast(inputSizeItk[0]) / + static_cast( + outputSizeItk[0])); // TODO: find out why the spacing is not correct, so we need that factor; ?!?! + outputSpacingItk[1] = + inputSpacing[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); outputSpacingItk[2] = outputSpacing[2]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSizeItk); resampleImageFilter->SetOutputSpacing(outputSpacingItk); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::USDiPhASImageSource::MultiplyImage(mitk::Image::Pointer inputImage, double value) { - typedef itk::MultiplyImageFilter MultiplyImageFilterType; + 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, +void mitk::USDiPhASImageSource::ImageDataCallback(short *rfDataChannelData, + int &channelDataChannelsPerDataset, + int &channelDataSamplesPerChannel, + int &channelDataTotalDatasets, - short* rfDataArrayBeamformed, - int& beamformedLines, - int& beamformedSamples, - int& beamformedTotalDatasets, + short *rfDataArrayBeamformed, + int &beamformedLines, + int &beamformedSamples, + int &beamformedTotalDatasets, - unsigned char* imageData, - int& imageWidth, - int& imageHeight, - int& imageBytesPerPixel, - int& imageSetsTotal, + unsigned char *imageData, + int &imageWidth, + int &imageHeight, + int &imageBytesPerPixel, + int &imageSetsTotal, - double& timeStamp) + 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)); + bool writeImage = ((m_DataType == DataType::Image_uChar) && (imageData != nullptr)) || + ((m_DataType == DataType::Beamformed_Short) && (rfDataArrayBeamformed != nullptr)); if (writeImage) { int currentBatch = -1; int currentImage = -1; long long currentImageTimestamp = std::chrono::high_resolution_clock::now().time_since_epoch().count(); // check whether we lost any images - if (m_CurrentlyRecording && - m_ImageTimestampsBuffer[m_LastBatch][m_LastImage] != 0 - && std::abs(currentImageTimestamp - m_ImageTimestampsBuffer[m_LastBatch][m_LastImage]) > 53 * std::pow(10, 6)) + if (m_CurrentlyRecording && m_ImageTimestampsBuffer[m_LastBatch][m_LastImage] != 0 && + std::abs(currentImageTimestamp - m_ImageTimestampsBuffer[m_LastBatch][m_LastImage]) > 53 * std::pow(10, 6)) { - MITK_ERROR << "Lost about " << (float)std::abs(currentImageTimestamp - m_ImageTimestampsBuffer[m_LastBatch][m_LastImage]) / (5.f*std::pow(10, 7)) - 1 << " images"; + MITK_ERROR << "Lost about " + << (float)std::abs(currentImageTimestamp - m_ImageTimestampsBuffer[m_LastBatch][m_LastImage]) / + (5.f * std::pow(10, 7)) - + 1 + << " images"; } if ((m_LastImage + 1) % m_BatchSize == 0) { if (m_CurrentlyRecording) { // save the completed batch - m_SaveThreads.push_back(std::thread(&USDiPhASImageSource::saveDataThread, this, m_LastBatch, m_RecordedImageCounter, m_SavingName)); + m_SaveThreads.push_back( + std::thread(&USDiPhASImageSource::saveDataThread, this, m_LastBatch, m_RecordedImageCounter, m_SavingName)); ++m_RecordedImageCounter; } - //switch to next one - currentBatch = (m_LastBatch + 1) %m_BufferBatches; + // switch to next one + currentBatch = (m_LastBatch + 1) % m_BufferBatches; currentImage = 0; } else { currentBatch = m_LastBatch; currentImage = (m_LastImage + 1); } // create new images and initialize them mitk::Image::Pointer imageUS = m_ImagesBuffer[currentBatch][currentImage].second; mitk::Image::Pointer imagePA = m_ImagesBuffer[currentBatch][currentImage].first; switch (m_DataType) { - case DataType::Image_uChar: { - if (!imagePA->IsInitialized() - || imagePA->GetDimension(0) != imageWidth - || imagePA->GetDimension(1) != imageHeight - || std::abs(imagePA->GetGeometry()->GetSpacing()[0] - m_ImageSpacing[0]) > std::numeric_limits::epsilon() - || std::abs(imagePA->GetGeometry()->GetSpacing()[1] - m_ImageSpacing[1]) > std::numeric_limits::epsilon()) + case DataType::Image_uChar: + { + if (!imagePA->IsInitialized() || imagePA->GetDimension(0) != imageWidth || + imagePA->GetDimension(1) != imageHeight || + std::abs(imagePA->GetGeometry()->GetSpacing()[0] - m_ImageSpacing[0]) > + std::numeric_limits::epsilon() || + std::abs(imagePA->GetGeometry()->GetSpacing()[1] - m_ImageSpacing[1]) > + std::numeric_limits::epsilon()) { MITK_INFO << "Update buffers for image data"; unsigned int imageDimensions[3]; imageDimensions[0] = imageWidth; imageDimensions[1] = imageHeight; imageDimensions[2] = 1; - short* imageData = new short[beamformedLines*beamformedSamples]; + short *imageData = new short[beamformedLines * beamformedSamples]; - for (int b = 0; b (mitk::Image::New(), mitk::Image::New()); + m_ImagesBuffer[b][i] = + std::pair(mitk::Image::New(), mitk::Image::New()); m_ImagesBuffer[b][i].first->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensions); m_ImagesBuffer[b][i].second->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensions); m_ImagesBuffer[b][i].first->SetSpacing(m_ImageSpacing); m_ImagesBuffer[b][i].second->SetSpacing(m_ImageSpacing); m_ImagesBuffer[b][i].first->SetImportVolume(imageData, 0, 0, mitk::Image::RtlCopyMemory); m_ImagesBuffer[b][i].second->SetImportVolume(imageData, 0, 0, mitk::Image::RtlCopyMemory); } } delete[] imageData; imageUS = m_ImagesBuffer[currentBatch][currentImage].second; imagePA = m_ImagesBuffer[currentBatch][currentImage].first; } break; } - case DataType::Beamformed_Short: { - if (!imagePA->IsInitialized() - || imagePA->GetDimension(0) != beamformedLines - || imagePA->GetDimension(1) != beamformedSamples - || std::abs(imagePA->GetGeometry()->GetSpacing()[0] - m_ImageSpacing[0]) > std::numeric_limits::epsilon() - || std::abs(imagePA->GetGeometry()->GetSpacing()[1] - m_ImageSpacing[1]) > std::numeric_limits::epsilon()) + case DataType::Beamformed_Short: + { + if (!imagePA->IsInitialized() || imagePA->GetDimension(0) != beamformedLines || + imagePA->GetDimension(1) != beamformedSamples || + std::abs(imagePA->GetGeometry()->GetSpacing()[0] - m_ImageSpacing[0]) > + std::numeric_limits::epsilon() || + std::abs(imagePA->GetGeometry()->GetSpacing()[1] - m_ImageSpacing[1]) > + std::numeric_limits::epsilon()) { MITK_INFO << "Update buffers for beamformed image data"; unsigned int imageDimensions[3]; imageDimensions[0] = beamformedLines; imageDimensions[1] = beamformedSamples; imageDimensions[2] = 1; - short* imageData = new short[beamformedLines*beamformedSamples]; + short *imageData = new short[beamformedLines * beamformedSamples]; - for (int b = 0; b (mitk::Image::New(), mitk::Image::New()); + m_ImagesBuffer[b][i] = + std::pair(mitk::Image::New(), mitk::Image::New()); m_ImagesBuffer[b][i].first->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensions); m_ImagesBuffer[b][i].second->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensions); m_ImagesBuffer[b][i].first->SetSpacing(m_ImageSpacing); m_ImagesBuffer[b][i].second->SetSpacing(m_ImageSpacing); m_ImagesBuffer[b][i].first->SetImportVolume(imageData, 0, 0, mitk::Image::RtlCopyMemory); m_ImagesBuffer[b][i].second->SetImportVolume(imageData, 0, 0, mitk::Image::RtlCopyMemory); } } delete[] imageData; imageUS = m_ImagesBuffer[currentBatch][currentImage].second; imagePA = m_ImagesBuffer[currentBatch][currentImage].first; } break; } } - + // write the given buffer into the image switch (m_DataType) { - case DataType::Image_uChar: { + case DataType::Image_uChar: + { if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) { imagePA->SetSlice(imageData); - imageUS->SetVolume(&imageData[imageHeight*imageWidth]); + imageUS->SetVolume(&imageData[imageHeight * imageWidth]); } - else + else { imageUS->SetVolume(imageData); } break; } - case DataType::Beamformed_Short: { + case DataType::Beamformed_Short: + { mitk::ImageWriteAccessor dataPAAccess(imagePA); mitk::ImageWriteAccessor dataUSAccess(imageUS); - short* dataPA = (short*)dataPAAccess.GetData(); - short* dataUS = (short*)dataUSAccess.GetData(); + short *dataPA = (short *)dataPAAccess.GetData(); + short *dataUS = (short *)dataUSAccess.GetData(); size_t pixelsPerImage = beamformedLines * beamformedSamples; if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) { for (unsigned short sample = 0; sample < beamformedSamples; sample++) { for (unsigned short line = 0; line < beamformedLines; line++) { - dataPA[sample*beamformedLines + line] - = rfDataArrayBeamformed[line*beamformedSamples + sample]; + dataPA[sample * beamformedLines + line] = rfDataArrayBeamformed[line * beamformedSamples + sample]; } } for (unsigned short sample = 0; sample < beamformedSamples; sample++) { for (unsigned short line = 0; line < beamformedLines; line++) { - dataUS[sample*beamformedLines + line] - = rfDataArrayBeamformed[pixelsPerImage + line*beamformedSamples + sample]; + dataUS[sample * beamformedLines + line] = + rfDataArrayBeamformed[pixelsPerImage + line * beamformedSamples + sample]; } } } else { for (unsigned short sample = 0; sample < beamformedSamples; sample++) { for (unsigned short line = 0; line < beamformedLines; line++) { - dataUS[sample*beamformedLines + line] - = rfDataArrayBeamformed[line*beamformedSamples + sample]; + dataUS[sample * beamformedLines + line] = rfDataArrayBeamformed[line * beamformedSamples + sample]; } } } break; } } if (m_SavingSettings.saveRaw && m_CurrentlyRecording && rfDataChannelData != nullptr) { mitk::Image::Pointer rawImageUS = m_RawImagesBuffer[currentBatch][currentImage].second; mitk::Image::Pointer rawImagePA = m_RawImagesBuffer[currentBatch][currentImage].first; mitk::Vector3D rawSpacing; rawSpacing[0] = m_Device->GetScanMode().transducerPitchMeter * 1e3; // save in mm - rawSpacing[1] = m_Device->GetScanMode().receivePhaseLengthSeconds / channelDataSamplesPerChannel * 1e6; // save in us + rawSpacing[1] = + m_Device->GetScanMode().receivePhaseLengthSeconds / channelDataSamplesPerChannel * 1e6; // save in us rawSpacing[2] = 1; - if (!rawImagePA->IsInitialized() - || rawImagePA->GetDimension(0) != channelDataChannelsPerDataset - || rawImagePA->GetDimension(1) != std::ceil((float)channelDataSamplesPerChannel / 2.f) - || rawImageUS->GetDimension(1) != channelDataSamplesPerChannel - || rawImageUS->GetDimension(2) != channelDataTotalDatasets - 1 - || std::abs(rawImagePA->GetGeometry()->GetSpacing()[0] - rawSpacing[0]) > std::numeric_limits::epsilon() - || std::abs(rawImagePA->GetGeometry()->GetSpacing()[1] - rawSpacing[1]) > std::numeric_limits::epsilon()) + if (!rawImagePA->IsInitialized() || rawImagePA->GetDimension(0) != channelDataChannelsPerDataset || + rawImagePA->GetDimension(1) != std::ceil((float)channelDataSamplesPerChannel / 2.f) || + rawImageUS->GetDimension(1) != channelDataSamplesPerChannel || + rawImageUS->GetDimension(2) != channelDataTotalDatasets - 1 || + std::abs(rawImagePA->GetGeometry()->GetSpacing()[0] - rawSpacing[0]) > + std::numeric_limits::epsilon() || + std::abs(rawImagePA->GetGeometry()->GetSpacing()[1] - rawSpacing[1]) > std::numeric_limits::epsilon()) { MITK_INFO << "Update buffers for raw image data"; unsigned int imageDimensionsPA[3]; imageDimensionsPA[0] = channelDataChannelsPerDataset; imageDimensionsPA[1] = std::ceil((float)channelDataSamplesPerChannel / 2.f); imageDimensionsPA[2] = 1; unsigned int imageDimensionsUS[3]; imageDimensionsUS[0] = channelDataChannelsPerDataset; imageDimensionsUS[1] = channelDataSamplesPerChannel; imageDimensionsUS[2] = channelDataTotalDatasets - 1; - short* imageData = new short[channelDataChannelsPerDataset*channelDataSamplesPerChannel]; // * (channelDataTotalDatasets - 1)]; + short *imageData = + new short[channelDataChannelsPerDataset * channelDataSamplesPerChannel]; // * (channelDataTotalDatasets - 1)]; for (int b = 0; b < m_BufferBatches; ++b) { for (int i = 0; i < m_BatchSize; ++i) { - m_RawImagesBuffer[b][i] = std::pair(mitk::Image::New(), mitk::Image::New()); + m_RawImagesBuffer[b][i] = + std::pair(mitk::Image::New(), mitk::Image::New()); m_RawImagesBuffer[b][i].first->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensionsPA); m_RawImagesBuffer[b][i].second->Initialize(mitk::MakeScalarPixelType(), 3, imageDimensionsUS); m_RawImagesBuffer[b][i].first->SetSpacing(rawSpacing); m_RawImagesBuffer[b][i].second->SetSpacing(rawSpacing); m_RawImagesBuffer[b][i].first->SetImportVolume(imageData, 0, 0, mitk::Image::RtlCopyMemory); // currently US raw Data is not acquired - //m_RawImagesBuffer[b][i].second->SetImportVolume(imageData, 0, 0, mitk::Image::RtlCopyMemory); + // m_RawImagesBuffer[b][i].second->SetImportVolume(imageData, 0, 0, mitk::Image::RtlCopyMemory); } } delete[] imageData; rawImagePA = m_RawImagesBuffer[currentBatch][currentImage].first; rawImageUS = m_RawImagesBuffer[currentBatch][currentImage].second; } short offset = m_Device->GetScanMode().accumulation * 2048; mitk::ImageWriteAccessor dataPAAccess(rawImagePA); mitk::ImageWriteAccessor dataUSAccess(rawImageUS); - short* dataPA = (short*)dataPAAccess.GetData(); - short* dataUS = (short*)dataUSAccess.GetData(); + short *dataPA = (short *)dataPAAccess.GetData(); + short *dataUS = (short *)dataUSAccess.GetData(); - size_t pixelsPerImage = channelDataSamplesPerChannel*channelDataChannelsPerDataset; + size_t pixelsPerImage = channelDataSamplesPerChannel * channelDataChannelsPerDataset; if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) { for (unsigned short sam = 0; sam < std::ceil((float)channelDataSamplesPerChannel / 2.f); ++sam) { for (unsigned short chan = 0; chan < channelDataChannelsPerDataset; ++chan) { dataPA[sam * channelDataChannelsPerDataset + chan] = - rfDataChannelData[sam * channelDataChannelsPerDataset + chan] - offset; // this offset in the raw Images is given by the API... + rfDataChannelData[sam * channelDataChannelsPerDataset + chan] - + offset; // this offset in the raw Images is given by the API... } } // currently not used! /*for (unsigned short sam = 0; sam < channelDataSamplesPerChannel; ++sam) { for (unsigned short chan = 0; chan < channelDataChannelsPerDataset; ++chan) { dataUS[sam * channelDataChannelsPerDataset + chan] = - rfDataChannelData[pixelsPerImage + sam * channelDataChannelsPerDataset + chan] - offset; // this offset in the raw Images is given by the API... + rfDataChannelData[pixelsPerImage + sam * channelDataChannelsPerDataset + chan] - offset; // this offset in + the raw Images is given by the API... } }*/ } else { // currently not used! /*for (unsigned short sam = 0; sam < channelDataSamplesPerChannel; ++sam) { for (unsigned short chan = 0; chan < channelDataChannelsPerDataset; ++chan) { dataUS[sam * channelDataChannelsPerDataset + chan] = - rfDataChannelData[sam * channelDataChannelsPerDataset + chan] - offset; // this offset in the raw Images is given by the API... + rfDataChannelData[sam * channelDataChannelsPerDataset + chan] - offset; // this offset in the raw Images + is given by the API... } }*/ } } m_LastBatch = currentBatch; m_LastImage = currentImage; m_ImageTimestampsBuffer[currentBatch][currentImage] = currentImageTimestamp; } } 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; + 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; + 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; + case DataType::Beamformed_Short: + { + int &imageWidth = reconstructionLines; + int &imageHeight = m_Device->GetScanMode().reconstructionSamplesPerLine; m_ImageSpacing[0] = pitch; m_ImageSpacing[1] = recordTime * speedOfSound / 2 * 1000 / imageHeight; break; } } m_ImageSpacing[2] = 1; - MITK_INFO << "Retreaving Image Geometry Information for Spacing " << m_ImageSpacing[0] << " ... " << m_ImageSpacing[1] << " ... " << m_ImageSpacing[2] << " ...[DONE]"; + 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; + case DataType::Image_uChar: + MITK_INFO << "height: " << m_Device->GetScanMode().imageHeight + << " width: " << m_Device->GetScanMode().imageWidth; + break; + case DataType::Beamformed_Short: + MITK_INFO << "samples: " << m_Device->GetScanMode().reconstructionSamplesPerLine + << " lines: " << m_Device->GetScanMode().reconstructionLines; + break; } } } void mitk::USDiPhASImageSource::SetUseBModeFilter(bool isSet) { m_UseBModeFilter = isSet; } void mitk::USDiPhASImageSource::SetVerticalSpacing(float mm) { m_VerticalSpacingNext = mm; m_VerticalSpacingModified = true; } void mitk::USDiPhASImageSource::SetSavingSettings(SavingSettings settings) { m_SavingSettings = settings; } void mitk::USDiPhASImageSource::SetSavingName(std::string name) { if (name == "") { m_SavingName = "-replace"; } else { m_SavingName = name; } } // this is just a little function to set the filenames below right -inline void replaceAll(std::string& str, const std::string& from, const std::string& to) { +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) { + 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) { if (m_SavingSettings.saveRaw) { m_Device->GetScanMode().transferChannelData = true; m_Device->UpdateScanmode(); // set the raw Data to be transfered } m_RecordedImageCounter = 0; // tell the callback to start recording images m_CurrentlyRecording = true; - //save the settings! + // save the settings! // get the time and date time_t time = std::time(nullptr); - time_t* timeptr = &time; + time_t *timeptr = &time; std::string currentDate = std::ctime(timeptr); replaceAll(currentDate, ":", "-"); currentDate.pop_back(); if (m_SavingName == "-replace") { m_SavingName = "c:\\ImageData\\" + currentDate; } std::string pathS = m_SavingName + ".settings" + ".txt"; ofstream settingsFile; settingsFile.open(pathS); - auto& sM = m_Device->GetScanMode(); + auto &sM = m_Device->GetScanMode(); settingsFile << "[General Parameters]\n"; settingsFile << "Scan Depth [mm] = " << sM.receivePhaseLengthSeconds * sM.averageSpeedOfSound / 2 * 1000 << "\n"; settingsFile << "Speed of Sound [m/s] = " << sM.averageSpeedOfSound << "\n"; settingsFile << "Excitation Frequency [MHz] = " << sM.transducerFrequencyHz / 1000000 << "\n"; settingsFile << "Voltage [V] = " << sM.voltageV << "\n"; settingsFile << "TGC min = " << (int)sM.tgcdB[0] << " max = " << (int)sM.tgcdB[7] << "\n"; settingsFile << "[Beamforming Parameters]\n"; settingsFile << "Reconstructed Lines = " << sM.reconstructionLines << "\n"; settingsFile << "Samples per Line = " << sM.reconstructionSamplesPerLine << "\n"; settingsFile.close(); } // save images, end recording, and clean up else { m_CurrentlyRecording = false; // wait for all saving Threads to finish for (size_t i = 0; i < m_SaveThreads.size(); ++i) { m_SaveThreads[i].join(); } // make sure raw Channel Data is not transferred anymore - m_Device->GetScanMode().transferChannelData = false; + m_Device->GetScanMode().transferChannelData = false; m_Device->UpdateScanmode(); // clear the save threads m_SaveThreads.clear(); // clean up all threads m_SavingName = "-replace"; } } -void mitk::USDiPhASImageSource::OrderImagesInterleaved(Image::Pointer PAImage, Image::Pointer USImage, std::vector> recordedList, bool raw) +void mitk::USDiPhASImageSource::OrderImagesInterleaved( + Image::Pointer PAImage, + Image::Pointer USImage, + std::vector> recordedList, + bool raw) { - unsigned int width = 32; + unsigned int width = 32; unsigned int heightPA = 32; unsigned int heightUS = 32; unsigned int events = m_Device->GetScanMode().transmitEventsCount; if (!raw) events = 1; // the beamformed image array contains only the resulting image of multiple events if (raw) { width = recordedList.at(0).first->GetDimension(0); heightPA = recordedList.at(0).first->GetDimension(1); heightUS = recordedList.at(0).second->GetDimension(1); } else if (m_DataType == DataType::Beamformed_Short) { width = m_Device->GetScanMode().reconstructionLines; heightPA = m_Device->GetScanMode().reconstructionSamplesPerLine; heightUS = m_Device->GetScanMode().reconstructionSamplesPerLine; } else if (m_DataType == DataType::Image_uChar) { width = m_Device->GetScanMode().imageWidth; heightPA = m_Device->GetScanMode().imageHeight; heightUS = m_Device->GetScanMode().imageHeight; } - unsigned int dimPA[] = { width, heightPA, (unsigned int)recordedList.size()}; - unsigned int dimUS[] = { width, heightUS, (unsigned int)(recordedList.size() * events)}; + unsigned int dimPA[] = {width, heightPA, (unsigned int)recordedList.size()}; + unsigned int dimUS[] = {width, heightUS, (unsigned int)(recordedList.size() * events)}; PAImage->Initialize(recordedList.back().first->GetPixelType(), 3, dimPA); PAImage->SetSpacing(recordedList.back().first->GetGeometry()->GetSpacing()); USImage->Initialize(recordedList.back().first->GetPixelType(), 3, dimUS); USImage->SetSpacing(recordedList.back().first->GetGeometry()->GetSpacing()); for (int index = 0; index < recordedList.size(); ++index) { mitk::ImageReadAccessor inputReadAccessorPA(recordedList.at(index).first); PAImage->SetSlice(inputReadAccessorPA.GetData(), index); if (!raw) { for (unsigned int i = 0; i < events; ++i) { - mitk::ImageReadAccessor inputReadAccessorUS(recordedList.at(index).second, recordedList.at(index).second->GetSliceData(i)); + mitk::ImageReadAccessor inputReadAccessorUS(recordedList.at(index).second, + recordedList.at(index).second->GetSliceData(i)); USImage->SetSlice(inputReadAccessorUS.GetData(), index + i); } } } } -void mitk::USDiPhASImageSource::OrderImagesUltrasound(Image::Pointer USImage, std::vector> recordedList) +void mitk::USDiPhASImageSource::OrderImagesUltrasound( + Image::Pointer USImage, std::vector> recordedList) { - unsigned int width = 32; + unsigned int width = 32; unsigned int height = 32; unsigned int events = m_Device->GetScanMode().transmitEventsCount; if (m_DataType == DataType::Beamformed_Short) { width = (unsigned int)m_Device->GetScanMode().reconstructionLines; height = (unsigned int)m_Device->GetScanMode().reconstructionSamplesPerLine; } else if (m_DataType == DataType::Image_uChar) { width = (unsigned int)m_Device->GetScanMode().imageWidth; height = (unsigned int)m_Device->GetScanMode().imageHeight; } - unsigned int dimSound[] = { width, height, (unsigned int)(recordedList.size() * events) }; + unsigned int dimSound[] = {width, height, (unsigned int)(recordedList.size() * events)}; USImage->Initialize(recordedList.back().second->GetPixelType(), 3, dimSound); USImage->SetSpacing(recordedList.back().second->GetGeometry()->GetSpacing()); for (int index = 0; index < recordedList.size(); ++index) { for (unsigned int i = 0; i < events; ++i) { - mitk::ImageReadAccessor inputReadAccessorUS(recordedList.at(index).second, recordedList.at(index).second->GetSliceData(i)); + mitk::ImageReadAccessor inputReadAccessorUS(recordedList.at(index).second, + recordedList.at(index).second->GetSliceData(i)); USImage->SetSlice(inputReadAccessorUS.GetData(), index + i); } } } void mitk::USDiPhASImageSource::saveDataThread(size_t batch, unsigned long long counter, std::string currentSaveName) { char postfix[25]; sprintf(postfix, "%07llu", counter); // initialize file paths and the images Image::Pointer PAImage = Image::New(); Image::Pointer USImage = Image::New(); std::string pathPA = currentSaveName + ".PA.bf." + postfix + ".nrrd"; std::string pathUS = currentSaveName + ".US.bf." + postfix + ".nrrd"; std::string pathTS = currentSaveName + ".ts." + postfix + ".csv"; // raw Images (if chosen to be saved) Image::Pointer PAImageRaw = Image::New(); Image::Pointer USImageRaw = Image::New(); std::string pathPARaw = currentSaveName + ".PA.rf." + postfix + ".nrrd"; std::string pathUSRaw = currentSaveName + ".US.rf." + postfix + ".nrrd"; - if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::Interleaved_OA_US) // save a PAImage if we used interleaved mode + if (m_Device->GetScanMode().beamformingAlgorithm == + (int)Beamforming::Interleaved_OA_US) // save a PAImage if we used interleaved mode { // first, save the pyro data m_Pyro->SaveData(currentSaveName + ".pyro." + postfix + ".csv"); // now order the images and save them // the beamformed ones... OrderImagesInterleaved(PAImage, USImage, m_ImagesBuffer[batch], false); mitk::IOUtil::Save(USImage, pathUS); if (m_SavingSettings.saveBeamformed) { mitk::IOUtil::Save(PAImage, pathPA); } // ...and the raw images if (m_SavingSettings.saveRaw) { OrderImagesInterleaved(PAImageRaw, USImageRaw, m_RawImagesBuffer[batch], true); // mitk::IOUtil::Save(USImageRaw, pathUSRaw); mitk::IOUtil::Save(PAImageRaw, pathPARaw); } // save the timestamps! ofstream timestampFile; timestampFile.open(pathTS); timestampFile << ",timestamp"; // write the header for (size_t index = 0; index < m_ImageTimestampsBuffer[batch].size(); ++index) { timestampFile << "\n" << index << "," << m_ImageTimestampsBuffer[batch][index]; } timestampFile.close(); } - else if (m_Device->GetScanMode().beamformingAlgorithm == (int)Beamforming::PlaneWaveCompound) // save no PAImage if we used US only mode + else if (m_Device->GetScanMode().beamformingAlgorithm == + (int)Beamforming::PlaneWaveCompound) // save no PAImage if we used US only mode { OrderImagesUltrasound(USImage, m_ImagesBuffer[batch]); mitk::IOUtil::Save(USImage, pathUS); } MITK_INFO << "The saving Thread for batch " << batch << " has finished."; } \ No newline at end of file diff --git a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h index d40dd8d4a4..3495b0e686 100644 --- a/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h +++ b/Modules/US/USHardwareDiPhAS/mitkUSDiPhASImageSource.h @@ -1,193 +1,196 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKUSDiPhASImageSource_H_HEADER_INCLUDED_ #define MITKUSDiPhASImageSource_H_HEADER_INCLUDED_ #include "mitkUSImageSource.h" #include "mitkUSDiPhASCustomControls.h" #include "Framework.IBMT.US.CWrapper.h" #include "mitkImageReadAccessor.h" #include "itkFastMutexLock.h" #include #include #include #include #include #include #include #include #include namespace mitk { class USDiPhASDevice; /** * \brief Implementation of mitk::USImageSource for DiPhAS API devices. * The method mitk::USImageSource::GetNextRawImage() is implemented for * getting images from the DiPhAS API. * * The image data is given to this class from the DiPhAS API by calling * a callback method that writes the image data to an mitk::image */ class USDiPhASImageSource : public USImageSource { public: mitkClassMacro(USDiPhASImageSource, USImageSource); mitkNewMacro1Param(Self, mitk::USDiPhASDevice*); itkCloneMacro(Self); - typedef itk::Image< float, 3 > itkFloatImageType; + typedef itk::Image itkFloatImageType; + typedef itk::Image itkUCharImageType; typedef mitk::USDiPhASDeviceCustomControls::DataType DataType; typedef mitk::USDiPhASDeviceCustomControls::SavingSettings SavingSettings; /** * Implementation of the superclass method. Returns the pointer * to the mitk::Image filled by DiPhAS API callback. */ virtual void GetNextRawImage( std::vector& ) override; /** * The API calls this function to pass the image data to the * user; here the m_Image is updated */ void mitk::USDiPhASImageSource::ImageDataCallback( short* rfDataChannelData, int& channelDataChannelsPerDataset, int& channelDataSamplesPerChannel, int& channelDataTotalDatasets, short* rfDataArrayBeamformed, int& beamformedLines, int& beamformedSamples, int& beamformedTotalDatasets, unsigned char* imageData, int& imageWidth, int& imageHeight, int& imagePixelFormat, int& imageSetsTotal, double& timeStamp); /** This starts or ends the recording session*/ void SetRecordingStatus(bool record); void SetSavingSettings(SavingSettings settings); void SetVerticalSpacing(float mm); void SetSavingName(std::string name); void ModifyDataType(DataType dataT); void ModifyUseBModeFilter(bool isSet); void ModifyScatteringCoefficient(int coeff); void ModifyCompensateForScattering(bool useIt); void ModifyEnergyCompensation(bool compensate); /** * Sets the spacing used in the image based on the informations of the ScanMode in USDiPhAS Device */ void UpdateImageGeometry(); protected: void SetDataType(DataType dataT); void SetUseBModeFilter(bool isSet); void CheckModifiedVariables(); void ResizeFluenceImage(mitk::Vector3D spacing, unsigned int* dimensions); USDiPhASImageSource(mitk::USDiPhASDevice* device); virtual ~USDiPhASImageSource( ); /** This vector holds all the images we record, if recording is set to active. */ std::vector>> m_ImagesBuffer; // first image US, second image PA std::vector>> m_RawImagesBuffer; std::vector> m_ImageTimestampsBuffer; // stores all timestamps since recording started std::string m_SavingName; std::vector m_SaveThreads; void saveDataThread(size_t batch, unsigned long long counter, std::string currentSaveName); bool m_CurrentlyRecording; mitk::OphirPyro::Pointer m_Pyro; bool m_PyroConnected; std::vector m_FluenceCompOriginal; std::vector m_FluenceCompResized; std::vector::Pointer> m_FluenceCompResizedItk; int m_LastBatch; int m_LastImage; size_t m_RecordedImageCounter; int m_BufferBatches; int m_BatchSize; mitk::Vector3D m_ImageSpacing; + void NormalizeImage(mitk::Image::Pointer image, double rescale = 8192); + mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer image, bool useLogFilter = false); mitk::Image::Pointer CutOffTop(mitk::Image::Pointer image, int cutOffSize = 165); mitk::Image::Pointer ResampleOutputVertical(mitk::Image::Pointer image, float verticalSpacing = 0.1); mitk::Image::Pointer ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scatteringCoefficient); mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, mitk::Vector3D outputSpacing, unsigned int outputSize[3]); mitk::Image::Pointer MultiplyImage(mitk::Image::Pointer inputImage, double value); void OrderImagesInterleaved(Image::Pointer PAImage, Image::Pointer USImage, std::vector> recordedList, bool raw); void OrderImagesUltrasound(Image::Pointer USImage, std::vector> recordedList); mitk::USDiPhASDevice* m_Device; /** * Variables for management of current state. */ SavingSettings m_SavingSettings; float m_StartTime; BeamformerStateInfoNative m_BeamformerInfos; bool m_UseBModeFilter; bool m_DataTypeModified; DataType m_DataTypeNext; bool m_UseBModeFilterModified; bool m_UseBModeFilterNext; float m_VerticalSpacing; float m_VerticalSpacingNext; bool m_VerticalSpacingModified; int m_ScatteringCoefficient; int m_ScatteringCoefficientNext; bool m_ScatteringCoefficientModified; bool m_CompensateForScattering; bool m_CompensateForScatteringNext; bool m_CompensateForScatteringModified; bool m_CompensateEnergy; bool m_CompensateEnergyNext; bool m_CompensateEnergyModified; DataType m_DataType; }; } // namespace mitk #endif // MITKUSDiPhASImageSource_H diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index 05ea8dcffc..b894640c04 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,712 +1,712 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSDevice.h" #include "mitkImageReadAccessor.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" // Microservices #include #include #include #include mitk::USDevice::PropertyKeys mitk::USDevice::GetPropertyKeys() { static mitk::USDevice::PropertyKeys propertyKeys; return propertyKeys; } mitk::USDevice::USImageCropArea mitk::USDevice::GetCropArea() { MITK_INFO << "Return Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; return m_CropArea; } mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource(), m_FreezeBarrier(nullptr), m_FreezeMutex(), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_ImageVector(), m_Spacing(), m_IGTLServer(nullptr), m_IGTLMessageProvider(nullptr), m_ImageToIGTLMsgFilter(nullptr), m_IsFreezed(false), m_DeviceState(State_NoState), m_NumberOfOutputs(1), m_ServiceProperties(), m_ServiceRegistration(), m_Manufacturer(manufacturer), m_Name(model), m_Comment(), m_SpawnAcquireThread(true), m_UnregisteringStarted(false) { USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(m_NumberOfOutputs); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::USDevice(mitk::USImageMetadata::Pointer metadata) : mitk::ImageSource(), m_FreezeBarrier(nullptr), m_FreezeMutex(), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), m_ImageVector(), m_Spacing(), m_IGTLServer(nullptr), m_IGTLMessageProvider(nullptr), m_ImageToIGTLMsgFilter(nullptr), m_IsFreezed(false), m_DeviceState(State_NoState), m_NumberOfOutputs(1), m_ServiceProperties(), m_ServiceRegistration(), m_SpawnAcquireThread(true), m_UnregisteringStarted(false) { m_Manufacturer = metadata->GetDeviceManufacturer(); m_Name = metadata->GetDeviceModel(); m_Comment = metadata->GetDeviceComment(); USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(m_NumberOfOutputs); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::~USDevice() { if (m_ThreadID >= 0) { m_MultiThreader->TerminateThread(m_ThreadID); } // make sure that the us device is not registered at the micro service // anymore after it is destructed this->UnregisterOnService(); } mitk::USAbstractControlInterface::Pointer mitk::USDevice::GetControlInterfaceCustom() { MITK_INFO << "Custom control interface does not exist for this object."; return nullptr; } mitk::USControlInterfaceBMode::Pointer mitk::USDevice::GetControlInterfaceBMode() { MITK_INFO << "Control interface BMode does not exist for this object."; return nullptr; } mitk::USControlInterfaceProbes::Pointer mitk::USDevice::GetControlInterfaceProbes() { MITK_INFO << "Control interface Probes does not exist for this object."; return nullptr; } mitk::USControlInterfaceDoppler::Pointer mitk::USDevice::GetControlInterfaceDoppler() { MITK_INFO << "Control interface Doppler does not exist for this object."; return nullptr; } void mitk::USDevice::SetManufacturer(std::string manufacturer) { m_Manufacturer = manufacturer; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER, manufacturer); } } void mitk::USDevice::SetName(std::string name) { m_Name = name; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME, name); } } void mitk::USDevice::SetComment(std::string comment) { m_Comment = comment; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_COMMENT, comment); } } us::ServiceProperties mitk::USDevice::ConstructServiceProperties() { mitk::USDevice::PropertyKeys propertyKeys = mitk::USDevice::GetPropertyKeys(); us::ServiceProperties props; props[propertyKeys.US_PROPKEY_ISCONNECTED] = this->GetIsConnected() ? "true" : "false"; props[propertyKeys.US_PROPKEY_ISACTIVE] = this->GetIsActive() ? "true" : "false"; props[propertyKeys.US_PROPKEY_LABEL] = this->GetServicePropertyLabel(); // get identifier of selected probe if there is one selected mitk::USControlInterfaceProbes::Pointer probesControls = this->GetControlInterfaceProbes(); if (probesControls.IsNotNull() && probesControls->GetIsActive()) { mitk::USProbe::Pointer probe = probesControls->GetSelectedProbe(); if (probe.IsNotNull()) { props[propertyKeys.US_PROPKEY_PROBES_SELECTED] = probe->GetName(); } } props[propertyKeys.US_PROPKEY_CLASS] = GetDeviceClass(); props[propertyKeys.US_PROPKEY_MANUFACTURER] = m_Manufacturer; props[propertyKeys.US_PROPKEY_NAME] = m_Name; props[propertyKeys.US_PROPKEY_COMMENT] = m_Comment; m_ServiceProperties = props; return props; } void mitk::USDevice::UnregisterOnService() { // unregister on micro service if (m_ServiceRegistration && !m_UnregisteringStarted) { // make sure that unregister is not started a second // time due to a callback during unregister for example m_UnregisteringStarted = true; m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } } bool mitk::USDevice::Initialize() { if (!this->OnInitialization()) { return false; } m_DeviceState = State_Initialized; // Get Context and Module us::ModuleContext* context = us::GetModuleContext(); us::ServiceProperties props = this->ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); return true; } bool mitk::USDevice::Connect() { MITK_DEBUG << "mitk::USDevice::Connect() called"; if (this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Tried to connect an ultrasound device that " "was already connected. Ignoring call..."; return true; } if (!this->GetIsInitialized()) { MITK_ERROR("mitkUSDevice") << "Cannot connect device if it is not in initialized state."; return false; } // Prepare connection, fail if this fails. if (!this->OnConnection()) { return false; } // Update state m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, true); return true; } void mitk::USDevice::ConnectAsynchron() { this->m_MultiThreader->SpawnThread(this->ConnectThread, this); } bool mitk::USDevice::Disconnect() { if (!GetIsConnected()) { MITK_WARN << "Tried to disconnect an ultrasound device that was not " "connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (!this->OnDisconnection()) return false; // Update state m_DeviceState = State_Initialized; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, false); return true; } bool mitk::USDevice::Activate() { if (!this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Cannot activate device if it is not in connected state."; return true; } if (OnActivation()) { m_DeviceState = State_Activated; m_FreezeBarrier = itk::ConditionVariable::New(); // spawn thread for aquire images if us device is active if (m_SpawnAcquireThread) { this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); } this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, true); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); // initialize the b mode control properties of the micro service mitk::USControlInterfaceBMode::Pointer bmodeControls = this->GetControlInterfaceBMode(); if (bmodeControls.IsNotNull()) { bmodeControls->Initialize(); } } this->ProvideViaOIGTL(); return m_DeviceState == State_Activated; } void mitk::USDevice::ProvideViaOIGTL() { // create a new OpenIGTLink Server if (m_IGTLServer.IsNull()) m_IGTLServer = mitk::IGTLServer::New(true); m_IGTLServer->SetName(this->GetName()); // create a new OpenIGTLink Device source if (m_IGTLMessageProvider.IsNull()) m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); // set the OpenIGTLink server as the source for the device source m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); // register the provider so that it can be configured with the IGTL manager // plugin. This could be hardcoded but now I already have the fancy plugin. m_IGTLMessageProvider->RegisterAsMicroservice(); m_ImageToIGTLMsgFilter = mitk::ImageToIGTLMessageFilter::New(); - m_ImageToIGTLMsgFilter->ConnectTo(this); + m_ImageToIGTLMsgFilter->ConnectTo(this, 0, 0); // set the name of this filter to identify it easier m_ImageToIGTLMsgFilter->SetName(this->GetName()); // register this filter as micro service. The message provider looks for // provided IGTLMessageSources, once it found this microservice and someone // requested this data type then the provider will connect with this filter // automatically. m_ImageToIGTLMsgFilter->RegisterAsMicroservice(); } void mitk::USDevice::Deactivate() { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot deactivate a device which is not activae."; return; } if (!OnDeactivation()) { return; } DisableOIGTL(); m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, false); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); } void mitk::USDevice::DisableOIGTL() { // TODO: This seems not to be enough cleanup to catch all cases. For example, if the device is disconnected // from the OIGTL GUI, this won't get cleaned up correctly. m_IGTLServer->CloseConnection(); m_IGTLMessageProvider->UnRegisterMicroservice(); m_ImageToIGTLMsgFilter->UnRegisterMicroservice(); } void mitk::USDevice::SetIsFreezed(bool freeze) { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot freeze or unfreeze if device is not active."; return; } this->OnFreeze(freeze); if (freeze) { m_IsFreezed = true; } else { m_IsFreezed = false; // wake up the image acquisition thread m_FreezeBarrier->Signal(); } } bool mitk::USDevice::GetIsFreezed() { /* if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice")("mitkUSTelemedDevice") << "Cannot get freeze state if the hardware interface is not ready. " "Returning false..."; return false; }*/ return m_IsFreezed; } void mitk::USDevice::PushFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } imageSource->PushFilter(filter); } void mitk::USDevice::PushFilterIfNotPushedBefore( AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } if (!imageSource->GetIsFilterInThePipeline(filter)) { imageSource->PushFilter(filter); } } bool mitk::USDevice::RemoveFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when removing a filter."; } return imageSource->RemoveFilter(filter); } void mitk::USDevice::UpdateServiceProperty(std::string key, std::string value) { m_ServiceProperties[key] = value; m_ServiceRegistration.SetProperties(m_ServiceProperties); // send event to notify listeners about the changed property m_PropertyChangedMessage(key, value); } void mitk::USDevice::UpdateServiceProperty(std::string key, double value) { std::stringstream stream; stream << value; this->UpdateServiceProperty(key, stream.str()); } void mitk::USDevice::UpdateServiceProperty(std::string key, bool value) { this->UpdateServiceProperty( key, value ? std::string("true") : std::string("false")); } /** mitk::Image* mitk::USDevice::GetOutput() { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetPrimaryOutput()); } mitk::Image* mitk::USDevice::GetOutput(unsigned int idx) { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetOutput(idx)); } void mitk::USDevice::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::USDevice::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter only has " << this->GetNumberOfOutputs() << " Outputs."); } if ( !graft ) { itkExceptionMacro(<<"Requested to graft output with a nullptr pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a nullptr pointer" ); } // Call Graft on USImage to copy member data output->Graft( graft ); } */ void mitk::USDevice::GrabImage() { std::vector image = this->GetUSImageSource()->GetNextImage(); m_ImageMutex->Lock(); this->SetImageVector(image); m_ImageMutex->Unlock(); } //########### GETTER & SETTER ##################// bool mitk::USDevice::GetIsInitialized() { return m_DeviceState == State_Initialized; } bool mitk::USDevice::GetIsActive() { return m_DeviceState == State_Activated; } bool mitk::USDevice::GetIsConnected() { return m_DeviceState == State_Connected; } std::string mitk::USDevice::GetDeviceManufacturer() { return m_Manufacturer; } std::string mitk::USDevice::GetDeviceModel() { return m_Name; } std::string mitk::USDevice::GetDeviceComment() { return m_Comment; } void mitk::USDevice::SetSpacing(double xSpacing, double ySpacing) { m_Spacing[0] = xSpacing; m_Spacing[1] = ySpacing; m_Spacing[2] = 1; if( m_ImageVector.size() > 0 ) { for( size_t index = 0; index < m_ImageVector.size(); ++index ) { auto& image = m_ImageVector[index]; if( image.IsNotNull() && image->IsInitialized() ) { image->GetGeometry()->SetSpacing(m_Spacing); } } this->Modified(); } MITK_INFO << "Spacing: " << m_Spacing; } void mitk::USDevice::GenerateData() { m_ImageMutex->Lock(); for (unsigned int i = 0; i < m_ImageVector.size() && i < this->GetNumberOfIndexedOutputs(); ++i) { - auto& image = m_ImageVector[i]; + auto image = m_ImageVector[i]; if (image.IsNull() || !image->IsInitialized()) { // skip image } else { mitk::Image::Pointer output = this->GetOutput(i); if (!output->IsInitialized() || output->GetDimension(0) != image->GetDimension(0) || output->GetDimension(1) != image->GetDimension(1) || output->GetDimension(2) != image->GetDimension(2) || output->GetPixelType() != image->GetPixelType()) { output->Initialize(image->GetPixelType(), image->GetDimension(), image->GetDimensions()); } // copy contents of the given image into the member variable mitk::ImageReadAccessor inputReadAccessor(image); output->SetImportVolume(inputReadAccessor.GetData()); output->SetGeometry(image->GetGeometry()); } } m_ImageMutex->Unlock(); }; std::string mitk::USDevice::GetServicePropertyLabel() { std::string isActive; if (this->GetIsActive()) { isActive = " (Active)"; } else { isActive = " (Inactive)"; } // e.g.: Zonare MyLab5 (Active) return m_Manufacturer + " " + m_Name + isActive; } ITK_THREAD_RETURN_TYPE mitk::USDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; while (device->GetIsActive()) { // lock this thread when ultrasound device is freezed if (device->m_IsFreezed) { itk::SimpleMutexLock* mutex = &(device->m_FreezeMutex); mutex->Lock(); if (device->m_FreezeBarrier.IsNotNull()) { device->m_FreezeBarrier->Wait(mutex); } } device->GrabImage(); } return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::USDevice::ConnectThread(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; device->Connect(); return ITK_THREAD_RETURN_VALUE; } void mitk::USDevice::ProbeChanged(std::string probename) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED, probename); } void mitk::USDevice::DepthChanged(double depth) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH, depth); } diff --git a/Modules/US/USModel/mitkUSDevice.h b/Modules/US/USModel/mitkUSDevice.h index 095f3fbf1b..6af96a1c9f 100644 --- a/Modules/US/USModel/mitkUSDevice.h +++ b/Modules/US/USModel/mitkUSDevice.h @@ -1,489 +1,489 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKUSDevice_H_HEADER_INCLUDED_ #define MITKUSDevice_H_HEADER_INCLUDED_ // STL #include // MitkUS #include "mitkUSProbe.h" #include #include "mitkUSImageSource.h" // MitkIGTL #include "mitkIGTLMessageProvider.h" #include "mitkIGTLServer.h" #include "mitkIGTLDeviceSource.h" #include "mitkImageToIGTLMessageFilter.h" // MITK #include #include #include // ITK #include #include // Microservices #include #include #include // DEPRECATED #include "mitkUSImageMetadata.h" namespace itk { template class SmartPointer; } namespace mitk { class USAbstractControlInterface; class USControlInterfaceBMode; class USControlInterfaceProbes; class USControlInterfaceDoppler; /** * \brief A device holds information about it's model, make and the connected probes. It is the * common super class for all devices and acts as an image source for mitkUSImages. It is the base class * for all US Devices, and every new device should extend it. * * US Devices support output of calibrated images, i.e. images that include a specific geometry. * To achieve this, call SetCalibration, and make sure that the subclass also calls apply * transformation at some point (The USDevice does not automatically apply the transformation to the image) * * Note that USDevices will be removed from micro servive when their * destructor is called. Registering into micro service is done when * mitk::USDevice::Initialize() is called. * * \ingroup US */ class MITKUS_EXPORT USDevice : public mitk::ImageSource { public: enum DeviceStates { State_NoState, State_Initialized, State_Connected, State_Activated }; mitkClassMacro(USDevice, mitk::ImageSource); itkSetMacro(SpawnAcquireThread, bool); itkGetMacro(SpawnAcquireThread, bool); struct USImageCropArea { int cropLeft; int cropRight; int cropBottom; int cropTop; }; /** * \brief These constants are used in conjunction with Microservices. * The constants aren't defined as static member attributes to avoid the * "static initialization order fiasco", which would occur when objects of * this class are used in module activators (for restoring stored device, * for example). */ struct PropertyKeys { const std::string US_INTERFACE_NAME; // Common Interface name of all US Devices. Used to refer to this device via Microservices const std::string US_PROPKEY_MANUFACTURER; const std::string US_PROPKEY_NAME; const std::string US_PROPKEY_COMMENT; const std::string US_PROPKEY_LABEL; // Human readable text represntation of this device const std::string US_PROPKEY_ISCONNECTED; // Whether this device is connected or not. const std::string US_PROPKEY_ISACTIVE; // Whether this device is active or not. const std::string US_PROPKEY_CLASS; // Class Name of this Object const std::string US_PROPKEY_PROBES_SELECTED; const std::string US_PROPKEY_BMODE_FREQUENCY; const std::string US_PROPKEY_BMODE_POWER; const std::string US_PROPKEY_BMODE_DEPTH; const std::string US_PROPKEY_BMODE_GAIN; const std::string US_PROPKEY_BMODE_REJECTION; const std::string US_PROPKEY_BMODE_DYNAMIC_RANGE; PropertyKeys() : US_INTERFACE_NAME("org.mitk.services.UltrasoundDevice"), US_PROPKEY_MANUFACTURER(US_INTERFACE_NAME + ".manufacturer"), US_PROPKEY_NAME(US_INTERFACE_NAME + ".name"), US_PROPKEY_COMMENT(US_INTERFACE_NAME + ".comment"), US_PROPKEY_LABEL(US_INTERFACE_NAME + ".label"), US_PROPKEY_ISCONNECTED(US_INTERFACE_NAME + ".isConnected"), US_PROPKEY_ISACTIVE(US_INTERFACE_NAME + ".isActive"), US_PROPKEY_CLASS(US_INTERFACE_NAME + ".class"), US_PROPKEY_PROBES_SELECTED(US_INTERFACE_NAME + ".probes.selected"), US_PROPKEY_BMODE_FREQUENCY(US_INTERFACE_NAME + ".bmode.frequency"), US_PROPKEY_BMODE_POWER(US_INTERFACE_NAME + ".bmode.power"), US_PROPKEY_BMODE_DEPTH(US_INTERFACE_NAME + ".bmode.depth"), US_PROPKEY_BMODE_GAIN(US_INTERFACE_NAME + ".bmode.gain"), US_PROPKEY_BMODE_REJECTION(US_INTERFACE_NAME + ".bmode.rejection"), US_PROPKEY_BMODE_DYNAMIC_RANGE(US_INTERFACE_NAME + ".bmode.dynamicRange") {} }; /** * \brief Event for being notified about changes of the micro service properties. * This event can be used if no micro service context is available. */ mitkNewMessage2Macro(PropertyChanged, const std::string&, const std::string&) /** * \return keys for the microservice properties of ultrasound devices */ static mitk::USDevice::PropertyKeys GetPropertyKeys(); /** * \brief Default getter for the custom control interface. * Has to be implemented in a subclass if a custom control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceCustom(); /** * \brief Default getter for the b mode control interface. * Has to be implemented in a subclass if a b mode control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceBMode(); /** * \brief Default getter for the probes control interface. * Has to be implemented in a subclass if a probes control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceProbes(); /** * \brief Default getter for the doppler control interface. * Has to be implemented in a subclass if a doppler control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceDoppler(); /** * \brief Changes device state to mitk::USDevice::State_Initialized. * During initialization the virtual method * mitk::USDevice::OnInitialization will be called. If this method * returns false the initialization process will be canceled. Otherwise * the mitk::USDevice is registered in a micro service. */ bool Initialize(); /** * \brief Connects this device. A connected device is ready to deliver images (i.e. be Activated). A Connected Device can be active. A disconnected Device cannot be active. * Internally calls onConnect and then registers the device with the service. A device usually should * override the OnConnection() method, but never the Connect() method, since this will possibly exclude the device * from normal service management. The exact flow of events is: * 0. Check if the device is already connected. If yes, return true anyway, but don't do anything. * 1. Call OnConnection() Here, a device should establish it's connection with the hardware Afterwards, it should be ready to start transmitting images at any time. * 2. If OnConnection() returns true ("successful"), then the device is registered with the service. * 3. if not, it the method itself returns false or may throw an expection, depeneding on the device implementation. * */ bool Connect(); void ConnectAsynchron(); /** * \brief Works analogously to mitk::USDevice::Connect(). Don't override this Method, but onDisconnection instead. */ bool Disconnect(); /** * \brief Activates this device. * After the activation process, the device will start to produce images. * This Method will fail, if the device is not connected. */ bool Activate(); /** * \brief Deactivates this device. * After the deactivation process, the device will no longer produce * images, but still be connected. */ void Deactivate(); /** * \brief Can toggle if ultrasound image is currently updated or freezed. * * \param freeze true to stop updating the ultrasound image, false to start updating again */ virtual void SetIsFreezed(bool freeze); /** * \return true if device is currently freezed (no image update is done), false otherwise */ virtual bool GetIsFreezed(); void PushFilter(AbstractOpenCVImageFilter::Pointer filter); void PushFilterIfNotPushedBefore(AbstractOpenCVImageFilter::Pointer filter); bool RemoveFilter(AbstractOpenCVImageFilter::Pointer filter); /** * @brief To be called when the used probe changed. Will update the service properties * @param probename of the now used probe */ void ProbeChanged(std::string probename); /** * @brief To be called when the scanning depth of the probe changed. Will update the service properties * @param depth that is now used */ void DepthChanged(double depth); /** * \brief Given property is updated in the device micro service. * This method is mainly for being used by the control interface * superclasses. You do not need to call it by yoursefs in your * concrete control interface classes. */ void UpdateServiceProperty(std::string key, std::string value); void UpdateServiceProperty(std::string key, double value); void UpdateServiceProperty(std::string key, bool value); //########### GETTER & SETTER ##################// /** * \brief Returns the Class of the Device. This Method must be reimplemented by every Inheriting Class. */ virtual std::string GetDeviceClass() = 0; /** * \brief True, if the device object is created and initialized, false otherwise. */ bool GetIsInitialized(); /** * \brief True, if the device is currently generating image data, false otherwise. */ bool GetIsActive(); /** * \brief True, if the device is currently ready to start transmitting image data or is already * transmitting image data. A disconnected device cannot be activated. */ bool GetIsConnected(); /* @return Returns the area that will be cropped from the US image. Is disabled / [0,0,0,0] by default. */ mitk::USDevice::USImageCropArea GetCropArea(); /* @return Returns the size of the m_ImageVector of the ultrasound device.*/ unsigned int GetSizeOfImageVector(); /** @return Returns the current image source of this device. */ virtual USImageSource::Pointer GetUSImageSource() = 0; /** \brief Deprecated -> use GetManufacturer() instead */ DEPRECATED(std::string GetDeviceManufacturer()); /** \brief Deprecated -> use GetName() instead */ DEPRECATED(std::string GetDeviceModel()); /** \brief Deprecated -> use GetCommend() instead */ DEPRECATED(std::string GetDeviceComment()); itkGetMacro(Manufacturer, std::string); itkGetMacro(Name, std::string); itkGetMacro(Comment, std::string); void SetManufacturer(std::string manufacturer); void SetName(std::string name); void SetComment(std::string comment); itkGetMacro(DeviceState, DeviceStates) itkGetMacro(ServiceProperties, us::ServiceProperties) void GrabImage(); virtual void SetSpacing(double xSpacing, double ySpacing); protected: // Threading-Related itk::ConditionVariable::Pointer m_FreezeBarrier; itk::SimpleMutexLock m_FreezeMutex; itk::MultiThreader::Pointer m_MultiThreader; ///< itk::MultiThreader used for thread handling itk::FastMutexLock::Pointer m_ImageMutex; ///< mutex for images provided by the image source int m_ThreadID; ///< ID of the started thread virtual void SetImageVector(std::vector vec) { if (this->m_ImageVector != vec) { this->m_ImageVector = vec; - this->Modified(); + this->Modified(); } } static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); static ITK_THREAD_RETURN_TYPE ConnectThread(void* pInfoStruct); std::vector m_ImageVector; // Variables to determine if spacing was calibrated and needs to be applied to the incoming images mitk::Vector3D m_Spacing; /** * \brief Registers an OpenIGTLink device as a microservice so that we can send the images of * this device via the network. */ void ProvideViaOIGTL(); /** * \brief Deregisters the microservices for OpenIGTLink. */ void DisableOIGTL(); mitk::IGTLServer::Pointer m_IGTLServer; mitk::IGTLMessageProvider::Pointer m_IGTLMessageProvider; mitk::ImageToIGTLMessageFilter::Pointer m_ImageToIGTLMsgFilter; bool m_IsFreezed; DeviceStates m_DeviceState; /* @brief defines the area that should be cropped from the US image */ USImageCropArea m_CropArea; /** * \brief This Method constructs the service properties which can later be used to * register the object with the Microservices * Return service properties */ us::ServiceProperties ConstructServiceProperties(); /** * \brief Remove this device from the micro service. */ void UnregisterOnService(); /** * \brief Is called during the initialization process. * Override this method in a subclass to handle the actual initialization. * If it returns false, the initialization process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnInitialization() = 0; /** * \brief Is called during the connection process. * Override this method in a subclass to handle the actual connection. * If it returns false, the connection process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnConnection() = 0; /** * \brief Is called during the disconnection process. * Override this method in a subclass to handle the actual disconnection. * If it returns false, the disconnection process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnDisconnection() = 0; /** * \brief Is called during the activation process. * After this method is finished, the device should be generating images. * If it returns false, the activation process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnActivation() = 0; /** * \brief Is called during the deactivation process. * After a call to this method the device should still be connected, * but not producing images anymore. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnDeactivation() = 0; /** * \brief Called when mitk::USDevice::SetIsFreezed() is called. * Subclasses can overwrite this method to do additional actions. Default * implementation does noting. */ virtual void OnFreeze(bool) { } /** * \brief Enforces minimal Metadata to be set. */ USDevice(std::string manufacturer, std::string model); /** * \brief Constructs a device with the given Metadata. Make sure the Metadata contains meaningful content! * \deprecated Use USDevice(std::string manufacturer, std::string model) instead. */ USDevice(mitk::USImageMetadata::Pointer metadata); ~USDevice() override; /** * \brief Grabs the next frame from the Video input. * This method is called internally, whenever Update() is invoked by an Output. */ void GenerateData() override; std::string GetServicePropertyLabel(); unsigned int m_NumberOfOutputs; /** * \brief Properties of the device's Microservice. */ us::ServiceProperties m_ServiceProperties; /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ us::ServiceRegistration m_ServiceRegistration; private: std::string m_Manufacturer; std::string m_Name; std::string m_Comment; bool m_SpawnAcquireThread; bool m_UnregisteringStarted; }; } // namespace mitk // This is the microservice declaration. Do not meddle! MITK_DECLARE_SERVICE_INTERFACE(mitk::USDevice, "org.mitk.services.UltrasoundDevice") #endif // MITKUSDevice_H_HEADER_INCLUDED_ diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui index 2e114f54da..0c3ed3da4b 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomDiPhASDeviceWidget.ui @@ -1,797 +1,800 @@ QmitkUSControlsCustomDiPhASDeviceWidget 0 0 351 993 Form <html><head/><body><p><span style=" font-weight:600;">Record Images</span></p></body></html> Save PA Beamformed false Save PA Raw true 250 50 E:/ImageData/recordingName 100 25 Start Recording Qt::Horizontal 40 20 <html><head/><body><p><span style=" font-weight:600;">Beamforming Parameters</span></p></body></html> 256 4096 256 2048 3 0.005000000000000 10.000000000000000 0.005000000000000 0.150000000000000 Qt::PreventContextMenu 128 1024 128 256 Samples per Line Reconstructed Lines 1000 1000000 5 1540 Speed of Sound [m/s] Pitch of Transducer [mm] <html><head/><body><p><span style=" font-weight:600;">Receive Parameters</span></p></body></html> 1 100 1 Scan Depth [mm] Averaging Count TGC Max 42 42 Qt::Horizontal 0 TGC Min 42 42 Qt::Horizontal false Beamformed Data Image Data DataType 3.000000000000000 200.000000000000000 50.000000000000000 42 38 Qt::Horizontal TextLabel 42 34 Qt::Horizontal 42 42 Qt::Horizontal 42 40 Qt::Horizontal 42 36 Qt::Horizontal TextLabel TextLabel TextLabel TextLabel TextLabel 0 0 0 0 16777215 16777215 42 32 Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Time Gain Compensation</span></p></body></html> true Compensate Fluence For Scattering true 5 25 15 false Avg. μs' [1/cm] <html><head/><body><p><span style=" font-weight:600;">Display Parameters</span></p></body></html> Envelope Filter true false Compensate Energy Values + + 3 + 0.010000000000000 1.200000000000000 0.050000000000000 0.100000000000000 Vertical Spacing <html><head/><body><p><span style=" font-weight:600;">Transmit Parameters</span></p></body></html> 1.000000000000000 15.000000000000000 0.100000000000000 7.500000000000000 1 11 2 3 Transmit Events true false 1 1.000000000000000 10000.000000000000000 4.000000000000000 Transmit Phase Length [us] Excitation Frequency [MHz] false Interleaved Ultrasound only false 0 75 10 Voltage [V] Mode false <html><head/><body><p><span style=" font-weight:600;">Bandpass Parameters</span></p></body></html> false High Cut [MHz] false Low Cut [MHz] false Bandpass Enabled false false 5.000000000000000 false Off On Qt::Vertical 20 40 diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp index 33fec65be1..544b6da68d 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.cpp @@ -1,208 +1,242 @@ /*=================================================================== 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 "mitkScaleLegendAnnotation.h" #include "mitkTextAnnotation2D.h" +#include +#include #include "QmitkPAUSViewerView.h" #include #include const std::string QmitkPAUSViewerView::VIEW_ID = "org.mitk.views.photoacoustics.pausviewer"; -QmitkPAUSViewerView::QmitkPAUSViewerView() : m_PADataStorage(mitk::StandaloneDataStorage::New()), m_USDataStorage(mitk::StandaloneDataStorage::New()) +QmitkPAUSViewerView::QmitkPAUSViewerView() + : m_PADataStorage(mitk::StandaloneDataStorage::New()), m_USDataStorage(mitk::StandaloneDataStorage::New()) { } QmitkPAUSViewerView::~QmitkPAUSViewerView() { - this->GetDataStorage()->AddNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); - this->GetDataStorage()->AddNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::RemovedNodeFromStorage)); - this->GetDataStorage()->ChangedNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); + this->GetDataStorage()->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); + this->GetDataStorage()->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, + &QmitkPAUSViewerView::RemovedNodeFromStorage)); + this->GetDataStorage()->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); } -void QmitkPAUSViewerView::InitWindows() +void QmitkPAUSViewerView::UpdateRenderWindowVisibility() { - AddOverlays(); + if (m_Controls->m_ShowSU->isChecked()) + { + m_Controls->m_UnmixingRenderWindow->setHidden(false); + m_Controls->m_UnmixingLevelWindow->setHidden(false); + m_Controls->labelUnmixing->setHidden(false); + } + else + { + m_Controls->m_UnmixingRenderWindow->setHidden(true); + m_Controls->m_UnmixingLevelWindow->setHidden(true); + m_Controls->labelUnmixing->setHidden(true); + } } -void QmitkPAUSViewerView::SetFocus() +void QmitkPAUSViewerView::InitWindows() { + AddOverlays(); } +void QmitkPAUSViewerView::SetFocus() {} + void QmitkPAUSViewerView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, - const QList& /*nodes*/) + const QList & /*nodes*/) { } void QmitkPAUSViewerView::CreateQtPartControl(QWidget *parent) { - MITK_INFO << "in here"; m_Controls = new Ui::QmitkPAUSViewerViewControls; m_Controls->setupUi(parent); + connect(m_Controls->m_ShowSU, SIGNAL(stateChanged(int)), this, SLOT(UpdateRenderWindowVisibility())); + UpdateRenderWindowVisibility(); + SetPADataStorage(m_PADataStorage); SetUSDataStorage(m_USDataStorage); - //create a dummy image (gray values 0..255) for correct initialization of level window, etc. + // create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); m_USData = mitk::DataNode::New(); std::stringstream USnodeName; USnodeName << "US Image Stream"; m_USData->SetName(USnodeName.str()); m_USData->SetData(dummyImage); m_USDataStorage->Add(m_USData); m_PAData = mitk::DataNode::New(); std::stringstream PAnodeName; PAnodeName << "PA Image Stream"; m_PAData->SetName(PAnodeName.str()); m_PAData->SetData(dummyImage); m_PADataStorage->Add(m_PAData); + + /*m_SUData = mitk::DataNode::New(); + std::stringstream SUnodeName; + PAnodeName << "SU Image Stream"; + m_SUData->SetName(SUnodeName.str()); + m_SUData->SetData(dummyImage); + m_SUDataStorage->Add(m_SUData); + m_Controls->m_UnmixingRenderWindow->GetRenderer()->SetDataStorage(m_SUDataStorage); + m_Controls->m_UnmixingLevelWindow->SetDataStorage(m_SUDataStorage);*/ InitWindows(); - this->GetDataStorage()->AddNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); - this->GetDataStorage()->RemoveNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::RemovedNodeFromStorage)); - this->GetDataStorage()->ChangedNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); + this->GetDataStorage()->AddNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); + this->GetDataStorage()->RemoveNodeEvent.AddListener( + mitk::MessageDelegate1(this, + &QmitkPAUSViewerView::RemovedNodeFromStorage)); + this->GetDataStorage()->ChangedNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkPAUSViewerView::ScanDataStorage)); ScanDataStorage(nullptr); } void QmitkPAUSViewerView::SetPADataStorage(mitk::StandaloneDataStorage::Pointer paStore) { if (m_Controls == nullptr) return; m_PADataStorage = paStore; m_Controls->m_PARenderWindow->GetRenderer()->SetDataStorage(m_PADataStorage); m_Controls->m_PALevelWindow->SetDataStorage(m_PADataStorage); } void QmitkPAUSViewerView::SetUSDataStorage(mitk::StandaloneDataStorage::Pointer usStore) { if (m_Controls == nullptr) return; m_USDataStorage = usStore; m_Controls->m_USRenderWindow->GetRenderer()->SetDataStorage(m_USDataStorage); m_Controls->m_USLevelWindow->SetDataStorage(m_USDataStorage); } -vtkRenderWindow* QmitkPAUSViewerView::GetPARenderWindow() +vtkRenderWindow *QmitkPAUSViewerView::GetPARenderWindow() { if (m_Controls == nullptr) return nullptr; return m_Controls->m_PARenderWindow->GetRenderWindow(); } -vtkRenderWindow* QmitkPAUSViewerView::GetUSRenderWindow() +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::ScaleLegendAnnotation::Pointer scaleAnnotation = mitk::ScaleLegendAnnotation::New(); - //scaleAnnotation->SetLeftAxisVisibility(true); - //scaleAnnotation->SetRightAxisVisibility(false); - //scaleAnnotation->SetRightAxisVisibility(false); - //scaleAnnotation->SetTopAxisVisibility(false); - //scaleAnnotation->SetCornerOffsetFactor(0); + // scaleAnnotation->SetLeftAxisVisibility(true); + // scaleAnnotation->SetRightAxisVisibility(false); + // scaleAnnotation->SetRightAxisVisibility(false); + // scaleAnnotation->SetTopAxisVisibility(false); + // scaleAnnotation->SetCornerOffsetFactor(0); // Add Overlays //![TextAnnotation2D] // Create a textAnnotation2D mitk::TextAnnotation2D::Pointer textAnnotation = mitk::TextAnnotation2D::New(); textAnnotation->SetText("Test!"); // set UTF-8 encoded text to render textAnnotation->SetFontSize(40); textAnnotation->SetColor(1, 0, 0); // Set text color to red textAnnotation->SetOpacity(0.5); // The position of the Annotation can be set to a fixed coordinate on the display. mitk::Point2D pos; pos[0] = 10; pos[1] = 20; textAnnotation->SetPosition2D(pos); std::string rendererID = m_PARenderer->GetName(); // The LayoutAnnotationRenderer can place the TextAnnotation2D at some defined corner positions mitk::LayoutAnnotationRenderer::AddAnnotation( textAnnotation, rendererID, mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); mitk::LayoutAnnotationRenderer::AddAnnotation( textAnnotation, m_PARenderer.GetPointer(), mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); - mitk::ManualPlacementAnnotationRenderer::AddAnnotation( - textAnnotation, m_PARenderer.GetPointer()); - + mitk::ManualPlacementAnnotationRenderer::AddAnnotation(textAnnotation, m_PARenderer.GetPointer()); - mitk::LayoutAnnotationRenderer::AddAnnotation(scaleAnnotation.GetPointer(), m_PARenderer->GetName(), mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); - mitk::LayoutAnnotationRenderer::AddAnnotation(scaleAnnotation.GetPointer(), m_USRenderer, mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); + mitk::LayoutAnnotationRenderer::AddAnnotation( + scaleAnnotation.GetPointer(), m_PARenderer->GetName(), mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); + mitk::LayoutAnnotationRenderer::AddAnnotation( + scaleAnnotation.GetPointer(), m_USRenderer, mitk::LayoutAnnotationRenderer::TopLeft, 5, 5, 1); } void QmitkPAUSViewerView::RemoveOverlays() { // m_PAOverlayManager->RemoveAllOverlays(); } -void QmitkPAUSViewerView::ScanDataStorage(const mitk::DataNode* dataNode) +void QmitkPAUSViewerView::ScanDataStorage(const mitk::DataNode *dataNode) { auto storage = this->GetDataStorage(); auto nodeUS = storage->GetNamedNode("US Viewing Stream - Image 1"); auto nodePA = storage->GetNamedNode("US Viewing Stream - Image 0"); if (nodeUS != nullptr) { - m_USData->SetData(dynamic_cast(nodeUS->GetData())); + m_USData->SetData(dynamic_cast(nodeUS->GetData())); } if (nodePA != nullptr) { - m_PAData->SetData(dynamic_cast(nodePA->GetData())); + m_PAData->SetData(dynamic_cast(nodePA->GetData())); } auto renderingManager = mitk::RenderingManager::GetInstance(); renderingManager->RequestUpdate(GetPARenderWindow()); renderingManager->RequestUpdate(GetUSRenderWindow()); } -void QmitkPAUSViewerView::RemovedNodeFromStorage(const mitk::DataNode* dataNode) +void QmitkPAUSViewerView::RemovedNodeFromStorage(const mitk::DataNode *dataNode) { auto nodeUS = m_USDataStorage->GetNamedNode(dataNode->GetName()); auto nodePA = m_PADataStorage->GetNamedNode(dataNode->GetName()); - //create a dummy image (gray values 0..255) for correct initialization of level window, etc. + // create a dummy image (gray values 0..255) for correct initialization of level window, etc. mitk::Image::Pointer dummyImage = mitk::ImageGenerator::GenerateRandomImage(100, 100, 1, 1, 1, 1, 1, 255, 0); m_USData->SetData(dummyImage); m_PAData->SetData(dummyImage); } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.h b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.h index 097ab998bc..87b4f85e29 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/src/QmitkPAUSViewerView.h @@ -1,76 +1,83 @@ /*=================================================================== 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 "ui_QmitkPAUSViewerViewControls.h" #include "org_mitk_gui_qt_photoacoustics_pausviewer_Export.h" #include "mitkCommon.h" 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 +private slots: + void UpdateRenderWindowVisibility(); + public: static const std::string VIEW_ID; QmitkPAUSViewerView(); virtual ~QmitkPAUSViewerView(); virtual void CreateQtPartControl(QWidget *parent) override; void InitWindows(); void SetPADataStorage(mitk::StandaloneDataStorage::Pointer paStore); void SetUSDataStorage(mitk::StandaloneDataStorage::Pointer usStore); protected: void AddOverlays(); void RemoveOverlays(); mitk::StandaloneDataStorage::Pointer m_PADataStorage; mitk::StandaloneDataStorage::Pointer m_USDataStorage; + mitk::StandaloneDataStorage::Pointer m_SUDataStorage; mitk::DataNode::Pointer m_PAData; mitk::DataNode::Pointer m_USData; + mitk::DataNode::Pointer m_SUData; mitk::BaseRenderer::Pointer m_PARenderer; mitk::BaseRenderer::Pointer m_USRenderer; + mitk::BaseRenderer::Pointer m_SURenderer; virtual void SetFocus() override; virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList&) override; Ui::QmitkPAUSViewerViewControls* m_Controls; void ScanDataStorage(const mitk::DataNode* dataNode); void RemovedNodeFromStorage(const mitk::DataNode* dataNode); vtkRenderWindow* GetPARenderWindow(); - vtkRenderWindow* GetUSRenderWindow(); + vtkRenderWindow *GetUSRenderWindow(); + vtkRenderWindow *GetSURenderWindow(); }; #endif // QMITKPAUSVIEWERVIEW_H_INCLUDED 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 8d192e8de4..a850c3a3a4 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,129 +1,199 @@ QmitkPAUSViewerViewControls 0 0 - 1086 - 744 + 1659 + 1009 0 0 QmitkTemplate false + + + + + 0 + 0 + + + + 0 0 75 true Ultrasound - - - - - 0 - 0 - - - - 75 true Photoacoustics 0 0 20 20 + m_PARenderWindow 0 0 20 20 + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Spectral Unmixing</span></p></body></html> + + + + + + + + + QLayout::SetDefaultConstraint + + + 0 + + + + + + 50 + false + + + + Do Spectral Unmixing + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + QmitkRenderWindow QListView
QmitkRenderWindow.h
QmitkLevelWindowWidget QWidget
QmitkLevelWindowWidget.h
1
QmitkDataStorageComboBox.h