Skip to content

Commit

Permalink
[ENH] add MEG support
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Levitas committed Jan 18, 2024
1 parent 920fceb commit befac12
Show file tree
Hide file tree
Showing 9 changed files with 674 additions and 110 deletions.
2 changes: 1 addition & 1 deletion handler/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ RUN apt update && \
RUN apt install -y parallel python3 python3-pip tree curl unzip git jq python libgl-dev python-numpy

RUN pip3 install numpy==1.23.0 nibabel==4.0.0 pandas==1.0.1 matplotlib pyyaml==5.4.1 pydicom==2.3.1 natsort pydeface && \
pip3 install quickshear pypet2bids
pip3 install quickshear pypet2bids mne mne-bids

RUN apt-get install -y build-essential pkg-config cmake git pigz rename zstd libopenjp2-7 libgdcm-tools wget libopenblas-dev && \
apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y
Expand Down
4 changes: 4 additions & 0 deletions handler/bids.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ rootDir="$root/bids/$datasetName"
#clean up from previous run
rm -rf $root/bids

# run MEG BIDS conversion if relevant data found
echo "converting MEG data (if present)"
./convert_meg.py $root/finalized.json $rootDir

echo "converting output to bids"
./convert.js $root

Expand Down
93 changes: 93 additions & 0 deletions handler/convert_meg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env python3

"""
Takes the ezBIDS data (finalized.json) and uses MNE-BIDS to perform the BIDS conversion for this
specific modality data.
"""

import sys
import json
from mne.io import read_raw
from mne_bids import (BIDSPath, write_raw_bids)

# Begin:
finalized_json_data = json.load(open(sys.argv[1]), strict=False)
bids_root_dir = sys.argv[2]

# subjects = finalized_json_data["subjects"] # Is this the final say?
subjects = [x["_entities"]["subject"] for x in finalized_json_data["objects"]]

# Let's see how many MEG objects there are
for obj in finalized_json_data["objects"]:
obj_type = obj["_type"]
if "meg" in obj_type:
datatype = "meg"
img_data = obj["_SeriesDescription"]

raw = read_raw(img_data, verbose=0)

# Get entity information
entities = obj["_entities"]
sub_idx = obj["subject_idx"]
ses_idx = obj["session_idx"]

# sub
sub = subjects[sub_idx]["subject"]

# ses
ses = subjects[sub_idx]["sessions"][ses_idx]
if ses["session"] == "" or ses["exclude"] is True:
ses = None

# task
task = entities["task"]

# acquisition
if entities["acquisition"] == "":
acq = None
else:
acq = entities["acquisition"]

# run
if entities["run"] == "":
run = None
else:
run = entities["run"]

# processing
if entities["processing"] == "":
proc = None
else:
proc = entities["processing"]

# split
if entities["split"] == "":
split = None
else:
split = entities["split"]

# Create an MNE BIDSpath
bids_path = BIDSPath(
subject=sub,
session=ses,
task=task,
acquisition=acq,
run=run,
processing=proc,
split=split,
datatype=datatype,
root=bids_root_dir
)

print("Converting MEG data to BIDS")
empty_room = None
if "emptyroom" in subjects and sub != "emptyroom":
er_idx = subjects.index("emptyroom")
raw_er_data = finalized_json_data["objects"][er_idx]["SeriesDescription"]
raw_er = read_raw(raw_er_data, verbose=0)
empty_room = raw_er

write_raw_bids(raw, bids_path=bids_path, verbose=0, empty_room=empty_room, overwrite=True)

print("Finished MEG BIDS conversion (with MNE-BIDS)")
print("")
55 changes: 48 additions & 7 deletions handler/ezBIDS_core/createThumbnailsMovies.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,53 @@
import nibabel as nib
from PIL import Image
from math import floor
from natsort import natsorted
matplotlib.use('Agg')
plt.style.use('dark_background')

os.environ['MPLCONFIGDIR'] = os.getcwd() + "/configs/"

DATA_DIR = sys.argv[1]


# Functions

