Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Roi from model bounds #152

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

amymmorton
Copy link
Contributor

@amymmorton amymmorton commented Dec 11, 2024

A start to the subvolume 3d registration testing, implements the roi generation from model bounds

TO DO:
iterate on all Models | load from file

image

@amymmorton amymmorton requested a review from sbelsk December 11, 2024 21:43
@amymmorton
Copy link
Contributor Author

@sbelsk You can take this and help iterate on it or make another from scratch

TO DO:

  • load stl from file- iterate for all Model nodes
  • use CropVolume
   /// Perform non-interpolated (voxel-based) cropping.
   /// If limitToInputExtent is set to true (default) then the extent can only be smaller than the input volume.
   static int CropVoxelBased(vtkMRMLDisplayableNode* roi, vtkMRMLVolumeNode* inputVolume,
      vtkMRMLVolumeNode* outputNode, bool limitToInputExtent=true, double fillValue=0.0); 

and the generated roi to generate subvolumes

@jcfr
Copy link
Contributor

jcfr commented Dec 11, 2024

Thanks @amymmorton for creating this PR along side issue #151 describing the overall workflow and providing reference to datasets 🙏

@amymmorton
Copy link
Contributor Author

@sbelsk can you help me fix my failing precommit, Commit messages please? :(

@jcfr
Copy link
Contributor

jcfr commented Dec 12, 2024

pre-commit check

The pre-commit failures have been addressed.

commit message check

The commit message check is failing because some commits start with WIP: prefix, this is described here

Addressing this could be done by using git rebase --interactive 06acebe and then editing the "faulty" commit messages. For example WIP: Initial Extension Setup -> ENH: Initial Extension Setup

amymmorton and others added 10 commits December 12, 2024 15:36
From Extension wizard
Currently  broken ui elements module
Tutorial mcode diff example
Content stl file read
Remove mcode examples
TO DO: assign to roi
TO DO: Use model bounds and input Volume to generate subvolume
Loads Models form folder and iteratively generates each roi
Since the base class associated with scripted module class `ScriptedLoadableModuleTest`
is `unittest.TestCase`, using function like assertEqual is legitimate and
should not be replaced with `assert`.

References:
* https://docs.python.org/3/library/unittest.html#unittest.TestCase
* https://docs.astral.sh/ruff/rules/#flake8-pytest-style-pt
* Remove end of line spaces
* Reorder imports
* Prefer explicit imports instead of "*"
* Add missing spaces
* Add ARG002 linting exceptions for unused "modelBounds" parameters

Most of the fixes where either automatically fixed or identified
running `pre-commit run -a`.
Cleanup commented out irrelevant lines and migrate functionality into logic class
@jcfr
Copy link
Contributor

jcfr commented Dec 16, 2024

To address the commit message failure, the following commit title would have to be updated:

-ENH:: Crop Volumes generated from roi
+ENH: Crop Volumes generated from roi

amymmorton and others added 2 commits December 16, 2024 10:29
Comment on lines 308 to 341
def modelBounds(self, inputModel):

inputModel: vtkMRMLModelNode

tB = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
inputModel.GetBounds(tB)
# print(tB)
# modelC = [0.0]*3
# modelSize = [0.0]*3
# strange that the model nodes have a getBounds- but no center and size..
# and the roi has bno.. set Bounds- just center and size

# numpy for array operatots:
tnp_min = np.array([tB[0], tB[2], tB[4]])
tnp_max = np.array([tB[1], tB[3], tB[5]])

tnp_C = (tnp_min + tnp_max) / 2
tnpS = tnp_min - tnp_max

# inputModel.GetCenter(modelC)
# inputModel.GetSize(modelSize)
mname = inputModel.GetName()

# use tB lims to size roi
# Create ROI node
modelROI = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsROINode")
modelROI.SetCenter(tnp_C.tolist())
modelROI.SetSize(tnpS.tolist())
modelROI.CreateDefaultDisplayNodes() # only needed for display

roi_name = mname + "_roi"
modelROI.SetName(roi_name)

return modelROI
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def modelBounds(self, inputModel):
inputModel: vtkMRMLModelNode
tB = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
inputModel.GetBounds(tB)
# print(tB)
# modelC = [0.0]*3
# modelSize = [0.0]*3
# strange that the model nodes have a getBounds- but no center and size..
# and the roi has bno.. set Bounds- just center and size
# numpy for array operatots:
tnp_min = np.array([tB[0], tB[2], tB[4]])
tnp_max = np.array([tB[1], tB[3], tB[5]])
tnp_C = (tnp_min + tnp_max) / 2
tnpS = tnp_min - tnp_max
# inputModel.GetCenter(modelC)
# inputModel.GetSize(modelSize)
mname = inputModel.GetName()
# use tB lims to size roi
# Create ROI node
modelROI = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsROINode")
modelROI.SetCenter(tnp_C.tolist())
modelROI.SetSize(tnpS.tolist())
modelROI.CreateDefaultDisplayNodes() # only needed for display
roi_name = mname + "_roi"
modelROI.SetName(roi_name)
return modelROI
def createROINodeFromModel(self, inputModel: vtkMRMLModelNode):
"""
Create an ROI node from a given model node by computing its axis-aligned bounding box.
:param inputModel: Model node from which to derive the ROI
:return: ROI node enclosing the input model
"""
# Retrieve the bounding box of the model: [xmin, xmax, ymin, ymax, zmin, zmax]
modelBounds = [0.0] * 6
inputModel.GetBounds(modelBounds)
# Convert the bounding values into min/max coordinate arrays
modelMin = np.array([modelBounds[0], modelBounds[2], modelBounds[4]])
modelMax = np.array([modelBounds[1], modelBounds[3], modelBounds[5]])
# Compute the center and size of the bounding box
modelCenter = (modelMin + modelMax) / 2.0
modelSize = modelMax - modelMin
# Create a new ROI node centered on the model
roiNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsROINode")
roiNode.SetName(f"{inputModel.GetName()}_roi")
roiNode.SetCenter(modelCenter.tolist())
roiNode.SetSize(modelSize.tolist())
roiNode.CreateDefaultDisplayNodes() # Only needed for display
return roiNode

Prospective ui elements for transforms and target volume, but functionality not yet implemented
@amymmorton
Copy link
Contributor Author

amymmorton commented Dec 30, 2024

Current functionality:

image

  • stl loaded from folder
  • roi generated for each model and cropped volume extracted from roi of input volume

TO DO:

  • generate 3d interactive transform for "parent" model - prompt for user alignment
  • apply transform to roi - extract subvolume 'target' volume
  • use elastix to register
  • apply output elastik tform to model (and child model)

Separated model load from file and roi from crop volume and tform generation actions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants