Skip to content

Commit

Permalink
Many member functions have been changed to property attributes. There…
Browse files Browse the repository at this point in the history
… is a new Zval model where one Scan has many Zvals. A particular scan model now has a slice_coords attribute which is an array (via the Zval model) of all the slice coordinates of the image volume. This will make the library more consistent so that coordinates are not given as indexes in-slice, while z-values are given between-slice.
  • Loading branch information
notmatthancock committed Mar 22, 2018
1 parent eb44105 commit f12c0e3
Show file tree
Hide file tree
Showing 10 changed files with 1,171 additions and 53 deletions.
46 changes: 33 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,17 @@ You can engage an interactive slice view by calling:

scan.visualize()

Note that calling `visualize` on a scan object doesn't include its annotation information -- you must call the `visualize_in_scan` member function of an `Annotation` object to do this.
By default, note that calling `visualize` on a scan object doesn't include its annotation information. However, if `scan.visualize` is supplied with a list of `Annotation` objects (say, grouped by the `scan.cluster_annotations()` function), then this annotation information *will* be displayed. For example

nodules = scan.cluster_annotations()
print(len(nodules))
# => 3

# Visualize the slices with the provided annotations indicated by arrows.
scan.visualize(annotations)

`scan.cluster_annotations` returns a list. Each element of the list is a list of `Annotation` objects where each `Annotation` refers to the same nodule in the scan (probably). See [Clustering annotations](#clustering-annotations-to-identify-those-which-refer-to-the-same-physical-nodule) for more details on this function.


#### The `Annotation` model

Expand All @@ -102,11 +112,11 @@ Let's grab the first annotation from the `Scan` object above:
print(ann.scan.patient_id)
# => LIDC-IDRI-0066

print(ann.spiculation, ann.Spiculation())
print(ann.spiculation, ann.Spiculation)
# => 3, Medium Spiculation

print(ann.estimate_diameter(), ann.estimate_volume())
# => 15.4920358194, 888.052284241
print("%.2f, %.2f, %.2f" % (ann.diameter, ann.surface_area, ann.volume))
# => 15.49, 1041.37, 888.05

ann.print_formatted_feature_table()
# => Feature Meaning #
Expand All @@ -121,19 +131,29 @@ Let's grab the first annotation from the `Scan` object above:
# => Texture | Solid | 5
# => Malignancy | Moderately Suspicious | 4

from pylidc.Annotation import feature_names as fnames
fvals, fstrings = ann.feature_vals(return_str=True)
print(fnames[0].title(), fstrings[0], fvals[0])
# => Subtlety, Obvious, 5

for fname,fval,fstr in zip(pl.annotation_feature_names, fvals, fstrings):
print(fname.title(), fval, fstr)
# => 'Subtlety', 5, 'Obvious'
# => 'Internalstructure', 1, 'Soft Tissue'
# => 'Calcification', 6, 'Absent'
# => 'Sphericity', 3, 'Ovoid'
# => 'Margin', 1, 'Poorly Defined'
# => 'Lobulation', 4, 'Near Marked Lobulation'
# => 'Spiculation', 3, 'Medium Spiculation'
# => 'Texture', 5, 'Solid'
# => 'Malignancy', 4, 'Moderately Suspicious'

Let's try a different query on the annotations directly:

qu = pl.query(pl.Annotation).filter(pl.Annotation.lobulation > 3, pl.Annotation.malignancy == 5)
qu = pl.query(pl.Annotation).filter(pl.Annotation.lobulation > 3,
pl.Annotation.malignancy == 5)
print(qu.count())
# => 183

ann = qu.first()
print(ann.lobulation, ann.Lobulation(), ann.malignancy, ann.Malignancy())
print(ann.lobulation, ann.Lobulation, ann.malignancy, ann.Malignancy)
# => 4, Near Marked Lobulation, 5, Highly Suspicious

print(len(ann.contours))
Expand All @@ -142,7 +162,7 @@ Let's try a different query on the annotations directly:
print(ann.contours_to_matrix().shape)
# => (671, 3)

print(ann.contours_to_matrix().mean(axis=0) - ann.centroid())
print(ann.contours_to_matrix().mean(axis=0) - ann.centroid)
# => [ 0. 0. 0.]

You can engage an interactive slice viewer that displays annotation values and the radiologist-drawn contours:
Expand Down Expand Up @@ -211,12 +231,12 @@ import pylidc as pl
scan = pl.query(pl.Scan).first()
nods = scan.cluster_annotations()
print "Scan is estimated to have", len(nods), "nodules."
print("Scan is estimated to have", len(nods), "nodules.")
for i,nod in enumerate(nods):
print "Nodule", i+1, "has", len(nod), "annotations."
print("Nodule", i+1, "has", len(nod), "annotations.")
for j,ann in enumerate(nod):
print "-- Annotation", j+1, "centroid:", ann.centroid()
print("-- Annotation", j+1, "centroid:", ann.centroid)
```

Output:
Expand Down
19 changes: 19 additions & 0 deletions _populate_db/add_zvals_to_scans.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import numpy as np
import pylidc as pl


scans = pl.query(pl.Scan)
nscans = scans.count()
for i,scan in enumerate(scans):
print i+1,"/",nscans

images = scan.load_all_dicom_images(verbose=0)
img_zs = [float(img.ImagePositionPatient[-1]) for img in images]
img_zs = np.unique(img_zs)

for zval in img_zs:
z = pl.Zval()
z.val = float(zval)
z.scan = scan

pl._session.commit()
7 changes: 7 additions & 0 deletions _populate_db/make_zvals.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE zvals (
id INTEGER NOT NULL,
scan_id INTEGER,
val FLOAT,
PRIMARY KEY (id),
FOREIGN KEY(scan_id) REFERENCES scans (id)
);
Loading

0 comments on commit f12c0e3

Please sign in to comment.