7 #include "fwGdcmIO/container/DicomSurface.hpp" 8 #include "fwGdcmIO/reader/ie/Surface.hpp" 10 #include "fwGdcmIO/helper/DicomDataReader.hxx" 11 #include "fwGdcmIO/helper/DicomDataTools.hpp" 13 #include <fwData/Color.hpp> 14 #include <fwData/Reconstruction.hpp> 16 #include <fwDataIO/reader/DictionaryReader.hpp> 18 #include <fwDataTools/helper/Mesh.hpp> 20 #include <fwMedData/DicomSeries.hpp> 22 #include <fwRuntime/profile/Profile.hpp> 24 #include <boost/algorithm/clamp.hpp> 25 #include <boost/algorithm/string/trim.hpp> 26 #include <boost/date_time/posix_time/posix_time.hpp> 31 #include <gdcmSurfaceHelper.h> 45 const SPTR(::gdcm::Reader)& reader,
46 const ::fwGdcmIO::container::DicomInstance::sptr& instance,
47 const ::fwMedData::ModelSeries::sptr& series,
48 const ::fwLog::Logger::sptr& logger,
49 ProgressCallback progress,
50 CancelRequestedCallback cancel) :
51 ::
fwGdcmIO::reader::ie::InformationEntity< ::
fwMedData::ModelSeries >(dicomSeries, reader, instance, series,
52 logger, progress, cancel)
64 bool Surface::loadSegmentedPropertyRegistry(const ::boost::filesystem::path& filepath)
66 return m_segmentedPropertyRegistry.readSegmentedPropertyRegistryFile(filepath,
true, m_logger);
71 void Surface::readSurfaceSegmentationAndSurfaceMeshModules()
74 SPTR(::gdcm::SurfaceReader) surfaceReader = std::static_pointer_cast< ::gdcm::SurfaceReader >(m_reader);
77 const ::gdcm::DataSet& dataset = surfaceReader->GetFile().GetDataSet();
80 const ::gdcm::DataElement& sequenceDataElement = dataset.GetDataElement(::gdcm::Tag(0x0062, 0x0002));
81 const auto segmentSequence = sequenceDataElement.GetValueAsSQ();
84 const auto& segmentContainer = surfaceReader->GetSegments();
87 ::fwMedData::ModelSeries::ReconstructionVectorType reconstructionDB = m_object->getReconstructionDB();
90 auto displayError = [&](const ::gdcm::SmartPointer< ::gdcm::Segment >& segment,
91 const std::string& error)
93 std::string segmentLabel = segment->GetSegmentLabel();
94 segmentLabel = ::gdcm::LOComp::Trim(segmentLabel.c_str());
95 const std::string msg =
"Error while reading the '" + segmentLabel +
"' segment: " + error;
100 m_logger->critical(msg);
107 std::size_t itemIndex = 1;
108 for(
const auto& segment : segmentContainer)
111 if (segment->GetSurfaceCount() != 1 || segment->GetSurfaces().size() != 1)
113 displayError(segment,
"Unsupported surface count.");
118 ::fwData::Reconstruction::sptr reconstruction = ::fwData::Reconstruction::New();
121 const ::gdcm::Item& segmentItem = segmentSequence->GetItem(itemIndex++);
124 const auto& surfaceContainer = segment->GetSurfaces();
125 const ::gdcm::SmartPointer< ::gdcm::Surface >& surface = surfaceContainer[0];
130 readSurfaceSegmentationModule(reconstruction, segment, segmentItem);
133 readSurfaceMeshModule(reconstruction, surface);
135 catch(const ::fwGdcmIO::exception::Failed& exception)
137 displayError(segment, exception.what());
142 reconstructionDB.push_back(reconstruction);
145 if(reconstructionDB.empty())
147 throw ::fwGdcmIO::exception::Failed(
"Unable to read the Surface Segmentation: no segments have been found.");
151 m_object->setReconstructionDB(reconstructionDB);
157 std::string getStructureTypeFromSegmentIdentification(const ::gdcm::SmartPointer< ::gdcm::Segment >& segment,
158 const ::fwGdcmIO::helper::SegmentedPropertyRegistry&
registry)
161 const auto format = [&](const ::gdcm::SegmentHelper::BasicCodedEntry& entry) -> std::string
165 return "(" + ::gdcm::LOComp::Trim(entry.CV.c_str()) +
166 ";" + ::gdcm::LOComp::Trim(entry.CSD.c_str()) +
167 ";" + ::gdcm::LOComp::Trim(entry.CM.c_str()) +
")";
174 const auto formatVector = [&](
const std::vector< ::gdcm::SegmentHelper::BasicCodedEntry >& entries) -> std::string
178 for(
const auto& entry : entries)
180 result += format(entry);
187 return registry.getStructureType(format(segment->GetPropertyType()),
188 format(segment->GetPropertyCategory()),
189 formatVector(segment->GetPropertyTypeModifiers()),
190 format(segment->GetAnatomicRegion()),
191 formatVector(segment->GetAnatomicRegionModifiers()));
197 void Surface::readSurfaceSegmentationModule(const ::fwData::Reconstruction::sptr& reconstruction,
198 const ::gdcm::SmartPointer< ::gdcm::Segment >& segment,
199 const ::gdcm::Item& segmentItem)
202 const ::gdcm::DataSet& segmentDataset = segmentItem.GetNestedDataSet();
205 std::string organName = segment->GetSegmentLabel();
206 organName = ::gdcm::LOComp::Trim(organName.c_str());
207 reconstruction->setOrganName(organName);
210 const ::gdcm::Tag structureTypeTag(0x5649, 0x1000);
211 auto privateCreator = ::gdcm::LOComp::Trim(segmentDataset.GetPrivateCreator(structureTypeTag).c_str());
212 if(segmentDataset.FindDataElement(structureTypeTag))
214 const auto structureType = ::fwGdcmIO::helper::DicomDataReader::getTagValue< 0x5649, 0x1000 >(segmentDataset);
215 reconstruction->setStructureType(structureType);
220 const auto structureType = getStructureTypeFromSegmentIdentification(segment, m_segmentedPropertyRegistry);
221 if(structureType.empty())
223 const std::string msg =
"Unable to retrieve structure type from segment identification " 224 "for segment '" + organName +
"'.";
229 m_logger->warning(msg);
235 const ::gdcm::Tag computedMaskVolumeTag(0x5649, 0x1001);
236 privateCreator = ::gdcm::LOComp::Trim(segmentDataset.GetPrivateCreator(computedMaskVolumeTag).c_str());
237 if(segmentDataset.FindDataElement(computedMaskVolumeTag))
239 ::gdcm::Attribute< 0x5649, 0x1001, ::gdcm::VR::OD, ::gdcm::VM::VM1 > attribute;
240 attribute.SetFromDataSet(segmentDataset);
241 const double volume = attribute.GetValue();
242 reconstruction->setComputedMaskVolume(volume);
253 void Surface::readSurfaceMeshModule(const ::fwData::Reconstruction::sptr& reconstruction,
254 const ::gdcm::SmartPointer< ::gdcm::Surface >& surface)
257 ::fwData::Material::sptr material = fwData::Material::New();
260 const unsigned short* lab = surface->GetRecommendedDisplayCIELabValue();
261 ::gdcm::SurfaceHelper::ColorArray CIELab(lab, lab +
sizeof(lab) /
sizeof(
unsigned short));
262 std::vector<float> colorVector = ::gdcm::SurfaceHelper::RecommendedDisplayCIELabToRGB(CIELab, 1);
265 colorVector.push_back(surface->GetRecommendedPresentationOpacity());
268 ::fwData::Color::ColorArray rgba;
269 ::boost::algorithm::clamp_range(colorVector.begin(), colorVector.end(), rgba.begin(), 0.f, 1.f);
272 const double epsilon = 1e-3;
273 reconstruction->setIsVisible(rgba[3] > epsilon);
276 ::fwData::Color::sptr color = ::fwData::Color::New();
277 color->setRGBA( rgba );
278 material->setDiffuse(color);
279 OSLM_TRACE(
"RGBA color : " << rgba[0]<<
" "<< rgba[1]<<
" "<< rgba[2]<<
" "<< rgba[3]);
282 const auto representationMode =
284 material->setRepresentationMode(representationMode);
287 if (surface->GetManifold() == ::gdcm::Surface::YES)
289 throw ::fwGdcmIO::exception::Failed(
"Manifold meshes are not supported by the selected reader.");
293 ::gdcm::SmartPointer< ::gdcm::MeshPrimitive > meshPrimitive = surface->GetMeshPrimitive();
294 if (meshPrimitive->GetPrimitiveType() != ::gdcm::MeshPrimitive::TRIANGLE)
296 throw ::fwGdcmIO::exception::Failed(
"The primitive type is not supported by the selected reader.");
300 const ::gdcm::ByteValue* pointCoordinates = surface->GetPointCoordinatesData().GetByteValue();
301 if(!pointCoordinates || !pointCoordinates->GetPointer())
303 throw ::fwGdcmIO::exception::Failed(
"No point coordinates data found.");
307 const auto pointCoordinatesSize = pointCoordinates->GetLength() /
sizeof(float);
308 if((pointCoordinatesSize / 3) != surface->GetNumberOfSurfacePoints())
310 throw ::fwGdcmIO::exception::Failed(
"Point coordinates data are corrupted.");
314 const ::gdcm::ByteValue* normalCoordinates = surface->GetVectorCoordinateData().GetByteValue();
315 const char* normalCoordinatesPointer =
nullptr;
316 if (!surface->GetVectorCoordinateData().IsEmpty())
319 if(!normalCoordinates || !normalCoordinates->GetPointer())
321 throw ::fwGdcmIO::exception::Failed(
"No normal coordinates data found.");
324 normalCoordinatesPointer = normalCoordinates->GetPointer();
327 const unsigned long normalCoordinateSize = normalCoordinates->GetLength() /
sizeof(float);
328 if ((normalCoordinateSize / 3) != surface->GetNumberOfVectors() || normalCoordinateSize != pointCoordinatesSize)
330 throw ::fwGdcmIO::exception::Failed(
"Normal coordinates data are corrupted.");
335 const ::gdcm::ByteValue* pointIndices = meshPrimitive->GetPrimitiveData().GetByteValue();
336 if (!pointIndices || !pointIndices->GetPointer())
338 throw ::fwGdcmIO::exception::Failed(
"No triangle point index list found.");
342 const unsigned long indexSize = pointIndices->GetLength() /
sizeof(uint32_t);
346 pointCoordinatesSize,
347 reinterpret_cast<const uint32_t*>(pointIndices->GetPointer()),
349 reinterpret_cast<const float*>(normalCoordinatesPointer));
352 reconstruction->setMaterial( material );
353 reconstruction->setMesh( surfaceContainer.convertToData() );
This class defines one surface mesh item in order to transform into DICOM/FW4SPL form.
Contains fwAtomsFilter::registry details.
Namespace containing medical data.
#define OSLM_TRACE(message)
The namespace fwGdcmIO contains reader, writer and helper for dicom data.
static FWDATA_API const double s_NO_COMPUTED_MASK_VOLUME
Constant to inform that mask volume has not been computed yet.
FWGDCMIO_API Surface(const std::shared_ptr< const ::fwMedData::DicomSeries > &dicomSeries, const std::shared_ptr< ::gdcm::Reader > &reader, const std::shared_ptr< ::fwGdcmIO::container::DicomInstance > &instance, const ::fwMedData::ModelSeries::sptr &series, const ::fwLog::Logger::sptr &logger=nullptr, ProgressCallback progress=nullptr, CancelRequestedCallback cancel=nullptr)
Constructor.
#define SLM_WARN_IF(message, cond)