Skip to content

Commit

Permalink
Merge pull request #11 from cni/intent-spectroscopy
Browse files Browse the repository at this point in the history
move spectroscopy to intent
  • Loading branch information
lmperry authored Jul 11, 2019
2 parents 4589bed + 1773435 commit 64b979c
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 45 deletions.
96 changes: 82 additions & 14 deletions classification_from_label.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,72 @@
#!/usr/bin/env python
'''
Infer acquisition classification by parsing the description label.
'''

import re

Example DB usage:

## Update acquisition measurement in the DB
labels=list(db.acquisitions.find({},['label']))
def feature_check(label):
'''Check the label for a list of features.'''

labels_only = []
for l in labels:
labels_only.append(l['label'])
feature_list = ['2D', 'AAscout', 'Spin-Echo', 'Gradient-Echo',
'EPI', 'WASSR', 'FAIR', 'FAIREST', 'PASL', 'EPISTAR',
'PICORE', 'pCASL', 'MPRAGE', 'MP2RAGE', 'FLAIR',
'SWI', 'QSM', 'RMS', 'DTI', 'DSI', 'DKI', 'HARDI',
'NODDI', 'Water-Reference', 'Transmit-Reference',
'SBRef', 'Uniform', 'Singlerep', 'QC', 'TRACE',
'FA', 'MIP', 'Navigator', 'Contrast-Agent',
'Phase-Contrast', 'TOF', 'VASO', 'iVASO', 'DSC',
'DCE', 'Task', 'Resting-State', 'PRESS', 'STEAM',
'M0', 'Phase-Reversed', 'Spiral', 'SPGR',
'Quantitative', 'Multi-Shell', 'Multi-Echo', 'Multi-Flip',
'Multi-Band', 'Steady-State', '3D', 'Compressed-Sensing',
'Eddy-Current-Corrected', 'Fieldmap-Corrected',
'Gradient-Unwarped', 'Motion-Corrected', 'Physio-Corrected',
'Derived', 'In-Plane', 'Phase', 'Magnitude']

unique_labels = set(labels_only)
uls = list(unique_labels)
return _find_matches(label, feature_list)

