過去のPhilipsのfMRIデータをdcm2niixで変換しようとした時に4次元データにならない問題の解決法

ある施設のrs-fMRIのDICOMデータをNiftiに変換しようとした時に、以下のようになってしまい、4次元データができませんでした。

sub1_+rsfMRI_201.nii
sub1_+rsfMRI_201_t10000.nii
sub1_+rsfMRI_201_t100000.nii
sub1_+rsfMRI_201_t102500.nii
sub1_+rsfMRI_201_t105000.nii
sub1_+rsfMRI_201_t107500.nii
sub1_+rsfMRI_201_t110000.nii
sub1_+rsfMRI_201_t112500.nii
sub1_+rsfMRI_201_t115000.nii
sub1_+rsfMRI_201_t117500.nii
sub1_+rsfMRI_201_t120000.nii
sub1_+rsfMRI_201_t122500.nii
sub1_+rsfMRI_201_t12500.nii
...

ポイントは、ファイル名の後ろに tの後に数字がつくことです。

この原因を探っていたところ、dcm2niixのGitHubページを見つけました。
https://github.com/rordenlab/dcm2niix/issues/428

ここで開発者のChris Rorden教授が以下のように述べています。

your files have a bogus value for cardiac trigger time (0018,1060). This is a limitation of your images, not dcm2niix. You should work with your Philips Research Collaboration manager to fix your scanner. For archival-quality data you could purge the invalid tags from your images, e.g. gdcmanon –dumb –remove 0018,1060 -i … -o …

Cardiac Trigger Timeというタグに値が入ってしまっていることで、dcm2niixはこれを別々のものと認識してひとつにしないようです。過去に撮像したデータの場合、0018,1060を削除するのは一手ではないかとおっしゃっています。実際に確認したところ、そのタグが入っていました。

そこで、このタグを削除する以下のようなPythonスクリプトを書いてみました。pydicomが入っていれば動くはずです。
こちらから手に入れられます。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Script to remove trigger time from Philips fMRI
# source: https://github.com/rordenlab/dcm2niix/issues/428
# 14 Oct 2023 K. Nemoto

import sys, os, time, argparse
import pydicom

__version__ = '20231004'

__desc__ = '''
Remove Trigger Time (0018,1060) from Philips rsfMRI
'''
__epilog__ = '''
examples:
  dcm_rm_trigger_time.py DICOM_DIR1 DICOM_DIR2 ...
'''

def remove_triggertime(src_dir):
    # modify files
    for root, dirs, files in os.walk(src_dir):
        for file in files:
            try:
                src_file = os.path.join(root, file)
                ds = pydicom.dcmread(src_file)
                pid = src_dir.replace('/','')
                del ds[0x0018, 0x1060]
                ds.save_as(src_file)
            except:
                pass

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='DICOM directories.', nargs='+')

    err = 0
    try:
        args = parser.parse_args()
        for dicom_dir in args.dirs:  # Loop through all the provided directories
            print(f'remove dicom tag (0018,1060) from {dicom_dir}')
            remove_triggertime(dicom_dir)
        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)

これは、

dcm_rm_triggertime.py DICOMフォルダ

とすることで、そのフォルダ内のtrigger timeタグを削除します。

この処理をした後のDICOMを使って dcm2niix を行ったところ、問題なく変換されました。

困っている人がいると思うので共有しておきます。

dcm2niix -r y でDICOMソートができる!

DICOMファイルがひとつのディレクトリに入っていて、パルスシーケンスごとにわけたくなることがありませんか?
これまで、私はpydicomを使ったり、DCMTKのツールを使ったスクリプトを使用していました。
しかし、先日、dcm2niixにDICOMソート機能があることを知りました。

ヘルプには

-r : rename instead of convert DICOMs (y/n, default n)

としか書いていないのですが、dcm2niix のGitHubのissue 604に以下の記載がありました。
https://github.com/rordenlab/dcm2niix/issues/604#issuecomment-1120269405

dcm2niix -r y /path/to/DICOMS – this will simply rename rather than convert the data. It sorts each session into a separate folder, which makes subsequent conversion much easier.

実際試してみます。DICOM というディレクトリにDICOM画像が入っていて、sorted というディレクトリに保存したいとします。

mkdir sorted
dcm2niix -r y -o sorted DICOM

これで見事、sortedディレクトリの下に撮像年月日のディレクトリが作成され、その下にシーケンスごとにサブディレクトリにソートされたDICOM画像ができていました!

既に匿名化されているDICOMなどは、これを使うだけでソートが問題なくできますね。

知られていない裏技だと思うので紹介しておきます。

MRIcroGL および dcm2niix の MacOSでのセットアップ方法

2019.01.07 追記: MRIcroGLは開発者のChris Rorden教授のGitHubから直接ダウンロードした方がバージョンが新しいので、こちらで案内することとしました。

DICOM -> nifti ツールとして dcm2nii が有名ですが、開発者の Chris Rorden は、 dcm2nii の開発はすでに終了しており、後継の dcm2niix の開発を継続しています。
dcm2niix は dcm2nii よりも変換速度が非常に速く、BIDS形式にも対応しているなど、使い勝手も向上しています。
MRIcroGLに搭載されていますので、MRIcroGLをインストールすることで使えますが、パスの設定を通しておかないともったいないのでその方法を記載します。

続きを読む