freesurfer.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. """
  2. Read hippocampal subfield volumes computed by Freesurfer
  3. https://surfer.nmr.mgh.harvard.edu/fswiki/HippocampalSubfields
  4. >>> from freesurfer_volume_reader.freesurfer import HippocampalSubfieldsVolumeFile
  5. >>>
  6. >>> for volume_file in HippocampalSubfieldsVolumeFile.find('/my/freesurfer/subjects'):
  7. >>> print(volume_file.read_volumes_mm3())
  8. >>> print(volume_file.read_volumes_dataframe())
  9. """
  10. import os
  11. import re
  12. import typing
  13. import pandas
  14. class HippocampalSubfieldsVolumeFile:
  15. # https://surfer.nmr.mgh.harvard.edu/fswiki/HippocampalSubfields
  16. FILENAME_PATTERN = r'^(?P<h>[lr])h\.hippoSfVolumes' \
  17. r'(?P<T1>-T1)?(-(?P<analysis_id>.+?))?\.v10.txt$'
  18. FILENAME_REGEX = re.compile(FILENAME_PATTERN)
  19. FILENAME_HEMISPHERE_PREFIX_MAP = {'l': 'left', 'r': 'right'}
  20. def __init__(self, path: str):
  21. self._absolute_path = os.path.abspath(path)
  22. subject_dir_path = os.path.dirname(os.path.dirname(self._absolute_path))
  23. self.subject = os.path.basename(subject_dir_path)
  24. filename_match = self.FILENAME_REGEX.match(os.path.basename(path))
  25. assert filename_match, self._absolute_path
  26. filename_groups = filename_match.groupdict()
  27. assert filename_groups['T1'] or filename_groups['analysis_id'], self._absolute_path
  28. self.hemisphere = self.FILENAME_HEMISPHERE_PREFIX_MAP[filename_groups['h']]
  29. self.t1_input = filename_groups['T1'] is not None
  30. self.analysis_id = filename_groups['analysis_id']
  31. @property
  32. def absolute_path(self):
  33. return self._absolute_path
  34. def read_volumes_mm3(self) -> typing.Dict[str, float]:
  35. subfield_volumes = {}
  36. with open(self.absolute_path, 'r') as volume_file:
  37. for line in volume_file.read().rstrip().split('\n'):
  38. # https://github.com/freesurfer/freesurfer/blob/release_6_0_0/HippoSF/src/segmentSubjectT1T2_autoEstimateAlveusML.m#L8
  39. # https://github.com/freesurfer/freesurfer/blob/release_6_0_0/HippoSF/src/segmentSubjectT1T2_autoEstimateAlveusML.m#L1946
  40. subfield_name, subfield_volume_mm3_str = line.split(' ')
  41. subfield_volumes[subfield_name] = float(subfield_volume_mm3_str)
  42. return subfield_volumes
  43. def read_volumes_dataframe(self) -> pandas.DataFrame:
  44. volumes_frame = pandas.DataFrame([
  45. {'subfield': s, 'volume_mm^3': v}
  46. for s, v in self.read_volumes_mm3().items()
  47. ])
  48. volumes_frame['subject'] = self.subject
  49. volumes_frame['hemisphere'] = self.hemisphere
  50. # volumes_frame['hemisphere'] = volumes_frame['hemisphere'].astype('category')
  51. volumes_frame['T1_input'] = self.t1_input
  52. volumes_frame['analysis_id'] = self.analysis_id
  53. return volumes_frame
  54. @classmethod
  55. def find(cls, root_dir_path: str,
  56. filename_regex: typing.Pattern = FILENAME_REGEX) -> typing.Iterator[str]:
  57. for dirpath, _, filenames in os.walk(root_dir_path):
  58. for filename in filter(filename_regex.search, filenames):
  59. yield cls(path=os.path.join(dirpath, filename))