def create_MEG_thumbnail():
"""
Generate a simple visualization of the MEG data.
"""
import mne.viz

uploaded_json_list = natsorted(pd.read_csv("list", header=None, lineterminator='\n').to_numpy().flatten().tolist())

MEG_extensions = [".ds", ".fif", ".sqd", ".con", ".raw", ".ave", ".mrk", ".kdf", ".mhd", ".trg", ".chn", ".dat"]

"""
Get the MEG data organized
"""
data_files = [x.split("./")[-1] for x in uploaded_json_list]
MEG_data_files = []
for data in data_files:
if any(x in data for x in MEG_extensions):
MEG_data_files.append(data)

if len(MEG_data_files):
for meg in MEG_data_files:
fname = f"{DATA_DIR}/{meg}"
raw = mne.io.read_raw(fname, verbose=0)
mne.viz.set_browser_backend('matplotlib', verbose=None)

png_types = ["channels", "psd"]
for png_type in png_types:
output_file = fname.split(".")[0] + f"_{png_type}.png"

if png_type == "channels":
fig = raw.plot()
elif png_type == "psd":
fig = raw.compute_psd().plot()

fig.savefig(output_file, bbox_inches='tight')


def create_thumbnail(nifti_file, image):
"""
Expand Down Expand Up @@ -118,7 +157,7 @@ def create_DWIshell_thumbnails(nifti_file, image, bval_file):

w, h, d = buf.shape
png = Image.frombytes("RGBA", (w, h), buf.tobytes())
png.save("{}_shell-{}.png".format(output_file, bval))
png.save(f"{output_file}_shell-{bval}.png")


# Begin:
Expand All @@ -133,14 +172,16 @@ def create_DWIshell_thumbnails(nifti_file, image, bval_file):
print(nifti_file)
print("")

if not os.path.isfile("{}/{}".format(data_dir, nifti_file)): # no corresponding nifti, so don't process
print("{} does not have a corresponding NIfTI file, cannot process".format(json_file))
create_MEG_thumbnail()

if not os.path.isfile(f"{data_dir}/{nifti_file}"): # no corresponding nifti, so don't process
print(f"{json_file} does not have a corresponding NIfTI file, cannot process")
else:
output_dir = nifti_file.split(".nii.gz")[0]
image = nib.load(nifti_file)

if len([x for x in image.shape if x < 0]): # image has negative dimension(s), cannot process
print("{} has negative dimension(s), cannot process".format(nifti_file))
print(f"{nifti_file} has negative dimension(s), cannot process")
else:
# if image.get_data_dtype() == [('R', 'u1'), ('G', 'u1'), ('B', 'u1')]:
if image.get_data_dtype() not in ["<i2", "<u2", "<f4", "int16", "uint16"]:
Expand All @@ -155,7 +196,7 @@ def create_DWIshell_thumbnails(nifti_file, image, bval_file):
# object_img_array = image.dataobj[:]

bval_file = json_file.split(".json")[0].split("./")[-1] + ".bval"
if not os.path.isfile("{}/{}".format(data_dir, bval_file)):
if not os.path.isfile(f"{data_dir}/{bval_file}"):
bval_file = "n/a"
else:
bvals = [x.split(" ") for x in pd.read_csv(bval_file).columns.tolist()][0]
Expand All @@ -167,14 +208,14 @@ def create_DWIshell_thumbnails(nifti_file, image, bval_file):
# Create thumbnail
if nifti_file != "n/a":
print("")
print("Creating thumbnail for {}".format(nifti_file))
print(f"Creating thumbnail for {nifti_file}")
print("")
create_thumbnail(nifti_file, image)

# Create thumbnail of each DWI's unique shell
if bval_file != "n/a":
print("")
print("Creating thumbnail(s) for each DWI shell in {}".format(nifti_file))
print(f"Creating thumbnail(s) for each DWI shell in {nifti_file}")
print("")
create_DWIshell_thumbnails(nifti_file, image, bval_file)

Expand Down
Loading

0 comments on commit befac12

Please sign in to comment.