diff --git a/Modules/PhotoacousticSimulation/Testing/mitkPhotoacousticVolumeTest.cpp b/Modules/PhotoacousticSimulation/Testing/mitkPhotoacousticVolumeTest.cpp index 86fd023d8c..67802356c1 100644 --- a/Modules/PhotoacousticSimulation/Testing/mitkPhotoacousticVolumeTest.cpp +++ b/Modules/PhotoacousticSimulation/Testing/mitkPhotoacousticVolumeTest.cpp @@ -1,162 +1,179 @@ /*=================================================================== 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 #include #include #include "mitkPhotoacousticVolume.h" +#include "mitkPhotoacousticTissueGeneratorParameters.h" class mitkPhotoacousticVolumeTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticVolumeTestSuite); MITK_TEST(TestInitializedTissueContainsOnlyZeros); MITK_TEST(TestConvertedMitkImageContainsOnlyZerosOrAir); MITK_TEST(TestTissueVolumeContainsCorrectAbsorptionNumber); MITK_TEST(TestTissueVolumeContainsCorrectScatteringNumber); MITK_TEST(TestTissueVolumeContainsCorrectAnisotropyNumber); CPPUNIT_TEST_SUITE_END(); private: mitk::PhotoacousticVolume::Pointer m_PhotoacousticVolume; + mitk::PhotoacousticTissueGeneratorParameters::Pointer m_TissueGeneratorParameters; public: void setUp() { m_PhotoacousticVolume = mitk::PhotoacousticVolume::New(); + m_TissueGeneratorParameters = mitk::PhotoacousticTissueGeneratorParameters::New(); } void TestInitializedTissueContainsOnlyZeros() { int dims = 30; - m_PhotoacousticVolume->Initialize(dims, dims, dims, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, 0, 0); + m_TissueGeneratorParameters->SetXDim(dims); + m_TissueGeneratorParameters->SetYDim(dims); + m_TissueGeneratorParameters->SetZDim(dims); + m_PhotoacousticVolume->Initialize(m_TissueGeneratorParameters); for(int x = 0; xGetVolumeAbsorptionValue(x, y, z), 0.0); } } } } void TestConvertedMitkImageContainsOnlyZerosOrAir() { int dims = 30; - - m_PhotoacousticVolume->Initialize(dims, dims, dims, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, 0, 0); + m_TissueGeneratorParameters->SetXDim(dims); + m_TissueGeneratorParameters->SetYDim(dims); + m_TissueGeneratorParameters->SetZDim(dims); + m_PhotoacousticVolume->Initialize(m_TissueGeneratorParameters); mitk::Image::Pointer testImage = m_PhotoacousticVolume->ConvertToMitkImage(); mitk::ImageReadAccessor imgMemAcc(testImage); double* imagePointer = (double*)imgMemAcc.GetData(); for(int index = 0; indexInitialize(dims, dims, dims, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, 0, 0); + m_TissueGeneratorParameters->SetXDim(dims); + m_TissueGeneratorParameters->SetYDim(dims); + m_TissueGeneratorParameters->SetZDim(dims); + m_PhotoacousticVolume->Initialize(m_TissueGeneratorParameters); m_PhotoacousticVolume->SetVolumeValues(0, 0, 0, 0, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 0, 1, 1, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 1, 0, 2, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 1, 1, 3, 0, 0); m_PhotoacousticVolume->SetVolumeValues(1, 0, 0, 4, 0, 0); m_PhotoacousticVolume->SetVolumeValues(1, 0, 1, 5, 0, 0); m_PhotoacousticVolume->SetVolumeValues(1, 1, 0, 6, 0, 0); m_PhotoacousticVolume->SetVolumeValues(1, 1, 1, 7, 0, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 0.0, m_PhotoacousticVolume->GetVolumeAbsorptionValue(0, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 1.0, m_PhotoacousticVolume->GetVolumeAbsorptionValue(0, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 2.0, m_PhotoacousticVolume->GetVolumeAbsorptionValue(0, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 3.0, m_PhotoacousticVolume->GetVolumeAbsorptionValue(0, 1, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 4.0, m_PhotoacousticVolume->GetVolumeAbsorptionValue(1, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 5.0, m_PhotoacousticVolume->GetVolumeAbsorptionValue(1, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 6.0, m_PhotoacousticVolume->GetVolumeAbsorptionValue(1, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 7.0, m_PhotoacousticVolume->GetVolumeAbsorptionValue(1, 1, 1)); } void TestTissueVolumeContainsCorrectScatteringNumber() { int dims = 2; - m_PhotoacousticVolume->Initialize(dims, dims, dims, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, 0, 0); + m_TissueGeneratorParameters->SetXDim(dims); + m_TissueGeneratorParameters->SetYDim(dims); + m_TissueGeneratorParameters->SetZDim(dims); + m_PhotoacousticVolume->Initialize(m_TissueGeneratorParameters); m_PhotoacousticVolume->SetVolumeValues(0, 0, 0, 0, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 0, 1, 0, 1, 0); m_PhotoacousticVolume->SetVolumeValues(0, 1, 0, 0, 2, 0); m_PhotoacousticVolume->SetVolumeValues(0, 1, 1, 0, 3, 0); m_PhotoacousticVolume->SetVolumeValues(1, 0, 0, 0, 4, 0); m_PhotoacousticVolume->SetVolumeValues(1, 0, 1, 0, 5, 0); m_PhotoacousticVolume->SetVolumeValues(1, 1, 0, 0, 6, 0); m_PhotoacousticVolume->SetVolumeValues(1, 1, 1, 0, 7, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 0.0, m_PhotoacousticVolume->GetVolumeScatteringValue(0, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 1.0, m_PhotoacousticVolume->GetVolumeScatteringValue(0, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 2.0, m_PhotoacousticVolume->GetVolumeScatteringValue(0, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 3.0, m_PhotoacousticVolume->GetVolumeScatteringValue(0, 1, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 4.0, m_PhotoacousticVolume->GetVolumeScatteringValue(1, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 5.0, m_PhotoacousticVolume->GetVolumeScatteringValue(1, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 6.0, m_PhotoacousticVolume->GetVolumeScatteringValue(1, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 7.0, m_PhotoacousticVolume->GetVolumeScatteringValue(1, 1, 1)); } void TestTissueVolumeContainsCorrectAnisotropyNumber() { int dims = 2; - m_PhotoacousticVolume->Initialize(dims, dims, dims, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, 0, 0); + m_TissueGeneratorParameters->SetXDim(dims); + m_TissueGeneratorParameters->SetYDim(dims); + m_TissueGeneratorParameters->SetZDim(dims); + m_PhotoacousticVolume->Initialize(m_TissueGeneratorParameters); m_PhotoacousticVolume->SetVolumeValues(0, 0, 0, 0, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 0, 1, 0, 0, 1); m_PhotoacousticVolume->SetVolumeValues(0, 1, 0, 0, 0, 2); m_PhotoacousticVolume->SetVolumeValues(0, 1, 1, 0, 0, 3); m_PhotoacousticVolume->SetVolumeValues(1, 0, 0, 0, 0, 4); m_PhotoacousticVolume->SetVolumeValues(1, 0, 1, 0, 0, 5); m_PhotoacousticVolume->SetVolumeValues(1, 1, 0, 0, 0, 6); m_PhotoacousticVolume->SetVolumeValues(1, 1, 1, 0, 0, 7); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 0.0, m_PhotoacousticVolume->GetVolumeAnisotropyValue(0, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 1.0, m_PhotoacousticVolume->GetVolumeAnisotropyValue(0, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 2.0, m_PhotoacousticVolume->GetVolumeAnisotropyValue(0, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 3.0, m_PhotoacousticVolume->GetVolumeAnisotropyValue(0, 1, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 4.0, m_PhotoacousticVolume->GetVolumeAnisotropyValue(1, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 5.0, m_PhotoacousticVolume->GetVolumeAnisotropyValue(1, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 6.0, m_PhotoacousticVolume->GetVolumeAnisotropyValue(1, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 7.0, m_PhotoacousticVolume->GetVolumeAnisotropyValue(1, 1, 1)); } void tearDown() { m_PhotoacousticVolume = nullptr; } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticVolume) diff --git a/Modules/PhotoacousticSimulation/files.cmake b/Modules/PhotoacousticSimulation/files.cmake index 95bf74e5e6..2153b543ad 100644 --- a/Modules/PhotoacousticSimulation/files.cmake +++ b/Modules/PhotoacousticSimulation/files.cmake @@ -1,24 +1,25 @@ set(CPP_FILES Utils/mitkPhotoacousticPropertyCalculator.cpp Utils/mitkPhotoacousticSmartVector.cpp Utils/mitkPhotoacousticStatefulObject.cpp + Utils/mitkPhotoacousticTissueGeneratorParameters.cpp Algorithms/mitkPhotoacousticVolume.cpp Algorithms/mitkPhotoacousticTissueGenerator.cpp Algorithms/mitkPhotoacousticVesselTree.cpp Algorithms/mitkPhotoacousticVessel.cpp Algorithms/mitkPhotoacousticVesselMeanderStrategy.cpp Algorithms/mitkPhotoacousticNoiseGenerator.cpp Algorithms/mitkPhotoacoustic3dVolume.cpp Algorithms/mitkPhotoacousticFatTissueGenerator.cpp Algorithms/mitkPhotoacousticComposedVolume.cpp Algorithms/mitkPhotoacousticSlicedVolumeGenerator.cpp ProbeDesign/mitkPhotoacousticProbe.cpp ProbeDesign/mitkPhotoacousticLightSource.cpp IO/mitkPhotoacousticIO.cpp Thread/mitkMonteCarloThreadHandler.cpp ) set(RESOURCE_FILES photoacoustics128x128.png spectralLIB.dat ) diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticFatTissueGenerator.cpp b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticFatTissueGenerator.cpp index 5fa219aaa0..857e93b1cf 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticFatTissueGenerator.cpp +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticFatTissueGenerator.cpp @@ -1,54 +1,53 @@ #include "mitkPhotoacousticFatTissueGenerator.h" #include #include #include -void mitk::PhotoacousticFatTissueGenerator::CreateFatGlobules(mitk::PhotoacousticVolume::Pointer image, double bodyFatPercentage, - double fatAbsorption, double fatScattering, double fatAnisotropy, +void mitk::PhotoacousticFatTissueGenerator::CreateFatGlobules(mitk::PhotoacousticVolume::Pointer image, mitk::PhotoacousticTissueGeneratorParameters::Pointer parameters, std::mt19937* rng) { - if (bodyFatPercentage < mitk::eps) + if (parameters->GetFatPercentage() < mitk::eps) return; const double VOLUME_CONSTANT = 4.0 / 3.0 * 3.14159265359; const double NORMAL_DISTRIBUTION_SIGMA = 0.2; const double MINIMUM_FAT_GLOBULES_FACTOR = 0.83; const double MAXIMUM_FAT_GLOBULES_FACTOR = 1.2; int xDim = image->getXDim(); int yDim = image->getYDim(); int zDim = image->getZDim(); long length = xDim*yDim*zDim; double sqrtLength = 2 * sqrt(sqrt(length)); std::uniform_int_distribution<> numberOfFatGlobulesDist(MINIMUM_FAT_GLOBULES_FACTOR*sqrtLength, MAXIMUM_FAT_GLOBULES_FACTOR*sqrtLength); std::normal_distribution<> normalDistribution(1, NORMAL_DISTRIBUTION_SIGMA); int numberOfFatGlobules = numberOfFatGlobulesDist(*rng); - double radius = pow(length*bodyFatPercentage/100.0/(numberOfFatGlobules * VOLUME_CONSTANT), (1.0/3.0)); + double radius = pow(length*parameters->GetFatPercentage()/100.0/(numberOfFatGlobules * VOLUME_CONSTANT), (1.0/3.0)); std::uniform_int_distribution<> xDist(-radius, xDim+radius); std::uniform_int_distribution<> yDist(-radius, yDim+radius); std::uniform_int_distribution<> zDist(1.5*radius, zDim+radius); for(int fatGlobuleIdx = 0; fatGlobuleIdxSetVolumeValues(x, y, z, fatAbsorption, fatScattering, fatAnisotropy, mitk::PhotoacousticVolume::SegmentationType::FAT); + image->SetVolumeValues(x, y, z, parameters->GetFatAbsorption(), parameters->GetFatScattering(), parameters->GetFatAnisotropy(), mitk::PhotoacousticVolume::SegmentationType::FAT); } } } } diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticFatTissueGenerator.h b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticFatTissueGenerator.h index 13ed049ca7..e4588a47cf 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticFatTissueGenerator.h +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticFatTissueGenerator.h @@ -1,40 +1,40 @@ /*=================================================================== 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 MITKPHOTOACOUSTICFATTISSUEGENERATOR_H #define MITKPHOTOACOUSTICFATTISSUEGENERATOR_H #include "MitkPhotoacousticSimulationExports.h" #include "mitkPhotoacousticVolume.h" +#include "mitkPhotoacousticTissueGeneratorParameters.h" namespace mitk { class MITKPHOTOACOUSTICSIMULATION_EXPORT PhotoacousticFatTissueGenerator { public: - static void CreateFatGlobules(mitk::PhotoacousticVolume::Pointer image, double bodyFatPercentage, - double fatAbsorption, double fatScattering, double fatAnisotropy, + static void CreateFatGlobules(mitk::PhotoacousticVolume::Pointer image, mitk::PhotoacousticTissueGeneratorParameters::Pointer, std::mt19937* rng); private: PhotoacousticFatTissueGenerator(); ~PhotoacousticFatTissueGenerator(); }; } #endif // MITKPHOTOACOUSTICFATTISSUEGENERATOR_H diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticNoiseGenerator.cpp b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticNoiseGenerator.cpp index e5ec01dee8..4daeedcfb7 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticNoiseGenerator.cpp +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticNoiseGenerator.cpp @@ -1,43 +1,43 @@ #include "mitkPhotoacousticNoiseGenerator.h" #include #include #include -void mitk::PhotoacousticNoiseGenerator::ApplyNoiseModel(ImageType image, double detectorNoise, double speckleNoise) +void mitk::PhotoacousticNoiseGenerator::ApplyNoiseModel(mitk::Photoacoustic3dVolume::Pointer image, double detectorNoise, double speckleNoise) { if(detectorNoise < 0 || speckleNoise < 0) { std::string msg = "detectorNoise must be >= 0 and speckleNoise must be >= 0"; MITK_ERROR << msg; mitkThrow() << msg; } if(detectorNoise == 0 && speckleNoise == 1) { return; } std::mt19937 rng; std::random_device randomDevice; if(randomDevice.entropy()>mitk::eps) { rng.seed(randomDevice()); } else { rng.seed(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); } std::normal_distribution<> detector(detectorNoise/2, detectorNoise/2); std::normal_distribution<> speckle(1, speckleNoise); //TODO: Determine realistic noise model. for(int x = 0, xLength=image->GetXDim(); x < xLength; x++) for(int y = 0, yLength=image->GetYDim(); y < yLength; y++) for(int z = 0, zLength=image->GetZDim(); z < zLength; z++) { double additiveNoise = detector(rng); if(additiveNoise<=0) additiveNoise = 0; image->SetData((image->GetData(x, y, z)+additiveNoise)*speckle(rng), x, y, z); } } diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticNoiseGenerator.h b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticNoiseGenerator.h index 730ffa3673..2efd334fc1 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticNoiseGenerator.h +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticNoiseGenerator.h @@ -1,48 +1,46 @@ /*=================================================================== 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 MITKPHOTOACOUSTICNOISEGENERATOR_H #define MITKPHOTOACOUSTICNOISEGENERATOR_H #include "MitkPhotoacousticSimulationExports.h" #include "mitkPhotoacoustic3dVolume.h" namespace mitk { class MITKPHOTOACOUSTICSIMULATION_EXPORT PhotoacousticNoiseGenerator final { public: - typedef mitk::Photoacoustic3dVolume::Pointer ImageType; - /** * @brief ApplyNoiseModel * Applies noise to an image. * @param image the image to apply the noise to * @param detectorNoise >= 0 * @param speckleNoise >= 1 */ - static void ApplyNoiseModel(ImageType image, double detectorNoise, double speckleNoise); + static void ApplyNoiseModel(mitk::Photoacoustic3dVolume::Pointer image, double detectorNoise, double speckleNoise); private: PhotoacousticNoiseGenerator(); ~PhotoacousticNoiseGenerator(); }; } #endif // MITKPHOTOACOUSTICNOISEGENERATOR_H diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticSlicedVolumeGenerator.cpp b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticSlicedVolumeGenerator.cpp index 72d9617610..a653f5bdad 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticSlicedVolumeGenerator.cpp +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticSlicedVolumeGenerator.cpp @@ -1,109 +1,129 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPhotoacousticSlicedVolumeGenerator.h" #include #include mitk::PhotoacousticSlicedVolumeGenerator::PhotoacousticSlicedVolumeGenerator() { m_State = UNINITIALIZED; m_YSlice = -1; m_Precorrect = false; m_PrecorrectionVolume = nullptr; } mitk::PhotoacousticSlicedVolumeGenerator::~PhotoacousticSlicedVolumeGenerator() { m_State = UNINITIALIZED; m_YSlice = -1; m_Precorrect = false; m_PrecorrectionVolume = nullptr; } void mitk::PhotoacousticSlicedVolumeGenerator::Initialize(int ySlice, bool precorrect, std::string precorrectionVolumeFilename, bool inverse) { m_State = INITIALIZED; m_YSlice = ySlice; m_Precorrect = precorrect; m_Inverse = inverse; if(m_Precorrect) m_PrecorrectionVolume = mitk::PhotoacousticIO::LoadNrrd(precorrectionVolumeFilename); } mitk::Photoacoustic3dVolume::Pointer mitk::PhotoacousticSlicedVolumeGenerator::GetSlicedFluenceImageFromComposedVolume(mitk::PhotoacousticComposedVolume::Pointer composedVolume) { if(m_State !=INITIALIZED) throw mitk::Exception("Sliced Volume Generator not initialized yet."); int fluenceComponents = composedVolume->GetNumberOfFluenceComponents(); int xDim = composedVolume->getXDim(); int zDim = composedVolume->getZDim(); double* imageArray = new double[xDim*zDim*fluenceComponents]; for(int fluenceComponentIdx = 0; fluenceComponentIdx< fluenceComponents; fluenceComponentIdx++) for(int z = 0; z< zDim; z++) for(int x = 0; x< xDim; x++) { int index = z * xDim * fluenceComponents + x * fluenceComponents + fluenceComponentIdx; imageArray[index] = composedVolume->GetFluenceValue(fluenceComponentIdx, x, m_YSlice, z); if(m_Precorrect) imageArray[index] = imageArray[index] / m_PrecorrectionVolume->GetData(x, m_YSlice, z); //TODO: Set this value to INF if imageArray[index] = 0? if(m_Inverse ) { if(imageArray[index]!=0) { imageArray[index] = 1 / imageArray[index]; } else { imageArray[index] = INFINITY; } } } return mitk::Photoacoustic3dVolume::New(imageArray, xDim, fluenceComponents, zDim); } mitk::Photoacoustic3dVolume::Pointer mitk::PhotoacousticSlicedVolumeGenerator::GetSlicedSignalImageFromComposedVolume(mitk::PhotoacousticComposedVolume::Pointer composedVolume) { if(m_State !=INITIALIZED) throw mitk::Exception("Sliced Volume Generator not initialized yet."); int fluenceComponents = composedVolume->GetNumberOfFluenceComponents(); int xDim = composedVolume->getXDim(); int zDim = composedVolume->getZDim(); double* imageArray = new double[xDim*zDim*fluenceComponents]; for(int fluenceComponentIdx = 0; fluenceComponentIdx< fluenceComponents; fluenceComponentIdx++) for(int z = 0; z< zDim; z++) for(int x = 0; x< xDim; x++) { int y = m_YSlice+composedVolume->GetYOffsetForFluenceComponent(fluenceComponentIdx); imageArray[z * xDim * fluenceComponents + x * fluenceComponents + fluenceComponentIdx] = composedVolume->GetFluenceValue(fluenceComponentIdx, x, m_YSlice, z) * composedVolume->GetVolumeAbsorptionValue(x, y, z); } return mitk::Photoacoustic3dVolume::New(imageArray, xDim, fluenceComponents, zDim); } + +void mitk::PhotoacousticSlicedVolumeGenerator::PrecorrectSignalImage(mitk::Photoacoustic3dVolume::Pointer signalVolume) +{ + if(m_PrecorrectionVolume.IsNull()) + { + MITK_WARN << "precorrection could not be performed, because a precorrection volume was not loaded."; + return; + } + int xDim = signalVolume->GetXDim(); + int zDim = signalVolume->GetZDim(); + int yDim = signalVolume->GetYDim(); + + for(int z = 0; z < zDim; z++) + for(int y = 0; y < yDim; y++) + for(int x = 0; x < xDim; x++) + { + signalVolume->SetData(signalVolume->GetData(x, y, z) / m_PrecorrectionVolume->GetData(x, m_YSlice, z), x, y, z); + } + +} diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticSlicedVolumeGenerator.h b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticSlicedVolumeGenerator.h index 1c22875faa..6f387f7b53 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticSlicedVolumeGenerator.h +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticSlicedVolumeGenerator.h @@ -1,60 +1,62 @@ /*=================================================================== 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 MITKPHOTOACOUSTICSLICEDVOLUMEGENERATOR_H #define MITKPHOTOACOUSTICSLICEDVOLUMEGENERATOR_H #include #include #include #include //Includes for smart pointer usage #include "mitkCommon.h" #include "itkLightObject.h" namespace mitk { class MITKPHOTOACOUSTICSIMULATION_EXPORT PhotoacousticSlicedVolumeGenerator : public itk::LightObject { public: mitkClassMacroItkParent(mitk::PhotoacousticSlicedVolumeGenerator, itk::LightObject) itkFactorylessNewMacro(Self) void Initialize(int ySlice, bool precorrect, std::string precorrectionVolumeFilename, bool inverse); mitk::Photoacoustic3dVolume::Pointer GetSlicedFluenceImageFromComposedVolume(mitk::PhotoacousticComposedVolume::Pointer composedVolume); mitk::Photoacoustic3dVolume::Pointer GetSlicedSignalImageFromComposedVolume(mitk::PhotoacousticComposedVolume::Pointer composedVolume); + void PrecorrectSignalImage(mitk::Photoacoustic3dVolume::Pointer signalVolume); + protected: PhotoacousticSlicedVolumeGenerator(); virtual ~PhotoacousticSlicedVolumeGenerator(); enum State{ UNINITIALIZED, INITIALIZED }; State m_State; int m_YSlice; bool m_Precorrect; bool m_Inverse; mitk::Photoacoustic3dVolume::Pointer m_PrecorrectionVolume; }; } #endif // MITKPHOTOACOUSTICSLICEDVOLUMEGENERATOR_H diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticTissueGenerator.cpp b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticTissueGenerator.cpp index f9ccad987a..2f951d5203 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticTissueGenerator.cpp +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticTissueGenerator.cpp @@ -1,175 +1,151 @@ /*=================================================================== 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 "mitkPhotoacousticTissueGenerator.h" #include "mitkPhotoacousticSmartVector.h" #include "mitkPhotoacousticFatTissueGenerator.h" -mitk::PhotoacousticVolume::Pointer mitk::PhotoacousticTissueGenerator::GenerateInSilicoData(int xDim, int yDim, int zDim, double spacing, - double basicAbsorption, double basicScattering, double basicAnisotropy, double airThickness, - double skinAbsorption, double skinScattering, double skinAnisotropy, double skinThickness, - double fatAbsorption, double fatScattering, double fatAnisotropy, double fatPercentage, - bool randomizePhysicalProperties, double randomPercentage, - int minNumberOfVessels, int maxNumberOfVessels, - double minBending, double maxBending, - double minAbs, double maxAbs, - double minRadius, double maxRadius, - double mcflag, double launchflag, double boundaryflag, - double launchPointX, double launchPointY, double launchPointZ, - double focusPointX, double focusPointY, double focusPointZ, - double trajectoryVectorX, double trajectoryVectorY, double trajectoryVectorZ, - double radius, double waist, - double sigma, bool doGauss, int bifurcationFrequency, - double vesselScatteringMinimum, double vesselScatteringMaximum, - double vesselAnisotropyMinimum, double vesselAnisotropyMaximum, - bool useRngSeed, long rngSeed, - mitk::PhotoacousticVessel::CalculateNewVesselPositionCallback calculateNewVesselPositionCallback) +mitk::PhotoacousticVolume::Pointer mitk::PhotoacousticTissueGenerator::GenerateInSilicoData(mitk::PhotoacousticTissueGeneratorParameters::Pointer parameters) { MITK_DEBUG << "Initializing Empty Volume"; mitk::PhotoacousticVolume::Pointer generatedVolume = mitk::PhotoacousticVolume::New(); - generatedVolume->Initialize(xDim, yDim, zDim, spacing, - basicAbsorption, basicScattering, basicAnisotropy, - mcflag, launchflag, boundaryflag, - launchPointX, launchPointY, launchPointZ, - focusPointX, focusPointY, focusPointZ, - trajectoryVectorX, trajectoryVectorY, trajectoryVectorZ, - radius, waist, - sigma, doGauss, - airThickness, skinThickness, - skinAbsorption, skinScattering, skinAnisotropy); + generatedVolume->Initialize(parameters); const double DIRECTION_VECTOR_INITIAL_VARIANCE = 0.2; std::mt19937 randomNumberGenerator; std::random_device randomDevice; - if(useRngSeed) + if(parameters->GetUseRngSeed()) { - randomNumberGenerator.seed(rngSeed); + randomNumberGenerator.seed(parameters->GetRngSeed()); } else { if(randomDevice.entropy()>0.1) { randomNumberGenerator.seed(randomDevice()); } else { randomNumberGenerator.seed(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); } } - mitk::PhotoacousticFatTissueGenerator::CreateFatGlobules(generatedVolume, fatPercentage, fatAbsorption, fatScattering, fatAnisotropy, &randomNumberGenerator); + mitk::PhotoacousticFatTissueGenerator::CreateFatGlobules(generatedVolume, parameters, &randomNumberGenerator); - std::uniform_int_distribution randomNumVesselDistribution(minNumberOfVessels, maxNumberOfVessels); - std::uniform_real_distribution randomBendingDistribution(minBending, maxBending); - std::uniform_real_distribution randomAbsorptionDistribution(minAbs, maxAbs); - std::uniform_real_distribution randomRadiusDistribution(minRadius, maxRadius); - std::uniform_real_distribution randomScatteringDistribution(vesselScatteringMinimum, vesselScatteringMaximum); - std::uniform_real_distribution randomAnisotropyDistribution(vesselAnisotropyMinimum, vesselAnisotropyMaximum); + std::uniform_int_distribution randomNumVesselDistribution(parameters->GetMinNumberOfVessels(), parameters->GetMaxNumberOfVessels()); + std::uniform_real_distribution randomBendingDistribution(parameters->GetMinVesselBending(), parameters->GetMaxVesselBending()); + std::uniform_real_distribution randomAbsorptionDistribution(parameters->GetMinVesselAbsorption(), parameters->GetMaxVesselAbsorption()); + std::uniform_real_distribution randomRadiusDistribution(parameters->GetMinVesselRadius(), parameters->GetMaxVesselRadius()); + std::uniform_real_distribution randomScatteringDistribution(parameters->GetMinVesselScattering(), parameters->GetMaxVesselScattering()); + std::uniform_real_distribution randomAnisotropyDistribution(parameters->GetMinVesselAnisotropy(), parameters->GetMaxVesselAnisotropy()); std::uniform_int_distribution borderTypeDistribution(0, 3); int numberOfBloodVessels = randomNumVesselDistribution(randomNumberGenerator); generatedVolume->AddIntProperty("numberOfVessels", numberOfBloodVessels); - generatedVolume->AddIntProperty("bifurcationFrequency", bifurcationFrequency); + generatedVolume->AddIntProperty("bifurcationFrequency", parameters->GetVesselBifurcationFrequency()); - int airvoxels = airThickness / spacing / 10; - - MITK_DEBUG << "Simulating vessel structures"; + MITK_INFO << "Simulating "<< numberOfBloodVessels <<" vessel structures"; for(int vesselNumber = 0; vesselNumber < numberOfBloodVessels; vesselNumber++) { mitk::PhotoacousticSmartVector::Pointer initialPosition = mitk::PhotoacousticSmartVector::New(); mitk::PhotoacousticSmartVector::Pointer initialDirection = mitk::PhotoacousticSmartVector::New(); - double initialRadius = randomRadiusDistribution(randomNumberGenerator) / spacing / 10; + double initialRadius = randomRadiusDistribution(randomNumberGenerator) / parameters->GetVoxelSpacing() / 10; std::stringstream radiusString; radiusString <<"vessel_"<AddDoubleProperty(radiusString.str(), initialRadius); double absorptionCoefficient = randomAbsorptionDistribution(randomNumberGenerator); std::stringstream absorptionString; absorptionString <<"vessel_"<AddDoubleProperty(absorptionString.str(), absorptionCoefficient); double bendingFactor = randomBendingDistribution(randomNumberGenerator); std::stringstream bendingString; bendingString <<"vessel_"<AddDoubleProperty(bendingString.str(), bendingFactor); double vesselScattering = randomScatteringDistribution(randomNumberGenerator); std::stringstream scatteringString; scatteringString <<"vessel_"<AddDoubleProperty(scatteringString.str(), vesselScattering); double vesselAnisotropy= randomAnisotropyDistribution(randomNumberGenerator); std::stringstream anisotropyString; anisotropyString <<"vessel_"<AddDoubleProperty(anisotropyString.str(), vesselAnisotropy); /*The vessel tree shall start at one of the 4 sides of the volume. * The vessels will always be completely contained in the volume * when starting to meander. * They will meander in a direction perpendicular to the * plane they started from (within the limits of the * DIRECTION_VECTOR_INITIAL_VARIANCE) */ int borderType = borderTypeDistribution(randomNumberGenerator); switch(borderType) { case 0: - initialPosition->Randomize(0, 0, initialRadius, yDim-initialRadius, airvoxels+initialRadius, zDim-initialRadius, &randomNumberGenerator); + initialPosition->Randomize(0, 0, initialRadius, parameters->GetYDim()-initialRadius, parameters->GetMinNumberOfVessels()/10/parameters->GetVoxelSpacing(), + parameters->GetMaxNumberOfVessels()/10/parameters->GetVoxelSpacing(), &randomNumberGenerator); initialDirection->Randomize(1, 2, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE,&randomNumberGenerator); break; case 1: - initialPosition->Randomize(xDim, xDim, initialRadius, yDim - initialRadius, airvoxels+initialRadius, zDim, &randomNumberGenerator); + initialPosition->Randomize(parameters->GetXDim(), parameters->GetXDim(), initialRadius, parameters->GetYDim() - initialRadius, parameters->GetMinNumberOfVessels()/10/parameters->GetVoxelSpacing(), + parameters->GetMaxNumberOfVessels()/10/parameters->GetVoxelSpacing(), &randomNumberGenerator); initialDirection->Randomize(-2, -1, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, &randomNumberGenerator); break; case 2: - initialPosition->Randomize(initialRadius, xDim - initialRadius, 0, 0, airvoxels+initialRadius, zDim - initialRadius, &randomNumberGenerator); + initialPosition->Randomize(initialRadius, parameters->GetXDim() - initialRadius, 0, 0, parameters->GetMinNumberOfVessels()/10/parameters->GetVoxelSpacing(), + parameters->GetMaxNumberOfVessels()/10/parameters->GetVoxelSpacing(), &randomNumberGenerator); initialDirection->Randomize(-DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, 1, 2, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, &randomNumberGenerator); break; case 3: - initialPosition->Randomize(initialRadius, xDim - initialRadius, yDim, yDim, airvoxels+initialRadius, zDim - initialRadius, &randomNumberGenerator); + initialPosition->Randomize(initialRadius, parameters->GetXDim() - initialRadius, parameters->GetYDim(), parameters->GetYDim(), parameters->GetMinNumberOfVessels()/10/parameters->GetVoxelSpacing(), + parameters->GetMaxNumberOfVessels()/10/parameters->GetVoxelSpacing(), &randomNumberGenerator); initialDirection->Randomize(-DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, -2, -1, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, &randomNumberGenerator); break; } mitk::PhotoacousticVesselTree::Pointer vesselTree = mitk::PhotoacousticVesselTree::New(); - MITK_DEBUG << "Initializing vessel structure"; - vesselTree->Initialize(initialPosition, initialDirection, initialRadius, absorptionCoefficient, vesselScattering, vesselAnisotropy, bifurcationFrequency, &randomNumberGenerator); + MITK_INFO << "Initializing vessel structure"; + vesselTree->Initialize(initialPosition, initialDirection, initialRadius, absorptionCoefficient, vesselScattering, vesselAnisotropy, parameters->GetVesselBifurcationFrequency(), &randomNumberGenerator); - MITK_DEBUG << "Simulating vessel structure"; + MITK_INFO << "Simulating vessel structure"; while(!vesselTree->IsFinished()) { - vesselTree->Step(generatedVolume, calculateNewVesselPositionCallback, bendingFactor, &randomNumberGenerator); + MITK_INFO << "Step"; + vesselTree->Step(generatedVolume, parameters->GetCalculateNewVesselPositionCallback(), bendingFactor, &randomNumberGenerator); } } generatedVolume->GaussianBlur3D(); - generatedVolume->FinalizeVolume(randomizePhysicalProperties, randomPercentage, useRngSeed, rngSeed); + generatedVolume->FinalizeVolume(parameters); return generatedVolume; } diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticTissueGenerator.h b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticTissueGenerator.h index c6221df255..e594054a47 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticTissueGenerator.h +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticTissueGenerator.h @@ -1,113 +1,55 @@ /*=================================================================== 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 mitkPhotoacousticTissueGenerator_h #define mitkPhotoacousticTissueGenerator_h #include #include #include #include #include +#include #include "mitkPhotoacousticVesselTree.h" #include "mitkPhotoacousticVolume.h" #include "mitkCommon.h" namespace mitk { class MITKPHOTOACOUSTICSIMULATION_EXPORT PhotoacousticTissueGenerator final { public: /** * @brief GenerateInSilicoData This method will return a PhotoacousticVolume created in terms of the given parameters. - * @param xDim x dimension of the generated volume - * @param yDim y dimension of the generated volume - * @param zDim z dimension of the generated volume - * @param spacing voxel spacing. Every dimension is equally spaced. - * @param basicAbsorption absorption coefficient for standard tissue - * @param basicScattering scattering coefficient for standard tissue - * @param basicAnisotropy anisotropy factor for standard tissue - * @param airThickness - * @param skinAbsorption - * @param skinScattering - * @param skinAnisotropy - * @param skinThickness - * @param fatAbsorption - * @param fatScattering - * @param fatAnisotropy - * @param fatPercentage, - * @param minNumberOfVessels minimum number of vessels generated in volume - * @param maxNumberOfVessels maximum number of vessels generated in volume - * @param minBending minimum bending coefficient (0 = not bending; >1 = bending a lot) - * @param maxBending maximum bending coefficient - * @param minAbs minimum absorption coefficient for blood vessel - * @param maxAbs maximum absorption coefficient for blood vessel - * @param minRadius minimum vessel radius - * @param maxRadius maximum vessel radius - * @param mcflag the montecarlo flag (chosen probe design) - * @param launchflag - * @param boundaryflag - * @param launchPointX - * @param launchPointY - * @param launchPointZ - * @param focusPointX - * @param focusPointY - * @param focusPointZ - * @param trajectoryVectorX - * @param trajectoryVectorY - * @param trajectoryVectorZ - * @param radius - * @param waist - * @param sigma - * @param doGauss - * @param bifurcationFrequency - * @param calculateNewVesselPositionCallback + * @param parameters * @return */ - static mitk::PhotoacousticVolume::Pointer GenerateInSilicoData(int xDim, int yDim, int zDim, double spacing, - double basicAbsorption, double basicScattering, double basicAnisotropy, double airThickness, - double skinAbsorption, double skinScattering, double skinAnisotropy, double skinThickness, - double fatAbsorption, double fatScattering, double fatAnisotropy, double fatPercentage, - bool randomizePhysicalproperties, double randomPercentage, - int minNumberOfVessels, int maxNumberOfVessels, - double minBending, double maxBending, - double minAbs, double maxAbs, - double minRadius, double maxRadius, - double mcflag, double launchflag, double boundaryflag, - double launchPointX, double launchPointY, double launchPointZ, - double focusPointX, double focusPointY, double focusPointZ, - double trajectoryVectorX, double trajectoryVectorY, double trajectoryVectorZ, - double radius, double waist, - double sigma, bool doGauss, int bifurcationFrequency, - double vesselScatteringMinimum, double vesselScatteringMaximum, - double vesselAnisotropyMinimum, double vesselAnisotropyMaximum, - bool useRngSeed, long rngSeed, - mitk::PhotoacousticVessel::CalculateNewVesselPositionCallback calculateNewVesselPositionCallback); + static mitk::PhotoacousticVolume::Pointer GenerateInSilicoData(mitk::PhotoacousticTissueGeneratorParameters::Pointer parameters); private: PhotoacousticTissueGenerator(); virtual ~PhotoacousticTissueGenerator(); }; } #endif diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticVolume.cpp b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticVolume.cpp index 0a3dcf25e7..d388a4c943 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticVolume.cpp +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticVolume.cpp @@ -1,460 +1,461 @@ /*=================================================================== 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 #include #include #include #include #include #include #include #include -void mitk::PhotoacousticVolume::Initialize(int xDim, int yDim, int zDim, double spacing, double initAbsorption, double initScattering, double initAnisotropy, - int mcflag, int launchflag, int boundaryflag, - double launchPointX, double launchPointY, double launchPointZ, - double focusPointX, double focusPointY, double focusPointZ, - double trajectoryVectorX, double trajectoryVectorY, double trajectoryVectorZ, - double radius, double waist, - double sigma, bool doGauss, - double airThickness, double epidermisThickness, - double skinAbsorption, double skinScattering, double skinAnisotropy) +void mitk::PhotoacousticVolume::Initialize(mitk::PhotoacousticTissueGeneratorParameters::Pointer parameters) { AssertState(UNINITIALIZED); - int size = xDim*yDim*zDim; + int size = parameters->GetXDim()*parameters->GetYDim()*parameters->GetZDim(); m_AbsorptionArray = new double[size]; m_ScatteringArray = new double[size]; m_AnisotropyArray = new double[size]; m_SegmentationArray = new double[size]; - m_ThicknessAir = airThickness; - m_ThicknessSkin = epidermisThickness; + m_ThicknessAir = parameters->GetAirThickness(); + m_ThicknessSkin = parameters->GetSkinThickness(); - m_AbsorptionSkin = skinAbsorption; - m_ScatteringSkin = skinScattering; - m_AnisotropySkin = skinAnisotropy; + m_AbsorptionSkin = parameters->GetSkinAbsorption(); + m_ScatteringSkin = parameters->GetSkinScattering(); + m_AnisotropySkin = parameters->GetSkinAnisotropy(); - m_XDim = xDim; - m_YDim = yDim; - m_ZDim = zDim; + m_XDim = parameters->GetXDim(); + m_YDim = parameters->GetYDim(); + m_ZDim = parameters->GetZDim(); m_TDim = 4; - m_Spacing = spacing; + m_Spacing = parameters->GetVoxelSpacing(); for (int index = 0; index < size; index++) { - m_AbsorptionArray[index]=initAbsorption; - m_ScatteringArray[index]=initScattering; - m_AnisotropyArray[index]=initAnisotropy; + m_AbsorptionArray[index]=parameters->GetBackgroundAbsorption(); + m_ScatteringArray[index]=parameters->GetBackgroundScattering(); + m_AnisotropyArray[index]=parameters->GetBackgroundAnisotropy(); m_SegmentationArray[index] = SegmentationType::BACKGROUND; } - if(doGauss) + if(parameters->GetDoVolumeSmoothing()) { - m_Sigma = sigma; + m_Sigma = parameters->GetVolumeSmoothingSigma(); } else { m_Sigma = 0; } //Set properties - AddIntProperty("mcflag", mcflag); - AddIntProperty("launchflag", launchflag); - AddIntProperty("boundaryflag", boundaryflag); - AddDoubleProperty("launchPointX", launchPointX); - AddDoubleProperty("launchPointY", launchPointY); - AddDoubleProperty("launchPointZ", launchPointZ); - AddDoubleProperty("focusPointX", focusPointX); - AddDoubleProperty("focusPointY", focusPointY); - AddDoubleProperty("focusPointZ", focusPointZ); - AddDoubleProperty("trajectoryVectorX", trajectoryVectorX); - AddDoubleProperty("trajectoryVectorY", trajectoryVectorY); - AddDoubleProperty("trajectoryVectorZ", trajectoryVectorZ); - AddDoubleProperty("radius", radius); - AddDoubleProperty("waist", waist); + AddIntProperty("mcflag", parameters->GetMCflag()); + AddIntProperty("launchflag", parameters->GetMCLaunchflag()); + AddIntProperty("boundaryflag", parameters->GetMCBoundaryflag()); + AddDoubleProperty("launchPointX", parameters->GetMCLaunchPointX()); + AddDoubleProperty("launchPointY", parameters->GetMCLaunchPointY()); + AddDoubleProperty("launchPointZ", parameters->GetMCLaunchPointZ()); + AddDoubleProperty("focusPointX", parameters->GetMCFocusPointX()); + AddDoubleProperty("focusPointY", parameters->GetMCFocusPointY()); + AddDoubleProperty("focusPointZ", parameters->GetMCFocusPointZ()); + AddDoubleProperty("trajectoryVectorX", parameters->GetMCTrajectoryVectorX()); + AddDoubleProperty("trajectoryVectorY", parameters->GetMCTrajectoryVectorY()); + AddDoubleProperty("trajectoryVectorZ", parameters->GetMCTrajectoryVectorZ()); + AddDoubleProperty("radius", parameters->GetMCRadius()); + AddDoubleProperty("waist", parameters->GetMCWaist()); AddDoubleProperty("sigma", m_Sigma); - AddDoubleProperty("standardTissueAbsorption", initAbsorption); - AddDoubleProperty("standardTissueScattering", initScattering); - AddDoubleProperty("standardTissueAnisotropy", initAnisotropy); + AddDoubleProperty("standardTissueAbsorption", parameters->GetBackgroundAbsorption()); + AddDoubleProperty("standardTissueScattering", parameters->GetBackgroundScattering()); + AddDoubleProperty("standardTissueAnisotropy", parameters->GetBackgroundAnisotropy()); AddDoubleProperty("airThickness", m_ThicknessAir); AddDoubleProperty("skinThickness", m_ThicknessSkin); m_State = INITIALIZED; } void mitk::PhotoacousticVolume::AddDoubleProperty(std::string label, double value) { m_PropertyList->SetDoubleProperty(label.c_str(), value); mitk::CoreServices::GetPropertyPersistence()->AddInfo(label, mitk::PropertyPersistenceInfo::New(label)); } void mitk::PhotoacousticVolume::AddIntProperty(std::string label, int value) { m_PropertyList->SetIntProperty(label.c_str(), value); mitk::CoreServices::GetPropertyPersistence()->AddInfo(label, mitk::PropertyPersistenceInfo::New(label)); } mitk::Image::Pointer mitk::PhotoacousticVolume::ConvertToMitkImage() { AssertState(INITIALIZED); mitk::Image::Pointer resultImage = mitk::Image::New(); mitk::PixelType TPixel = mitk::MakeScalarPixelType(); unsigned int* dimensionsOfImage = new unsigned int[4]; // Copy dimensions dimensionsOfImage[0] = m_YDim; dimensionsOfImage[1] = m_XDim; dimensionsOfImage[2] = m_ZDim; dimensionsOfImage[3] = m_TDim; MITK_DEBUG << "Initializing image..."; resultImage->Initialize(TPixel, 4, dimensionsOfImage, 1); MITK_DEBUG << "Initializing image...[Done]"; mitk::Vector3D spacing; spacing.Fill(m_Spacing); resultImage->SetSpacing(spacing); MITK_DEBUG << "Set Import Volumes..."; //Copy memory, deal with cleaning up memory yourself! resultImage->SetImportVolume(m_AbsorptionArray, 0, 0, mitk::Image::CopyMemory); resultImage->SetImportVolume(m_ScatteringArray, 1, 0, mitk::Image::CopyMemory); resultImage->SetImportVolume(m_AnisotropyArray, 2, 0, mitk::Image::CopyMemory); resultImage->SetImportVolume(m_SegmentationArray, 3, 0, mitk::Image::CopyMemory); MITK_DEBUG << "Set Import Volumes...[Done]"; resultImage->SetPropertyList(m_PropertyList); return resultImage; } mitk::PhotoacousticVolume::PhotoacousticVolume() { m_State = UNINITIALIZED; m_XDim = 0; m_YDim = 0; m_ZDim = 0; m_AbsorptionAir = 0.0001; m_ScatteringAir = 1.0; m_AnisotropyAir = 1.0; m_Sigma = 0; m_PropertyList = mitk::PropertyList::New(); } mitk::PhotoacousticVolume::~PhotoacousticVolume() { m_State = UNINITIALIZED; m_XDim = 0; m_YDim = 0; m_ZDim = 0; if(m_AbsorptionArray!=nullptr) { delete[] m_AbsorptionArray; m_AbsorptionArray = nullptr; } if(m_ScatteringArray!=nullptr) { delete[] m_ScatteringArray; m_ScatteringArray = nullptr; } if(m_AnisotropyArray!=nullptr) { delete[] m_AnisotropyArray; m_AnisotropyArray = nullptr; } } int mitk::PhotoacousticVolume::GetIndex(int x, int y, int z) { return z * m_XDim * m_YDim + x * m_YDim + y; } void mitk::PhotoacousticVolume::SetVolumeValues(int x, int y, int z, double absorption, double scattering, double anisotropy, SegmentationType segmentType) { AssertState(INITIALIZED); if(IsInsideVolume(x, y, z)) { int index = GetIndex(x, y, z); m_AbsorptionArray[index] = absorption; m_ScatteringArray[index] = scattering; m_AnisotropyArray[index] = anisotropy; m_SegmentationArray[index] = segmentType; } } bool mitk::PhotoacousticVolume::IsInsideVolume(int x, int y, int z) { AssertState(INITIALIZED); return x >= 0 && x < m_XDim && y >= 0 && y < m_YDim && z >= 0 && z < m_ZDim; } double mitk::PhotoacousticVolume::GetVolumeAbsorptionValue(int x, int y, int z) { AssertState(INITIALIZED); return m_AbsorptionArray[GetIndex(x, y, z)]; } double mitk::PhotoacousticVolume::GetVolumeSegmentationValue(int x, int y, int z) { AssertState(INITIALIZED); return m_SegmentationArray[GetIndex(x, y, z)]; } -void mitk::PhotoacousticVolume::FinalizeVolume(bool randomize, double percentage, bool useRngSeed, long rngSeed) +void mitk::PhotoacousticVolume::FinalizeVolume(mitk::PhotoacousticTissueGeneratorParameters::Pointer parameters) { //Calculate the index location according to thickness in cm double airvoxel = m_ThicknessAir / m_Spacing / 10; double skinvoxel = airvoxel + m_ThicknessSkin / m_Spacing / 10; for(int y = 0; y < m_YDim; y++) { for(int x = 0; x < m_XDim; x++) { // Add air from index 0 to airvoxel if(m_ThicknessAir > mitk::eps) FillZLayer(x, y, 0, airvoxel, m_AbsorptionAir, m_ScatteringAir, m_AnisotropyAir, SegmentationType::AIR); //Add skin from index airvoxel to skinvoxel if(m_ThicknessSkin > mitk::eps) FillZLayer(x, y, airvoxel, skinvoxel, m_AbsorptionSkin, m_ScatteringSkin, m_AnisotropySkin, SegmentationType::SKIN); } } +// for(int y = 0; y < m_YDim; y++) +// { +// for(int x = 0; x < m_XDim; x++) +// { +// int index = GetIndex(x, y, 37); +// m_AbsorptionArray[index] = 100; +// } +// } + // If specified, randomize all tissue parameters - if(randomize) - RandomizeTissueCoefficients(rngSeed, useRngSeed, percentage); + if(parameters->GetRandomizePhysicalProperties()) + RandomizeTissueCoefficients(parameters->GetUseRngSeed(), parameters->GetRngSeed(), parameters->GetRandomizePhysicalPropertiesPercentage()); } void mitk::PhotoacousticVolume::FillZLayer(int x, int y, double startIdx, double endIdx, double absorption, double scattering, double anisotropy, SegmentationType segmentationType) { for(int z=startIdx; z < endIdx; z++) { int index = GetIndex(x, y, z); if(endIdx-z < 1) { //Simulate partial volume effects m_AbsorptionArray[index] = (1 - (endIdx - z)) * m_AbsorptionArray[index] + (endIdx - z) * absorption; m_ScatteringArray[index] = (1 - (endIdx - z)) * m_ScatteringArray[index] + (endIdx - z) * scattering; m_AnisotropyArray[index] = (1 - (endIdx - z)) * m_AnisotropyArray[index] + (endIdx - z) * anisotropy; if(endIdx-z > 0.5) { //Only put the segmentation label if more than half of the partial volume is the wanted tissue type m_SegmentationArray[index] = segmentationType; } } else { m_AbsorptionArray[index] = absorption; m_ScatteringArray[index] = scattering; m_AnisotropyArray[index] = anisotropy; m_SegmentationArray[index] = segmentationType; } } } void mitk::PhotoacousticVolume::RandomizeTissueCoefficients(long rngSeed, bool useRngSeed, double percentage) { std::mt19937 rng; std::random_device randomDevice; if(useRngSeed) { rng.seed(rngSeed); } else { if(randomDevice.entropy()>0.1) { rng.seed(randomDevice()); } else { rng.seed(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); } } std::normal_distribution<> percentageDistribution(1, percentage/100); for(int y = 0; y < m_YDim; y++) { for(int x = 0; x < m_XDim; x++) { for(int z = 0; z < m_ZDim; z++) { int index = GetIndex(x, y, z); m_AbsorptionArray[index] = m_AbsorptionArray[index]*percentageDistribution(rng); m_ScatteringArray[index] = m_ScatteringArray[index]*percentageDistribution(rng); } } } } double mitk::PhotoacousticVolume::GetVolumeScatteringValue(int x, int y, int z) { AssertState(INITIALIZED); return m_ScatteringArray[GetIndex(x, y, z)]; } double mitk::PhotoacousticVolume::GetVolumeAnisotropyValue(int x, int y, int z) { AssertState(INITIALIZED); return m_AnisotropyArray[GetIndex(x, y, z)]; } void mitk::PhotoacousticVolume::GaussianBlur3D() { GaussianBlur3D(m_AbsorptionArray, m_YDim, m_XDim, m_ZDim, m_Sigma); GaussianBlur3D(m_ScatteringArray, m_YDim, m_XDim, m_ZDim, m_Sigma); GaussianBlur3D(m_AnisotropyArray, m_YDim, m_XDim, m_ZDim, m_Sigma); } /** * @brief Fast 3D Gaussian convolution IIR approximation * @param volume * @param width * @param height * @param depth * @param sigma * @author Pascal Getreuer * * Copyright (c) 2011, Pascal Getreuer * All rights reserved. * * This program is free software: you can redistribute it and/or modify it * under the terms of the simplified BSD license. * * You should have received a copy of these licenses along with this program. * If not, see . */ void mitk::PhotoacousticVolume::GaussianBlur3D(double *volume, long width, long height, long depth, double sigma) { const long plane = width*height; const long numel = plane*depth; double lambda, dnu; double nu, boundaryscale, postscale; double *ptr; long i, x, y, z; int step; if(sigma <= 0) return; lambda = (sigma*sigma)/(8.0); dnu = (1.0 + 2.0*lambda - sqrt(1.0 + 4.0*lambda))/(2.0*lambda); nu = dnu; boundaryscale = 1.0/(1.0 - dnu); postscale = pow(dnu/lambda,12); /* Filter horizontally along each row */ for(z = 0; z < depth; z++) { for(y = 0; y < height; y++) { for(step = 0; step < 4; step++) { ptr = volume + width*(y + height*z); ptr[0] *= boundaryscale; /* Filter rightwards */ for(x = 1; x < width; x++) { ptr[x] += nu*ptr[x - 1]; } ptr[x = width - 1] *= boundaryscale; /* Filter leftwards */ for(; x > 0; x--) { ptr[x - 1] += nu*ptr[x]; } } } } /* Filter vertically along each column */ for(z = 0; z < depth; z++) { for(x = 0; x < width; x++) { for(step = 0; step < 4; step++) { ptr = volume + x + plane*z; ptr[0] *= boundaryscale; /* Filter downwards */ for(i = width; i < plane; i += width) { ptr[i] += nu*ptr[i - width]; } ptr[i = plane - width] *= boundaryscale; /* Filter upwards */ for(; i > 0; i -= width) { ptr[i - width] += nu*ptr[i]; } } } } /* Filter along z-dimension */ for(y = 0; y < height; y++) { for(x = 0; x < width; x++) { for(step = 0; step < 4; step++) { ptr = volume + x + width*y; ptr[0] *= boundaryscale; for(i = plane; i < numel; i += plane) { ptr[i] += nu*ptr[i - plane]; } ptr[i = numel - plane] *= boundaryscale; for(; i > 0; i -= plane) { ptr[i - plane] += nu*ptr[i]; } } } } for(i = 0; i < numel; i++) { volume[i] *= postscale; } return; } diff --git a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticVolume.h b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticVolume.h index 6afb73fd4d..cc4992323d 100644 --- a/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticVolume.h +++ b/Modules/PhotoacousticSimulation/src/Algorithms/mitkPhotoacousticVolume.h @@ -1,222 +1,193 @@ /*=================================================================== 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 MITKPHOTOACOUSTICVOLUME_H #define MITKPHOTOACOUSTICVOLUME_H #include #include #include +#include #include "mitkPhotoacousticStatefulObject.h" //Includes for smart pointer usage #include "mitkCommon.h" #include "itkLightObject.h" namespace mitk { class MITKPHOTOACOUSTICSIMULATION_EXPORT PhotoacousticVolume : public itk::LightObject, public mitk::PhotoacousticStatefulObject { public: mitkClassMacroItkParent(mitk::PhotoacousticVolume, itk::LightObject) itkFactorylessNewMacro(Self) enum SegmentationType { AIR = -1, BACKGROUND = 0, VESSEL = 1, FAT = 2, SKIN = 3 }; /** * @brief Initialize initializes this PhotoacousticVolume with the given parameters. * - * @param xDim - * @param yDim - * @param zDim - * @param spacing - * @param initAbsorption - * @param initScattering - * @param initAnisotropy - * @param mcflag - * @param launchflag - * @param boundaryflag - * @param launchPointX - * @param launchPointY - * @param launchPointZ - * @param focusPointX - * @param focusPointY - * @param focusPointZ - * @param trajectoryVectorX - * @param trajectoryVectorY - * @param trajectoryVectorZ - * @param radius - * @param waist - * @param sigma - * @param doGauss + * @param parameters */ - void Initialize(int xDim, int yDim, int zDim, double spacing, double initAbsorption, double initScattering, double initAnisotropy, - int mcflag, int launchflag, int boundaryflag, - double launchPointX, double launchPointY, double launchPointZ, - double focusPointX, double focusPointY, double focusPointZ, - double trajectoryVectorX, double trajectoryVectorY, double trajectoryVectorZ, - double radius, double waist, - double sigma, bool doGauss, - double airThickness, double epidermisThickness, - double skinAbsorption, double skinScattering, double skinAnisotropy); + void Initialize(mitk::PhotoacousticTissueGeneratorParameters::Pointer parameters); /** * @brief ConvertToMitkImage * @return a pointer to an mitk image containing this volume. */ mitk::Image::Pointer ConvertToMitkImage(); /** * @brief SetVolumeValues sets the values for aborption, scattering and anisotropy at the specified voxel location. * * @param x * @param y * @param z * @param absorption * @param scattering * @param anisotropy * @param segmentType */ void SetVolumeValues(int x, int y, int z, double absorption, double scattering, double anisotropy, SegmentationType segmentType = SegmentationType::BACKGROUND); /** * @brief GetVolumeAbsorptionValue * * @param x * @param y * @param z * @return the aborption value at the specified voxel location */ double GetVolumeAbsorptionValue(int x, int y, int z); /** * @brief GetVolumeScatteringValue * * @param x * @param y * @param z * @return the scattering value at the specified voxel location */ double GetVolumeScatteringValue(int x, int y, int z); /** * @brief GetVolumeAnisotropyValue * * @param x * @param y * @param z * @return the anisotropy value at the specified voxel location */ double GetVolumeAnisotropyValue(int x, int y, int z); /** * @brief GetVolumeSegmentationValue * * @param x * @param y * @param z * @return the segmentation type at the specified voxel location */ double GetVolumeSegmentationValue(int x, int y, int z); /** * @brief IsInsideVolume * * @param x * @param y * @param z * @return true if the voxel location is inside the volume */ bool IsInsideVolume(int x, int y, int z); /** * @brief AddDoubleProperty adds a persistent property to the volume, which will be exported to the mitk image. * * @param label * @param value */ void AddDoubleProperty(std::string label, double value); /** * @brief AddIntProperty adds a persistent property to the volume, which will be exported to the mitk image. * * @param label * @param value */ void AddIntProperty(std::string label, int value); int getXDim(){return m_XDim;} int getYDim(){return m_YDim;} int getZDim(){return m_ZDim;} int getTDim(){return m_TDim;} - void FinalizeVolume(bool randomize, double percentage, bool useRngSeed, long rngSeed); + void FinalizeVolume(mitk::PhotoacousticTissueGeneratorParameters::Pointer parameters); void GaussianBlur3D(); protected: PhotoacousticVolume(); virtual ~PhotoacousticVolume(); double* m_AbsorptionArray; double* m_ScatteringArray; double* m_AnisotropyArray; double* m_SegmentationArray; double m_AbsorptionAir; double m_ScatteringAir; double m_AnisotropyAir; double m_AbsorptionSkin; double m_ScatteringSkin; double m_AnisotropySkin; double m_ThicknessAir; double m_ThicknessSkin; int m_XDim; int m_YDim; int m_ZDim; int m_TDim; double m_Spacing; double m_Sigma; void GaussianBlur3D(double* array, long width, long height, long depth, double sigma); int GetIndex(int x, int y, int z); void RandomizeTissueCoefficients(long rngSeed, bool useRngSeed, double percentage); void FillZLayer(int x, int y, double startIdx, double endIdx, double absorption, double scattering, double anisotropy, SegmentationType segmentationType); mitk::PropertyList::Pointer m_PropertyList; }; } #endif // MITKPHOTOACOUSTICVOLUME_H diff --git a/Modules/PhotoacousticSimulation/src/IO/mitkPhotoacousticIO.cpp b/Modules/PhotoacousticSimulation/src/IO/mitkPhotoacousticIO.cpp index 7e1b755c28..a5199793b5 100644 --- a/Modules/PhotoacousticSimulation/src/IO/mitkPhotoacousticIO.cpp +++ b/Modules/PhotoacousticSimulation/src/IO/mitkPhotoacousticIO.cpp @@ -1,225 +1,224 @@ #include "mitkPhotoacousticIO.h" #include "mitkIOUtil.h" #include "mitkImageReadAccessor.h" #include "boost/filesystem.hpp" #include #include #include static std::vector splitString(const std::string &s, const char* delim) { std::vector elems; std::stringstream ss(s); std::string item; while (std::getline(ss, item, *delim)) { int numb; std::stringstream(item) >> numb; elems.push_back(numb); } return elems; } static bool hasEnding (std::string const &fullString, std::string const &ending) { if (fullString.length() >= ending.length()) { return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); } else { return false; } } mitk::PhotoacousticIO::PhotoacousticIO(){} mitk::PhotoacousticIO::~PhotoacousticIO(){} mitk::Photoacoustic3dVolume::Pointer mitk::PhotoacousticIO::LoadNrrd(std::string filename, double blur) { if(filename.empty() || filename == "") return nullptr; mitk::Image::Pointer inputImage = mitk::IOUtil::LoadImage(filename); if(inputImage.IsNull()) return nullptr; int xDim = inputImage->GetDimensions()[1]; int yDim = inputImage->GetDimensions()[0]; int zDim = inputImage->GetDimensions()[2]; mitk::ImageReadAccessor readAccess(inputImage, inputImage->GetVolumeData(0)); double* dataArray = new double[xDim*yDim*zDim]; const double* srcData = (const double*) readAccess.GetData(); memcpy(dataArray, srcData , xDim*yDim*zDim*sizeof(double)); GaussianBlur3D(dataArray, yDim, xDim, zDim, blur); return mitk::Photoacoustic3dVolume::New(dataArray, xDim, yDim, zDim); } std::map -mitk::PhotoacousticIO::LoadMultipleNrrdFiles(std::string foldername, double blur, - int* progress) +mitk::PhotoacousticIO::LoadMultipleNrrdFiles(std::string foldername, double blur, int* progress) { std::map resultMap; boost::filesystem::directory_iterator end_itr; for(boost::filesystem::directory_iterator itr(foldername); itr!=end_itr; itr++) { if(boost::filesystem::is_directory(itr->status())) continue; std::string filename = itr->path().string(); if(!hasEnding(filename, ".nrrd")) continue; size_t s = filename.find("_p"); size_t e = filename.find("Fluence", s); std::string sub = filename.substr(s + 2, e - s -2); std::vector coords = splitString(sub, ","); if(coords.size() != 3) { MITK_ERROR << "Some of the data to read was corrupted or did not match the "<< "naming pattern *_pN,N,NFluence*.nrrd"; mitkThrow() << "Some of the data to read was corrupted or did not match the"<< " naming pattern *_pN,N,NFluence*.nrrd"; } else { MITK_DEBUG << "Extracted coords: " << coords[0] << "|" << coords[1] << "|" << coords[2] << " from string " << sub; mitk::Photoacoustic3dVolume::Pointer nrrdFile = LoadNrrd(filename, blur); resultMap[mitk::PhotoacousticIO::Position{coords[0], coords[2]}] = nrrdFile; *progress = *progress + 1; } } return resultMap; } /** * @brief Fast 3D Gaussian convolution IIR approximation * @param volume * @param width * @param height * @param depth * @param sigma * @author Pascal Getreuer * * Copyright (c) 2011, Pascal Getreuer * All rights reserved. * * This program is free software: you can redistribute it and/or modify it * under the terms of the simplified BSD license. * * You should have received a copy of these licenses along with this program. * If not, see . */ void mitk::PhotoacousticIO::GaussianBlur3D(double *volume, long width, long height, long depth, double sigma) { const long plane = width*height; const long numel = plane*depth; double lambda, dnu; double nu, boundaryscale, postscale; double *ptr; long i, x, y, z; int step; if(sigma <= mitk::eps) return; lambda = (sigma*sigma)/(8.0); dnu = (1.0 + 2.0*lambda - sqrt(1.0 + 4.0*lambda))/(2.0*lambda); nu = dnu; boundaryscale = 1.0/(1.0 - dnu); postscale = pow(dnu/lambda,12); /* Filter horizontally along each row */ for(z = 0; z < depth; z++) { for(y = 0; y < height; y++) { for(step = 0; step < 4; step++) { ptr = volume + width*(y + height*z); ptr[0] *= boundaryscale; /* Filter rightwards */ for(x = 1; x < width; x++) { ptr[x] += nu*ptr[x - 1]; } ptr[x = width - 1] *= boundaryscale; /* Filter leftwards */ for(; x > 0; x--) { ptr[x - 1] += nu*ptr[x]; } } } } /* Filter vertically along each column */ for(z = 0; z < depth; z++) { for(x = 0; x < width; x++) { for(step = 0; step < 4; step++) { ptr = volume + x + plane*z; ptr[0] *= boundaryscale; /* Filter downwards */ for(i = width; i < plane; i += width) { ptr[i] += nu*ptr[i - width]; } ptr[i = plane - width] *= boundaryscale; /* Filter upwards */ for(; i > 0; i -= width) { ptr[i - width] += nu*ptr[i]; } } } } /* Filter along z-dimension */ for(y = 0; y < height; y++) { for(x = 0; x < width; x++) { for(step = 0; step < 4; step++) { ptr = volume + x + width*y; ptr[0] *= boundaryscale; for(i = plane; i < numel; i += plane) { ptr[i] += nu*ptr[i - plane]; } ptr[i = numel - plane] *= boundaryscale; for(; i > 0; i -= plane) { ptr[i - plane] += nu*ptr[i]; } } } } for(i = 0; i < numel; i++) { volume[i] *= postscale; } return; } diff --git a/Modules/PhotoacousticSimulation/src/Utils/mitkPhotoacousticTissueGeneratorParameters.cpp b/Modules/PhotoacousticSimulation/src/Utils/mitkPhotoacousticTissueGeneratorParameters.cpp new file mode 100644 index 0000000000..c2a85e0ca8 --- /dev/null +++ b/Modules/PhotoacousticSimulation/src/Utils/mitkPhotoacousticTissueGeneratorParameters.cpp @@ -0,0 +1,81 @@ +/*=================================================================== + +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 "mitkPhotoacousticTissueGeneratorParameters.h" + +mitk::PhotoacousticTissueGeneratorParameters::PhotoacousticTissueGeneratorParameters() +{ + m_XDim = 50; + m_YDim = 50; + m_ZDim = 50; + m_VoxelSpacing = 1; + m_VolumeSmoothingSigma = 0; + m_DoVolumeSmoothing = false; + m_UseRngSeed = false; + m_RngSeed = 1337L; + m_RandomizePhysicalProperties = false; + m_RandomizePhysicalPropertiesPercentage = 0; + + m_BackgroundAbsorption = 0.1; + m_BackgroundScattering = 15; + m_BackgroundAnisotropy = 0.9; + m_AirThickness = 1; + m_SkinAbsorption = 0.1; + m_SkinScattering = 15; + m_SkinAnisotropy = 0.9; + m_SkinThickness = 0; + m_FatAbsorption = 0.1; + m_FatScattering = 15; + m_FatAnisotropy = 0.9; + m_FatPercentage = 0; + + m_CalculateNewVesselPositionCallback = &mitk::PhotoacousticVesselMeanderStrategy::CalculateRandomlyDivergingPosition; + m_MinNumberOfVessels = 0; + m_MaxNumberOfVessels = 0; + m_MinVesselBending = 0; + m_MaxVesselBending = 0.1; + m_MinVesselAbsorption = 1; + m_MaxVesselAbsorption = 8; + m_MinVesselRadius = 1; + m_MaxVesselRadius = 3; + m_VesselBifurcationFrequency = 25; + m_MinVesselScattering = 15; + m_MaxVesselScattering = 15; + m_MinVesselAnisotropy = 0.9; + m_MaxVesselAnisotropy = 0.9; + m_MinVesselZOrigin = 10; + m_MaxVesselZOrigin = 40; + + m_MCflag = 1; + m_MCLaunchflag = 0; + m_MCBoundaryflag = 2; + m_MCLaunchPointX = 25; + m_MCLaunchPointY = 25; + m_MCLaunchPointZ = 2; + m_MCFocusPointX = 25; + m_MCFocusPointY = 25; + m_MCFocusPointZ = 25; + m_MCTrajectoryVectorX = 0; + m_MCTrajectoryVectorY = 0; + m_MCTrajectoryVectorZ = 1; + m_MCRadius = 2; + m_MCWaist = 4; +} + +mitk::PhotoacousticTissueGeneratorParameters::~PhotoacousticTissueGeneratorParameters() +{ + +} diff --git a/Modules/PhotoacousticSimulation/src/Utils/mitkPhotoacousticTissueGeneratorParameters.h b/Modules/PhotoacousticSimulation/src/Utils/mitkPhotoacousticTissueGeneratorParameters.h new file mode 100644 index 0000000000..e93490c1e2 --- /dev/null +++ b/Modules/PhotoacousticSimulation/src/Utils/mitkPhotoacousticTissueGeneratorParameters.h @@ -0,0 +1,221 @@ +/*=================================================================== + +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 MITKPHOTOACOUSTICTISSUEGENERATORPARAMETERS_H +#define MITKPHOTOACOUSTICTISSUEGENERATORPARAMETERS_H + +#include +#include + +//Includes for smart pointer usage +#include "mitkCommon.h" +#include "itkLightObject.h" + +namespace mitk { + + +class MITKPHOTOACOUSTICSIMULATION_EXPORT PhotoacousticTissueGeneratorParameters : public itk::Object +{ +public: + mitkClassMacroItkParent(mitk::PhotoacousticTissueGeneratorParameters, itk::Object) + itkFactorylessNewMacro(Self) + + /** + * Callback function definition of a PhotoacousticVesselMeanderStrategy + */ + typedef void (mitk::PhotoacousticVesselMeanderStrategy::*CalculateNewVesselPositionCallback) + (mitk::PhotoacousticSmartVector::Pointer, mitk::PhotoacousticSmartVector::Pointer, double, std::mt19937*); + + itkGetMacro(XDim, int) + itkGetMacro(YDim, int) + itkGetMacro(ZDim, int) + itkGetMacro(VoxelSpacing, double) + itkGetMacro(VolumeSmoothingSigma, double) + itkGetMacro(DoVolumeSmoothing, bool) + itkGetMacro(UseRngSeed, bool) + itkGetMacro(RngSeed, long) + itkGetMacro(RandomizePhysicalProperties, bool) + itkGetMacro(RandomizePhysicalPropertiesPercentage, double) + + itkGetMacro(BackgroundAbsorption, double) + itkGetMacro(BackgroundScattering, double) + itkGetMacro(BackgroundAnisotropy, double) + itkGetMacro(AirThickness, double) + itkGetMacro(SkinAbsorption, double) + itkGetMacro(SkinScattering, double) + itkGetMacro(SkinAnisotropy, double) + itkGetMacro(SkinThickness, double) + itkGetMacro(FatAbsorption, double) + itkGetMacro(FatScattering, double) + itkGetMacro(FatAnisotropy, double) + itkGetMacro(FatPercentage, double) + + itkGetMacro(CalculateNewVesselPositionCallback, CalculateNewVesselPositionCallback) + itkGetMacro(MinNumberOfVessels, int) + itkGetMacro(MaxNumberOfVessels, int) + itkGetMacro(MinVesselBending, double) + itkGetMacro(MaxVesselBending, double) + itkGetMacro(MinVesselAbsorption, double) + itkGetMacro(MaxVesselAbsorption, double) + itkGetMacro(MinVesselRadius, double) + itkGetMacro(MaxVesselRadius, double) + itkGetMacro(VesselBifurcationFrequency, int) + itkGetMacro(MinVesselScattering, double) + itkGetMacro(MaxVesselScattering, double) + itkGetMacro(MinVesselAnisotropy, double) + itkGetMacro(MaxVesselAnisotropy, double) + itkGetMacro(MinVesselZOrigin, double) + itkGetMacro(MaxVesselZOrigin, double) + + itkGetMacro(MCflag, double) + itkGetMacro(MCLaunchflag, double) + itkGetMacro(MCBoundaryflag, double) + itkGetMacro(MCLaunchPointX, double) + itkGetMacro(MCLaunchPointY, double) + itkGetMacro(MCLaunchPointZ, double) + itkGetMacro(MCFocusPointX, double) + itkGetMacro(MCFocusPointY, double) + itkGetMacro(MCFocusPointZ, double) + itkGetMacro(MCTrajectoryVectorX, double) + itkGetMacro(MCTrajectoryVectorY, double) + itkGetMacro(MCTrajectoryVectorZ, double) + itkGetMacro(MCRadius, double) + itkGetMacro(MCWaist, double) + + itkSetMacro(XDim, int) + itkSetMacro(YDim, int) + itkSetMacro(ZDim, int) + itkSetMacro(VoxelSpacing, double) + itkSetMacro(VolumeSmoothingSigma, double) + itkSetMacro(DoVolumeSmoothing, bool) + itkSetMacro(UseRngSeed, bool) + itkSetMacro(RngSeed, long) + itkSetMacro(RandomizePhysicalProperties, bool) + itkSetMacro(RandomizePhysicalPropertiesPercentage, double) + + itkSetMacro(BackgroundAbsorption, double) + itkSetMacro(BackgroundScattering, double) + itkSetMacro(BackgroundAnisotropy, double) + itkSetMacro(AirThickness, double) + itkSetMacro(SkinAbsorption, double) + itkSetMacro(SkinScattering, double) + itkSetMacro(SkinAnisotropy, double) + itkSetMacro(SkinThickness, double) + itkSetMacro(FatAbsorption, double) + itkSetMacro(FatScattering, double) + itkSetMacro(FatAnisotropy, double) + itkSetMacro(FatPercentage, double) + + itkSetMacro(CalculateNewVesselPositionCallback, CalculateNewVesselPositionCallback) + itkSetMacro(MinNumberOfVessels, int) + itkSetMacro(MaxNumberOfVessels, int) + itkSetMacro(MinVesselBending, double) + itkSetMacro(MaxVesselBending, double) + itkSetMacro(MinVesselAbsorption, double) + itkSetMacro(MaxVesselAbsorption, double) + itkSetMacro(MinVesselRadius, double) + itkSetMacro(MaxVesselRadius, double) + itkSetMacro(VesselBifurcationFrequency, int) + itkSetMacro(MinVesselScattering, double) + itkSetMacro(MaxVesselScattering, double) + itkSetMacro(MinVesselAnisotropy, double) + itkSetMacro(MaxVesselAnisotropy, double) + itkSetMacro(MinVesselZOrigin, double) + itkSetMacro(MaxVesselZOrigin, double) + + itkSetMacro(MCflag, double) + itkSetMacro(MCLaunchflag, double) + itkSetMacro(MCBoundaryflag, double) + itkSetMacro(MCLaunchPointX, double) + itkSetMacro(MCLaunchPointY, double) + itkSetMacro(MCLaunchPointZ, double) + itkSetMacro(MCFocusPointX, double) + itkSetMacro(MCFocusPointY, double) + itkSetMacro(MCFocusPointZ, double) + itkSetMacro(MCTrajectoryVectorX, double) + itkSetMacro(MCTrajectoryVectorY, double) + itkSetMacro(MCTrajectoryVectorZ, double) + itkSetMacro(MCRadius, double) + itkSetMacro(MCWaist, double) + + +protected: + PhotoacousticTissueGeneratorParameters(); + virtual ~PhotoacousticTissueGeneratorParameters(); + +private: + + int m_XDim; + int m_YDim; + int m_ZDim; + double m_VoxelSpacing; + double m_VolumeSmoothingSigma; + bool m_DoVolumeSmoothing; + bool m_UseRngSeed; + long m_RngSeed; + bool m_RandomizePhysicalProperties; + double m_RandomizePhysicalPropertiesPercentage; + + double m_BackgroundAbsorption; + double m_BackgroundScattering; + double m_BackgroundAnisotropy; + double m_AirThickness; + double m_SkinAbsorption; + double m_SkinScattering; + double m_SkinAnisotropy; + double m_SkinThickness; + double m_FatAbsorption; + double m_FatScattering; + double m_FatAnisotropy; + double m_FatPercentage; + + CalculateNewVesselPositionCallback m_CalculateNewVesselPositionCallback; + int m_MinNumberOfVessels; + int m_MaxNumberOfVessels; + double m_MinVesselBending; + double m_MaxVesselBending; + double m_MinVesselAbsorption; + double m_MaxVesselAbsorption; + double m_MinVesselRadius; + double m_MaxVesselRadius; + int m_VesselBifurcationFrequency; + double m_MinVesselScattering; + double m_MaxVesselScattering; + double m_MinVesselAnisotropy; + double m_MaxVesselAnisotropy; + double m_MinVesselZOrigin; + double m_MaxVesselZOrigin; + + double m_MCflag; + double m_MCLaunchflag; + double m_MCBoundaryflag; + double m_MCLaunchPointX; + double m_MCLaunchPointY; + double m_MCLaunchPointZ; + double m_MCFocusPointX; + double m_MCFocusPointY; + double m_MCFocusPointZ; + double m_MCTrajectoryVectorX; + double m_MCTrajectoryVectorY; + double m_MCTrajectoryVectorZ; + double m_MCRadius; + double m_MCWaist; + +}; + +} + +#endif // MITKPHOTOACOUSTICTISSUEGENERATORPARAMETERS_H diff --git a/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulator.cpp b/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulator.cpp index ee6c3571ed..8b1fd0cd4e 100644 --- a/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulator.cpp +++ b/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulator.cpp @@ -1,323 +1,317 @@ /*=================================================================== 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 // Qmitk #include "PASimulator.h" // Qt #include #include #include // mitk #include #include #include #ifdef __linux__ #include #include #else #include #endif #include #include const std::string PASimulator::VIEW_ID = "org.mitk.views.pasimulator"; void PASimulator::SetFocus() { m_Controls.pushButtonShowRandomTissue->setFocus(); } void PASimulator::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); connect(m_Controls.pushButtonShowRandomTissue, SIGNAL(clicked()), this, SLOT(DoImageProcessing()) ); connect(m_Controls.checkBoxGauss, SIGNAL(stateChanged(int)), this, SLOT(ClickedGaussBox())); connect(m_Controls.pushButtonOpenPath, SIGNAL(clicked()), this, SLOT(OpenFolder()) ); connect(m_Controls.pushButtonOpenBinary, SIGNAL(clicked()), this, SLOT(OpenBinary()) ); connect(m_Controls.checkBoxGenerateBatch, SIGNAL(clicked()), this, SLOT(UpdateVisibilityOfBatchCreation()) ); connect(m_Controls.pushButtonAjustWavelength, SIGNAL(clicked()), this, SLOT(UpdateParametersAccordingToWavelength()) ); connect(m_Controls.checkBoxRngSeed, SIGNAL(clicked()), this, SLOT(ClickedCheckboxFixedSeed()) ); connect(m_Controls.checkBoxRandomizeParameters, SIGNAL(clicked()), this, SLOT(ClickedRandomizePhysicalParameters()) ); m_Controls.spinboxSigma->setEnabled(false); m_Controls.labelSigma->setEnabled(false); m_Controls.label_NrrdFilePath->setText((std::string(getenv("HOME"))+"/").c_str()); m_PhotoacousticPropertyCalculator = mitk::PhotoacousticPropertyCalculator::New(); UpdateVisibilityOfBatchCreation(); ClickedRandomizePhysicalParameters(); ClickedCheckboxFixedSeed(); ClickedGaussBox(); } void PASimulator::ClickedRandomizePhysicalParameters() { m_Controls.spinboxRandomizeParameters->setEnabled(m_Controls.checkBoxRandomizeParameters->isChecked()); } void PASimulator::ClickedCheckboxFixedSeed() { m_Controls.spinBoxRngSeed->setEnabled(m_Controls.checkBoxRngSeed->isChecked()); } void PASimulator::UpdateParametersAccordingToWavelength() { int wavelength = m_Controls.spinboxWavelength->value(); double bloodOxygenation = m_Controls.spinboxBloodOxygenSaturation->value()/100; mitk::PhotoacousticPropertyCalculator::Properties result = m_PhotoacousticPropertyCalculator->CalculatePropertyForSpecificWavelength( mitk::PhotoacousticPropertyCalculator::TissueType::BLOOD, wavelength, bloodOxygenation); m_Controls.spinboxMaxAbsorption->setValue(result.mua); m_Controls.spinboxMinAbsorption->setValue(result.mua); m_Controls.spinboxBloodVesselScatteringMinimum->setValue(result.mus); m_Controls.spinboxBloodVesselScatteringMaximum->setValue(result.mus); m_Controls.spinboxBloodVesselAnisotropyMinimum->setValue(result.g); m_Controls.spinboxBloodVesselAnisotropyMaximum->setValue(result.g); result = m_PhotoacousticPropertyCalculator->CalculatePropertyForSpecificWavelength( mitk::PhotoacousticPropertyCalculator::TissueType::EPIDERMIS, wavelength, bloodOxygenation); m_Controls.spinboxSkinAbsorption->setValue(result.mua); m_Controls.spinboxSkinScattering->setValue(result.mus); m_Controls.spinboxSkinAnisotropy->setValue(result.g); result = m_PhotoacousticPropertyCalculator->CalculatePropertyForSpecificWavelength( mitk::PhotoacousticPropertyCalculator::TissueType::FAT, wavelength, bloodOxygenation); m_Controls.spinboxFatAbsorption->setValue(result.mua); m_Controls.spinboxFatScattering->setValue(result.mus); m_Controls.spinboxFatAnisotropy->setValue(result.g); result = m_PhotoacousticPropertyCalculator->CalculatePropertyForSpecificWavelength( mitk::PhotoacousticPropertyCalculator::TissueType::STANDARD_TISSUE, wavelength, bloodOxygenation); m_Controls.spinboxBackgroundAbsorption->setValue(result.mua); m_Controls.spinboxBackgroundScattering->setValue(result.mus); m_Controls.spinboxBackgroundAnisotropy->setValue(result.g); } void PASimulator::UpdateVisibilityOfBatchCreation() { m_Controls.widgetBatchFile->setVisible(m_Controls.checkBoxGenerateBatch->isChecked()); } void PASimulator::DoImageProcessing() { if(m_Controls.checkBoxGenerateBatch->isChecked()) { if(m_Controls.labelBinarypath->text().isNull() || m_Controls.labelBinarypath->text().isEmpty()) { QMessageBox::warning(nullptr, QString("Warning"), QString("You need to specify the binary first!")); return; } } int numberOfVolumes = m_Controls.spinboxNumberVolumes->value(); if(numberOfVolumes<1) { QMessageBox::warning(nullptr, QString("Warning"), QString("You need to create at least one volume!")); return; } + mitk::PhotoacousticTissueGeneratorParameters::Pointer parameters = mitk::PhotoacousticTissueGeneratorParameters::New(); + // Getting settings from UI // General settings - int xDim = m_Controls.spinboxXDim->value(); - int yDim = m_Controls.spinboxYDim->value(); - int zDim = m_Controls.spinboxZDim->value(); - bool doGauss = m_Controls.checkBoxGauss->isChecked(); - bool randomizePhysicalProperties = m_Controls.checkBoxRandomizeParameters->isChecked(); - double randomPercentage = m_Controls.spinboxRandomizeParameters->value(); - double spacing = m_Controls.spinboxSpacing->value(); - bool useRngSeed = m_Controls.checkBoxRngSeed->isChecked(); - long rngSeed = m_Controls.spinBoxRngSeed->value(); + parameters->SetXDim(m_Controls.spinboxXDim->value()); + parameters->SetYDim(m_Controls.spinboxYDim->value()); + parameters->SetZDim(m_Controls.spinboxZDim->value()); + parameters->SetDoVolumeSmoothing(m_Controls.checkBoxGauss->isChecked()); + parameters->SetVolumeSmoothingSigma(m_Controls.spinboxSigma->value()); + parameters->SetRandomizePhysicalProperties(m_Controls.checkBoxRandomizeParameters->isChecked()); + parameters->SetRandomizePhysicalPropertiesPercentage(m_Controls.spinboxRandomizeParameters->value()); + parameters->SetVoxelSpacing(m_Controls.spinboxSpacing->value()); + parameters->SetUseRngSeed(m_Controls.checkBoxRngSeed->isChecked()); + parameters->SetRngSeed(m_Controls.spinBoxRngSeed->value()); // Monte Carlo simulation parameters - int mcflag = m_Controls.spinboxMcFlag->value(); - int launchflag = m_Controls.spinboxLaunchFlag->value(); - int boundaryflag = m_Controls.spinboxboundaryFlag->value(); - double launchPointX = m_Controls.spinboxLaunchpointX->value(); - double launchPointY = m_Controls.spinboxLaunchpointY->value(); - double launchPointZ = m_Controls.spinboxLaunchpointZ->value(); - double focusPointX = m_Controls.spinboxFocuspointX->value(); - double focusPointY = m_Controls.spinboxFocuspointY->value(); - double focusPointZ = m_Controls.spinboxFocuspointZ->value(); - double trajectoryVectorX = m_Controls.spinboxTrajectoryVectorX->value(); - double trajectoryVectorY = m_Controls.spinboxTrajectoryVectorY->value(); - double trajectoryVectorZ = m_Controls.spinboxTrajectoryVectorZ->value(); - double radius = m_Controls.spinboxRadius->value(); - double waist = m_Controls.spinboxWaist->value(); - double sigma = m_Controls.spinboxSigma->value(); + parameters->SetMCflag(m_Controls.spinboxMcFlag->value()); + parameters->SetMCLaunchflag(m_Controls.spinboxLaunchFlag->value()); + parameters->SetMCBoundaryflag(m_Controls.spinboxboundaryFlag->value()); + parameters->SetMCLaunchPointX(m_Controls.spinboxLaunchpointX->value()); + parameters->SetMCLaunchPointY(m_Controls.spinboxLaunchpointY->value()); + parameters->SetMCLaunchPointZ(m_Controls.spinboxLaunchpointZ->value()); + parameters->SetMCFocusPointX(m_Controls.spinboxFocuspointX->value()); + parameters->SetMCFocusPointY(m_Controls.spinboxFocuspointY->value()); + parameters->SetMCFocusPointZ(m_Controls.spinboxFocuspointZ->value()); + parameters->SetMCTrajectoryVectorX(m_Controls.spinboxTrajectoryVectorX->value()); + parameters->SetMCTrajectoryVectorY(m_Controls.spinboxTrajectoryVectorY->value()); + parameters->SetMCTrajectoryVectorZ(m_Controls.spinboxTrajectoryVectorZ->value()); + parameters->SetMCRadius(m_Controls.spinboxRadius->value()); + parameters->SetMCWaist(m_Controls.spinboxWaist->value()); // Vessel settings - double maxAbsorption = m_Controls.spinboxMaxAbsorption->value(); - double minAbsorption = m_Controls.spinboxMinAbsorption->value(); - double maxBending= m_Controls.spinboxMaxBending->value(); - double minBending = m_Controls.spinboxMinBending->value(); - double maxRadius = m_Controls.spinboxMaxDiameter->value(); - double minRadius = m_Controls.spinboxMinDiameter->value(); - int maxVessels = m_Controls.spinboxMaxVessels->value(); - int minVessels = m_Controls.spinboxMinVessels->value(); - double vesselScatteringMinimum = m_Controls.spinboxBloodVesselScatteringMinimum->value(); - double vesselScatteringMaximum = m_Controls.spinboxBloodVesselScatteringMaximum->value(); - double vesselAnisotropyMinimum = m_Controls.spinboxBloodVesselAnisotropyMinimum->value(); - double vesselAnisotropyMaximum = m_Controls.spinboxBloodVesselAnisotropyMaximum->value(); - int bifurcationFrequency = m_Controls.spinboxBifurcationFrequency->value(); + parameters->SetMaxVesselAbsorption(m_Controls.spinboxMaxAbsorption->value()); + parameters->SetMinVesselAbsorption(m_Controls.spinboxMinAbsorption->value()); + parameters->SetMaxVesselBending(m_Controls.spinboxMaxBending->value()); + parameters->SetMinVesselBending(m_Controls.spinboxMinBending->value()); + parameters->SetMaxVesselRadius(m_Controls.spinboxMaxDiameter->value()); + parameters->SetMinVesselRadius(m_Controls.spinboxMinDiameter->value()); + parameters->SetMaxNumberOfVessels(m_Controls.spinboxMaxVessels->value()); + parameters->SetMinNumberOfVessels(m_Controls.spinboxMinVessels->value()); + parameters->SetMinVesselScattering(m_Controls.spinboxBloodVesselScatteringMinimum->value()); + parameters->SetMaxVesselScattering(m_Controls.spinboxBloodVesselScatteringMaximum->value()); + parameters->SetMinVesselAnisotropy(m_Controls.spinboxBloodVesselAnisotropyMinimum->value()); + parameters->SetMaxVesselAnisotropy(m_Controls.spinboxBloodVesselAnisotropyMaximum->value()); + parameters->SetVesselBifurcationFrequency(m_Controls.spinboxBifurcationFrequency->value()); // Background tissue settings - double basicAbsorption = m_Controls.spinboxBackgroundAbsorption->value(); - double basicScattering = m_Controls.spinboxBackgroundScattering->value(); - double basicAnisotropy = m_Controls.spinboxBackgroundAnisotropy->value(); + parameters->SetBackgroundAbsorption(m_Controls.spinboxBackgroundAbsorption->value()); + parameters->SetBackgroundScattering(m_Controls.spinboxBackgroundScattering->value()); + parameters->SetBackgroundAnisotropy(m_Controls.spinboxBackgroundAnisotropy->value()); // Air settings - double airThickness = m_Controls.spinboxAirThickness->value(); + parameters->SetAirThickness(m_Controls.spinboxAirThickness->value()); //Fat tissue settings - double fatPercentage = m_Controls.spinboxFatPercentage->value(); - double fatAbsorption = m_Controls.spinboxFatAbsorption->value(); - double fatScattering = m_Controls.spinboxFatScattering->value(); - double fatAnisotropy = m_Controls.spinboxFatAnisotropy->value(); + parameters->SetFatPercentage(m_Controls.spinboxFatPercentage->value()); + parameters->SetFatAbsorption(m_Controls.spinboxFatAbsorption->value()); + parameters->SetFatScattering(m_Controls.spinboxFatScattering->value()); + parameters->SetFatAnisotropy(m_Controls.spinboxFatAnisotropy->value()); //Skin tissue settings - double skinThickness = m_Controls.spinboxSkinThickness->value(); - double skinAbsorption = m_Controls.spinboxSkinAbsorption->value(); - double skinScattering = m_Controls.spinboxSkinScattering->value(); - double skinAnisotropy = m_Controls.spinboxSkinAnisotropy->value(); + parameters->SetSkinThickness(m_Controls.spinboxSkinThickness->value()); + parameters->SetSkinAbsorption(m_Controls.spinboxSkinAbsorption->value()); + parameters->SetSkinScattering(m_Controls.spinboxSkinScattering->value()); + parameters->SetSkinAnisotropy(m_Controls.spinboxSkinAnisotropy->value()); + + parameters->SetCalculateNewVesselPositionCallback(&mitk::PhotoacousticVesselMeanderStrategy::CalculateRandomlyDivergingPosition); for(int volumeIndex = 0; volumeIndex < numberOfVolumes; volumeIndex++) { MITK_DEBUG << "Generating in silico data"; - mitk::PhotoacousticVolume::Pointer volume = mitk::PhotoacousticTissueGenerator::GenerateInSilicoData(xDim, yDim, zDim, spacing, - basicAbsorption, basicScattering, basicAnisotropy, airThickness, - skinAbsorption, skinScattering, skinAnisotropy, skinThickness, - fatAbsorption, fatScattering, fatAnisotropy, fatPercentage, - randomizePhysicalProperties, randomPercentage, - minVessels, maxVessels, - minBending, maxBending, - minAbsorption, maxAbsorption, - minRadius, maxRadius, - mcflag, launchflag, boundaryflag, - launchPointX, launchPointY, launchPointZ, - focusPointX, focusPointY, focusPointZ, - trajectoryVectorX, trajectoryVectorY, trajectoryVectorZ, - radius, waist, - sigma, doGauss, bifurcationFrequency, - vesselScatteringMinimum, vesselScatteringMaximum, vesselAnisotropyMinimum, vesselAnisotropyMaximum, - useRngSeed, rngSeed, - &mitk::PhotoacousticVesselMeanderStrategy::CalculateRandomlyDivergingPosition); + mitk::PhotoacousticVolume::Pointer volume = mitk::PhotoacousticTissueGenerator::GenerateInSilicoData(parameters); MITK_DEBUG << "Generating mitk::Image"; mitk::Image::Pointer tissueVolume = volume->ConvertToMitkImage(); if(m_Controls.checkBoxGenerateBatch->isChecked()) { std::string volumeNumber = ""; if(volumeIndex<10) { volumeNumber = "00" + std::to_string(volumeIndex); } else if(volumeIndex<100) { volumeNumber = "0" + std::to_string(volumeIndex); } else { volumeNumber = std::to_string(volumeIndex); } + std::string outputFolderName = m_Controls.label_NrrdFilePath->text().toStdString() + m_Controls.lineEditTissueName->text().toStdString() + volumeNumber; std::string savePath = outputFolderName + ".nrrd"; mitk::IOUtil::Save(tissueVolume, savePath); std::string filename = "executescript"; std::string filenameAllSimulation = "simulate_all"; #ifdef __linux__ mkdir(outputFolderName.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); filename += ".sh"; filenameAllSimulation += ".sh"; #else mkdir(outputFolderName.c_str()); filename += ".bat"; filenameAllSimulation += ".bat"; #endif std::ofstream file(outputFolderName+"/"+filename); + outputFolderName = "/home/ubuntu/sim/" + m_Controls.lineEditTissueName->text().toStdString() + volumeNumber; + savePath = outputFolderName + ".nrrd"; + if(file.is_open()) { for(double d = -1.8; d <=1.9; d+=0.12) { - file << m_Controls.labelBinarypath->text().toStdString() << " -i " << savePath << " -o " << outputFolderName << "/" << m_Controls.lineEditTissueName->text().toStdString() << "_yo" << round(d*100) / 100 << ".nrrd" << " -yo " << round(d*100) / 100 << " -n " << (m_Controls.spinboxNumberPhotons->value()*1000L) << "\n"; + file << m_Controls.labelBinarypath->text().toStdString() << " -p PROBE_DESIGN.xml -i " << savePath << " -o " << outputFolderName << "/" << m_Controls.lineEditTissueName->text().toStdString() << "_yo" << round(d*100) / 100 << ".nrrd" << " -yo " << round(d*100) / 100 << " -n " << (m_Controls.spinboxNumberPhotons->value()*1000L) << "\n"; } + file << "mv " << outputFolderName << "/ " << "/home/ubuntu/E130-Projekte/Biophotonics/qPAT/InVitroData/\n"; file.close(); } std::ofstream fileAllSimulation(m_Controls.label_NrrdFilePath->text().toStdString()+"/"+filenameAllSimulation, std::ios_base::app); if(fileAllSimulation.is_open()) { for(double d = -1.8; d <=1.9; d+=0.12) { - fileAllSimulation << m_Controls.labelBinarypath->text().toStdString() << " -i " << savePath << " -o " << outputFolderName << "/" << m_Controls.lineEditTissueName->text().toStdString() << "_yo" << round(d*100) / 100 << ".nrrd" << " -yo " << round(d*100) / 100 << " -n " << (m_Controls.spinboxNumberPhotons->value()*1000L) << "\n"; + fileAllSimulation << m_Controls.labelBinarypath->text().toStdString() << " -p PROBE_DESIGN.xml -i " << savePath << " -o " << outputFolderName << "/" << m_Controls.lineEditTissueName->text().toStdString() << "_yo" << round(d*100) / 100 << ".nrrd" << " -yo " << round(d*100) / 100 << " -n " << (m_Controls.spinboxNumberPhotons->value()*1000L) << "\n"; } + fileAllSimulation << "mv " << outputFolderName << "/ " << "/home/ubuntu/E130-Projekte/Biophotonics/qPAT/InVitroData/\n"; fileAllSimulation.close(); } } - - mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); - dataNode->SetData(tissueVolume); - dataNode->SetName(m_Controls.lineEditTissueName->text().toStdString()); - - this->GetDataStorage()->Add(dataNode); - mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); + else + { + mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); + dataNode->SetData(tissueVolume); + dataNode->SetName(m_Controls.lineEditTissueName->text().toStdString()); + this->GetDataStorage()->Add(dataNode); + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); + } } MITK_DEBUG << "Handing stuff to UI Thread now.."; } void PASimulator::ClickedGaussBox() { if(m_Controls.checkBoxGauss->isChecked()) { m_Controls.spinboxSigma->setEnabled(true); m_Controls.labelSigma->setEnabled(true); } else { m_Controls.spinboxSigma->setEnabled(false); m_Controls.labelSigma->setEnabled(false); } } void PASimulator::OpenFolder() { m_Controls.label_NrrdFilePath->setText(QFileDialog::getExistingDirectory().append("/")); } void PASimulator::OpenBinary() { m_Controls.labelBinarypath->setText(QFileDialog::getOpenFileName()); } diff --git a/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulator.h b/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulator.h index db409bd8e9..0983f3692f 100644 --- a/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulator.h +++ b/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulator.h @@ -1,77 +1,78 @@ /*=================================================================== 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 PASimulator_h #define PASimulator_h #include #include #include "ui_PASimulatorControls.h" #include "mitkPhotoacousticTissueGenerator.h" +#include "mitkPhotoacousticTissueGeneratorParameters.h" #include "mitkPhotoacousticVolume.h" #include "mitkPhotoacousticPropertyCalculator.h" /** \brief PASimulator \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ class PASimulator : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; protected slots: /// \brief Called when the user clicks the GUI button void DoImageProcessing(); void ClickedGaussBox(); void ClickedCheckboxFixedSeed(); void ClickedRandomizePhysicalParameters(); void OpenFolder(); void OpenBinary(); void UpdateVisibilityOfBatchCreation(); void UpdateParametersAccordingToWavelength(); protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; Ui::PASimulatorControls m_Controls; mitk::PhotoacousticPropertyCalculator::Pointer m_PhotoacousticPropertyCalculator; private: }; #endif // PASimulator_h diff --git a/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulatorControls.ui b/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulatorControls.ui index d2f55dfa33..86f6890ab4 100644 --- a/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulatorControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacousticsimulation/src/internal/PASimulatorControls.ui @@ -1,4934 +1,4939 @@ PASimulatorControls 0 0 433 655 0 0 Roboto Qt::NoContextMenu QmitkTemplate :/org.mitk.gui.qt.photoacousticsimulation/resources/icon.xpm:/org.mitk.gui.qt.photoacousticsimulation/resources/icon.xpm 0 0 415 600 + + + Ubuntu + + 0 Generator 10 10 391 581 0 0 391 581 0 0 0 0 75 true Volume parameters 0 0 0 25 16777215 25 Tissue name: 0 0 0 25 16777215 25 Size x: 0 0 0 25 16777215 25 50 false Spacing: 0 0 0 25 16777215 25 PhotoacousticTissue 0 0 0 25 16777215 25 1 9999 70 0 0 0 25 16777215 25 y: 0 0 0 25 16777215 25 9999 100 0 0 0 25 16777215 25 z: 0 0 0 25 16777215 25 9999 90 0 0 0 25 16777215 25 voxels Qt::Horizontal 40 20 0 0 0 25 16777215 25 2 0.010000000000000 0.060000000000000 0 0 0 25 16777215 25 cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 Randomize: 0 0 0 25 16777215 25 Partial volume effects: 0 0 0 25 16777215 25 Custom seed: 0 0 0 25 16777215 25 false true 0 0 0 25 16777215 25 - true + false true 0 0 0 25 16777215 25 0 0 0 25 16777215 25 sigma: 0 0 0 25 16777215 25 0 100.000000000000000 0.010000000000000 2.000000000000000 0 0 0 25 16777215 25 % Qt::Horizontal 40 20 0 0 0 25 16777215 25 sigma: 0 0 0 25 16777215 25 10.000000000000000 0.100000000000000 1.000000000000000 0 0 0 25 16777215 25 voxels Qt::Horizontal 40 20 0 0 0 25 16777215 25 999999999 170704057 Qt::Horizontal 40 20 Generate batch file output: false Number of volumes to generate: 1 9999999 1 Qt::Horizontal 40 20 Save generated tissue path: 0 0 50 0 50 16777215 open Path to MitkMcxyz binary: 0 0 50 0 50 16777215 open Number of Photons (x1000): 0 999999999 1 100000 0 0 Generate Tissue Qt::Vertical 20 40 Tissue 10 10 391 581 0 0 391 581 0 0 0 0 0 0 0 25 16777215 25 11 75 false true false Air Parameters 0 0 0 25 16777215 25 50 false Thickness: 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 false true false Background Parameters 0 0 0 25 16777215 25 Absorption coefficient: 0 0 0 25 16777215 25 Scattering coefficient: 0 0 0 25 16777215 25 Anisotropy facor: 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 false true false Skin Parameters 0 0 0 25 16777215 25 Thickness: 0 0 0 25 16777215 25 Absorption coefficient: 0 0 0 25 16777215 25 Scattering coefficient: 0 0 0 25 16777215 25 Anisotropy facor: 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 false true false Fat Parameters 0 0 0 25 16777215 25 Body fat percentage: 0 0 0 25 16777215 25 Absorption coefficient: 0 0 0 25 16777215 25 Scattering coefficient: 0 0 0 25 16777215 25 Anisotropy facor: 0 0 0 25 16777215 25 11 75 true 0 0 0 25 16777215 25 999.990000000000009 0.100000000000000 12.000000000000000 0 0 0 25 16777215 25 mm Qt::Horizontal 40 20 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 true 0 0 0 25 16777215 25 0.010000000000000 0.100000000000000 0.100000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 0.010000000000000 1000.000000000000000 0.500000000000000 15.000000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 0.010000000000000 1.000000000000000 0.010000000000000 0.900000000000000 Qt::Horizontal 40 20 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 true 0 0 0 25 16777215 25 0.100000000000000 0.000000000000000 0 0 0 25 16777215 25 mm Qt::Horizontal 40 20 0 0 0 25 16777215 25 0.010000000000000 0.100000000000000 3.000000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 0.010000000000000 1000.000000000000000 0.500000000000000 20.000000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 0.010000000000000 1.000000000000000 0.010000000000000 0.900000000000000 Qt::Horizontal 40 20 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 true 0 0 0 25 16777215 25 0 1.000000000000000 0.000000000000000 0 0 0 25 16777215 25 % Qt::Horizontal 40 20 0 0 0 25 16777215 25 0.010000000000000 0.100000000000000 0.200000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 0.010000000000000 1000.000000000000000 0.500000000000000 18.000000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 0.010000000000000 1.000000000000000 0.010000000000000 0.900000000000000 Qt::Horizontal 40 20 Qt::Vertical 20 40 Vessels 10 10 391 581 0 0 391 581 0 0 0 0 75 true Vessel Parameters 0 25 16777215 25 The number of bloos vessels to generate Count: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0 25 16777215 25 The radius of the blood vessels in mm Radius: 0 25 16777215 25 the absorption coefficient refers to the number of absorption events per centimeter. Absorption: 0 25 16777215 25 The reduced scattering coefficient. It refers to the amount of scattering events per centimeter. Scattering: 0 25 16777215 25 The anisotropy factor is the probability of a photon to not change its direction after a scattering event. Anisotropy factor: 0 25 16777215 25 The bifurcation frequency determines how often the vessel should bifurcate. The vessel will bifurcate after meandering a mean of the specified amount of voxels. When given a value of 0, the vessel will never bifurcate. Bifurcation frequency: 0 25 16777215 25 The curvedness it a setting to determine how much the vessel is allowed to bend during creation. A value of 0 refers to no bending at all and a value of 5 is the maximum. Curvedness: 0 25 16777215 25 The minimum number of blood vessels 0 - 1 + 0 0 25 16777215 25 to 0 25 16777215 25 The maximum number of blood vessels - 1 + 0 0 25 16777215 25 Vessels Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum radius - 4.500000000000000 + 2.250000000000000 0 25 16777215 25 to 0 25 16777215 25 The maximum radius - 8.100000000000000 + 4.050000000000000 0 25 16777215 25 mm Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum absorption coefficient 0.010000000000000 2.000000000000000 0 25 16777215 25 to 0 25 16777215 25 The maximum absorption coefficient 0.010000000000000 8.000000000000000 0 25 16777215 25 per cm Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum scattering 2 0.010000000000000 999.000000000000000 1.000000000000000 15.000000000000000 0 25 16777215 25 to 0 25 16777215 25 The minimum scattering 2 0.010000000000000 999.000000000000000 1.000000000000000 15.000000000000000 0 25 16777215 25 per cm Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum anisotropy factor 2 0.010000000000000 1.000000000000000 0.100000000000000 0.900000000000000 0 25 16777215 25 to 0 25 16777215 25 The maximum anisotropy factor 2 0.010000000000000 1.000000000000000 0.100000000000000 0.900000000000000 Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The bifurcation frequency determines how often the vessel should bifurcate. The vessel will bifurcate after meandering a mean of the specified amount of voxels. When given a value of 0, the vessel will never bifurcate. 0 1.000000000000000 999999999.000000000000000 5.000000000000000 5000.000000000000000 0 25 16777215 25 voxels Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimal curvedness of the vessel. A value of 0 refers to no bending at all and a value of 5 is the maximum. 5.000000000000000 - 0.100000000000000 + 0.000000000000000 0 25 16777215 25 to 0 25 16777215 25 The maximal curvedness of the vessel. A value of 0 refers to no bending at all and a value of 5 is the maximum. 5.000000000000000 0.010000000000000 - 0.500000000000000 + 0.200000000000000 0 25 16777215 25 A.U. Qt::Horizontal QSizePolicy::Expanding 60 20 Qt::Vertical 20 40 Monte Carlo 10 10 391 581 0 0 391 581 0 0 0 0 75 true Monte Carlo Parameters 0 25 16777215 25 50 false General: 0 0 0 25 16777215 25 Mcflag: 0 0 0 25 16777215 25 Launchflag: 0 0 0 25 16777215 25 Boundaryflag: 0 0 0 25 16777215 25 1 4 Qt::Horizontal 40 20 0 0 0 25 16777215 25 0 0 Qt::Horizontal 40 20 0 0 0 25 16777215 25 1 2 Qt::Horizontal 40 20 0 25 16777215 25 50 false Initial launch point: 0 25 16777215 25 x 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 y 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 z 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 Qt::Horizontal 40 20 0 25 16777215 25 50 false Focus point: 0 25 16777215 25 x 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 y 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 z 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 Qt::Horizontal 40 20 0 25 16777215 25 50 false Trajectory vector: 0 25 16777215 25 x 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 y 0 25 16777215 25 4 1000000.000000000000000 0.342000000000000 0 25 16777215 25 z 0 25 16777215 25 4 1000000.000000000000000 0.939700000000000 Qt::Horizontal 40 20 radius: waist: 4 1000.000000000000000 0.500000000000000 Qt::Horizontal 40 20 4 1000.000000000000000 0.010000000000000 Qt::Horizontal 40 20 Qt::Vertical 20 40 Wavelength 10 10 391 581 0 0 391 581 Qt::NoContextMenu 0 0 0 0 75 true Adjust physical properties by wavelength false 16777215 150 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Roboto'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">This widget enables the adjustment of the physical properties of the tissue according to a selected wavelength of the light and the oxygen saturation of the blood.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu';"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">The algorithm and measurements were provided by the publication </span><span style=" font-family:'Ubuntu'; font-weight:600;">Optical properties of biological tissues: a review </span><span style=" font-family:'Ubuntu';">by Steve L. Jacques.</span></p></body></html> +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This widget enables the adjustment of the physical properties of the tissue according to a selected wavelength of the light and the oxygen saturation of the blood.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The algorithm and measurements were provided by the publication <span style=" font-weight:600;">Optical properties of biological tissues: a review </span>by Steve L. Jacques.</p></body></html> 0 0 0 25 16777215 25 Wavelength: 0 0 0 25 16777215 25 Vessel oxygen saturation: 0 0 0 25 16777215 25 0 300.000000000000000 1000.000000000000000 650.000000000000000 Qt::Horizontal 40 20 0 0 0 25 16777215 25 0 100.000000000000000 75.000000000000000 0 0 0 25 16777215 25 % Qt::Horizontal 40 20 Adjust tissue properties Qt::Vertical 20 40