Bläddra i källkod

updated code for first revision

arefks 2 veckor sedan
förälder
incheckning
0d577261dc

+ 16 - 9
code/AIDAqc_Code/README.md

@@ -1,4 +1,4 @@
-
+<img align="right" src="https://github.com/Aswendt-Lab/AIDAqc/blob/main/docs/AIDA_Logo_wide.001.png" width="500">
 <h1>AIDA<i>qc</i></h1>
 
 *An automated and simple tool for fast quality analysis of animal MRI*
@@ -6,26 +6,33 @@
 <br/>
 <h3>Features</h3> 
 
-- **Input:** Bruker raw data or NIFTI (T2-weighted MRI, diffusion-weighted MRI or DTI, and rs-fMRI)
-- **Calculations:** SNR, tSNR, movement variability, data quality categorization (finds bad quality outlier)
-- **Output Format:** CSV sheets & pdf & images
+- **Input:** Bruker raw data or NIFTY (T2-weighted MRI, diffusion-weighted MRI, or DTI, and rs-fMRI)
+- **Calculations:** SNR, tSNR, movement variability, data quality categorization (finds bad quality outliers)
+- **Output Format:** CSV sheets, PDFs, & images
 
+<img align="left" src="https://github.com/Aswendt-Lab/AIDAqc/blob/main/docs/AIDAqc_workflow.png">
 
 <br/>
 <br/>
 
