シェルスクリプトを記載する時、bashで実行されることを意識する際、冒頭のシェバン (shebang) 行に
#!/bin/bash
と記載することが多いです。
Linuxではこれで全く問題ないのですが、近年の macOS の状況を見ていると、これはちょっと考え直した方がいいかなと思ってきました。
簡潔に言うと、
#!/usr/bin/env bash
とするのが汎用性の高い運用になると思います。
シェルスクリプトを記載する時、bashで実行されることを意識する際、冒頭のシェバン (shebang) 行に
#!/bin/bash
と記載することが多いです。
Linuxではこれで全く問題ないのですが、近年の macOS の状況を見ていると、これはちょっと考え直した方がいいかなと思ってきました。
簡潔に言うと、
#!/usr/bin/env bash
とするのが汎用性の高い運用になると思います。
mkdir -p
は mkdir --parents
であり、必要に応じて親ディレクトリを作成する便利なオプションです。
しかし、ふと、man を見たらもうひとつの機能があることに気づきました。それは「ディレクトリが存在していてもエラーを返さない」というものです。
私はこれまでいつもスクリプトでディレクトリを作成する際は、
[[ -d some_directory ]] || mkdir some_directory
としていました。
しかし、実は、これは
mkdir -p some_directory
で終わってしまうということですね。
小さなことですが、勉強になったので、備忘録として記録しておきます。
NVIDIAのGPUドライバーがプロプライエタリからオープンソースに移行したことに伴い、過去にプロプライエタリドライバを使っていた方がアップデートがうまくいかずトラブル場合が多々あります。
その時の対処法を以下に示します。
私はWindowsは仮想環境で使うことが多いのですが、Windows11が22H2以降、アップデートできない現象に遭遇しました。
対処法を簡単に書いておきます。検索すればたくさん情報は出てきます。ちなみに、これはシステム要件を満たしているのにアップデートできない場合とお考えください。
Windows11のISOを入手。方法は2つ
コマンドプロンプトを管理者権限で実行
マウントされたドライブに移動。Dドライブなら cd d:
で移動できる
以下のコマンドを実行
setup /product server
やはり、最後の手段はCLIですね。
VirtualBox上でDebianをインストールしていろいろ試しているのですが、Guest Additionsをインストールしようとしてちょっと困ったので、備忘録として残しておきます。
cd /media/cdrom sudo sh VBoxLinuxAdditions.run
でいけます
最初、普通Ubuntuでやるように
cd /media/cdrom sudo ./VBoxLinuxAdditions.run
としたところ、
sudo: unable to execute ./VBoxLinuxAdditions.run: Permission denied
となりました。
なんでだろうと思ったところ、https://forums.virtualbox.org/viewtopic.php?t=58799にヒントが書かれていました。
cdromをマウントする際、/etc/fstabに
/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0
と書かれています。この noauto を exec にすることで、実行可能になるということでした。
もちろん、これを exec に変えるのも方法ですが、この場合、任意のCDが実行されてしまうリスクもはらんでいます。
それ以外の方法がないかと考えたところ、直接実行するのではなく、シェルから実行するという方法があるかなと思いました。
そうしたら、上記のリンクの最後にその旨が書かれていました。
なので、実際に試してみました。
cd /media/cdrom sudo sh VBoxLinuxAdditions.run
そうしたところ、あっさりと動きました。
スクリプトを直接実行ではなく、シェルから実行というのは常に頭のどこかに置いておくといいんだなということを学びました。
PythonのPydicomライブラリを用いて、DICOMヘッダーをCSVにまとめて保存
Pydicomは、DICOMのヘッダーや画像を操作するのに用いるライブラリである。
Pydicomのインストールは、以下のコマンドを実行。
pip3 install pydicom
CSV形式の表データを扱うには、Pandasライブラリを用いる。
Pandasライブラリのインストールは、以下のコマンドを実行。
pip3 install pandas
次のような、フォルダ構造でデータを準備する。この場合では、各被験者フォルダの中にDICOMが保存されている。
DICOM_folder ├── Subject001 │ ├── XXX.dcm │ ├── ... │ └── XXX.dcm ├── Subject002 │ ├── XXX.dcm │ ├── ... │ └── XXX.dcm ├── ... └── SubjectXXX
次のコードを、extract_dcm_header.py
として保存する。このとき、スクリプトはDICOM_folder
フォルダと同じ階層に保存する。
import os import pydicom import pandas as pd input='DICOM_folder' # Input folder output='dicom_headers.csv' # Output CSV dcm_dfs = [] failed_files = [] processed_files = [] for root, _, files in os.walk(input): # Find DICOM file for each subject if len(files) != 0: # If DICOM files exist try: f = os.path.join(root, files[0]) dcm = pydicom.dcmread(f) # Read DICOM _df = pd.DataFrame({dcm[k].keyword: [dcm[k].value] for k in dcm.keys() if dcm[k].keyword != "PixelData"}) # Read Headers dcm_dfs.append(_df) # Gather headers of all subjects in a list processed_files.append(f) except: failed_files.append(f) dcm_dfs = pd.concat(dcm_dfs, ignore_index=True) # Concat headers of all subjects in a table dcm_dfs.to_csv(output, index=False) # Save as CSV
2.3. スクリプトの準備で用意した、extract_dcm_header.py
を実行するには、次のコマンドを実行する。
python3 ./extract_dcm_header.py
収集したDICOMヘッダーは、dicom_headers.csv
として保存される。
まず、必要なライブラリを読み込む。
import os import pydicom import pandas as pd
ここでは、入力となるDICOMフォルダーと出力となるDICOMヘッダーのまとまったCSVの名前を定義している。
今回の場合だとinput='DICOM_folder'
、output='dicom_headers.csv'
。
input='DICOM_folder' # Input folder output='dicom_headers.csv' # Output CSV
データを格納するための、箱(リスト)を定義。
dcm_dfs = [] failed_files = [] processed_files = []
被験者ごとのDICOMファイルを検索。
for root, _, files in os.walk(input): # Find DICOM file for each subject
DICOMファイルがある場合のみ、処理を実行。
if len(files) != 0: # If DICOM files exist
Pydicomを用いて、DICOMデータを読み込む。
try: f = os.path.join(root, files[0]) dcm = pydicom.dcmread(f) # Read DICOM
DICOMからヘッダー(Header)情報を、Pandasで読み込む。
PixelData
タグを含めると、出力(CSV)が崩れておかしくなるので、収集に含めないようにしている。
_df = pd.DataFrame({dcm[k].keyword: [dcm[k].value] for k in dcm.keys() if dcm[k].keyword != "PixelData"}) # Read Headers
収集した結果を、被験者ごとに処理をして、一つの箱(リスト)にまとめる。
dcm_dfs.append(_df) # Gather headers of all subjects in a list processed_files.append(f) except: failed_files.append(f)
すべての被験者のヘッダー情報を、一つの表形式のデータ(DataFrame
型)に変換する。
dcm_dfs = pd.concat(dcm_dfs, ignore_index=True) # Concat headers of all subjects in a table
結果を、CSVとして保存する。
dcm_dfs.to_csv(output, index=False) # Save as CSV
ときどきこの質問を受けるので言及しておきます。
2024年4月にUbuntu 24.04が公開されました。
しかし、Ubuntu 24.04上では現行のFreeSurfer 7.4.1は動きません。
このため、FreeSurferを実行したい場合は、しばらくUbuntu 22.04からアップグレードしないようにしましょう。
SPMで位置合わせする方法は2つあります。
ここでは、Coregister について述べます。
Pythonを勉強していると、「この型のメソッドは何だろう?」と思う時があります。
この時、オブジェクトを obj とすると
dir(obj)
とすることで、一覧を得ることができます。
たとえば、リスト型のメソッドを知りたいとします。dir() を使うと以下のようになります。
x = [1, 2] dir(x) [code lang=text] ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] [/code]
ここで、”–” からはじまるメソッドは特殊メソッドと言われ、その型の振る舞いを細かく調整するものとのことです。今回はここには踏み込みません。
今、私は、「通常メソッドだけリストアップしたい」と思いました。どうしたらできるでしょうか?
UNIX系OSで、 df
というコマンドがあります。ファイルシステムのディスク使用量を知るためのコマンドです。
df -h
はファイルサイズをわかりやすく示してくれます。
それぞれの違いを見てみます。
seq -w
は、連続する数字のゼロ埋めをする時に便利です。
たとえば
seq -w 10 とすると
$ seq -w 10 01 02 03 04 05 06 07 08 09 10
となります。ひと桁の数字も最初に0をつけて2桁になるようにしてくれます。
Ubuntu 22.04 から、ターミナルでの変数を使ったディレクトリ移動が厄介になりました。
例を挙げます。
FSLのインストールパス は変数 $FSLDIR に入っています。私はこれまでは、$FSLDIR/standard にアクセスしたい場合
cd $FSLDIR までタイプしたら、その後、タブキーをタイプすると、シェルが自動で cd /usr/local/fsl と変数を展開してくれて、その後のディレクトリをタイプしていました。
しかし、Ubuntu 22.04 から、同じことをすると
cd \$FSLDIR/
と変数がエスケープされてしまい展開されなくなってしまいました。
これは不便です。
調べたところ、shopt というコマンドがあることを知りました。
過去に、Anacondaに頼らない、pipとvenvを用いたPython環境の構築 という記事を書きました。今回、改めて、Pythonの仮想環境について理解が深まったので書きたいと思います。
また、LinuxやmacOSにおいて、Pythonは、システムの重要なところを担っていたりします。Ubuntuであれば、 dpkg -l | grep python3
とすると、どれだけ多くの Python3に関連したパッケージがシステムにインストールされているかを確認することができます。
このような状況において、システムのPythonに追加でパッケージを入れていって、もし不具合が起きた場合、システムそのものが不安定になる可能性があります。
Pythonの仮想環境を使うと、システムの中に、独立したPythonの環境を構築することができます。「独立している」というのは、システムに一切影響を与えないということを意味します。不要になったらばっさり削除しても一切問題ありません。
そこで、以下で、仮想環境の構築の仕方を解説します
macOSでPythonを使おうとする時、様々な選択肢があります。
まず、それぞれのインストール方法とそのPythonのパスを明確にします。バージョンは2024年1月現在のものになります。
2023年11月9日に普通にアップデートしたら以下の問題が発生しました。
環境はUbuntu 22.04です。
$ sudo apt update ---(中略)--- これらを直すためには 'apt --fix-broken install' を実行する必要があるかもしれません。 以下のパッケージには満たせない依存関係があります: nvidia-dkms-535 : 依存: nvidia-kernel-common-535 (= 535.129.03-0ubuntu1) しかし、535.129.03-0ubuntu0.22.04.1 はインストールされています nvidia-driver-535 : 依存: nvidia-compute-utils-535 (= 535.129.03-0ubuntu1) しかし、535.129.03-0ubuntu0.22.04.1 はインストールされています 推奨: libnvidia-gl-535:i386 (= 535.129.03-0ubuntu1) E: 未解決の依存関係です。'apt --fix-broken install' を実行してみてください (または解法を明示してください)。
nvidia-dkms-535 が nvidia-kernel-common-535 に依存しているとあります。
よくみると、
nvidia-kernel-common-535は
535.129.03-0ubuntu1 が必要なようですが、 535.129.03-0ubuntu0.22.04.1がインストールされていると言われています。
バージョンの小さな違いがエラーを引き起こしているようです。
ある施設の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 を行ったところ、問題なく変換されました。
困っている人がいると思うので共有しておきます。
Windows 10/11 では、Windows Subsystem for Linux (WSL) を使ってUbuntuなどのLinuxをインストールできます。WSL2 を使うと、GPUも使えるとのことです。
しかし、WSL2は基本、コマンドラインです。LinuxのGUIを起動するためには、工夫が必要です。現在、いくつかのアプリが公開されていますが、FSLの公式ページでは、VcXsrv を勧めていますのでそれを使うのが無難でしょう。
Ubuntu 22.04 も発表されて1年が過ぎて安定してきましたので、ここでは、
をいれたうえで、FSL をインストールしてみます。
なお、このページは、FSLの公式サイトを参考に作成しました。
When using FreeSurfer and FSL 6.0.6 or later, a certain issue may arise:
First, I will explain how to confirm if you are affected by this issue and then provide the solutions along with the reasons.
FreeSurfer と FSL 6.0.6以降を使っていると、ある事象が起きます。
これの影響を受けているかの確認法および対処法を最初に解説した後、その理由を述べます。