Skip to content
Snippets Groups Projects

ENH: first working version of slicerSMTK plugin (export only)

Closed Shreeraj Jadhav requested to merge feat-create-minimum-viable-plugin into master

This MR is for merging with master the branch containing the first version of a working slicerSMTK plugin. Currently it provides functionality for exporting MRML scene to the smtk (json) file format used by aevaCMB and aeva-session. The exported file is saved with extension .aeva.smtk which can then be loaded into aevaCMB application.

Features included:

  1. Export surface models as vtkPolyData (.vtp)
  2. Export solid models as vtkUnstructuredGrid (.vtu)
  3. Export Images/Volumes as vtkImageData (.vti)
  4. Export scene as smtk json format (.aeva.smtk)
  5. Individual component files (vtp, vtu, vti) are saved under a subfolder with the same name as the parent filename.
  6. Components undergo transformation hardening before saving, thereby carrying forward any registrations/transformations applied within Slicer.
  7. File names of component files are made more readable by using the user-specified MRML node name as a prefix to the file followed by the respective uuid. The prefix undergoes string sanitization to ensure that it is compatible as a file name.

Merge request reports

Approval is optional

Closed by Jean-Christophe Fillion-RobinJean-Christophe Fillion-Robin 3 years ago (Mar 3, 2022 6:49pm UTC)

