Mercurial > hg > orthanc-stl
comparison Sources/Plugin.cpp @ 6:c02d12eb34d4
added LoadNifti()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 18 Jul 2023 14:45:20 +0200 |
parents | 5ee4448a8ff8 |
children | e3e59de705f6 |
comparison
equal
deleted
inserted
replaced
5:1cc024bb662a | 6:c02d12eb34d4 |
---|---|
24 | 24 |
25 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" | 25 #include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" |
26 | 26 |
27 #include <EmbeddedResources.h> | 27 #include <EmbeddedResources.h> |
28 | 28 |
29 #include <Compression/GzipCompressor.h> | |
29 #include <ChunkedBuffer.h> | 30 #include <ChunkedBuffer.h> |
30 #include <DicomParsing/FromDcmtkBridge.h> | 31 #include <DicomParsing/FromDcmtkBridge.h> |
31 #include <DicomParsing/ParsedDicomFile.h> | 32 #include <DicomParsing/ParsedDicomFile.h> |
32 #include <Images/ImageProcessing.h> | 33 #include <Images/ImageProcessing.h> |
33 #include <Logging.h> | 34 #include <Logging.h> |
44 #include <vtkPolyDataNormals.h> | 45 #include <vtkPolyDataNormals.h> |
45 #include <vtkSmoothPolyDataFilter.h> | 46 #include <vtkSmoothPolyDataFilter.h> |
46 #include <vtkTriangle.h> | 47 #include <vtkTriangle.h> |
47 | 48 |
48 #include <boost/thread/shared_mutex.hpp> | 49 #include <boost/thread/shared_mutex.hpp> |
50 | |
51 #include <nifti1_io.h> | |
52 | |
49 | 53 |
50 // Forward declaration | 54 // Forward declaration |
51 void ReadStaticAsset(std::string& target, | 55 void ReadStaticAsset(std::string& target, |
52 const std::string& path); | 56 const std::string& path); |
53 | 57 |
1109 padding->SetOutputNumberOfScalarComponents(1); | 1113 padding->SetOutputNumberOfScalarComponents(1); |
1110 padding->SetOutputWholeExtent(-1, resolution, -1, resolution, -1, resolution); | 1114 padding->SetOutputWholeExtent(-1, resolution, -1, resolution, -1, resolution); |
1111 padding->SetInputData(resize->GetOutput()); | 1115 padding->SetInputData(resize->GetOutput()); |
1112 padding->Update(); | 1116 padding->Update(); |
1113 | 1117 |
1118 double range[2]; | |
1119 padding->GetOutput()->GetScalarRange(range); | |
1120 | |
1121 const double isoValue = (range[0] + range[1]) / 2.0; | |
1122 | |
1114 vtkNew<vtkMarchingCubes> surface; | 1123 vtkNew<vtkMarchingCubes> surface; |
1115 surface->SetInputData(padding->GetOutput()); | 1124 surface->SetInputData(padding->GetOutput()); |
1116 surface->ComputeNormalsOn(); | 1125 surface->ComputeNormalsOn(); |
1117 surface->SetValue(0, 128 /*isoValue*/); | 1126 surface->SetValue(0, isoValue); |
1118 surface->Update(); | 1127 surface->Update(); |
1119 | 1128 |
1120 if (smooth) | 1129 if (smooth) |
1121 { | 1130 { |
1122 vtkNew<vtkSmoothPolyDataFilter> smoothFilter; | 1131 vtkNew<vtkSmoothPolyDataFilter> smoothFilter; |
1395 stl.empty() ? NULL : stl.c_str(), stl.size(), Orthanc::MIME_STL); | 1404 stl.empty() ? NULL : stl.c_str(), stl.size(), Orthanc::MIME_STL); |
1396 } | 1405 } |
1397 } | 1406 } |
1398 | 1407 |
1399 | 1408 |
1409 | |
1410 class NiftiHeader : public boost::noncopyable | |
1411 { | |
1412 private: | |
1413 nifti_image* image_; | |
1414 | |
1415 public: | |
1416 NiftiHeader(const std::string& nifti) | |
1417 { | |
1418 nifti_1_header header; | |
1419 if (nifti.size() < sizeof(header)) | |
1420 { | |
1421 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
1422 } | |
1423 | |
1424 memcpy(&header, nifti.c_str(), sizeof(header)); | |
1425 if (!nifti_hdr_looks_good(&header)) | |
1426 { | |
1427 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
1428 } | |
1429 | |
1430 image_ = nifti_convert_nhdr2nim(header, "dummy_filename"); | |
1431 if (image_ == NULL) | |
1432 { | |
1433 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
1434 } | |
1435 } | |
1436 | |
1437 ~NiftiHeader() | |
1438 { | |
1439 nifti_image_free(image_); | |
1440 } | |
1441 | |
1442 const nifti_image& GetInfo() const | |
1443 { | |
1444 assert(image_ != NULL); | |
1445 return *image_; | |
1446 } | |
1447 }; | |
1448 | |
1449 | |
1450 static void LoadNifti(vtkImageData* volume, | |
1451 std::string& nifti) | |
1452 { | |
1453 if (volume == NULL) | |
1454 { | |
1455 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
1456 } | |
1457 | |
1458 const uint8_t* p = reinterpret_cast<const uint8_t*>(nifti.c_str()); | |
1459 | |
1460 if (nifti.size() >= 2 && | |
1461 p[0] == 0x1f && | |
1462 p[1] == 0x8b) | |
1463 { | |
1464 Orthanc::GzipCompressor compressor; | |
1465 std::string uncompressed; | |
1466 Orthanc::IBufferCompressor::Uncompress(uncompressed, compressor, nifti); | |
1467 nifti.swap(uncompressed); | |
1468 } | |
1469 | |
1470 NiftiHeader header(nifti); | |
1471 | |
1472 if (header.GetInfo().ndim != 3) | |
1473 { | |
1474 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, | |
1475 "Only 3D NIfTI volumes are allowed"); | |
1476 } | |
1477 | |
1478 if (header.GetInfo().datatype != DT_UNSIGNED_CHAR) | |
1479 { | |
1480 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
1481 } | |
1482 | |
1483 assert(static_cast<int>(header.GetInfo().nvox) == header.GetInfo().nx * header.GetInfo().ny * header.GetInfo().nz); | |
1484 | |
1485 const size_t pixelDataOffset = sizeof(nifti_1_header) + 4 /* extension */; | |
1486 | |
1487 if (nifti.size() != pixelDataOffset + header.GetInfo().nvox) | |
1488 { | |
1489 throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile); | |
1490 } | |
1491 | |
1492 volume->SetDimensions(header.GetInfo().nx, header.GetInfo().ny, header.GetInfo().nz); | |
1493 volume->AllocateScalars(VTK_UNSIGNED_CHAR, 1); | |
1494 volume->SetSpacing(header.GetInfo().dx, header.GetInfo().dy, header.GetInfo().dz); | |
1495 memcpy(volume->GetScalarPointer(), &nifti[pixelDataOffset], header.GetInfo().nvox * sizeof(unsigned char)); | |
1496 } | |
1497 | |
1400 extern "C" | 1498 extern "C" |
1401 { | 1499 { |
1402 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | 1500 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) |
1403 { | 1501 { |
1404 OrthancPlugins::SetGlobalContext(context); | 1502 OrthancPlugins::SetGlobalContext(context); |