for l in uls:
measurement = infer_measurement(l)
db.acquisitions.update_many({'label': l}, {'$set': {'measurement': measurement}})
'''

import re
def measurement_check(label):
'''Check the label for a list of measurements.'''

measurement_list = ['MRA', 'CEST', 'T1rho', 'SVS', 'CSI', 'EPSI', 'BOLD',
'Phoenix','B0', 'B1', 'T1', 'T2', 'T2*', 'PD', 'MT',
'Perfusion','Diffusion', 'Susceptibility', 'Fingerprinting']

return _find_matches(label, measurement_list)


def intent_check(label):
'''Check the label for a list of intents.'''

intent_list = [ 'Localizer', 'Shim', 'Calibration', 'Fieldmap', 'Structural',
'Functional', 'Screenshot', 'Non-Image', 'Spectroscopy' ]

return _find_matches(label, intent_list)


def _find_matches(label, list):
"""For a given list find those entries that match a given label."""

matches = []

for l in list:
regex = _compile_regex(l)
if regex.findall(label):
matches.append(l)

return matches


def _compile_regex(string):
"""Generate the regex for label checking"""

regex = re.compile(r"(\b%s\b)|(_%s_)|(_%s)|(%s_)" % (string,string,string,string), re.IGNORECASE)

return regex


# Anatomy, T1
def is_anatomy_t1(label):
Expand Down Expand Up @@ -310,12 +356,34 @@ def infer_classification(label):
elif is_susceptability(label):
classification['Measurement'] = ['Susceptability']
elif is_spectroscopy(label):
classification['Measurement'] = ['Spectroscopy']
classification['Intent'] = ['Spectroscopy']
elif is_phase_map(label):
classification['Custom'] = ['Phase Map']
elif is_screenshot(label):
classification['Intent'] = ['Screenshot']
else:
print label.strip('\n') + ' --->>>> unknown'


# Add features to classification
features = feature_check(label)
if features:
class_features = classification.get('Features', [])
[ class_features.append(x) for x in features if x not in class_features ]
classification['Features'] = class_features

# Add measurements to classification
measurements = measurement_check(label)
if measurements:
class_measurement = classification.get('Measurement', [])
[ class_measurement.append(x) for x in measurements if x not in class_measurement ]
classification['Measurement'] = class_measurement

# Add intents to classification
intents = intent_check(label)
if intents:
class_intent = classification.get('Intent', [])
[ class_intent.append(x) for x in intents if x not in class_intent ]
classification['Intent'] = class_intent

return classification
11 changes: 3 additions & 8 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"cite": "pfile-tools: GE P-File Utilities (https://github.com/njvack/pfile-tools)",
"license": "BSD-2-Clause",
"flywheel": "0",
"version": "1.8.0",
"version": "2.0.0",
"custom": {
"docker-image": "stanfordcni/pfile-mr-classifier:1.8.0",
"docker-image": "stanfordcni/pfile-mr-classifier:2.0.0",
"gear-builder": {
"image": "stanfordcni/pfile-mr-classifier:1.8.0",
"image": "stanfordcni/pfile-mr-classifier:2.0.0",
"category": "converter"
},
"flywheel": {
Expand All @@ -25,11 +25,6 @@
"description": "Time Zone to which all timestamps should be localized. This will set the default time zone in the Gear and thus localize the timestamps to that time zone. Examples: 'UTC', 'America/Los_Angeles', 'America/New_York'. [default = 'America/Los_Angeles'].",
"type": "string",
"default": "America/Los_Angeles"
},
"sync": {
"description": "Synchronize classification definitions with the latest known updates found at scitran-apps/dicom-mr-classifier [default = true].",
"type": "boolean",
"default": true
}
},
"inputs": {
Expand Down
4 changes: 2 additions & 2 deletions pfile-mr-classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ def get_pfile_classification(pfile):
elif PSD == 'sprl_hos':
classification['Intent'] = ['Shim']
elif PSD == 'spep_cni':
classification['Measurement'] = ['ASL']
classification['Measurement'] = ['Perfusion']
classification['Intent'] = ['Functional']
elif PSD == 'sprt':
classification['Measurement'] = ['B0']
classification['Intent'] = ['Fieldmap']
elif PSD.startswith('nfl') or PSD.startswith('special') or PSD.startswith('probe-mega') or PSD.startswith('imspecial') or PSD.startswith('gaba'):
classification['Measurement'] = ['Spectroscopy']
classification['Intent'] = ['Spectroscopy']

else:
log.info("Using series description for classification!")
Expand Down
21 changes: 0 additions & 21 deletions run
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,6 @@ echo "$TZ" > /etc/timezone && ln -snf /usr/share/zoneinfo/"$TZ" /etc/localtime
dpkg-reconfigure -f noninteractive tzdata


##############################################################################
# Handle sync option

SYNC=$(parse_config 'sync')
if [[ ${SYNC} == "true" ]]; then
echo -e "$CONTAINER Syncing classification code from scitran-apps/dicom-mr-classifier/sync-classification-e4..."
mv ${FLYWHEEL_BASE}/classification_from_label.py /tmp
wget --quiet -O ${FLYWHEEL_BASE}/classification_from_label.py \
https://raw.githubusercontent.com/scitran-apps/dicom-mr-classifier/sync-classification-e4/classification_from_label.py
STAT_GET=$?
if [[ $STAT_GET != 0 ]]; then
echo -e "$CONTAINER Error during sync!"
mv /tmp/classification_from_label.py ${FLYWHEEL_BASE}
else
chmod +x ${FLYWHEEL_BASE}/classification_from_label.py
fi
else
echo -e "$CONTAINER Not syncing classification code. Using built-in version..."
fi


##############################################################################
# Check I/O directories and Generate metadata

Expand Down

0 comments on commit 64b979c

Please sign in to comment.