-[**See the poster for all details**](https://gin.g-node.org/Aswendt_Lab/2023_Kalantari_AIDAqc/src/master/code/AIDAqc_Code/docs/AIDAqc_Poster_Summary.pdf) 
+[**See the poster for all details**](https://github.com/Aswendt-Lab/AIDAqc/blob/main/docs/AIDAqc_Poster_Summary.pdf) 
 
 <h3>Installation</h3> 
-Download the repository => Install Python 3.6 or higher (Anaconda) => Import AIDAqc conda environment aidaqc.yaml or install all necessery libraries via requirements.txt (recommended).
+Download the repository => Install Python 3.6 (Anaconda) => Import AIDAqc conda environment aidaqc.yaml
 
 Main function: *ParsingData*
 
-See the full manual [here](https://gin.g-node.org/Aswendt_Lab/2023_Kalantari_AIDAqc/src/master/code/AIDAqc_Code/docs/AIDAqc_v2_1.pdf).
+See the full manual [here](https://github.com/Aswendt-Lab/AIDAqc/blob/main/docs/AIDAqc_v2_1.pdf).
 
 <h3>The story behind this tool</h3> 
 
-It can be challenging to acquire MR images of consistent quality or to decide between good vs. bad quality data in large databases. Manual screening without quantitative criteria is strictly user-dependent and for large databases is neither practical nor in the spirit of good scientific practice. In contrast to clinical MRI, in animal MRI, there is no consensus on the standardization of quality control measures or categorization of good vs. bad quality images. As we were forced for a recent project to screen hundreds of scans, we decided to automate this process as part of our Atlas-based Processing Pipeline (AIDA).
+It can be challenging to acquire MR images of consistent quality or to decide between good vs. bad quality data in large databases. Manual screening without quantitative criteria is strictly user-dependent and for large databases is neither practical nor in the spirit of good scientific practice. In contrast to clinical MRI, in animal MRI, there is no consensus on the standardization of quality control measures or categorization of good vs. bad quality images. As we were forced to screen hundreds of scans for a recent project, we decided to automate this process as part of our Atlas-based Processing Pipeline (AIDA).
+
+<h3>Validation and Datasets</h3> 
+
+This tool has been validated and used in the following publication: [Publication Link](https://gin.g-node.org/Aswendt_Lab/2023_Kalantari_AIDAqc)
+
+A total of 23 datasets from various institutes were used for validation and testing. These datasets can be found via: [Datasets Link](https://gin.g-node.org/Aswendt_Lab/2023_Kalantari_AIDAqc)
 
 <h3>Download test dataset</h3>
 https://gin.g-node.org/Aswendt_Lab/testdata_aidaqc
@@ -35,4 +42,4 @@ Aref Kalantari (aref.kalantari-sarcheshmehATuk-koeln.de) and Markus Aswendt (mar
 
 <h3><b>LICENSE</h3></b>
 
-[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html)
+[GNU General Public License v3.0](https://github.com/aswendtlab/AIDAqc/blob/main/LICENSE)

+ 221 - 0
code/AIDAqc_Code/aidaqc.yaml

@@ -0,0 +1,221 @@
+name: aidaqc
+channels:
+  - defaults
+dependencies:
+  - alabaster=0.7.12=py36_0
+  - appdirs=1.4.4=pyhd3eb1b0_0
+  - argh=0.26.2=py36_0
+  - arrow=0.13.1=py36_0
+  - astroid=2.6.6=py36haa95532_0
+  - async_generator=1.10=py36h28b3542_0
+  - atomicwrites=1.4.0=py_0
+  - attrs=21.4.0=pyhd3eb1b0_0
+  - autopep8=1.5.6=pyhd3eb1b0_0
+  - babel=2.9.1=pyhd3eb1b0_0
+  - backcall=0.2.0=pyhd3eb1b0_0
+  - bcrypt=3.2.0=py36he774522_0
+  - binaryornot=0.4.4=pyhd3eb1b0_1
+  - black=19.10b0=py_0
+  - bleach=4.1.0=pyhd3eb1b0_0
+  - brotlipy=0.7.0=py36h2bbff1b_1003
+  - ca-certificates=2021.10.26=haa95532_4
+  - certifi=2021.5.30=py36haa95532_0
+  - cffi=1.14.6=py36h2bbff1b_0
+  - chardet=4.0.0=py36haa95532_1003
+  - charset-normalizer=2.0.4=pyhd3eb1b0_0
+  - click=8.0.3=pyhd3eb1b0_0
+  - cloudpickle=2.0.0=pyhd3eb1b0_0
+  - colorama=0.4.4=pyhd3eb1b0_0
+  - cookiecutter=1.7.2=pyhd3eb1b0_0
+  - cryptography=35.0.0=py36h71e12ea_0
+  - defusedxml=0.7.1=pyhd3eb1b0_0
+  - diff-match-patch=20200713=pyhd3eb1b0_0
+  - docutils=0.17.1=py36haa95532_1
+  - entrypoints=0.3=py36_0
+  - flake8=3.9.0=pyhd3eb1b0_0
+  - future=0.18.2=py36_1
+  - icu=58.2=ha925a31_3
+  - idna=3.3=pyhd3eb1b0_0
+  - imagesize=1.3.0=pyhd3eb1b0_0
+  - importlib-metadata=4.8.1=py36haa95532_0
+  - importlib_metadata=4.8.1=hd3eb1b0_0
+  - inflection=0.5.1=py36haa95532_0
+  - intervaltree=3.1.0=pyhd3eb1b0_0
+  - ipykernel=5.3.4=py36h5ca1d4c_0
+  - ipython=7.16.1=py36h5ca1d4c_0
+  - ipython_genutils=0.2.0=pyhd3eb1b0_1
+  - isort=5.9.3=pyhd3eb1b0_0
+  - jedi=0.17.2=py36haa95532_1
+  - jinja2=2.11.3=pyhd3eb1b0_0
+  - jinja2-time=0.2.0=pyhd3eb1b0_2
+  - jpeg=9d=h2bbff1b_0
+  - jsonschema=3.2.0=pyhd3eb1b0_2
+  - jupyter_client=7.1.2=pyhd3eb1b0_0
+  - jupyter_core=4.8.1=py36haa95532_0
+  - jupyterlab_pygments=0.1.2=py_0
+  - keyring=23.1.0=py36haa95532_0
+  - lazy-object-proxy=1.6.0=py36h2bbff1b_0
+  - libpng=1.6.37=h2a8f88b_0
+  - libspatialindex=1.9.3=h6c2663c_0
+  - markupsafe=1.1.1=py36he774522_0
+  - mccabe=0.6.1=py36_1
+  - mistune=0.8.4=py36he774522_0
+  - mypy_extensions=0.4.3=py36_0
+  - nbclient=0.5.3=pyhd3eb1b0_0
+  - nbconvert=6.0.7=py36_0
+  - nbformat=5.1.3=pyhd3eb1b0_0
+  - nest-asyncio=1.5.1=pyhd3eb1b0_0
+  - numpydoc=1.1.0=pyhd3eb1b0_1
+  - openssl=1.1.1m=h2bbff1b_0
+  - packaging=21.3=pyhd3eb1b0_0
+  - pandoc=2.12=haa95532_0
+  - pandocfilters=1.5.0=pyhd3eb1b0_0
+  - paramiko=2.8.1=pyhd3eb1b0_0
+  - parso=0.7.0=py_0
+  - pathspec=0.7.0=py_0
+  - pexpect=4.8.0=pyhd3eb1b0_3
+  - pickleshare=0.7.5=pyhd3eb1b0_1003
+  - pluggy=1.0.0=py36haa95532_0
+  - poyo=0.5.0=pyhd3eb1b0_0
+  - prompt-toolkit=3.0.20=pyhd3eb1b0_0
+  - psutil=5.8.0=py36h2bbff1b_1
+  - ptyprocess=0.7.0=pyhd3eb1b0_2
+  - pycodestyle=2.6.0=pyhd3eb1b0_0
+  - pycparser=2.21=pyhd3eb1b0_0
+  - pydocstyle=6.1.1=pyhd3eb1b0_0
+  - pyflakes=2.2.0=pyhd3eb1b0_0
+  - pygments=2.11.2=pyhd3eb1b0_0
+  - pylint=2.9.6=py36haa95532_1
+  - pyls-black=0.4.6=hd3eb1b0_0
+  - pyls-spyder=0.3.2=pyhd3eb1b0_0
+  - pynacl=1.4.0=py36h62dcd97_1
+  - pyopenssl=22.0.0=pyhd3eb1b0_0
+  - pyparsing=3.0.4=pyhd3eb1b0_0
+  - pyqt=5.9.2=py36h6538335_2
+  - pyrsistent=0.17.3=py36he774522_0
+  - pysocks=1.7.1=py36haa95532_0
+  - python=3.6.13=h3758d61_0
+  - python-dateutil=2.8.2=pyhd3eb1b0_0
+  - python-jsonrpc-server=0.4.0=py_0
+  - python-language-server=0.36.2=pyhd3eb1b0_0
+  - python-slugify=5.0.2=pyhd3eb1b0_0
+  - pytz=2021.3=pyhd3eb1b0_0
+  - pywin32=228=py36hbaba5e8_1
+  - pywin32-ctypes=0.2.0=py36_1000
+  - pyyaml=5.4.1=py36h2bbff1b_1
+  - pyzmq=22.2.1=py36hd77b12b_1
+  - qdarkstyle=3.0.2=pyhd3eb1b0_0
+  - qstylizer=0.1.10=pyhd3eb1b0_0
+  - qt=5.9.7=vc14h73c81de_0
+  - qtawesome=1.0.3=pyhd3eb1b0_0
+  - qtconsole=5.2.2=pyhd3eb1b0_0
+  - qtpy=1.11.2=pyhd3eb1b0_0
+  - regex=2021.8.3=py36h2bbff1b_0
+  - requests=2.27.1=pyhd3eb1b0_0
+  - rope=0.22.0=pyhd3eb1b0_0
+  - rtree=0.9.7=py36h2eaa2aa_1
+  - setuptools=58.0.4=py36haa95532_0
+  - sip=4.19.8=py36h6538335_0
+  - six=1.16.0=pyhd3eb1b0_0
+  - snowballstemmer=2.2.0=pyhd3eb1b0_0
+  - sortedcontainers=2.4.0=pyhd3eb1b0_0
+  - sphinx=4.4.0=pyhd3eb1b0_0
+  - sphinxcontrib-applehelp=1.0.2=pyhd3eb1b0_0
+  - sphinxcontrib-devhelp=1.0.2=pyhd3eb1b0_0
+  - sphinxcontrib-htmlhelp=2.0.0=pyhd3eb1b0_0
+  - sphinxcontrib-jsmath=1.0.1=pyhd3eb1b0_0
+  - sphinxcontrib-qthelp=1.0.3=pyhd3eb1b0_0
+  - sphinxcontrib-serializinghtml=1.1.5=pyhd3eb1b0_0
+  - spyder=5.0.5=py36haa95532_2
+  - spyder-kernels=2.0.5=py36haa95532_0
+  - sqlite=3.37.2=h2bbff1b_0
+  - testpath=0.5.0=pyhd3eb1b0_0
+  - text-unidecode=1.3=pyhd3eb1b0_0
+  - textdistance=4.2.1=pyhd3eb1b0_0
+  - three-merge=0.1.1=pyhd3eb1b0_0
+  - tinycss=0.4=pyhd3eb1b0_1002
+  - toml=0.10.2=pyhd3eb1b0_0
+  - tornado=6.1=py36h2bbff1b_0
+  - traitlets=4.3.3=py36haa95532_0
+  - typed-ast=1.4.3=py36h2bbff1b_1
+  - typing-extensions=3.10.0.2=hd3eb1b0_0
+  - typing_extensions=3.10.0.2=pyh06a4308_0
+  - ujson=4.0.2=py36hd77b12b_0
+  - unidecode=1.2.0=pyhd3eb1b0_0
+  - urllib3=1.26.8=pyhd3eb1b0_0
+  - vc=14.2=h21ff451_1
+  - vs2015_runtime=14.27.29016=h5e58377_2
+  - watchdog=2.1.3=py36haa95532_0
+  - wcwidth=0.2.5=pyhd3eb1b0_0
+  - webencodings=0.5.1=py36_1
+  - wheel=0.37.1=pyhd3eb1b0_0
+  - whichcraft=0.6.1=pyhd3eb1b0_0
+  - win_inet_pton=1.1.0=py36haa95532_0
+  - wincertstore=0.2=py36h7fe50ca_0
+  - wrapt=1.12.1=py36he774522_1
+  - yaml=0.2.5=he774522_0
+  - yapf=0.31.0=pyhd3eb1b0_0
+  - zipp=3.6.0=pyhd3eb1b0_0
+  - zlib=1.2.11=h8cc25b3_4
+  - pip:
+    - about-time==3.1.1
+    - alive-progress==2.1.0
+    - ansicon==1.89.0
+    - asteval==0.9.26
+    - blessed==1.19.1
+    - ci-info==0.2.0
+    - configobj==5.0.8
+    - configparser==5.2.0
+    - cycler==0.11.0
+    - dataclasses==0.8
+    - decorator==4.4.2
+    - et-xmlfile==1.1.0
+    - etelemetry==0.2.2
+    - filelock==3.4.1
+    - fitz==0.0.1.dev2
+    - flyingcircus==0.1.4.0
+    - flyingcircus-numeric==0.1.1.2
+    - fpdf==1.7.2
+    - grapheme==0.6.0
+    - httplib2==0.21.0
+    - imageio==2.15.0
+    - isodate==0.6.1
+    - jinxed==1.2.0
+    - joblib==1.1.1
+    - kiwisolver==1.3.1
+    - lmfit==1.0.3
+    - lxml==4.9.2
+    - matplotlib==3.3.4
+    - networkx==2.5.1
+    - nibabel==3.2.2
+    - nipype==1.7.1
+    - numpy==1.19.5
+    - openpyxl==3.0.9
+    - pandas==1.1.5
+    - pathlib==1.0.1
+    - pillow==8.4.0
+    - pip==21.3.1
+    - progressbar==2.5
+    - prov==2.0.0
+    - pydot==1.4.2
+    - pypdf2==3.0.1
+    - pywavelets==1.1.1
+    - pyxnat==1.5
+    - raster-geometry==0.1.4.1
+    - rdflib==5.0.0
+    - scikit-image==0.17.2
+    - scikit-learn==0.24.2
+    - scipy==1.5.4
+    - seaborn==0.11.2
+    - setuptools-scm==6.4.2
+    - simplejson==3.18.3
+    - svg-stack==0.1.0
+    - svgutils==0.3.4
+    - threadpoolctl==3.1.0
+    - tifffile==2020.9.3
+    - tinycss2==1.1.1
+    - tomli==1.2.3
+    - traits==6.4.1
+    - uncertainties==3.1.7
+    - xlrd==2.0.1
+    - xlsxwriter==3.0.3

BIN
code/AIDAqc_Code/docs/AIDAqc_v2_1.pdf


+ 2 - 1
code/AIDAqc_Code/scripts/pv_parser.py

@@ -313,7 +313,8 @@ def read_param_file(filename):
     elif 'JCAMP-DX' in header:
         version = float(header['JCAMP-DX'])
     else:
-        sys.exit("The file header is not correct.")
+        raise KeyError("The file header does not contain the key 'JCAMP-DX'.")
+        #sys.exit("The file header is not correct.")
 
     if (version != 4.24) and (version != 5):
         print("Warning: JCAMP version %s is not supported (%s)." % (version, filename), file=sys.stderr)

+ 41 - 0
code/MotionAddition_rsfmri.m

@@ -0,0 +1,41 @@
+% Input folder path containing fMRI data
+input_folder = "C:\Users\aswen\Desktop\TestingData\Aswendt_qc_data\proc_data";
+
+% Get all rsfMRI files in the input folder
+searchpath = fullfile(input_folder, '**', 'func', '*EPI.nii.gz');
+rsfmri_files = dir(searchpath);
+rsfmri_files = fullfile({rsfmri_files.folder}, {rsfmri_files.name});
+
+% Parameters for motion addition
+translation_amount_initial = 7; % Initial translation amount in pixels
+translation_amount_growth = 1; % Amount by which translation increases at each time point
+translation_amount_max = 30; % Maximum translation amount in pixels
+timepoints = size(Im, 4); % Number of time points
+
+% Loop through each rsfMRI file for motion addition
+for i = 1:numel(rsfmri_files)
+    % Read file
+    file = rsfmri_files{i};
+    
+    % Load the 4D rsfMRI image and its info
+    Im = niftiread(file);
+    info = niftiinfo(file);
+
+    % Initialize translation amount
+    translation_amount = translation_amount_initial;
+    
+    % Add motion by shifting each volume in the time series
+    for t = 1:timepoints
+        % Apply translation to simulate motion
+        Im(:,:,:,t) = imtranslate(Im(:,:,:,t), [translation_amount, 0, 0]);
+        
+        % Update translation amount for the next time point
+        translation_amount = min(translation_amount + translation_amount_growth, translation_amount_max);
+    end
+    
+    % Save the motion-added 4D rsfMRI image
+    [filepath, filename, ext] = fileparts(file);
+    output_filename = [filename '_motion_added' ext]; % Appending '_motion_added' to the filename
+    output_path = fullfile(filepath, output_filename);
+    niftiwrite(Im, output_path, info, 'Compressed', true);
+end