Getting Started with Fitting
==Example for NBCR Summer Institute, 8/3/10==
- In the following example, we will fit a biventricular rabbit heart to data from MRI. This is done in two main steps: first, we will make use of a tool that automatically generates the topology of a biventricular mesh using salient anatomic landmarks, such as the apex of the heart. What we mean by "topology" is that we want an object that captures the essential morphological structural features of rabbit ventricles. To put it simply, we want a reasonable "starting point" after which we can "fine-tune" our mesh in a fit.
- Once we have a reasonable "starting mesh", we want to do a fit to that mesh to capture some of the finer features and curvature in the mesh. To capture finer and finer surface features in our mesh, we would need to "subdivide" our initial mesh into more and more elements. After we have a mesh of the desired "refinement", we will fit to the edges of cardiac surfaces to get a final anatomic mesh.
Using the Landmarks Tool
- By specifying major anatomic landmarks in the two ventricles, we can generate an "initial mesh" that captures the essential features of our mesh. A detailed description of the process appears here:
Download the stack of MRI images here and unzip it to a new folder
- Open Continuity 6.4 and load "mesh" and "fitting" modules
In the menu, go to "Fitting" --> "Edit" ---> "Images"
In the Edit Images window, go to "File" --> "Open Stack", and select the unzipped folder and open it.
- You can use the slide bar in the bottom half of the screen to scroll through the different slices of MRI data.
There is nothing to stop you from defining your own set of landmarks with a basic knowledge of cardiac anatomy (and knowledge of the orientation of the stack of images), but we provide you with a file specifying the landmarks here.
Go to "Landmarks" tab --> "Load Landmarks"
- Find the Rabbit Landmarks text file and open it.. you should be able to see yellow dots representing landmarks throughout the stack
Go to "Transformation" tab --> specify scales: x = 0.14, y = 0.14, z = 1 (scaling in mm/voxel, i.e. multiply for pixel to mm)
- Press enter in each column to confirm the scaling
- Go back to the "Landmarks" tab and click "Transform Landmarks"
- Go to the "Calculate" tab and under the Calculate heading, click "Landmarks"
Still in the "Calculate" tab, under the "Results" heading, pick "Send to mesh", and then above that click "Calculate"
Go to Mesh --> Edit --> Basis and add "3D Lagrange Linear-Linear-Linear". Ignore the warning that pops up.
- Click "Add Linear-Linear-Linear" and then click "OK"
Go to Mesh --> Edit --> Nodes and under each Coordinate (1, 2, and 3) change the pulldown menu where it says "Select Basis Number" to "Linear-Linear-Linear Lagrange 3*3*3", then click OK
- Click "Send" and then "Calculate Mesh"
- Render the Nodes, Lines, and Elements. You may want to render the elements at xi3 = 0 and xi3 = 1.
The final model is here
Image segmentation and Edge Detection
- The initial mesh, of course, is not perfect. For example, one can visibly see that the right ventricle is too small. Fortunately, this is not of grave importance, because it can be corrected in our subsequent fit. To complete our fit, we will need to "tag" the pixels in the image stack as belonging to a certain part of the heart (for example, a pixel belongs to left vs. right ventricular wall).
- Continuity has a built-in tool for segmenting images, but you can also use a different segmentation tool of your choice to complete segmentation and edge detection and import the results
We did the segmentation for you. We have a spreadsheet full of all of the edges of the left ventricle endocardium, septum, epicardium, and right ventricular free wall here.
Fitting the Mesh
As discussed earlier today, an essential first operation of fitting is that data points are projected onto surfaces. The mesh generated had 3D elements, but data points can only sensibly be projected onto a surface. We created a new list of nodes and elements here for you to use. If you check an excel file describing the files, all we did in the elements form is decimate the 3d elements into 2D elements, and added "Labels" for each of the elements, as to group them for the fit.
- Load the datapoints file discussed above
Go to "Mesh" --> "Edit" --> "Coordinate System" and pick Prolate Spheroidal with f = 7, as found before
Select "Mesh" --> "Edit" --> "Basis Functions" and add 2D Hermite Cubic-Cubic and 2D Lagrange Linear-Linear
- Load the Nodes and Elements as discussed previously, but in the "Nodes" form, change the data type to RADIANS.
Go to "Mesh" --> "Refine" and do a Refine. Set all of the values in "xi" to be 1, and select "preserve nodal numbers"
Go to "Mesh" --> "Edit" --> "Nodes" and change the basis function to "Hermite Cubic-Cubic"
A final cont6 file that has the datapoints, nodes, and elements can be found here
- The main steps that we will undertake: observe our initial mesh and our data, specify fit weights, specify fit constraints, and fit
Visualize the mesh's nodes and elements: "Mesh" --> "Render" --> "Nodes" and "Mesh" --> "Render" --> "Elements". Under the elements box, you can separately render the lines and surfaces, as before
Go to the "Open Mesh" control button near the top-right, click the properties tab, and either delete or hide the nodes and elements
Go to "Mesh" --> "Refine" and select xi1 = 3, xi2 = 2, xi3 = 1, and click ok
- Repeat the steps above to visualize the nodes, lines, and surfaces of your mesh. Notice the elements will be much smaller.
You can also visualize the raw data that you will fit your surfaces to in "Fitting" --> "Render" --> "Raw Data"
Specify "Fitting" --> "Edit" --> "Fit Weights". To get the best behavior we could get fancier, but we can just set all of the Fit Weights to 0.2 for simplicity.
We need a set of constraints that tell the fit how to work. We will load in a constraints file but make a couple of changes to it to allow you to interact with the constraints form. Download the default constraints file here
- The refinement process created new nodes at the apex. We would like the points at the apex to not move in the fit, so we will add constraints to those and we will explain how to do that in class.
Performing the Fit
- Do a "Send" and "Calculate Mesh"!
Go to "Fitting" --> "Fit Data". Under the "Fitting Variable" tab, uncheck Coordinates 2 and 3 (we are only doing a fit to coordinate 1)
Go to "Xi projections" tab. Under "ignore points with", change the value next to "distance >" to "4.0" and change the selection to "absolute" instead of "sd"
- Under "Data List", type: blue;red;yellow;green
- Under "Points in Element List", type: LV;Epi;Sept;RVFW
- Make sure there are no spaces between the semicolons
- The rest of the data can be left as default, click "Fit" at the bottom
Go to "Fitting" --> "Render Element Data" --> "Projections" and Click OK
- Send and Calculate Mesh, and Render as described previously
A final version of the mesh is here
Old Geometry Instructions (This is not part of the above tutorial but is an old example kept for reference)
Load Fitting module (File > Load Module)
Download and extract image files
Define initial mesh properties (BiLinear, BiCubic basis functions, Material coordinates, etc.)
- Threshold, connected connected component labeling, edge detection, re-label
- Generate mesh with connected nodes
- see simple 3d heart topology.ppt in data15 as an example
- This should result in 57 nodes
Refine 1x1x1 and make BiCubic
- Export image data
Define fitting constraints
- Define fitting weights
Fit each surface by label which should produce a mesh like this.
Change to 3D mesh by using 3D element file and adding basis functions
Fit dYdMatl from diffusion tensor
- Generate Field Data for 6 diffusion tensor components
- Fit 6 fields
- Create dydMatl transf. based on fields
- Render surfaces, etc.
- Compute dY_dMatl from diffusion tensor
nodes = self.stored_data.nodes.obj nodes.diffusion_to_dYdMatl() self.stored_data.store(nodes)
- Setup appropriate Material Coordinates
- Render fibers