__init__.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """
  2. Read hippocampal subfield volumes computed by Freesurfer
  3. https://surfer.nmr.mgh.harvard.edu/fswiki/HippocampalSubfields
  4. """
  5. import argparse
  6. import os
  7. import re
  8. import typing
  9. import pandas
  10. # https://surfer.nmr.mgh.harvard.edu/fswiki/HippocampalSubfields
  11. HIPPOCAMPAL_VOLUME_FILENAME_PATTERN = r'^(?P<h>[lr])h\.hippoSfVolumes' \
  12. r'(?P<T1>-T1)?(-(?P<analysis_id>.+?))?\.v10.txt$'
  13. HIPPOCAMPAL_VOLUME_FILENAME_REGEX = re.compile(HIPPOCAMPAL_VOLUME_FILENAME_PATTERN)
  14. DEFAULT_HIPPOCAMPAL_VOLUME_FIND_FILENAME_PATTERN = re.sub(r'\?P<.+?>', '',
  15. HIPPOCAMPAL_VOLUME_FILENAME_PATTERN)
  16. VOLUME_FILENAME_HEMISPHERE_MAP = {'l': 'left', 'r': 'right'}
  17. def find_hippocampal_volume_files(root_dir_path: str,
  18. filename_regex: typing.Pattern = HIPPOCAMPAL_VOLUME_FILENAME_REGEX
  19. ) -> typing.Iterator[str]:
  20. for dirpath, _, filenames in os.walk(root_dir_path):
  21. for filename in filter(filename_regex.search, filenames):
  22. yield os.path.join(dirpath, filename)
  23. def read_hippocampal_volumes_mm3(volume_file_path: str) -> dict:
  24. subfield_volumes = {}
  25. with open(volume_file_path, 'r') as volume_file:
  26. for line in volume_file.read().rstrip().split('\n'):
  27. # https://github.com/freesurfer/freesurfer/blob/release_6_0_0/HippoSF/src/segmentSubjectT1T2_autoEstimateAlveusML.m#L8
  28. # https://github.com/freesurfer/freesurfer/blob/release_6_0_0/HippoSF/src/segmentSubjectT1T2_autoEstimateAlveusML.m#L1946
  29. subfield_name, subfield_volume_mm3_str = line.split(' ')
  30. subfield_volumes[subfield_name] = float(subfield_volume_mm3_str)
  31. return subfield_volumes
  32. def parse_hippocampal_volume_file_path(volume_file_path: str) -> dict:
  33. subject_dir_path = os.path.dirname(os.path.dirname(os.path.abspath(volume_file_path)))
  34. filename_match = HIPPOCAMPAL_VOLUME_FILENAME_REGEX.match(os.path.basename(volume_file_path))
  35. assert filename_match, volume_file_path
  36. filename_groups = filename_match.groupdict()
  37. assert filename_groups['T1'] or filename_groups['analysis_id'], volume_file_path
  38. return {
  39. 'subject': os.path.basename(subject_dir_path),
  40. 'hemisphere': VOLUME_FILENAME_HEMISPHERE_MAP[filename_groups['h']],
  41. 'T1_input': filename_groups['T1'] is not None,
  42. 'analysis_id': filename_groups['analysis_id'],
  43. }
  44. def read_hippocampal_volume_file_dataframe(volume_file_path: str) -> pandas.DataFrame:
  45. volumes_frame = pandas.DataFrame(
  46. read_hippocampal_volumes_mm3(volume_file_path).items(),
  47. columns=['subfield', 'volume_mm^3'])
  48. for key, value in parse_hippocampal_volume_file_path(volume_file_path).items():
  49. volumes_frame[key] = value
  50. # volumes_frame['hemisphere'] = volumes_frame['hemisphere'].astype('category')
  51. return volumes_frame
  52. def main():
  53. argparser = argparse.ArgumentParser(description=__doc__)
  54. argparser.add_argument('--filename-regex', type=re.compile,
  55. default=DEFAULT_HIPPOCAMPAL_VOLUME_FIND_FILENAME_PATTERN,
  56. help='default: %(default)s')
  57. argparser.add_argument('--output-format', choices=['csv'], default='csv',
  58. help='default: %(default)s')
  59. subjects_dir_path = os.environ.get('SUBJECTS_DIR', None)
  60. argparser.add_argument('root_dir_paths',
  61. metavar='ROOT_DIR',
  62. nargs='*' if subjects_dir_path else '+',
  63. default=[subjects_dir_path],
  64. help='default: $SUBJECTS_DIR ({})'.format(subjects_dir_path))
  65. args = argparser.parse_args()
  66. volume_file_paths = [p for d in args.root_dir_paths
  67. for p in find_hippocampal_volume_files(
  68. root_dir_path=d, filename_regex=args.filename_regex)]
  69. volume_frames = []
  70. for volume_file_path in volume_file_paths:
  71. volume_frame = read_hippocampal_volume_file_dataframe(volume_file_path)
  72. volume_frame['source_path'] = os.path.abspath(volume_file_path)
  73. volume_frames.append(volume_frame)
  74. united_volume_frame = pandas.concat(volume_frames, ignore_index=True)
  75. print(united_volume_frame.to_csv(index=False))
  76. if __name__ == '__main__':
  77. main()