{
  "id": 252942,
  "title": "Extract DICOM metadata",
  "url": "/competitions/rsna-miccai-brain-tumor-radiogenomic-classification/discussion/252942",
  "author_name": "Peter",
  "post_date": "2021-07-14T10:54:53.257000",
  "votes": 49,
  "comment_count": 6,
  "views": 0,
  "content": "<p>You can use this small script to extract metadata from the DICOM files. </p>\n<h3>Usage</h3>\n<pre><code>python dicom_meta.py --dataset train --input ./input --output ./ --n_jobs\n</code></pre>\n<ul>\n<li><strong>dataset</strong> train or test</li>\n<li><strong>input</strong> input folder (train | test subfolder should be inside this)</li>\n<li><strong>output</strong> output folder for the generated csv file</li>\n<li><strong>n_jobs</strong> Number of parallel processes</li>\n</ul>\n<p>Happy data analysis!</p>\n<h3>Code</h3>\n<pre><code>import argparse\nimport os\nimport pydicom\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom multiprocessing import Pool\n\nFIELDS = [\n    'AccessionNumber',\n    'AcquisitionMatrix',\n    'B1rms',\n    'BitsAllocated',\n    'BitsStored',\n    'Columns',\n    'ConversionType',\n    'DiffusionBValue',\n    'DiffusionGradientOrientation',\n    'EchoNumbers',\n    'EchoTime',\n    'EchoTrainLength',\n    'FlipAngle',\n    'HighBit',\n    'HighRRValue',\n    'ImageDimensions',\n    'ImageFormat',\n    'ImageGeometryType',\n    'ImageLocation',\n    'ImageOrientation',\n    'ImageOrientationPatient',\n    'ImagePosition',\n    'ImagePositionPatient',\n    'ImageType',\n    'ImagedNucleus',\n    'ImagingFrequency',\n    'InPlanePhaseEncodingDirection',\n    'InStackPositionNumber',\n    'InstanceNumber',\n    'InversionTime',\n    'Laterality',\n    'LowRRValue',\n    'MRAcquisitionType',\n    'MagneticFieldStrength',\n    'Modality',\n    'NumberOfAverages',\n    'NumberOfPhaseEncodingSteps',\n    'PatientID',\n    'PatientName',\n    'PatientPosition',\n    'PercentPhaseFieldOfView',\n    'PercentSampling',\n    'PhotometricInterpretation',\n    'PixelBandwidth',\n    'PixelPaddingValue',\n    'PixelRepresentation',\n    'PixelSpacing',\n    'PlanarConfiguration',\n    'PositionReferenceIndicator',\n    'PresentationLUTShape',\n    'ReconstructionDiameter',\n    'RescaleIntercept',\n    'RescaleSlope',\n    'RescaleType',\n    'Rows',\n    'SAR',\n    'SOPClassUID',\n    'SOPInstanceUID',\n    'SamplesPerPixel',\n    'SeriesDescription',\n    'SeriesInstanceUID',\n    'SeriesNumber',\n    'SliceLocation',\n    'SliceThickness',\n    'SpacingBetweenSlices',\n    'SpatialResolution',\n    'SpecificCharacterSet',\n    'StudyInstanceUID',\n    'TemporalResolution',\n    'TransferSyntaxUID',\n    'TriggerWindow',\n    'WindowCenter',\n    'WindowWidth'\n]\n\nFM_FIELDS = [\n    'FileMetaInformationGroupLength',\n    'FileMetaInformationVersion',\n    'ImplementationClassUID',\n    'ImplementationVersionName',\n    'MediaStorageSOPClassUID',\n    'MediaStorageSOPInstanceUID',\n    'SourceApplicationEntityTitle',\n    'TransferSyntaxUID',\n]\n\nfinal = []\n\n\ndef get_meta_info(dicom):\n    row = {f: dicom.get(f) for f in FIELDS}\n    row_fm = {f: dicom.file_meta.get(f) for f in FM_FIELDS}\n    row_other = {\n        'is_original_encoding': dicom.is_original_encoding,\n        'is_implicit_VR': dicom.is_implicit_VR,\n        'is_little_endian': dicom.is_little_endian,\n        'timestamp': dicom.timestamp,\n    }\n    return {**row, **row_fm, **row_other}\n\n\ndef get_dicom_files(input_dir, ds='train'):\n    dicoms = []\n\n    for subdir, dirs, files in os.walk(f\"{input_dir}/{ds}\"):\n        for filename in files:\n            filepath = subdir + os.sep + filename\n\n            if filepath.endswith(\".dcm\"):\n                dicoms.append(filepath)\n\n    return dicoms\n\n\ndef process_dicom(dicom_src, _x):\n    dicom = pydicom.dcmread(dicom_src)\n    file_data = dicom_src.split(\"/\")\n    file_src = \"/\".join(file_data[-4:])\n\n    tmp = {\"BraTS21ID\": file_data[-3], \"dataset\": file_data[-4], \"type\": file_data[-2], \"dicom_src\": f\"./{file_src}\"}\n    tmp.update(get_meta_info(dicom))\n\n    return tmp\n\n\ndef update(res):\n    if res is not None:\n        final.append(res)\n\n    pbar.update()\n\n\ndef error(e):\n    print(e)\n\n\nif __name__ == \"__main__\":\n    ap = argparse.ArgumentParser()\n    ap.add_argument(\"--input\", type=str, default=\"./input\")\n    ap.add_argument(\"--output\", type=str, default=\"./\")\n    ap.add_argument(\"--dataset\", type=str, default=\"train\")\n    ap.add_argument(\"--n_jobs\", type=int, default=20)\n    ap.add_argument(\"--debug\", type=int, default=0)\n\n    args = vars(ap.parse_args())\n\n    dicom_files = get_dicom_files(args[\"input\"], args[\"dataset\"])\n\n    if args[\"debug\"]:\n        dicom_files = dicom_files[:1000]\n\n    pool = Pool(processes=args[\"n_jobs\"])\n    pbar = tqdm(total=len(dicom_files))\n\n    for dicom_file in dicom_files:\n        pool.apply_async(\n            process_dicom,\n            args=(dicom_file, ''),\n            callback=update,\n            error_callback=error,\n        )\n\n    pool.close()\n    pool.join()\n    pbar.close()\n\n    final = pd.DataFrame(final)\n    final.to_csv(f\"{args['output']}/dicom_meta_{args['dataset']}.csv\", index=False)\n</code></pre>",
  "messages": [
    {
      "id": 1387663,
      "postDate": "2021-07-14T10:54:53.257Z",
      "content": "<p>You can use this small script to extract metadata from the DICOM files. </p>\n<h3>Usage</h3>\n<pre><code>python dicom_meta.py --dataset train --input ./input --output ./ --n_jobs\n</code></pre>\n<ul>\n<li><strong>dataset</strong> train or test</li>\n<li><strong>input</strong> input folder (train | test subfolder should be inside this)</li>\n<li><strong>output</strong> output folder for the generated csv file</li>\n<li><strong>n_jobs</strong> Number of parallel processes</li>\n</ul>\n<p>Happy data analysis!</p>\n<h3>Code</h3>\n<pre><code>import argparse\nimport os\nimport pydicom\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom multiprocessing import Pool\n\nFIELDS = [\n    'AccessionNumber',\n    'AcquisitionMatrix',\n    'B1rms',\n    'BitsAllocated',\n    'BitsStored',\n    'Columns',\n    'ConversionType',\n    'DiffusionBValue',\n    'DiffusionGradientOrientation',\n    'EchoNumbers',\n    'EchoTime',\n    'EchoTrainLength',\n    'FlipAngle',\n    'HighBit',\n    'HighRRValue',\n    'ImageDimensions',\n    'ImageFormat',\n    'ImageGeometryType',\n    'ImageLocation',\n    'ImageOrientation',\n    'ImageOrientationPatient',\n    'ImagePosition',\n    'ImagePositionPatient',\n    'ImageType',\n    'ImagedNucleus',\n    'ImagingFrequency',\n    'InPlanePhaseEncodingDirection',\n    'InStackPositionNumber',\n    'InstanceNumber',\n    'InversionTime',\n    'Laterality',\n    'LowRRValue',\n    'MRAcquisitionType',\n    'MagneticFieldStrength',\n    'Modality',\n    'NumberOfAverages',\n    'NumberOfPhaseEncodingSteps',\n    'PatientID',\n    'PatientName',\n    'PatientPosition',\n    'PercentPhaseFieldOfView',\n    'PercentSampling',\n    'PhotometricInterpretation',\n    'PixelBandwidth',\n    'PixelPaddingValue',\n    'PixelRepresentation',\n    'PixelSpacing',\n    'PlanarConfiguration',\n    'PositionReferenceIndicator',\n    'PresentationLUTShape',\n    'ReconstructionDiameter',\n    'RescaleIntercept',\n    'RescaleSlope',\n    'RescaleType',\n    'Rows',\n    'SAR',\n    'SOPClassUID',\n    'SOPInstanceUID',\n    'SamplesPerPixel',\n    'SeriesDescription',\n    'SeriesInstanceUID',\n    'SeriesNumber',\n    'SliceLocation',\n    'SliceThickness',\n    'SpacingBetweenSlices',\n    'SpatialResolution',\n    'SpecificCharacterSet',\n    'StudyInstanceUID',\n    'TemporalResolution',\n    'TransferSyntaxUID',\n    'TriggerWindow',\n    'WindowCenter',\n    'WindowWidth'\n]\n\nFM_FIELDS = [\n    'FileMetaInformationGroupLength',\n    'FileMetaInformationVersion',\n    'ImplementationClassUID',\n    'ImplementationVersionName',\n    'MediaStorageSOPClassUID',\n    'MediaStorageSOPInstanceUID',\n    'SourceApplicationEntityTitle',\n    'TransferSyntaxUID',\n]\n\nfinal = []\n\n\ndef get_meta_info(dicom):\n    row = {f: dicom.get(f) for f in FIELDS}\n    row_fm = {f: dicom.file_meta.get(f) for f in FM_FIELDS}\n    row_other = {\n        'is_original_encoding': dicom.is_original_encoding,\n        'is_implicit_VR': dicom.is_implicit_VR,\n        'is_little_endian': dicom.is_little_endian,\n        'timestamp': dicom.timestamp,\n    }\n    return {**row, **row_fm, **row_other}\n\n\ndef get_dicom_files(input_dir, ds='train'):\n    dicoms = []\n\n    for subdir, dirs, files in os.walk(f\"{input_dir}/{ds}\"):\n        for filename in files:\n            filepath = subdir + os.sep + filename\n\n            if filepath.endswith(\".dcm\"):\n                dicoms.append(filepath)\n\n    return dicoms\n\n\ndef process_dicom(dicom_src, _x):\n    dicom = pydicom.dcmread(dicom_src)\n    file_data = dicom_src.split(\"/\")\n    file_src = \"/\".join(file_data[-4:])\n\n    tmp = {\"BraTS21ID\": file_data[-3], \"dataset\": file_data[-4], \"type\": file_data[-2], \"dicom_src\": f\"./{file_src}\"}\n    tmp.update(get_meta_info(dicom))\n\n    return tmp\n\n\ndef update(res):\n    if res is not None:\n        final.append(res)\n\n    pbar.update()\n\n\ndef error(e):\n    print(e)\n\n\nif __name__ == \"__main__\":\n    ap = argparse.ArgumentParser()\n    ap.add_argument(\"--input\", type=str, default=\"./input\")\n    ap.add_argument(\"--output\", type=str, default=\"./\")\n    ap.add_argument(\"--dataset\", type=str, default=\"train\")\n    ap.add_argument(\"--n_jobs\", type=int, default=20)\n    ap.add_argument(\"--debug\", type=int, default=0)\n\n    args = vars(ap.parse_args())\n\n    dicom_files = get_dicom_files(args[\"input\"], args[\"dataset\"])\n\n    if args[\"debug\"]:\n        dicom_files = dicom_files[:1000]\n\n    pool = Pool(processes=args[\"n_jobs\"])\n    pbar = tqdm(total=len(dicom_files))\n\n    for dicom_file in dicom_files:\n        pool.apply_async(\n            process_dicom,\n            args=(dicom_file, ''),\n            callback=update,\n            error_callback=error,\n        )\n\n    pool.close()\n    pool.join()\n    pbar.close()\n\n    final = pd.DataFrame(final)\n    final.to_csv(f\"{args['output']}/dicom_meta_{args['dataset']}.csv\", index=False)\n</code></pre>",
      "rawMarkdown": "You can use this small script to extract metadata from the DICOM files. \n\n### Usage\n```\npython dicom_meta.py --dataset train --input ./input --output ./ --n_jobs\n```\n- **dataset** train or test\n- **input** input folder (train | test subfolder should be inside this)\n- **output** output folder for the generated csv file\n- **n_jobs** Number of parallel processes\n\nHappy data analysis!\n\n### Code\n```\nimport argparse\nimport os\nimport pydicom\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom multiprocessing import Pool\n\nFIELDS = [\n    'AccessionNumber',\n    'AcquisitionMatrix',\n    'B1rms',\n    'BitsAllocated',\n    'BitsStored',\n    'Columns',\n    'ConversionType',\n    'DiffusionBValue',\n    'DiffusionGradientOrientation',\n    'EchoNumbers',\n    'EchoTime',\n    'EchoTrainLength',\n    'FlipAngle',\n    'HighBit',\n    'HighRRValue',\n    'ImageDimensions',\n    'ImageFormat',\n    'ImageGeometryType',\n    'ImageLocation',\n    'ImageOrientation',\n    'ImageOrientationPatient',\n    'ImagePosition',\n    'ImagePositionPatient',\n    'ImageType',\n    'ImagedNucleus',\n    'ImagingFrequency',\n    'InPlanePhaseEncodingDirection',\n    'InStackPositionNumber',\n    'InstanceNumber',\n    'InversionTime',\n    'Laterality',\n    'LowRRValue',\n    'MRAcquisitionType',\n    'MagneticFieldStrength',\n    'Modality',\n    'NumberOfAverages',\n    'NumberOfPhaseEncodingSteps',\n    'PatientID',\n    'PatientName',\n    'PatientPosition',\n    'PercentPhaseFieldOfView',\n    'PercentSampling',\n    'PhotometricInterpretation',\n    'PixelBandwidth',\n    'PixelPaddingValue',\n    'PixelRepresentation',\n    'PixelSpacing',\n    'PlanarConfiguration',\n    'PositionReferenceIndicator',\n    'PresentationLUTShape',\n    'ReconstructionDiameter',\n    'RescaleIntercept',\n    'RescaleSlope',\n    'RescaleType',\n    'Rows',\n    'SAR',\n    'SOPClassUID',\n    'SOPInstanceUID',\n    'SamplesPerPixel',\n    'SeriesDescription',\n    'SeriesInstanceUID',\n    'SeriesNumber',\n    'SliceLocation',\n    'SliceThickness',\n    'SpacingBetweenSlices',\n    'SpatialResolution',\n    'SpecificCharacterSet',\n    'StudyInstanceUID',\n    'TemporalResolution',\n    'TransferSyntaxUID',\n    'TriggerWindow',\n    'WindowCenter',\n    'WindowWidth'\n]\n\nFM_FIELDS = [\n    'FileMetaInformationGroupLength',\n    'FileMetaInformationVersion',\n    'ImplementationClassUID',\n    'ImplementationVersionName',\n    'MediaStorageSOPClassUID',\n    'MediaStorageSOPInstanceUID',\n    'SourceApplicationEntityTitle',\n    'TransferSyntaxUID',\n]\n\nfinal = []\n\n\ndef get_meta_info(dicom):\n    row = {f: dicom.get(f) for f in FIELDS}\n    row_fm = {f: dicom.file_meta.get(f) for f in FM_FIELDS}\n    row_other = {\n        'is_original_encoding': dicom.is_original_encoding,\n        'is_implicit_VR': dicom.is_implicit_VR,\n        'is_little_endian': dicom.is_little_endian,\n        'timestamp': dicom.timestamp,\n    }\n    return {**row, **row_fm, **row_other}\n\n\ndef get_dicom_files(input_dir, ds='train'):\n    dicoms = []\n\n    for subdir, dirs, files in os.walk(f\"{input_dir}/{ds}\"):\n        for filename in files:\n            filepath = subdir + os.sep + filename\n\n            if filepath.endswith(\".dcm\"):\n                dicoms.append(filepath)\n\n    return dicoms\n\n\ndef process_dicom(dicom_src, _x):\n    dicom = pydicom.dcmread(dicom_src)\n    file_data = dicom_src.split(\"/\")\n    file_src = \"/\".join(file_data[-4:])\n\n    tmp = {\"BraTS21ID\": file_data[-3], \"dataset\": file_data[-4], \"type\": file_data[-2], \"dicom_src\": f\"./{file_src}\"}\n    tmp.update(get_meta_info(dicom))\n\n    return tmp\n\n\ndef update(res):\n    if res is not None:\n        final.append(res)\n\n    pbar.update()\n\n\ndef error(e):\n    print(e)\n\n\nif __name__ == \"__main__\":\n    ap = argparse.ArgumentParser()\n    ap.add_argument(\"--input\", type=str, default=\"./input\")\n    ap.add_argument(\"--output\", type=str, default=\"./\")\n    ap.add_argument(\"--dataset\", type=str, default=\"train\")\n    ap.add_argument(\"--n_jobs\", type=int, default=20)\n    ap.add_argument(\"--debug\", type=int, default=0)\n\n    args = vars(ap.parse_args())\n\n    dicom_files = get_dicom_files(args[\"input\"], args[\"dataset\"])\n\n    if args[\"debug\"]:\n        dicom_files = dicom_files[:1000]\n\n    pool = Pool(processes=args[\"n_jobs\"])\n    pbar = tqdm(total=len(dicom_files))\n\n    for dicom_file in dicom_files:\n        pool.apply_async(\n            process_dicom,\n            args=(dicom_file, ''),\n            callback=update,\n            error_callback=error,\n        )\n\n    pool.close()\n    pool.join()\n    pbar.close()\n\n    final = pd.DataFrame(final)\n    final.to_csv(f\"{args['output']}/dicom_meta_{args['dataset']}.csv\", index=False)\n\n```",
      "votes": 47
    },
    {
      "id": 1405397,
      "postDate": "2021-07-30T19:31:32.970Z",
      "content": "<p>To make it easier to run in a Kaggle Notebook just run this script in a cell which is an edited version of <a href=\"https://www.kaggle.com/pestipeti\" target=\"_blank\">@pestipeti</a> argparse code</p>\n<p>I also commented out the data that has only empty values.</p>\n<pre><code>import os\nimport pydicom\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom multiprocessing import Pool\nargs={}\nargs['input'] = '../input/rsna-miccai-brain-tumor-radiogenomic-classification'\nargs['output'] = './'\nargs['dataset'] = 'train'\nargs['n_jobs'] = 20\nargs['debug'] = 0\n\n\nFIELDS = [\n    'AccessionNumber',\n    'AcquisitionMatrix',\n#    'B1rms',  # Empty\n#    'BitsAllocated',  # = 16\n#    'BitsStored',  # = 16\n    'Columns',\n    'ConversionType',\n#    'DiffusionBValue',  # 0 or empty\n#    'DiffusionGradientOrientation',  # [0.0, 0.0, 0.0] or empty\n    'EchoNumbers',\n#    'EchoTime',  # empty\n    'EchoTrainLength',\n    'FlipAngle',\n#    'HighBit',  # = 15\n#    'HighRRValue',  #  0 or empty\n    'ImageDimensions',  # 2 or epty\n    'ImageFormat',\n    'ImageGeometryType',\n    'ImageLocation',\n    'ImageOrientation',\n    'ImageOrientationPatient',\n    'ImagePosition',\n    'ImagePositionPatient',\n#    'ImageType',  # ['DERIVED', 'SECONDARY']\n    'ImagedNucleus',\n    'ImagingFrequency',\n    'InPlanePhaseEncodingDirection',\n    'InStackPositionNumber',\n    'InstanceNumber',\n#    'InversionTime',   # empty\n#    'Laterality',  # empty\n#    'LowRRValue',  # empty\n    'MRAcquisitionType',\n    'MagneticFieldStrength',\n#    'Modality',  # MR\n    'NumberOfAverages',\n    'NumberOfPhaseEncodingSteps',\n    'PatientID',\n    'PatientName',\n#    'PatientPosition',  # HFS\n    'PercentPhaseFieldOfView',\n    'PercentSampling',\n#    'PhotometricInterpretation',  # MONOCHROME2\n    'PixelBandwidth',\n#    'PixelPaddingValue',  # empty or 0\n    'PixelRepresentation',\n    'PixelSpacing',\n#    'PlanarConfiguration',  # 0 or empty\n#    'PositionReferenceIndicator',  # 'NA' or empty\n    'PresentationLUTShape',\n    'ReconstructionDiameter',\n#    'RescaleIntercept',  # = 0\n#    'RescaleSlope',  # = 1\n#    'RescaleType',  # = US\n    'Rows',\n    'SAR',\n    'SOPClassUID',\n    'SOPInstanceUID',\n#    'SamplesPerPixel',  # = 1\n    'SeriesDescription',\n    'SeriesInstanceUID',\n    'SeriesNumber',\n    'SliceLocation',\n    'SliceThickness',\n    'SpacingBetweenSlices',\n    'SpatialResolution',\n    'SpecificCharacterSet',\n    'StudyInstanceUID',\n#    'TemporalResolution',  # 0 or empty\n#    'TransferSyntaxUID',  # = 1.2.840.10008.1.2\n#    'TriggerWindow',  # = 0\n    'WindowCenter',\n    'WindowWidth'\n]\n\n# All of the FM fields are empty\nFM_FIELDS = [\n    'FileMetaInformationGroupLength',\n    'FileMetaInformationVersion',\n    'ImplementationClassUID',\n    'ImplementationVersionName',\n    'MediaStorageSOPClassUID',\n    'MediaStorageSOPInstanceUID',\n    'SourceApplicationEntityTitle',\n    'TransferSyntaxUID',\n]\n\nfinal = []\n\n\ndef get_meta_info(dicom):\n    row = {f: dicom.get(f) for f in FIELDS}\n    row_fm = {f: dicom.file_meta.get(f) for f in FM_FIELDS}\n    row_other = {\n#        'is_original_encoding': dicom.is_original_encoding,  # = True\n#        'is_implicit_VR': dicom.is_implicit_VR,  # = True\n#        'is_little_endian': dicom.is_little_endian, # = True\n        'timestamp': dicom.timestamp,\n    }\n    return {**row,\n            #**row_fm,  # All are emtpy\n            **row_other}\n\n\ndef get_dicom_files(input_dir, ds='train'):\n    dicoms = []\n\n    for subdir, dirs, files in os.walk(f\"{input_dir}/{ds}\"):\n        for filename in files:\n            filepath = subdir + os.sep + filename\n\n            if filepath.endswith(\".dcm\"):\n                dicoms.append(filepath)\n\n    return dicoms\n\n\ndef process_dicom(dicom_src, _x):\n    dicom = pydicom.dcmread(dicom_src)\n    file_data = dicom_src.split(\"/\")\n    file_src = \"/\".join(file_data[-4:])\n\n    tmp = {\"BraTS21ID\": file_data[-3], \"dataset\": file_data[-4], \"type\": file_data[-2], \"dicom_src\": f\"./{file_src}\"}\n    tmp.update(get_meta_info(dicom))\n\n    return tmp\n\n\ndef update(res):\n    if res is not None:\n        final.append(res)\n\n    pbar.update()\n\n\ndef error(e):\n    print(e)\n\n\nif __name__ == \"__main__\":\n    dicom_files = get_dicom_files(args[\"input\"], args[\"dataset\"])\n\n    if args[\"debug\"]:\n        dicom_files = dicom_files[:1000]\n\n    pool = Pool(processes=args[\"n_jobs\"])\n    pbar = tqdm(total=len(dicom_files))\n\n    for dicom_file in dicom_files:\n        pool.apply_async(\n            process_dicom,\n            args=(dicom_file, ''),\n            callback=update,\n            error_callback=error,\n        )\n\n    pool.close()\n    pool.join()\n    pbar.close()\n\n    final = pd.DataFrame(final)\n    final.to_csv(f\"{args['output']}/dicom_meta_{args['dataset']}.csv\", index=False)\n</code></pre>",
      "rawMarkdown": "To make it easier to run in a Kaggle Notebook just run this script in a cell which is an edited version of @pestipeti argparse code\n\nI also commented out the data that has only empty values.\n\n```python\nimport os\nimport pydicom\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom multiprocessing import Pool\nargs={}\nargs['input'] = '../input/rsna-miccai-brain-tumor-radiogenomic-classification'\nargs['output'] = './'\nargs['dataset'] = 'train'\nargs['n_jobs'] = 20\nargs['debug'] = 0\n\n\nFIELDS = [\n    'AccessionNumber',\n    'AcquisitionMatrix',\n#    'B1rms',  # Empty\n#    'BitsAllocated',  # = 16\n#    'BitsStored',  # = 16\n    'Columns',\n    'ConversionType',\n#    'DiffusionBValue',  # 0 or empty\n#    'DiffusionGradientOrientation',  # [0.0, 0.0, 0.0] or empty\n    'EchoNumbers',\n#    'EchoTime',  # empty\n    'EchoTrainLength',\n    'FlipAngle',\n#    'HighBit',  # = 15\n#    'HighRRValue',  #  0 or empty\n    'ImageDimensions',  # 2 or epty\n    'ImageFormat',\n    'ImageGeometryType',\n    'ImageLocation',\n    'ImageOrientation',\n    'ImageOrientationPatient',\n    'ImagePosition',\n    'ImagePositionPatient',\n#    'ImageType',  # ['DERIVED', 'SECONDARY']\n    'ImagedNucleus',\n    'ImagingFrequency',\n    'InPlanePhaseEncodingDirection',\n    'InStackPositionNumber',\n    'InstanceNumber',\n#    'InversionTime',   # empty\n#    'Laterality',  # empty\n#    'LowRRValue',  # empty\n    'MRAcquisitionType',\n    'MagneticFieldStrength',\n#    'Modality',  # MR\n    'NumberOfAverages',\n    'NumberOfPhaseEncodingSteps',\n    'PatientID',\n    'PatientName',\n#    'PatientPosition',  # HFS\n    'PercentPhaseFieldOfView',\n    'PercentSampling',\n#    'PhotometricInterpretation',  # MONOCHROME2\n    'PixelBandwidth',\n#    'PixelPaddingValue',  # empty or 0\n    'PixelRepresentation',\n    'PixelSpacing',\n#    'PlanarConfiguration',  # 0 or empty\n#    'PositionReferenceIndicator',  # 'NA' or empty\n    'PresentationLUTShape',\n    'ReconstructionDiameter',\n#    'RescaleIntercept',  # = 0\n#    'RescaleSlope',  # = 1\n#    'RescaleType',  # = US\n    'Rows',\n    'SAR',\n    'SOPClassUID',\n    'SOPInstanceUID',\n#    'SamplesPerPixel',  # = 1\n    'SeriesDescription',\n    'SeriesInstanceUID',\n    'SeriesNumber',\n    'SliceLocation',\n    'SliceThickness',\n    'SpacingBetweenSlices',\n    'SpatialResolution',\n    'SpecificCharacterSet',\n    'StudyInstanceUID',\n#    'TemporalResolution',  # 0 or empty\n#    'TransferSyntaxUID',  # = 1.2.840.10008.1.2\n#    'TriggerWindow',  # = 0\n    'WindowCenter',\n    'WindowWidth'\n]\n\n# All of the FM fields are empty\nFM_FIELDS = [\n    'FileMetaInformationGroupLength',\n    'FileMetaInformationVersion',\n    'ImplementationClassUID',\n    'ImplementationVersionName',\n    'MediaStorageSOPClassUID',\n    'MediaStorageSOPInstanceUID',\n    'SourceApplicationEntityTitle',\n    'TransferSyntaxUID',\n]\n\nfinal = []\n\n\ndef get_meta_info(dicom):\n    row = {f: dicom.get(f) for f in FIELDS}\n    row_fm = {f: dicom.file_meta.get(f) for f in FM_FIELDS}\n    row_other = {\n#        'is_original_encoding': dicom.is_original_encoding,  # = True\n#        'is_implicit_VR': dicom.is_implicit_VR,  # = True\n#        'is_little_endian': dicom.is_little_endian, # = True\n        'timestamp': dicom.timestamp,\n    }\n    return {**row,\n            #**row_fm,  # All are emtpy\n            **row_other}\n\n\ndef get_dicom_files(input_dir, ds='train'):\n    dicoms = []\n\n    for subdir, dirs, files in os.walk(f\"{input_dir}/{ds}\"):\n        for filename in files:\n            filepath = subdir + os.sep + filename\n\n            if filepath.endswith(\".dcm\"):\n                dicoms.append(filepath)\n\n    return dicoms\n\n\ndef process_dicom(dicom_src, _x):\n    dicom = pydicom.dcmread(dicom_src)\n    file_data = dicom_src.split(\"/\")\n    file_src = \"/\".join(file_data[-4:])\n\n    tmp = {\"BraTS21ID\": file_data[-3], \"dataset\": file_data[-4], \"type\": file_data[-2], \"dicom_src\": f\"./{file_src}\"}\n    tmp.update(get_meta_info(dicom))\n\n    return tmp\n\n\ndef update(res):\n    if res is not None:\n        final.append(res)\n\n    pbar.update()\n\n\ndef error(e):\n    print(e)\n\n\nif __name__ == \"__main__\":\n    dicom_files = get_dicom_files(args[\"input\"], args[\"dataset\"])\n\n    if args[\"debug\"]:\n        dicom_files = dicom_files[:1000]\n\n    pool = Pool(processes=args[\"n_jobs\"])\n    pbar = tqdm(total=len(dicom_files))\n\n    for dicom_file in dicom_files:\n        pool.apply_async(\n            process_dicom,\n            args=(dicom_file, ''),\n            callback=update,\n            error_callback=error,\n        )\n\n    pool.close()\n    pool.join()\n    pbar.close()\n\n    final = pd.DataFrame(final)\n    final.to_csv(f\"{args['output']}/dicom_meta_{args['dataset']}.csv\", index=False)\n```",
      "votes": 7,
      "replies": [
        {
          "id": 1499160,
          "postDate": "2021-09-01T13:28:56.047Z",
          "content": "<p>Thanks <a href=\"https://www.kaggle.com/echo9k\" target=\"_blank\">@echo9k</a>! I implemented your code <a href=\"https://www.kaggle.com/rickandjoe/extract-metadata-from-dicom\" target=\"_blank\">here</a> and used it in my <a href=\"https://www.kaggle.com/rickandjoe/rsna-miccai-brain-tumor-domain-knowledge-eda\" target=\"_blank\">EDA</a>. </p>\n<p>However I find <code>WindowWidth</code> and <code>WindowCenter</code> columns to have different data types (string, int, float).  Do you know how to clean the <code>WindowWidth</code> and <code>WindowCenter</code> metadata columns? </p>",
          "rawMarkdown": "Thanks @echo9k! I implemented your code [here](https://www.kaggle.com/rickandjoe/extract-metadata-from-dicom) and used it in my [EDA](https://www.kaggle.com/rickandjoe/rsna-miccai-brain-tumor-domain-knowledge-eda). \n\nHowever I find `WindowWidth` and `WindowCenter` columns to have different data types (string, int, float).  Do you know how to clean the `WindowWidth` and `WindowCenter` metadata columns? "
        }
      ]
    },
    {
      "id": 1387913,
      "postDate": "2021-07-14T14:07:39.343Z",
      "content": "<p>Thanks for share excellent script. It helps a lot😍😍😍😍</p>",
      "rawMarkdown": "Thanks for share excellent script. It helps a lot😍😍😍😍",
      "votes": 1
    },
    {
      "id": 1387731,
      "postDate": "2021-07-14T11:53:05.590Z",
      "content": "<p>Thanks for showing a way for beginners like me</p>",
      "rawMarkdown": "Thanks for showing a way for beginners like me",
      "votes": 1
    },
    {
      "id": 1464719,
      "postDate": "2021-08-10T17:13:54.543Z",
      "content": "<p>Does anyone here have a code example of how I would attach this to a FastAI <code>ImageDataLoaders</code> so that it will convert from DICOM to PNG as I load the file?</p>",
      "rawMarkdown": "Does anyone here have a code example of how I would attach this to a FastAI `ImageDataLoaders` so that it will convert from DICOM to PNG as I load the file?"
    },
    {
      "id": 1390611,
      "postDate": "2021-07-16T20:52:49.780Z",
      "rawMarkdown": "",
      "isDeleted": true
    }
  ],
  "comments": [
    {
      "id": 1405397,
      "author_name": "Guillermo Alcántara",
      "author_url": "",
      "post_date": "2021-07-30T19:31:32.970000",
      "content": "<p>To make it easier to run in a Kaggle Notebook just run this script in a cell which is an edited version of <a href=\"https://www.kaggle.com/pestipeti\" target=\"_blank\">@pestipeti</a> argparse code</p>\n<p>I also commented out the data that has only empty values.</p>\n<pre><code>import os\nimport pydicom\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom multiprocessing import Pool\nargs={}\nargs['input'] = '../input/rsna-miccai-brain-tumor-radiogenomic-classification'\nargs['output'] = './'\nargs['dataset'] = 'train'\nargs['n_jobs'] = 20\nargs['debug'] = 0\n\n\nFIELDS = [\n    'AccessionNumber',\n    'AcquisitionMatrix',\n#    'B1rms',  # Empty\n#    'BitsAllocated',  # = 16\n#    'BitsStored',  # = 16\n    'Columns',\n    'ConversionType',\n#    'DiffusionBValue',  # 0 or empty\n#    'DiffusionGradientOrientation',  # [0.0, 0.0, 0.0] or empty\n    'EchoNumbers',\n#    'EchoTime',  # empty\n    'EchoTrainLength',\n    'FlipAngle',\n#    'HighBit',  # = 15\n#    'HighRRValue',  #  0 or empty\n    'ImageDimensions',  # 2 or epty\n    'ImageFormat',\n    'ImageGeometryType',\n    'ImageLocation',\n    'ImageOrientation',\n    'ImageOrientationPatient',\n    'ImagePosition',\n    'ImagePositionPatient',\n#    'ImageType',  # ['DERIVED', 'SECONDARY']\n    'ImagedNucleus',\n    'ImagingFrequency',\n    'InPlanePhaseEncodingDirection',\n    'InStackPositionNumber',\n    'InstanceNumber',\n#    'InversionTime',   # empty\n#    'Laterality',  # empty\n#    'LowRRValue',  # empty\n    'MRAcquisitionType',\n    'MagneticFieldStrength',\n#    'Modality',  # MR\n    'NumberOfAverages',\n    'NumberOfPhaseEncodingSteps',\n    'PatientID',\n    'PatientName',\n#    'PatientPosition',  # HFS\n    'PercentPhaseFieldOfView',\n    'PercentSampling',\n#    'PhotometricInterpretation',  # MONOCHROME2\n    'PixelBandwidth',\n#    'PixelPaddingValue',  # empty or 0\n    'PixelRepresentation',\n    'PixelSpacing',\n#    'PlanarConfiguration',  # 0 or empty\n#    'PositionReferenceIndicator',  # 'NA' or empty\n    'PresentationLUTShape',\n    'ReconstructionDiameter',\n#    'RescaleIntercept',  # = 0\n#    'RescaleSlope',  # = 1\n#    'RescaleType',  # = US\n    'Rows',\n    'SAR',\n    'SOPClassUID',\n    'SOPInstanceUID',\n#    'SamplesPerPixel',  # = 1\n    'SeriesDescription',\n    'SeriesInstanceUID',\n    'SeriesNumber',\n    'SliceLocation',\n    'SliceThickness',\n    'SpacingBetweenSlices',\n    'SpatialResolution',\n    'SpecificCharacterSet',\n    'StudyInstanceUID',\n#    'TemporalResolution',  # 0 or empty\n#    'TransferSyntaxUID',  # = 1.2.840.10008.1.2\n#    'TriggerWindow',  # = 0\n    'WindowCenter',\n    'WindowWidth'\n]\n\n# All of the FM fields are empty\nFM_FIELDS = [\n    'FileMetaInformationGroupLength',\n    'FileMetaInformationVersion',\n    'ImplementationClassUID',\n    'ImplementationVersionName',\n    'MediaStorageSOPClassUID',\n    'MediaStorageSOPInstanceUID',\n    'SourceApplicationEntityTitle',\n    'TransferSyntaxUID',\n]\n\nfinal = []\n\n\ndef get_meta_info(dicom):\n    row = {f: dicom.get(f) for f in FIELDS}\n    row_fm = {f: dicom.file_meta.get(f) for f in FM_FIELDS}\n    row_other = {\n#        'is_original_encoding': dicom.is_original_encoding,  # = True\n#        'is_implicit_VR': dicom.is_implicit_VR,  # = True\n#        'is_little_endian': dicom.is_little_endian, # = True\n        'timestamp': dicom.timestamp,\n    }\n    return {**row,\n            #**row_fm,  # All are emtpy\n            **row_other}\n\n\ndef get_dicom_files(input_dir, ds='train'):\n    dicoms = []\n\n    for subdir, dirs, files in os.walk(f\"{input_dir}/{ds}\"):\n        for filename in files:\n            filepath = subdir + os.sep + filename\n\n            if filepath.endswith(\".dcm\"):\n                dicoms.append(filepath)\n\n    return dicoms\n\n\ndef process_dicom(dicom_src, _x):\n    dicom = pydicom.dcmread(dicom_src)\n    file_data = dicom_src.split(\"/\")\n    file_src = \"/\".join(file_data[-4:])\n\n    tmp = {\"BraTS21ID\": file_data[-3], \"dataset\": file_data[-4], \"type\": file_data[-2], \"dicom_src\": f\"./{file_src}\"}\n    tmp.update(get_meta_info(dicom))\n\n    return tmp\n\n\ndef update(res):\n    if res is not None:\n        final.append(res)\n\n    pbar.update()\n\n\ndef error(e):\n    print(e)\n\n\nif __name__ == \"__main__\":\n    dicom_files = get_dicom_files(args[\"input\"], args[\"dataset\"])\n\n    if args[\"debug\"]:\n        dicom_files = dicom_files[:1000]\n\n    pool = Pool(processes=args[\"n_jobs\"])\n    pbar = tqdm(total=len(dicom_files))\n\n    for dicom_file in dicom_files:\n        pool.apply_async(\n            process_dicom,\n            args=(dicom_file, ''),\n            callback=update,\n            error_callback=error,\n        )\n\n    pool.close()\n    pool.join()\n    pbar.close()\n\n    final = pd.DataFrame(final)\n    final.to_csv(f\"{args['output']}/dicom_meta_{args['dataset']}.csv\", index=False)\n</code></pre>",
      "votes": 7,
      "replies": [
        {
          "id": 1499160,
          "author_name": "Jonathan Rico",
          "author_url": "",
          "post_date": "2021-09-01T13:28:56.047000",
          "content": "<p>Thanks <a href=\"https://www.kaggle.com/echo9k\" target=\"_blank\">@echo9k</a>! I implemented your code <a href=\"https://www.kaggle.com/rickandjoe/extract-metadata-from-dicom\" target=\"_blank\">here</a> and used it in my <a href=\"https://www.kaggle.com/rickandjoe/rsna-miccai-brain-tumor-domain-knowledge-eda\" target=\"_blank\">EDA</a>. </p>\n<p>However I find <code>WindowWidth</code> and <code>WindowCenter</code> columns to have different data types (string, int, float).  Do you know how to clean the <code>WindowWidth</code> and <code>WindowCenter</code> metadata columns? </p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1387913,
      "author_name": "Sani Kamal",
      "author_url": "",
      "post_date": "2021-07-14T14:07:39.343000",
      "content": "<p>Thanks for share excellent script. It helps a lot😍😍😍😍</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1387731,
      "author_name": "tharun_01",
      "author_url": "",
      "post_date": "2021-07-14T11:53:05.590000",
      "content": "<p>Thanks for showing a way for beginners like me</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1464719,
      "author_name": "Daniel Chen",
      "author_url": "",
      "post_date": "2021-08-10T17:13:54.543000",
      "content": "<p>Does anyone here have a code example of how I would attach this to a FastAI <code>ImageDataLoaders</code> so that it will convert from DICOM to PNG as I load the file?</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1390611,
      "author_name": "",
      "author_url": "",
      "post_date": "2021-07-16T20:52:49.780000",
      "content": "",
      "votes": 0,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "1387663": "You can use this small script to extract metadata from the DICOM files. \n\n### Usage\n```\npython dicom_meta.py --dataset train --input ./input --output ./ --n_jobs\n```\n- **dataset** train or test\n- **input** input folder (train | test subfolder should be inside this)\n- **output** output folder for the generated csv file\n- **n_jobs** Number of parallel processes\n\nHappy data analysis!\n\n### Code\n```\nimport argparse\nimport os\nimport pydicom\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom multiprocessing import Pool\n\nFIELDS = [\n    'AccessionNumber',\n    'AcquisitionMatrix',\n    'B1rms',\n    'BitsAllocated',\n    'BitsStored',\n    'Columns',\n    'ConversionType',\n    'DiffusionBValue',\n    'DiffusionGradientOrientation',\n    'EchoNumbers',\n    'EchoTime',\n    'EchoTrainLength',\n    'FlipAngle',\n    'HighBit',\n    'HighRRValue',\n    'ImageDimensions',\n    'ImageFormat',\n    'ImageGeometryType',\n    'ImageLocation',\n    'ImageOrientation',\n    'ImageOrientationPatient',\n    'ImagePosition',\n    'ImagePositionPatient',\n    'ImageType',\n    'ImagedNucleus',\n    'ImagingFrequency',\n    'InPlanePhaseEncodingDirection',\n    'InStackPositionNumber',\n    'InstanceNumber',\n    'InversionTime',\n    'Laterality',\n    'LowRRValue',\n    'MRAcquisitionType',\n    'MagneticFieldStrength',\n    'Modality',\n    'NumberOfAverages',\n    'NumberOfPhaseEncodingSteps',\n    'PatientID',\n    'PatientName',\n    'PatientPosition',\n    'PercentPhaseFieldOfView',\n    'PercentSampling',\n    'PhotometricInterpretation',\n    'PixelBandwidth',\n    'PixelPaddingValue',\n    'PixelRepresentation',\n    'PixelSpacing',\n    'PlanarConfiguration',\n    'PositionReferenceIndicator',\n    'PresentationLUTShape',\n    'ReconstructionDiameter',\n    'RescaleIntercept',\n    'RescaleSlope',\n    'RescaleType',\n    'Rows',\n    'SAR',\n    'SOPClassUID',\n    'SOPInstanceUID',\n    'SamplesPerPixel',\n    'SeriesDescription',\n    'SeriesInstanceUID',\n    'SeriesNumber',\n    'SliceLocation',\n    'SliceThickness',\n    'SpacingBetweenSlices',\n    'SpatialResolution',\n    'SpecificCharacterSet',\n    'StudyInstanceUID',\n    'TemporalResolution',\n    'TransferSyntaxUID',\n    'TriggerWindow',\n    'WindowCenter',\n    'WindowWidth'\n]\n\nFM_FIELDS = [\n    'FileMetaInformationGroupLength',\n    'FileMetaInformationVersion',\n    'ImplementationClassUID',\n    'ImplementationVersionName',\n    'MediaStorageSOPClassUID',\n    'MediaStorageSOPInstanceUID',\n    'SourceApplicationEntityTitle',\n    'TransferSyntaxUID',\n]\n\nfinal = []\n\n\ndef get_meta_info(dicom):\n    row = {f: dicom.get(f) for f in FIELDS}\n    row_fm = {f: dicom.file_meta.get(f) for f in FM_FIELDS}\n    row_other = {\n        'is_original_encoding': dicom.is_original_encoding,\n        'is_implicit_VR': dicom.is_implicit_VR,\n        'is_little_endian': dicom.is_little_endian,\n        'timestamp': dicom.timestamp,\n    }\n    return {**row, **row_fm, **row_other}\n\n\ndef get_dicom_files(input_dir, ds='train'):\n    dicoms = []\n\n    for subdir, dirs, files in os.walk(f\"{input_dir}/{ds}\"):\n        for filename in files:\n            filepath = subdir + os.sep + filename\n\n            if filepath.endswith(\".dcm\"):\n                dicoms.append(filepath)\n\n    return dicoms\n\n\ndef process_dicom(dicom_src, _x):\n    dicom = pydicom.dcmread(dicom_src)\n    file_data = dicom_src.split(\"/\")\n    file_src = \"/\".join(file_data[-4:])\n\n    tmp = {\"BraTS21ID\": file_data[-3], \"dataset\": file_data[-4], \"type\": file_data[-2], \"dicom_src\": f\"./{file_src}\"}\n    tmp.update(get_meta_info(dicom))\n\n    return tmp\n\n\ndef update(res):\n    if res is not None:\n        final.append(res)\n\n    pbar.update()\n\n\ndef error(e):\n    print(e)\n\n\nif __name__ == \"__main__\":\n    ap = argparse.ArgumentParser()\n    ap.add_argument(\"--input\", type=str, default=\"./input\")\n    ap.add_argument(\"--output\", type=str, default=\"./\")\n    ap.add_argument(\"--dataset\", type=str, default=\"train\")\n    ap.add_argument(\"--n_jobs\", type=int, default=20)\n    ap.add_argument(\"--debug\", type=int, default=0)\n\n    args = vars(ap.parse_args())\n\n    dicom_files = get_dicom_files(args[\"input\"], args[\"dataset\"])\n\n    if args[\"debug\"]:\n        dicom_files = dicom_files[:1000]\n\n    pool = Pool(processes=args[\"n_jobs\"])\n    pbar = tqdm(total=len(dicom_files))\n\n    for dicom_file in dicom_files:\n        pool.apply_async(\n            process_dicom,\n            args=(dicom_file, ''),\n            callback=update,\n            error_callback=error,\n        )\n\n    pool.close()\n    pool.join()\n    pbar.close()\n\n    final = pd.DataFrame(final)\n    final.to_csv(f\"{args['output']}/dicom_meta_{args['dataset']}.csv\", index=False)\n\n```",
    "1405397": "To make it easier to run in a Kaggle Notebook just run this script in a cell which is an edited version of @pestipeti argparse code\n\nI also commented out the data that has only empty values.\n\n```python\nimport os\nimport pydicom\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom multiprocessing import Pool\nargs={}\nargs['input'] = '../input/rsna-miccai-brain-tumor-radiogenomic-classification'\nargs['output'] = './'\nargs['dataset'] = 'train'\nargs['n_jobs'] = 20\nargs['debug'] = 0\n\n\nFIELDS = [\n    'AccessionNumber',\n    'AcquisitionMatrix',\n#    'B1rms',  # Empty\n#    'BitsAllocated',  # = 16\n#    'BitsStored',  # = 16\n    'Columns',\n    'ConversionType',\n#    'DiffusionBValue',  # 0 or empty\n#    'DiffusionGradientOrientation',  # [0.0, 0.0, 0.0] or empty\n    'EchoNumbers',\n#    'EchoTime',  # empty\n    'EchoTrainLength',\n    'FlipAngle',\n#    'HighBit',  # = 15\n#    'HighRRValue',  #  0 or empty\n    'ImageDimensions',  # 2 or epty\n    'ImageFormat',\n    'ImageGeometryType',\n    'ImageLocation',\n    'ImageOrientation',\n    'ImageOrientationPatient',\n    'ImagePosition',\n    'ImagePositionPatient',\n#    'ImageType',  # ['DERIVED', 'SECONDARY']\n    'ImagedNucleus',\n    'ImagingFrequency',\n    'InPlanePhaseEncodingDirection',\n    'InStackPositionNumber',\n    'InstanceNumber',\n#    'InversionTime',   # empty\n#    'Laterality',  # empty\n#    'LowRRValue',  # empty\n    'MRAcquisitionType',\n    'MagneticFieldStrength',\n#    'Modality',  # MR\n    'NumberOfAverages',\n    'NumberOfPhaseEncodingSteps',\n    'PatientID',\n    'PatientName',\n#    'PatientPosition',  # HFS\n    'PercentPhaseFieldOfView',\n    'PercentSampling',\n#    'PhotometricInterpretation',  # MONOCHROME2\n    'PixelBandwidth',\n#    'PixelPaddingValue',  # empty or 0\n    'PixelRepresentation',\n    'PixelSpacing',\n#    'PlanarConfiguration',  # 0 or empty\n#    'PositionReferenceIndicator',  # 'NA' or empty\n    'PresentationLUTShape',\n    'ReconstructionDiameter',\n#    'RescaleIntercept',  # = 0\n#    'RescaleSlope',  # = 1\n#    'RescaleType',  # = US\n    'Rows',\n    'SAR',\n    'SOPClassUID',\n    'SOPInstanceUID',\n#    'SamplesPerPixel',  # = 1\n    'SeriesDescription',\n    'SeriesInstanceUID',\n    'SeriesNumber',\n    'SliceLocation',\n    'SliceThickness',\n    'SpacingBetweenSlices',\n    'SpatialResolution',\n    'SpecificCharacterSet',\n    'StudyInstanceUID',\n#    'TemporalResolution',  # 0 or empty\n#    'TransferSyntaxUID',  # = 1.2.840.10008.1.2\n#    'TriggerWindow',  # = 0\n    'WindowCenter',\n    'WindowWidth'\n]\n\n# All of the FM fields are empty\nFM_FIELDS = [\n    'FileMetaInformationGroupLength',\n    'FileMetaInformationVersion',\n    'ImplementationClassUID',\n    'ImplementationVersionName',\n    'MediaStorageSOPClassUID',\n    'MediaStorageSOPInstanceUID',\n    'SourceApplicationEntityTitle',\n    'TransferSyntaxUID',\n]\n\nfinal = []\n\n\ndef get_meta_info(dicom):\n    row = {f: dicom.get(f) for f in FIELDS}\n    row_fm = {f: dicom.file_meta.get(f) for f in FM_FIELDS}\n    row_other = {\n#        'is_original_encoding': dicom.is_original_encoding,  # = True\n#        'is_implicit_VR': dicom.is_implicit_VR,  # = True\n#        'is_little_endian': dicom.is_little_endian, # = True\n        'timestamp': dicom.timestamp,\n    }\n    return {**row,\n            #**row_fm,  # All are emtpy\n            **row_other}\n\n\ndef get_dicom_files(input_dir, ds='train'):\n    dicoms = []\n\n    for subdir, dirs, files in os.walk(f\"{input_dir}/{ds}\"):\n        for filename in files:\n            filepath = subdir + os.sep + filename\n\n            if filepath.endswith(\".dcm\"):\n                dicoms.append(filepath)\n\n    return dicoms\n\n\ndef process_dicom(dicom_src, _x):\n    dicom = pydicom.dcmread(dicom_src)\n    file_data = dicom_src.split(\"/\")\n    file_src = \"/\".join(file_data[-4:])\n\n    tmp = {\"BraTS21ID\": file_data[-3], \"dataset\": file_data[-4], \"type\": file_data[-2], \"dicom_src\": f\"./{file_src}\"}\n    tmp.update(get_meta_info(dicom))\n\n    return tmp\n\n\ndef update(res):\n    if res is not None:\n        final.append(res)\n\n    pbar.update()\n\n\ndef error(e):\n    print(e)\n\n\nif __name__ == \"__main__\":\n    dicom_files = get_dicom_files(args[\"input\"], args[\"dataset\"])\n\n    if args[\"debug\"]:\n        dicom_files = dicom_files[:1000]\n\n    pool = Pool(processes=args[\"n_jobs\"])\n    pbar = tqdm(total=len(dicom_files))\n\n    for dicom_file in dicom_files:\n        pool.apply_async(\n            process_dicom,\n            args=(dicom_file, ''),\n            callback=update,\n            error_callback=error,\n        )\n\n    pool.close()\n    pool.join()\n    pbar.close()\n\n    final = pd.DataFrame(final)\n    final.to_csv(f\"{args['output']}/dicom_meta_{args['dataset']}.csv\", index=False)\n```",
    "1387913": "Thanks for share excellent script. It helps a lot😍😍😍😍",
    "1387731": "Thanks for showing a way for beginners like me",
    "1464719": "Does anyone here have a code example of how I would attach this to a FastAI `ImageDataLoaders` so that it will convert from DICOM to PNG as I load the file?",
    "1390611": ""
  }
}