Skip to content

Commit

Permalink
Merge pull request #15 from ofgulban/master
Browse files Browse the repository at this point in the history
Additional flags used to deface 7T data
  • Loading branch information
chrisgorgo authored Dec 21, 2017
2 parents 240912f + 2244e55 commit 4b92a46
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 141 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Defacing tool for nifti images.
Defacing tool for nifti images.

### Requirements:
- [FSL](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FSL)
Expand All @@ -14,5 +14,10 @@ python setup.py install

### To use:
```
pydeface.py infile.nii.gz
pydeface infile.nii.gz
```

Also see the help for additional options:
```
pydeface --help
```
Empty file added pydeface/__init__.py
Empty file.
148 changes: 148 additions & 0 deletions pydeface/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/usr/bin/env python
"""Defacing utility for MRI images."""

# Copyright 2011, Russell Poldrack. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY RUSSELL POLDRACK ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL RUSSELL POLDRACK OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import argparse
import os
import tempfile
from nipype.interfaces import fsl
from nibabel import load, Nifti1Image
from pkg_resources import require
from pydeface.utils import initial_checks, output_checks


def main():
"""Command line call argument parsing."""
parser = argparse.ArgumentParser()
parser.add_argument(
'infile', metavar='path',
help="Path to input nifti.")

parser.add_argument(
"--outfile", metavar='path', required=False,
help="If not provided adds '_defaced' suffix.")

parser.add_argument(
"--force", action='store_true',
help="Force to rewrite the output even if it exists.")

parser.add_argument(
'--applyto', nargs='+', required=False, metavar='',
help="Apply the created face mask to other images. Can take multiple "
"arguments.")

parser.add_argument(
"--cost", metavar='mutualinfo', required=False, default='mutualinfo',
help="FSL-FLIRT cost function. Default is 'mutualinfo'.")

parser.add_argument(
"--template", metavar='path', required=False,
help=("Optional template image that will be used as the registration "
"target instead of the default."))

parser.add_argument(
"--facemask", metavar='path', required=False,
help="Optional face mask image that will be used instead of the "
"default.")

parser.add_argument(
"--nocleanup", action='store_true',
help="Do not cleanup temporary files. Off by default.")

parser.add_argument(
"--verbose", action='store_true',
help="Show additional status prints. Off by default.")

welcome_str = 'pydeface ' + require("pydeface")[0].version
welcome_decor = '-' * len(welcome_str)
print(welcome_decor + '\n' + welcome_str + '\n' + welcome_decor)

args = parser.parse_args()
template, facemask = initial_checks(args.template, args.facemask)
infile = args.infile
outfile = output_checks(infile, args.outfile, args.force)

# temporary files
_, tmpmat = tempfile.mkstemp()
tmpmat = tmpmat + '.mat'
_, tmpfile = tempfile.mkstemp()
tmpfile = tmpfile + '.nii.gz'
if args.verbose:
print("Temporary files:\n %s\n %s" % (tmpmat, tmpfile))
_, tmpfile2 = tempfile.mkstemp()
_, tmpmat2 = tempfile.mkstemp()

print('Defacing...\n %s' % args.infile)

# register template to infile
flirt = fsl.FLIRT()
flirt.inputs.cost_func = args.cost
flirt.inputs.in_file = template
flirt.inputs.out_matrix_file = tmpmat
flirt.inputs.out_file = tmpfile2
flirt.inputs.reference = infile
flirt.run()

# warp facemask to infile
flirt = fsl.FLIRT()
flirt.inputs.in_file = facemask
flirt.inputs.in_matrix_file = tmpmat
flirt.inputs.apply_xfm = True
flirt.inputs.reference = infile
flirt.inputs.out_file = tmpfile
flirt.inputs.out_matrix_file = tmpmat2
flirt.run()

# multiply mask by infile and save
infile_img = load(infile)
tmpfile_img = load(tmpfile)
outdata = infile_img.get_data() * tmpfile_img.get_data()
outfile_img = Nifti1Image(outdata, infile_img.get_affine(),
infile_img.get_header())
outfile_img.to_filename(outfile)
print("Defaced image saved as:\n %s" % outfile)

# apply mask to other given images
if args.applyto is not None:
print("Defacing mask also applied to:")
for applyfile in args.applyto:
applyfile_img = load(applyfile)
outdata = applyfile_img.get_data() * tmpfile_img.get_data()
applyfile_img = Nifti1Image(outdata, applyfile_img.get_affine(),
applyfile_img.get_header())
outfile = output_checks(applyfile)
applyfile_img.to_filename(outfile)
print(' %s' % applyfile)

if args.nocleanup:
pass
else:
os.remove(tmpfile)
os.remove(tmpfile2)
os.remove(tmpmat)

print('Finished.')


if __name__ == "__main__":
main()
51 changes: 36 additions & 15 deletions pydeface/utils.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
"""Utility scripts for pydeface."""

import os
import sys
import subprocess
from pkg_resources import resource_filename, Requirement


def run_shell_cmd(cmd, cwd=[]):
"""Run a command in the shell using Popen."""
if cwd:
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
cwd=cwd)
else:
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
for line in process.stdout:
print(line.strip())
process.wait()
def initial_checks(template=None, facemask=None):
"""Initial sanity checks."""
if template is None:
template = resource_filename(Requirement.parse("pydeface"),
"pydeface/data/mean_reg2mean.nii.gz")
if facemask is None:
facemask = resource_filename(Requirement.parse("pydeface"),
"pydeface/data/facemask.nii.gz")

if not os.path.exists(template):
raise Exception('Missing template: %s' % template)
if not os.path.exists(facemask):
raise Exception('Missing face mask: %s' % facemask)

if 'FSLDIR' not in os.environ:
raise Exception("FSL must be installed and "
"FSLDIR environment variable must be defined.")
sys.exit(2)
return template, facemask


def usage():
"""Print the docstring and exit."""
sys.stdout.write(__doc__)
sys.exit(2)
def output_checks(infile, outfile=None, force=False):
"""Determine output file name."""
if force is None:
force = False
if outfile is None:
outfile = infile.replace('.nii', '_defaced.nii')

if os.path.exists(outfile) and force:
print('Previous output will be overwritten.')
elif os.path.exists(outfile):
raise Exception("%s already exists. Remove it first or use '--force' "
"flag to overwrite." % outfile)
else:
pass
return outfile
122 changes: 0 additions & 122 deletions scripts/pydeface.py

This file was deleted.

9 changes: 7 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#
# Some portions were borrowed from:
# https://github.com/mwaskom/lyman/blob/master/setup.py
# and:
# https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/

import os
from setuptools import setup
Expand All @@ -15,7 +17,7 @@
LICENSE = 'MIT'
URL = 'http://poldracklab.org'
DOWNLOAD_URL = 'https://github.com/poldracklab/pydeface/'
VERSION = '1.1'
VERSION = '2.0'

if os.path.exists('MANIFEST'):
os.remove('MANIFEST')
Expand All @@ -33,12 +35,15 @@
download_url=DOWNLOAD_URL,
packages=['pydeface'],
package_data=datafiles,
scripts=['scripts/pydeface.py'],
classifiers=['Intended Audience :: Science/Research',
'Programming Language :: Python :: 2.7',
'License :: OSI Approved :: BSD License',
'Operating System :: POSIX',
'Operating System :: Unix',
'Operating System :: MacOS'],
install_requires=['numpy', 'nibabel', 'nipype'],
entry_points={
'console_scripts': [
'pydeface = pydeface.__main__:main'
]},
)

0 comments on commit 4b92a46

Please sign in to comment.