1. 目的
2. 準備
2.1. pydicomのインストール
2.2. dcm2nii / dcm2niixのPATH設定
3. ソースコード
3.1. dcm2niiバージョン
3.2. dcm2niixバージョン
4. 使い方
1. 目的
- 様々なSeriesDescriptionで撮像されたDICOMデータを、SeriesDescriptionごとにフォルダ分け
- DICOMをNIfTI変換
- Pythonで実行
2. 準備
2.1. pydicomのインストール
PythonでDICOMを扱うために、pydicomを用いる。
pip3 install pydicom
2.2. dcm2nii / dcm2niixのPATH設定
dcm2nii
あるいはdcm2niix
のPATHを通す(言い換えれば、dcm2nii
やdcm2niix
はここにありますよ!ってPCに教えてあげるイメージ。もともと、dcm2niix
というコマンドはないけど、dcm2niix
にPATHが通してあることで、PC側でああ、あのdcm2niix
を実行しろということね?とdcm2niix
を実行してくれる)。
PATHの通し方は、以下の記事を参考にするとよい。
3. ソースコード
実際に、DICOMをNIfTIに変換するソフトは、Chris Rorden教授が開発したdcm2niiを用いる。
近年、dcm2niiの開発は終了し、代わりにdcm2niixの開発に移行したので最新版を使用したければdcm2niixを用いるとよい。
3.1. dcm2niiバージョン
dcm2niiを用いたソースコードは、次の通り。
以下のファイルを「dcm_sconv.py」として保存。
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys, os, time, re, shutil, argparse, subprocess import pydicom #from memory_profiler import profile __version__ = '1.2 (2020/01/27)' __desc__ = ''' sort dicom files, convert to nifti. ''' __epilog__ = ''' examples: dcm_sconv DICOM_DIR dcm_sconv DICOM_DIR -o SORTED_DICOM_DIR -n NIFTI_DIR dcm_sconv DICOM_DIR -o SORTED_DICOM_DIR -n NIFTI_DIR -r InstanceCreatorUID # --rule # SeriesDescription ... default # InstanceCreatorUID # SeriesTime ''' def generate_dest_dir_name(dicom_dataset, rule): datetime = name = "%s-%s" % (dicom_dataset.SeriesDate, dicom_dataset.SeriesTime) if rule == 'SeriesDescription': rule_text = dicom_dataset.SeriesDescription elif rule == 'InstanceCreatorUID': rule_text = dicom_dataset.InstanceCreatorUID elif rule == 'SeriesTime': rule_text = dicom_dataset.SerieseTime return re.sub(r'[\\|/|:|?|"|<|>|\|]|\*', '', name + '_' + rule_text) #@profile def copy_dicom_files(src_dir, out_dir, rule, nifdir): dir_names = [] # copy files for root, dirs, files in os.walk(src_dir): for file in files: try: src_file = os.path.join(root, file) dataset = pydicom.dcmread(src_file) dest_dir_name = generate_dest_dir_name(dataset, rule) dest_dir = os.path.join(out_dir, dest_dir_name) dir_names.append(dest_dir_name) os.makedirs(dest_dir, exist_ok=True) shutil.copy2(src_file, dest_dir) print("copy %s -> %s" % (src_file, dest_dir)) except: pass # convert files if nifdir: for dir_name in sorted(set(dir_names)): dest_dir = os.path.join(nifdir, dir_name) src_dir = os.path.join(out_dir, dir_name) os.makedirs(dest_dir, exist_ok=True) command = 'dcm2nii -o "%s" "%s"' % (os.path.abspath(dest_dir), os.path.abspath(src_dir)) print(command) subprocess.run(command, shell=True) if __name__ == '__main__': start_time = time.time() parser = argparse.ArgumentParser(description=__desc__, epilog=__epilog__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('dirs', metavar='DICOM_DIR', help='DIROM directory.', nargs=1) parser.add_argument('-r', '--rule', metavar='RULE', default='SeriesDescription', help='classification rule. deafult SeriesDescription') parser.add_argument('-o', '--out', metavar='OUT_DIR', default='.', help='output directory. default: CWD') parser.add_argument('-n', '--nifdir', metavar='NIFTI_DIR', help='convert nifti to NIFTI_DIR.') err = 0 try: args = parser.parse_args() copy_dicom_files(args.dirs[0], args.out, args.rule, args.nifdir) print("execution time: %.2f second." % (time.time() - start_time)) except Exception as e: print("%s: error: %s" % (__file__, str(e))) err = 1 sys.exit(err)
3.2. dcm2niixバージョン
dcm2niixを用いたソースコードは、次の通り。
以下のファイルを「dcm_sconv.py」として保存。
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys, os, time, re, shutil, argparse, subprocess import pydicom __version__ = '1.0 (2021/03/03)' __desc__ = ''' sort dicom files, convert to nifti. dcm2niix version. ''' __epilog__ = ''' examples: dcm_sconv DICOM_DIR dcm_sconv DICOM_DIR -o SORTED_DICOM_DIR -n NIFTI_DIR dcm_sconv DICOM_DIR -o SORTED_DICOM_DIR -n NIFTI_DIR -r InstanceCreatorUID ''' def generate_dest_dir_name(dicom_dataset): name = "%d_%s-%s_%s" % (dicom_dataset.SeriesNumber, dicom_dataset.SeriesDate, dicom_dataset.SeriesTime, dicom_dataset.SeriesDescription) name = re.sub(r'/', '-', name) name = re.sub(r' ', '_', name) name = re.sub(r'\*', 'x', name) return re.sub(r'[\\|/|:|?|"|<|>|\|]', '', name) def copy_dicom_files(src_dir, out_dir, nifdir): dir_names = [] # copy files for root, dirs, files in os.walk(src_dir): for file in files: try: src_file = os.path.join(root, file) dest_dir_name = generate_dest_dir_name(pydicom.dcmread(src_file)) print(src_file, dest_dir_name) dest_dir = os.path.join(out_dir, dest_dir_name) dir_names.append(dest_dir_name) os.makedirs(dest_dir, exist_ok=True) shutil.copy2(src_file, dest_dir) print("copy %s -> %s" % (src_file, dest_dir)) except: pass # convert files if nifdir: for dir_name in sorted(set(dir_names)): dest_dir = os.path.join(nifdir, dir_name) src_dir = os.path.join(out_dir, dir_name) os.makedirs(dest_dir, exist_ok=True) command = 'dcm2niix -z y -o "%s" "%s"' % (os.path.abspath(dest_dir), os.path.abspath(src_dir)) print(command) subprocess.run(command, shell=True) if __name__ == '__main__': start_time = time.time() parser = argparse.ArgumentParser(description=__desc__, epilog=__epilog__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('dirs', metavar='DICOM_DIR', help='DIROM directory.', nargs=1) parser.add_argument('-o', '--out', metavar='OUT_DIR', default='.', help='output directory. default: CWD') parser.add_argument('-n', '--nifdir', metavar='NIFTI_DIR', help='convert nifti to NIFTI_DIR.', default=None) err = 0 try: args = parser.parse_args() print(args.dirs[0]) print(args.out) copy_dicom_files(args.dirs[0], args.out, args.nifdir) print("execution time: %.2f second." % (time.time() - start_time)) except Exception as e: print("%s: error: %s" % (__file__, str(e))) err = 1 sys.exit(err)
4. 使い方
dcm_sconv.pyの基本的な使い方は、以下の通り。
デフォルトでは、「SeriesDescription」でDICOMをソートする。
- -r : ソートために参照するタグ
- -o : ソートされたDICOMの出力先
- -n : NIfTIの出力先
usage: dcm_sconv.py [-h] [-r RULE] [-o OUT_DIR] [-n NIFTI_DIR] DICOM_DIR sort dicom files, convert to nifti. positional arguments: DICOM_DIR DIROM directory. optional arguments: -h, --help show this help message and exit -r RULE, --rule RULE classification rule. deafult SeriesDescription -o OUT_DIR, --out OUT_DIR output directory. default: CWD -n NIFTI_DIR, --nifdir NIFTI_DIR convert nifti to NIFTI_DIR. examples: dcm_sconv DICOM_DIR dcm_sconv DICOM_DIR -o SORTED_DICOM_DIR -n NIFTI_DIR dcm_sconv DICOM_DIR -o SORTED_DICOM_DIR -n NIFTI_DIR -r InstanceCreatorUID # --rule # SeriesDescription ... default # InstanceCreatorUID # SeriesTime
例えば、ソート前の「DICOM」フォルダがあり、ソートしたDICOMを「DICOM_sort」フォルダに、NIfTI変換したものを「NIfTI」フォルダに出力する場合、次のようなコマンドを実行する。
dcm_sconv.py DICOM -o DICOM_sort -n NIfTI
実行すると、次のようにソートしたDICOMフォルダ(DICOM_sort)とDICOMをNIfTIに変換したNIfTIフォルダ(NIfTI)が出力される。
. ├── DICOM │ └── 20210215 │ └── 09430000 │ ├── 43170000 │ ├── 43170001 │ ├── 43170002 │ ├── 43170003 │ ├── 43170004 │ ├── 43170005 │ ├── 43170006 │ ├── 43170007 │ └── 43170008 ├── DICOM_sort │ ├── 20210215-084713.807000_AAHead_Scout │ ├── 20210215-084714.204000_AAHead_Scout_MPR_sag │ ├── 20210215-084714.279000_AAHead_Scout_MPR_cor │ ├── 20210215-084714.304000_AAHead_Scout_MPR_tra │ ├── 20210215-084917.121000_diffusion_ep2d_tra_TRACEW_DFC │ ├── 20210215-084917.352000_diffusion_ep2d_tra_ADC_DFC │ ├── 20210215-085009.550000_flair_tse_tra │ ├── 20210215-085420.073000_Head_MRA_ToF3d_p3 │ ├── 20210215-085421.657000_Head_MRA_ToF3d_p3_MIP_SAG │ ├── 20210215-085421.691000_Head_MRA_ToF3d_p3_MIP_COR │ ├── 20210215-085421.729000_Head_MRA_ToF3d_p3_MIP_TRA │ ├── 20210215-085434.632000_AC-PC_tra_setup │ ├── 20210215-085542.913000_MIP Range │ ├── 20210215-085549.528000_MIP Range[1] │ ├── 20210215-090029.565000_T1_MPR │ ├── 20210215-090041.792000_T1_MPR_MPR_Cor │ ├── 20210215-090042.377000_T1_MPR_MPR_Tra │ ├── 20210215-090601.946000_T2_SPC │ ├── 20210215-090621.390000_T2_SPC_MPR_Cor │ ├── 20210215-090622.471000_T2_SPC_MPR_Tra │ ├── 20210215-090738.025000_DWI_AP_dir68_SBRef │ ├── 20210215-090738.052000_DWI_AP_dir68 │ ├── 20210215-091149.566000_DWI_PA_dir69_SBRef │ ├── 20210215-091149.596000_DWI_PA_dir69 │ ├── 20210215-091447.563000_SEField1_AP │ ├── 20210215-091618.024000_BOLD_REST1_AP_SBRef │ ├── 20210215-091618.051000_BOLD_REST1_AP │ ├── 20210215-092008.622000_SEField1_PA │ ├── 20210215-092141.948000_BOLD_REST1_PA_SBRef │ ├── 20210215-092141.981000_BOLD_REST1_PA │ ├── 20210215-092810.969000_ASL_ADNI │ ├── 20210215-092811.016000_Perfusion_Weighted │ ├── 20210215-093329.565000_QSM_3D │ ├── 20210215-093329.770000_QSM_3D │ ├── 20210215-093405.589000_PhoenixZIPReport │ ├── 20210215-093425.884000_T2Star_Images │ └── 20210215-093747.855000_tse3_t1_Conc1_p1_Neuromelanin └── NIfTI ├── 20210215-084713.807000_AAHead_Scout ├── 20210215-084714.204000_AAHead_Scout_MPR_sag ├── 20210215-084714.279000_AAHead_Scout_MPR_cor ├── 20210215-084714.304000_AAHead_Scout_MPR_tra ├── 20210215-084917.121000_diffusion_ep2d_tra_TRACEW_DFC ├── 20210215-084917.352000_diffusion_ep2d_tra_ADC_DFC ├── 20210215-085009.550000_flair_tse_tra ├── 20210215-085420.073000_Head_MRA_ToF3d_p3 ├── 20210215-085421.657000_Head_MRA_ToF3d_p3_MIP_SAG ├── 20210215-085421.691000_Head_MRA_ToF3d_p3_MIP_COR ├── 20210215-085421.729000_Head_MRA_ToF3d_p3_MIP_TRA ├── 20210215-085434.632000_AC-PC_tra_setup ├── 20210215-085542.913000_MIP Range ├── 20210215-085549.528000_MIP Range[1] ├── 20210215-090029.565000_T1_MPR ├── 20210215-090041.792000_T1_MPR_MPR_Cor ├── 20210215-090042.377000_T1_MPR_MPR_Tra ├── 20210215-090601.946000_T2_SPC ├── 20210215-090621.390000_T2_SPC_MPR_Cor ├── 20210215-090622.471000_T2_SPC_MPR_Tra ├── 20210215-090738.025000_DWI_AP_dir68_SBRef ├── 20210215-090738.052000_DWI_AP_dir68 ├── 20210215-091149.566000_DWI_PA_dir69_SBRef ├── 20210215-091149.596000_DWI_PA_dir69 ├── 20210215-091447.563000_SEField1_AP ├── 20210215-091618.024000_BOLD_REST1_AP_SBRef ├── 20210215-091618.051000_BOLD_REST1_AP ├── 20210215-092008.622000_SEField1_PA ├── 20210215-092141.948000_BOLD_REST1_PA_SBRef ├── 20210215-092141.981000_BOLD_REST1_PA ├── 20210215-092810.969000_ASL_ADNI ├── 20210215-092811.016000_Perfusion_Weighted ├── 20210215-093329.565000_QSM_3D ├── 20210215-093329.770000_QSM_3D ├── 20210215-093405.589000_PhoenixZIPReport ├── 20210215-093425.884000_T2Star_Images └── 20210215-093747.855000_tse3_t1_Conc1_p1_Neuromelanin
ピングバック: 【MRtrix】MRtrixを用いた拡散MRIの前処理 ~歪み・頭の動き・渦電流の補正~