Merge details

  • The changes were not merged into master.

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
481 using smtk::session::aeva::Write;
482 auto writeOp = smtk::session::aeva::Write::create();
483 writeOp->parameters()->associate(resource);
484 writeOp->parameters()->findVoid("copy all data with resource")->setIsEnabled(false);
485 auto voidItem = writeOp->parameters()->findVoid("copy all data with resource");
486 if (voidItem)
487 {
488 voidItem->setIsEnabled(false);
489 }
490 else
491 {
492 qWarning() << "Unable to switch-off \"copy all data with resource\" flag.";
493 }
494
495 Write::Result result = writeOp->operate();
496 bool outcome = result->findInt("outcome")->value() == static_cast<int>(Write::Outcome::SUCCEEDED);
  • 487 {
    488 voidItem->setIsEnabled(false);
    489 }
    490 else
    491 {
    492 qWarning() << "Unable to switch-off \"copy all data with resource\" flag.";
    493 }
    494
    495 Write::Result result = writeOp->operate();
    496 bool outcome = result->findInt("outcome")->value() == static_cast<int>(Write::Outcome::SUCCEEDED);
    497
    498 // Forward smtk log records to Slicer's error log.
    499 auto logger = writeOp->log();
    500 qInfo() << logger.convertToString().data();
    501
    409 502 if (outcome)
  • 490 else
    491 {
    492 qWarning() << "Unable to switch-off \"copy all data with resource\" flag.";
    493 }
    494
    495 Write::Result result = writeOp->operate();
    496 bool outcome = result->findInt("outcome")->value() == static_cast<int>(Write::Outcome::SUCCEEDED);
    497
    498 // Forward smtk log records to Slicer's error log.
    499 auto logger = writeOp->log();
    500 qInfo() << logger.convertToString().data();
    501
    409 502 if (outcome)
    410 503 {
    411 qInfo() << "SMTK export successful";
    504 qInfo() << "SMTK export successful.";
    • Additional suggestions:

      • Introduce a function called exportMRMLSceneToAevaSMTKResources(vtkMRMLScene* scene, const std::string& smtkFileName, const std::string& smtkExportDir) that would be called by writeToSMTK.

        • Internally smtkFilePath would be set doing smtkExportDir + "/" + smtkFileName
        • Consider moving exportMRMLSceneToSMTKResources (and associated functions) into vtkSlicerSMTKFileWriterLogic) currently the only reason it depends on qSlicerBaseQTCore it because of use of qSlicerCoreIOManager::forceFileNameValidCharacters
      • Change importSeparatedSegmentations to exportSegmentationNodeToAevaSMTKResource(vtkMRMLSegmentationNode* segmentationNode, const smtk::session::aeva::Resource::Ptr& resource, const std::string& smtkExportDir)

      • Change importVTKImage to exportVolumeNodeToAevaSMTKResource(vtkMRMLVolumeNode* volumeNode, const smtk::session::aeva::Resource::Ptr& resource, const std::string& smtkExportDir)

      • Change addImageToResource to addVTKImageDataToAevaSMTKModelResource(vtkSmartPointer<vtkImageData> imageData, const smtk::session::aeva::Resource::Ptr& resource, const std::string& modelName, const std::string& smtkExportDir)

      • Change importVTKMesh to exportModelNodeToAevaSMTKResource(vtkMRMLModelNode* modelNode, const smtk::session::aeva::Resource::Ptr& resource, const std::string& smtkExportDir)

      • Change setFileNameProperty to setSMTKCellFilenameProperty

      • Remove unused vtkSlicerSMTKFileWriterLogic::LoadSMTKFile()

      Edited by Jean-Christophe Fillion-Robin
      • Rename writeToSMTK to writeToAevaSMTK

      • Instead of exporting to a file with only .smtk, I suggest to export as .aeva.smtk. That way it would be clear that this SMTK file requires the aeva-session plugin to be interpreted. @dcthomp What do you think ?

      • Add minimal docstrings to functions

      • Remove unused function like importMergedSegmentation

    • Considering that segmentation, volume and model nodes can all be part of a transform hierarchy, and assuming that:

      • aeva smtk doesn't have a concept of transform hierarchy
      • relative location of "object" is important

      the corresponding nodes should be first exported to a internal scene and the corresponding transform hardened.

      The good news is that the underlying logic (hardening) has been implemented by Ebrahim while adding the node export functionality (see https://github.com/Slicer/Slicer/pull/5876 and https://discourse.slicer.org/t/new-export-functionality/20950.

      Code available in https://github.com/Slicer/Slicer/blob/3de75b9c4c6f3ee9a1e5da17059b9f11517e16ab/Base/QTCore/qSlicerCoreIOManager.cxx#L785 should be factored out to be reusable.

      cc: @dcthomp @shreeraj.jadhav

    • .aeva.stmk

      aeva-session's write operator actually uses SMTK's functionality to write the json as .smtk. So I think the file should be readable independent of aeva-session too? Nonetheless, making changes will also be needed on aevaCMB side to use .aeva.smtk extension.

      transform hardening

      Retaining transformations is definitely needed, and as I understand smtk supports a transform property, so we may not need to apply the transform directly to the dataset geometry. There may be many other attributes we want to include in future iterations. We will also have to consider loading data back-and-forth between aevaSlicer and aevaCMB. Since this would need some work, I suggest we do this in future releases.

    • SMTK will (but does not currently) support storing transforms as property-data on components. The change required is small and will definitely be part of the next milestone as part of the annotation transfer work (smtk::extension::vtk::Geometry will need to check for the property on each component and apply it to the VTK data it produces).

      I'm not sure about hierarchical transforms. We would need to agree on how the hierarchy is represented in SMTK. I can certainly see checking whether a volume/face/edge/vertex cell's owning model has a transform, but what other cases are there that we need to handle?

    • We can revisit the hierarchical transforms issue in future milestones. it is not a high priority for aevaSlicer 2.4 release

    • For now, I suggest we harden the transform. If not, the exported models will likely have incorrect position relative to each other.

    • All review comments (@jcfr) addressed in the following commits:
      896c4b49 and 0a485a31

      Output extension changed from .smtk to .aeva.smtk, and added documentation comments to functions in the Logic class:
      f6204557

      Transform hardening implemented through the following commits:
      SlicerSMTK: 4b0d142d
      KitwareMedical/Slicer refactor: https://github.com/KitwareMedical/Slicer/commit/0eaf803012bbecdb7735a9c4b4b934754fe3c148

    • Please register or sign in to reply
  • @dcthomp @sjh26 Please review. Its a lot of commits, but previous master was mostly just a skeleton.

  • David Thompson
  • Jean-Christophe Fillion-Robin
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Please register or sign in to reply
    Loading