7 #include "fwGdcmIO/container/DicomSurface.hpp" 8 #include "fwGdcmIO/writer/ie/Surface.hpp" 10 #include "fwGdcmIO/helper/DicomCodedAttribute.hpp" 11 #include "fwGdcmIO/helper/DicomDataTools.hpp" 12 #include "fwGdcmIO/helper/DicomDataWriter.hxx" 14 #include <fwData/Reconstruction.hpp> 16 #include <fwDataIO/reader/DictionaryReader.hpp> 18 #include <fwDataTools/helper/Mesh.hpp> 20 #include <fwMedData/Series.hpp> 21 #include <fwMedData/types.hpp> 23 #include <fwRuntime/operations.hpp> 24 #include <fwRuntime/profile/Profile.hpp> 26 #include <fwTools/dateAndTime.hpp> 28 #include <boost/date_time/posix_time/posix_time.hpp> 30 #include <gdcmSurfaceHelper.h> 31 #include <gdcmSurfaceWriter.h> 32 #include <gdcmUIDGenerator.h> 48 const ::fwMedData::ModelSeries::csptr& series,
49 const ::fwLog::Logger::sptr& logger,
50 ProgressCallback progress,
51 CancelRequestedCallback cancel) :
53 logger, progress, cancel),
54 m_imageInstance(imageInstance)
56 SLM_ASSERT(
"Image instance should not be null.", imageInstance);
77 ::gdcm::DataSet& dataset =
m_writer->GetFile().GetDataSet();
80 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< 0x0008, 0x0016 >(
m_instance->getSOPClassUID(), dataset);
84 ::gdcm::UIDGenerator uidGenerator;
85 std::string sopInstanceUID = uidGenerator.Generate();
86 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< 0x0008, 0x0018 >(sopInstanceUID, dataset);
94 SPTR(::gdcm::SurfaceWriter) surfaceWriter = std::static_pointer_cast< ::gdcm::SurfaceWriter >(
m_writer);
97 ::gdcm::DataSet& dataset =
m_writer->GetFile().GetDataSet();
108 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< int, 0x0020, 0x0013 >(1, dataset);
111 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< 0x0070, 0x0080 >(
"SURFACE", dataset);
114 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< 0x0070, 0x0081 >(
"Surface Segmentation", dataset);
117 ::fwGdcmIO::helper::DicomDataWriter::setEmptyTagValue< 0x0070, 0x0084 >(dataset);
121 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< 0x0008, 0x0023 >(
m_object->getDate(), dataset);
124 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< 0x0008, 0x0033 >(
m_object->getTime(), dataset);
133 auto nbSurfaces =
static_cast<unsigned int>(
m_object->getReconstructionDB().size());
134 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< unsigned int, 0x0066, 0x0001 >(nbSurfaces, dataset);
139 auto segmentSequence = ::fwGdcmIO::helper::DicomDataWriter::createAndSetSequenceTagValue< 0x0062, 0x0002 >(dataset);
142 auto surfaceSequence = ::fwGdcmIO::helper::DicomDataWriter::createAndSetSequenceTagValue< 0x0066, 0x0002 >(dataset);
147 unsigned short segmentNumber = 1;
148 const auto& reconstuctionDB =
m_object->getReconstructionDB();
149 for(
const auto& reconstruction : reconstuctionDB)
152 ::gdcm::SmartPointer< ::gdcm::Segment > segment = new ::gdcm::Segment();
153 surfaceWriter->AddSegment(segment);
156 ::gdcm::Item segmentItem;
157 segmentItem.SetVLToUndefined();
160 segmentSequence->AddItem(segmentItem);
163 ::gdcm::SmartPointer< ::gdcm::Surface > surface = new ::gdcm::Surface();
164 segment->AddSurface(surface);
167 ::gdcm::Item surfaceItem;
168 surfaceItem.SetVLToUndefined();
171 surfaceSequence->AddItem(surfaceItem);
178 m_logger->information(
"Surface '" + reconstruction->getOrganName() +
"' has been exported");
186 void writeSegmentIdentification(
const std::string& structureType,
187 const ::gdcm::SmartPointer< ::gdcm::Segment >& segment,
188 const ::fwGdcmIO::helper::SegmentedPropertyRegistry&
registry,
189 ::fwLog::Logger::sptr logger)
192 if(!registry.hasEntry(structureType))
194 const std::string msg =
"No match in segmented property registry for structure '" + structureType +
"'";
198 logger->warning(msg);
205 const auto entry = registry.getEntry(structureType);
212 const std::string& anatomicRegion = entry[3];
213 if(!anatomicRegion.empty())
215 const auto codedAttributes =
217 if(!codedAttributes.empty())
220 segment->SetAnatomicRegion(codedAttributes[0]);
225 const std::string& anatomicRegionModifier = entry[4];
226 if(!anatomicRegionModifier.empty())
228 const auto codedAttributes =
230 if(!codedAttributes.empty())
233 segment->SetAnatomicRegionModifiers(codedAttributes);
240 const std::string& propertyCategory = entry[1];
241 const auto codedAttributes =
243 if(!codedAttributes.empty())
246 segment->SetPropertyCategory(codedAttributes[0]);
252 const std::string& propertyType = entry[0];
253 const auto codedAttributes =
255 if(!codedAttributes.empty())
258 segment->SetPropertyType(codedAttributes[0]);
265 const std::string& propertyTypeModifier = entry[2];
266 if(!propertyTypeModifier.empty())
268 const auto codedAttributes =
270 if(!codedAttributes.empty())
273 segment->SetPropertyTypeModifiers(codedAttributes);
282 void writePrivateTags(const ::fwData::Reconstruction::csptr& reconstruction,
283 ::gdcm::DataSet& dataset)
286 const auto reservedGroup = 0x5649;
287 const auto reservingElement = 0x0010;
288 const auto privateCreator =
"FW4SPL";
292 ::gdcm::Attribute< reservedGroup, reservingElement, ::gdcm::VR::LO, ::gdcm::VM::VM1 > attribute;
293 attribute.SetValue(privateCreator);
294 dataset.Insert(attribute.GetAsDataElement());
299 const auto structureType = reconstruction->getStructureType();
300 ::gdcm::Attribute< reservedGroup, 0x1000, ::gdcm::VR::LO, ::gdcm::VM::VM1 > attribute;
301 attribute.SetValue(structureType);
302 dataset.Insert(attribute.GetAsDataElement());
306 const double volume = reconstruction->getComputedMaskVolume();
309 ::gdcm::Attribute< reservedGroup, 0x1001, ::gdcm::VR::OD, ::gdcm::VM::VM1 > attribute;
310 attribute.SetValue(volume);
311 dataset.Insert(attribute.GetAsDataElement());
319 ::gdcm::Item& segmentItem,
320 const ::gdcm::SmartPointer< ::gdcm::Segment >& segment,
321 unsigned short segmentNumber)
324 ::gdcm::DataSet& segmentItemDataset = segmentItem.GetNestedDataSet();
331 segment->SetSegmentNumber(segmentNumber);
334 std::string segmentLabel = reconstruction->getOrganName();
335 segment->SetSegmentLabel(segmentLabel.c_str());
338 segment->SetSegmentAlgorithmType(::gdcm::Segment::SEMIAUTOMATIC);
345 const std::string structureType = reconstruction->getStructureType();
350 segment->SetSurfaceCount(1);
353 auto referencedSurfaceSequence =
354 ::fwGdcmIO::helper::DicomDataWriter::createAndSetSequenceTagValue< 0x0066, 0x002B >(segmentItemDataset);
357 ::gdcm::Item refSurfaceSeqItem;
358 refSurfaceSeqItem.SetVLToUndefined();
361 ::gdcm::DataSet& refSurfaceSeqItemDataset = refSurfaceSeqItem.GetNestedDataSet();
364 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< unsigned int, 0x0066, 0x002C >(segmentNumber,
365 refSurfaceSeqItemDataset);
373 auto surfaceSourceInstanceSequence =
374 ::fwGdcmIO::helper::DicomDataWriter::createAndSetSequenceTagValue< 0x0066, 0x002E >(
375 refSurfaceSeqItemDataset);
381 const std::vector< std::string >& referencedSOPInstanceUIDContainer =
383 const std::string& referencedSOPClassUID =
m_imageInstance->getSOPClassUID();
388 for(
const std::string& sopInstanceUID : referencedSOPInstanceUIDContainer)
391 ::gdcm::Item imageSOPItem;
392 imageSOPItem.SetVLToUndefined();
393 ::gdcm::DataSet& imageSOPDataset = imageSOPItem.GetNestedDataSet();
396 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< 0x0008, 0x1150 >(referencedSOPClassUID,
400 ::fwGdcmIO::helper::DicomDataWriter::setTagValue< 0x0008, 0x1155 >(sopInstanceUID,
403 surfaceSourceInstanceSequence->AddItem(imageSOPItem);
406 if(
m_logger && referencedSOPInstanceUIDContainer.empty())
408 m_logger->warning(
"No DICOM instances have been added as 'Referenced SOP Instance UID'");
412 referencedSurfaceSequence->AddItem(refSurfaceSeqItem);
415 writePrivateTags(reconstruction, segmentItemDataset);
422 ::gdcm::Item& surfaceItem,
423 const ::gdcm::SmartPointer< ::gdcm::Surface >& surface,
424 unsigned short segmentNumber)
427 ::gdcm::DataSet& surfaceItemDataset = surfaceItem.GetNestedDataSet();
430 ::fwData::Material::csptr material = reconstruction->getMaterial();
436 surface->SetSurfaceNumber(segmentNumber);
439 surface->SetSurfaceProcessing(
false);
442 const auto rgba = material->diffuse()->getRGBA();
443 std::vector< float > rgb { rgba[0], rgba[1], rgba[2] };
446 const auto grayscale = ::gdcm::SurfaceHelper::RGBToRecommendedDisplayGrayscale(rgb, 1.);
447 surface->SetRecommendedDisplayGrayscaleValue(grayscale);
450 const auto CIELab = ::gdcm::SurfaceHelper::RGBToRecommendedDisplayCIELab(rgb, 1.);
451 surface->SetRecommendedDisplayCIELabValue(CIELab);
454 surface->SetRecommendedPresentationOpacity(rgba[3]);
457 surface->SetRecommendedPresentationType(
462 surface->SetFiniteVolume(helperMesh.isClosed() ? (::gdcm::Surface::YES): (::gdcm::Surface::NO));
465 surface->SetManifold(::gdcm::Surface::NO);
468 auto pointsSequence =
469 ::fwGdcmIO::helper::DicomDataWriter::createAndSetSequenceTagValue< 0x0066, 0x0011 >(surfaceItemDataset);
472 ::gdcm::Item pointsItem;
473 pointsItem.SetVLToUndefined();
483 ::gdcm::DataElement& pointCoordData = surface->GetPointCoordinatesData();
484 pointCoordData.SetByteValue(reinterpret_cast<const char*>(surfaceContainer.
getPointBuffer().data()),
486 static_cast<uint32_t>(
sizeof(
float)));
488 pointsSequence->AddItem(pointsItem);
491 auto normalsSequence =
492 ::fwGdcmIO::helper::DicomDataWriter::createAndSetSequenceTagValue< 0x0066, 0x0012 >(surfaceItemDataset);
500 ::gdcm::Item normalsItem;
501 normalsItem.SetVLToUndefined();
507 surface->SetVectorDimensionality(1);
510 ::gdcm::DataElement& normalCoordData = surface->GetVectorCoordinateData();
511 normalCoordData.SetByteValue(reinterpret_cast<const char*>(surfaceContainer.
getNormalBuffer().data()),
513 static_cast<uint32_t>(
sizeof(
float)));
515 normalsSequence->AddItem(normalsItem);
519 auto primitivesSequence =
520 ::fwGdcmIO::helper::DicomDataWriter::createAndSetSequenceTagValue< 0x0066, 0x0013 >(surfaceItemDataset);
527 ::gdcm::SmartPointer< ::gdcm::MeshPrimitive > primitive = surface->GetMeshPrimitive();
528 primitive->SetPrimitiveType(::gdcm::MeshPrimitive::TRIANGLE);
531 ::gdcm::DataElement& pointIndexData = primitive->GetPrimitiveData();
532 pointIndexData.SetVL(
sizeof(uint32_t));
533 pointIndexData.SetByteValue(reinterpret_cast<const char*>(surfaceContainer.
getCellBuffer().data()),
535 static_cast<uint32_t>(
sizeof(uint32_t)));
543 surface->SetAlgorithmFamily(::gdcm::SegmentHelper::BasicCodedEntry(
"123109",
"DCM",
"Manual Processing"));
546 surface->SetAlgorithmName(
"FW4SPL");
549 surface->SetAlgorithmVersion(
"1");
This class defines one surface mesh item in order to transform into DICOM/FW4SPL form.
Contains fwAtomsFilter::registry details.
virtual FWGDCMIO_API void writeSurfaceSegmentationAndSurfaceMeshModules()
Write Surface Segmentation Module tags.
Namespace containing medical data.
FWGDCMIO_API std::size_t getCellBufferSize() const
Return cell buffer size.
This class defines a DICOM SOP instance. It is useful during the whole writing process. This class allows to share data between module writers.
The namespace fwGdcmIO contains reader, writer and helper for dicom data.
FWGDCMIO_API const DicomNormalBufferType & getNormalBuffer() const
Return normal buffer.
FWGDCMIO_API const DicomCellBufferType & getCellBuffer() const
Return cell buffer.
virtual FWGDCMIO_API ~Surface()
Destructor.
virtual FWGDCMIO_API void writeSOPCommonModule()
Write SOP Common Module tags.
FWGDCMIO_API const DicomPointBufferType & getPointBuffer() const
Return point coordinates buffer.
virtual FWGDCMIO_API void writeSegmentSequence(const std::shared_ptr< const ::fwData::Reconstruction > &reconstruction,::gdcm::Item &segmentItem, const ::gdcm::SmartPointer< ::gdcm::Segment > &segment, unsigned short segmentNumber)
Write Segment Item into Segment Sequence.
static FWGDCMIO_API::gdcm::Segment::BasicCodedEntryVector convertEntryToGDCMCodedAttribute(const std::string &entry)
Convert an entry of the form '(AAA;BBB;CCC)' into GDCM's BasicCodedEntryVector. Several DicomCodedAtt...
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
std::shared_ptr< ::fwGdcmIO::container::DicomInstance > m_imageInstance
DICOM Image Instance.
#define SLM_TRACE(message)
virtual FWGDCMIO_API void writeSurfaceSequence(const std::shared_ptr< const ::fwData::Reconstruction > &reconstruction,::gdcm::Item &surfaceItem, const ::gdcm::SmartPointer< ::gdcm::Surface > &surface, unsigned short segmentNumber)
Write Surface Item into Surface Sequence.
FWGDCMIO_API bool readSegmentedPropertyRegistryFile(const ::boost::filesystem::path &filepath, bool omitFirstLine=false, const std::shared_ptr< ::fwLog::Logger > &logger=0)
Read an extract registry values from a CSV file Each lines shall contain at least 6 elements : ...
::fwGdcmIO::helper::SegmentedPropertyRegistry m_segmentedPropertyRegistry
Structure Dictionary.
FWGDCMIO_API std::size_t getNormalBufferSize() const
Return normal buffer size.
FWGDCMIO_API Surface(const std::shared_ptr< ::gdcm::Writer > &writer, const std::shared_ptr< ::fwGdcmIO::container::DicomInstance > &instance, const std::shared_ptr< ::fwGdcmIO::container::DicomInstance > &imageInstance, const ::fwMedData::ModelSeries::csptr &series, const ::fwLog::Logger::sptr &logger=nullptr, ProgressCallback progress=nullptr, CancelRequestedCallback cancel=nullptr)
Constructor.
FWGDCMIO_API std::size_t getPointBufferSize() const
Return point coordinates buffer size.
FWGDCMIO_API bool loadSegmentedPropertyRegistry(const ::boost::filesystem::path &filepath)
Load Segmented Property Registry.
#define SLM_WARN_IF(message, cond)