Mercurial > hg > orthanc-stl
comparison Sources/Plugin.cpp @ 8:d1267c6c33e1
added route /stl/encode-nifti
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 18 Jul 2023 15:58:21 +0200 |
parents | e3e59de705f6 |
children | dd0cd39e6259 |
comparison
equal
deleted
inserted
replaced
7:e3e59de705f6 | 8:d1267c6c33e1 |
---|---|
1013 | 1013 |
1014 buffer.Flatten(target); | 1014 buffer.Flatten(target); |
1015 } | 1015 } |
1016 | 1016 |
1017 | 1017 |
1018 bool EncodeStructureSetMesh(std::string& stl, | 1018 bool EncodeVolume(std::string& stl, |
1019 vtkImageData* volume, | 1019 vtkImageData* volume, |
1020 unsigned int resolution, | 1020 unsigned int resolution, |
1021 bool smooth) | 1021 bool smooth) |
1022 { | 1022 { |
1023 if (volume == NULL) | 1023 if (volume == NULL) |
1024 { | 1024 { |
1025 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 1025 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
1026 } | 1026 } |
1163 (structureSet.GetMaxProjectionAlongNormal() - structureSet.GetMinProjectionAlongNormal()) / static_cast<double>(depth)); | 1163 (structureSet.GetMaxProjectionAlongNormal() - structureSet.GetMinProjectionAlongNormal()) / static_cast<double>(depth)); |
1164 | 1164 |
1165 // TODO | 1165 // TODO |
1166 // volume->SetOrigin() | 1166 // volume->SetOrigin() |
1167 | 1167 |
1168 return EncodeStructureSetMesh(stl, volume.Get(), resolution, smooth); | 1168 return EncodeVolume(stl, volume.Get(), resolution, smooth); |
1169 } | 1169 } |
1170 | 1170 |
1171 | 1171 |
1172 static Orthanc::ParsedDicomFile* LoadInstance(const std::string& instanceId) | 1172 static Orthanc::ParsedDicomFile* LoadInstance(const std::string& instanceId) |
1173 { | 1173 { |
1348 StructureSet structureSet(*dicom); | 1348 StructureSet structureSet(*dicom); |
1349 | 1349 |
1350 std::string stl; | 1350 std::string stl; |
1351 if (!EncodeStructureSetMesh(stl, structureSet, roiNames, resolution, smooth)) | 1351 if (!EncodeStructureSetMesh(stl, structureSet, roiNames, resolution, smooth)) |
1352 { | 1352 { |
1353 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot encode STL"); | 1353 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot encode STL from RT-STRUCT"); |
1354 } | 1354 } |
1355 else | 1355 else |
1356 { | 1356 { |
1357 std::string seriesDescription; | 1357 std::string seriesDescription; |
1358 | 1358 |
1497 { | 1497 { |
1498 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, | 1498 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, |
1499 "Only 3D NIfTI volumes are allowed"); | 1499 "Only 3D NIfTI volumes are allowed"); |
1500 } | 1500 } |
1501 | 1501 |
1502 if (header.GetInfo().datatype != DT_UNSIGNED_CHAR) | 1502 size_t itemSize; |
1503 { | 1503 int vtkType; |
1504 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 1504 |
1505 switch (header.GetInfo().datatype) | |
1506 { | |
1507 case DT_UNSIGNED_CHAR: | |
1508 itemSize = 1; | |
1509 vtkType = VTK_UNSIGNED_CHAR; | |
1510 break; | |
1511 | |
1512 case DT_FLOAT: | |
1513 itemSize = sizeof(float); | |
1514 vtkType = VTK_FLOAT; | |
1515 break; | |
1516 | |
1517 case DT_DOUBLE: | |
1518 itemSize = sizeof(double); | |
1519 vtkType = VTK_DOUBLE; | |
1520 break; | |
1521 | |
1522 default: | |
1523 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
1505 } | 1524 } |
1506 | 1525 |
1507 assert(static_cast<int>(header.GetInfo().nvox) == header.GetInfo().nx * header.GetInfo().ny * header.GetInfo().nz); | 1526 assert(static_cast<int>(header.GetInfo().nvox) == header.GetInfo().nx * header.GetInfo().ny * header.GetInfo().nz); |
1508 | 1527 |
1509 const size_t pixelDataOffset = sizeof(nifti_1_header) + 4 /* extension */; | 1528 const size_t pixelDataOffset = sizeof(nifti_1_header) + 4 /* extension */; |
1510 | 1529 |
1511 if (nifti.size() != pixelDataOffset + header.GetInfo().nvox) | 1530 if (nifti.size() != pixelDataOffset + header.GetInfo().nvox * itemSize) |
1512 { | 1531 { |
1513 throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile); | 1532 throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile); |
1514 } | 1533 } |
1515 | 1534 |
1516 volume->SetDimensions(header.GetInfo().nx, header.GetInfo().ny, header.GetInfo().nz); | 1535 volume->SetDimensions(header.GetInfo().nx, header.GetInfo().ny, header.GetInfo().nz); |
1517 volume->AllocateScalars(VTK_UNSIGNED_CHAR, 1); | 1536 volume->AllocateScalars(vtkType, 1); |
1518 volume->SetSpacing(header.GetInfo().dx, header.GetInfo().dy, header.GetInfo().dz); | 1537 volume->SetSpacing(header.GetInfo().dx, header.GetInfo().dy, header.GetInfo().dz); |
1519 memcpy(volume->GetScalarPointer(), &nifti[pixelDataOffset], header.GetInfo().nvox * sizeof(unsigned char)); | 1538 memcpy(volume->GetScalarPointer(), &nifti[pixelDataOffset], header.GetInfo().nvox * itemSize); |
1520 } | 1539 } |
1540 | |
1541 | |
1542 void EncodeNifti(OrthancPluginRestOutput* output, | |
1543 const char* url, | |
1544 const OrthancPluginHttpRequest* request) | |
1545 { | |
1546 static const char* const KEY_NIFTI = "Nifti"; | |
1547 static const char* const KEY_RESOLUTION = "Resolution"; | |
1548 static const char* const KEY_PARENT_STUDY = "ParentStudy"; | |
1549 static const char* const KEY_SMOOTH = "Smooth"; | |
1550 | |
1551 if (request->method != OrthancPluginHttpMethod_Post) | |
1552 { | |
1553 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "POST"); | |
1554 return; | |
1555 } | |
1556 | |
1557 Json::Value body; | |
1558 if (!Orthanc::Toolbox::ReadJson(body, request->body, request->bodySize)) | |
1559 { | |
1560 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest); | |
1561 } | |
1562 | |
1563 std::string mime, nifti; | |
1564 if (!Orthanc::Toolbox::DecodeDataUriScheme(mime, nifti, Orthanc::SerializationToolbox::ReadString(body, KEY_NIFTI))) | |
1565 { | |
1566 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest, "Missing the \"Nifti\" argument containing the NIfTI file"); | |
1567 } | |
1568 | |
1569 const std::string parentStudy = Orthanc::SerializationToolbox::ReadString(body, KEY_PARENT_STUDY); | |
1570 const bool smooth = (body.isMember(KEY_SMOOTH) ? | |
1571 Orthanc::SerializationToolbox::ReadBoolean(body, KEY_SMOOTH) : | |
1572 true /* smooth by default */); | |
1573 const unsigned int resolution = (body.isMember(KEY_RESOLUTION) ? | |
1574 Orthanc::SerializationToolbox::ReadUnsignedInteger(body, KEY_RESOLUTION) : | |
1575 256 /* default value */); | |
1576 | |
1577 vtkNew<vtkImageData> volume; | |
1578 LoadNifti(volume.Get(), nifti); | |
1579 | |
1580 std::string stl; | |
1581 if (!EncodeVolume(stl, volume.Get(), resolution, smooth)) | |
1582 { | |
1583 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot encode STL from NIfTI"); | |
1584 } | |
1585 else | |
1586 { | |
1587 const std::string title = "STL model generated from NIfTI"; | |
1588 | |
1589 const std::string frameOfReferenceUid = Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Instance); | |
1590 | |
1591 Json::Value answer; | |
1592 CallCreateDicom(answer, stl, body, parentStudy, title, frameOfReferenceUid, title); | |
1593 | |
1594 std::string s = answer.toStyledString(); | |
1595 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), Orthanc::MIME_JSON); | |
1596 } | |
1597 } | |
1598 | |
1521 | 1599 |
1522 extern "C" | 1600 extern "C" |
1523 { | 1601 { |
1524 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | 1602 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) |
1525 { | 1603 { |
1560 OrthancPlugins::RegisterRestCallback<ExtractStl>("/instances/([0-9a-f-]+)/stl", true); | 1638 OrthancPlugins::RegisterRestCallback<ExtractStl>("/instances/([0-9a-f-]+)/stl", true); |
1561 OrthancPlugins::RegisterRestCallback<ListStructures>("/stl/rt-struct/([0-9a-f-]+)", true); | 1639 OrthancPlugins::RegisterRestCallback<ListStructures>("/stl/rt-struct/([0-9a-f-]+)", true); |
1562 | 1640 |
1563 if (hasCreateDicomStl_) | 1641 if (hasCreateDicomStl_) |
1564 { | 1642 { |
1565 OrthancPlugins::RegisterRestCallback<EncodeStructureSet>("/stl/encode", true); | 1643 OrthancPlugins::RegisterRestCallback<EncodeStructureSet>("/stl/encode-rtstruct", true); |
1644 OrthancPlugins::RegisterRestCallback<EncodeNifti>("/stl/encode-nifti", true); | |
1566 } | 1645 } |
1567 | 1646 |
1568 // Extend the default Orthanc Explorer with custom JavaScript for STL | 1647 // Extend the default Orthanc Explorer with custom JavaScript for STL |
1569 std::string explorer; | 1648 std::string explorer; |
1570 | 1649 |