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の前処理 ~歪み・頭の動き・渦電流の補正~