Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added creation of bvec and bval files when creating NIfTI files #335

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/scripts_md/MRI.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,46 @@ INPUTS:
- $fileref : file hash ref
- $data\_dir: data directory (e.g. `/data/$PROJECT/data`)

### create\_dwi\_nifti\_bval\_file($file\_ref, $bval\_file)

Creates the NIfTI `.bval` file required for DWI acquisitions based on the
returned value of `acquisition:bvalues`.

INPUTS:
- $file\_ref : file hash ref
- $bval\_file: path to the `.bval` file to write into

RETURNS:
- undef if no `acquisition:bvalues` were found (skipping the creation
of the `.bval` file since there is nothing to write into)
- 1 after the `.bval` file was created

### create\_dwi\_nifti\_bvec\_file($file\_ref, $bvec\_file)

Creates the NIfTI `.bvec` file required for DWI acquisitions based on the
returned value of `acquisition:direction_x`, `acquisition:direction_y` and
`acquisition:direction_z`.

INPUTS:
- $file\_ref : file hash ref
- $bvec\_file: path to the `.bvec` file to write into

RETURNS:
- undef if no `acquisition:direction_x`, `acquisition:direction_y` and
`acquisition:direction_z` were found (skipping the creation
of the `.bvec` file since there is nothing to write into)
- 1 after the `.bvec` file was created

### write\_to\_file($file, $value, $mode)

This method writes into a file `$file` values stored in `$value`. The mode
in which the file should be open with is specified in `$mode`.

INPUTS:
- $file : output file to write into
- $value: value that needs to be written in the file
- $mode : mode with which the file should be open with (`'\`'> or `'\`\\>'>)

### make\_minc\_pics($dbhr, $TarchiveSource, $profile, $minFileID, $debug, $verbose)

Creates pics associated with MINC files.
Expand Down
27 changes: 27 additions & 0 deletions docs/scripts_md/create_nifti_bval_bvec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# NAME

create\_nifti\_bval\_bvec.pl -- a script that creates the missing bval and bvec
files for DWI NIfTI acquisitions.

# SYNOPSIS

perl tools/create\_nifti\_bval\_bvec.pl `[options]`

Available options are:

\-profile: name of the config file in `../dicom-archive/.loris_mri`
\-verbose: be verbose

# DESCRIPTION

This script will create the missing NIfTI bval and bvec files for DWI
acquisitions.

# LICENSING

License: GPLv3

# AUTHORS

LORIS community <loris.info@mcin.ca> and McGill Centre for Integrative
Neuroscience
204 changes: 204 additions & 0 deletions tools/create_nifti_bval_bvec.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
#! /usr/bin/perl

=pod

=head1 NAME

create_nifti_bval_bvec.pl -- a script that creates the missing bval and bvec
files for DWI NIfTI acquisitions.


=head1 SYNOPSIS

perl tools/create_nifti_bval_bvec.pl C<[options]>

Available options are:

-profile: name of the config file in C<../dicom-archive/.loris_mri>
-verbose: be verbose


=head1 DESCRIPTION

This script will create the missing NIfTI bval and bvec files for DWI
acquisitions.


=head1 LICENSING

License: GPLv3


=head1 AUTHORS

LORIS community <loris.info@mcin.ca> and McGill Centre for Integrative
Neuroscience

=cut



use strict;
use warnings;
use Getopt::Tabular;

use NeuroDB::File;
use NeuroDB::MRI;
use NeuroDB::DBI;
use NeuroDB::ExitCodes;




### Set up Getopt::Tabular

my $profile;
my $verbose = 0;
my $profile_desc = "Name of the config file in ../dicom-archive/.loris_mri";

my @opt_table = (
[ "-profile", "string", 1, \$profile, $profile_desc ],
[ "-verbose", "boolean", 1, \$verbose, "Be verbose" ]
);

my $Help = <<HELP;
******************************************************************************
CREATE NIFTI BVAL BVEC DWI FILES
******************************************************************************

This will check if the configuration flag for NIfTI files creation is set to
'yes' and will create .bvec and .bval files for the DWI acquisitions that
need to accompany the NIfTI DWI files (bug in mnc2nii that do not create
those files so we create them ourselves based on values present in the MINC
header for acquisition:bvalues, acquisition:direction_x,
acquisition:direction_y and acquisition:direction_z).

Documentation: perldoc create_nifti_bval_bvec.pl

HELP

my $Usage = <<USAGE;
Usage: $0 [options]
$0 -help to list options
USAGE

&Getopt::Tabular::SetHelp($Help, $Usage);
&Getopt::Tabular::GetOptions(\@opt_table, \@ARGV)
|| exit $NeuroDB::ExitCodes::GETOPT_FAILURE;



## input error checking

if (!$ENV{LORIS_CONFIG}) {
print STDERR "\n\tERROR: Environment variable 'LORIS_CONFIG' not set\n\n";
exit $NeuroDB::ExitCodes::INVALID_ENVIRONMENT_VAR;
}

if (!defined $profile || !-e "$ENV{LORIS_CONFIG}/.loris_mri/$profile") {
print $Help;
print STDERR "$Usage\n\tERROR: You must specify a valid and existing profile.\n\n";
exit $NeuroDB::ExitCodes::PROFILE_FAILURE;
}

{ package Settings; do "$ENV{LORIS_CONFIG}/.loris_mri/$profile" }

if ( !@Settings::db ) {
print STDERR "\n\tERROR: You don't have a \@db setting in the file "
. "$ENV{LORIS_CONFIG}/.loris_mri/$profile \n\n";
exit $NeuroDB::ExitCodes::DB_SETTINGS_FAILURE;
}



## establish database connection

my $dbh = &NeuroDB::DBI::connect_to_db(@Settings::db);
print "\n==> Successfully connected to the database \n" if $verbose;



## get config settings

my $data_dir = NeuroDB::DBI::getConfigSetting(\$dbh, 'dataDirBasepath');
my $create_nii = NeuroDB::DBI::getConfigSetting(\$dbh, 'create_nii');



## exit if create_nii is set to No

unless ($create_nii) {
print "\nConfig option 'create_nii' set to no. bvec/bval files will not be "
. "created as NIfTI files are not created by the imaging pipeline\n\n";
exit $NeuroDB::ExitCodes::SUCCESS;
}



## grep all FileIDs for which acquisition:bvalues are set

print "\n==> Fetching all FileIDs with acquisition:bvalues. \n" if $verbose;

( my $query = <<QUERY ) =~ s/\n/ /g;
SELECT
FileID
FROM
parameter_file
JOIN parameter_type USING (ParameterTypeID)
WHERE
parameter_type.Name=?
QUERY

my $sth = $dbh->prepare($query);
$sth->execute('acquisition:bvalues');

my @file_ids = map { $_->{'FileID'} } @{ $sth->fetchall_arrayref( {} ) };

unless (@file_ids) {
print "\n No files were found with header 'acquisition:bvalues' so no need "
. "to create bval/bvec files \n";
exit $NeuroDB::ExitCodes::SUCCESS;
}



## loop through all FileIDs and create bvec/bval files
foreach my $file_id (@file_ids) {

# load the file based on the FileID
my $file = NeuroDB::File->new(\$dbh);
$file->loadFile($file_id);

# determine paths for bval/bvec files
my $minc = $file->getFileDatum('File');
my ($bval_file, $bvec_file) = ($minc) x 2;
$bval_file =~ s/mnc$/bval/;
$bvec_file =~ s/mnc$/bvec/;

# create complementary nifti files for DWI acquisitions
my $bval_success = NeuroDB::MRI::create_dwi_nifti_bval_file(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like "$data_dir/$bval_file" better than $data_dir . '/' . $bval_file

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

\$file, "$data_dir/$bval_file"
);
my $bvec_success = NeuroDB::MRI::create_dwi_nifti_bvec_file(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like "$data_dir/$bvec_file" better than $data_dir . '/' . $bvec_file

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

\$file, "$data_dir/$bvec_file"
);

# check if bval/bvec created & update parameter_file table with their paths
if ($bval_success) {
print "\n==> Successfully created bval file for $minc \n";
# update parameter_file table with bval path
$file->setParameter('check_bval_filename', $bval_file);
}
if ($bvec_success) {
print "\n==> Successfully created bvec file for $minc \n";
# update parameter_file table with bvec path
$file->setParameter('check_bvec_filename', $bvec_file);
}

}



## disconnect from the database and exit the script with SUCCESS exit code
$dbh->disconnect();
exit $NeuroDB::ExitCodes::SUCCESS;
100 changes: 95 additions & 5 deletions uploadNeuroDB/NeuroDB/MRI.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1394,19 +1394,109 @@ sub make_nii {
# Get MINC filename and NIfTI filename
my $file = $$fileref;
my $minc = $file->getFileDatum('File');
my $nifti = $minc;
$nifti =~ s/mnc$/nii/g;
my ($nifti, $bval_file, $bvec_file) = ($minc) x 3;
$nifti =~ s/mnc$/nii/;
$bval_file =~ s/mnc$/bval/;
$bvec_file =~ s/mnc$/bvec/;

# mnc2nii command
my $m2n_cmd = "mnc2nii -nii -quiet " .
$data_dir . "/" . $minc . " " .
$data_dir . "/" . $nifti;
my $m2n_cmd = "mnc2nii -nii -quiet $data_dir/$minc $data_dir/$nifti";
system($m2n_cmd);

# create complementary nifti files for DWI acquisitions
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I think "$data_dir/$bval_file" and "$data_dir/$bvec_file" are clearer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed. A lot clearer. I also did that for the command four lines before and it all fits in one line :)

my $bval_success = create_dwi_nifti_bval_file($fileref, "$data_dir/$bval_file");
my $bvec_success = create_dwi_nifti_bvec_file($fileref, "$data_dir/$bvec_file");

# update mri table (parameter_file table)
$file->setParameter('check_nii_filename', $nifti);
$file->setParameter('check_bval_filename', $bval_file) if $bval_success;
$file->setParameter('check_bvec_filename', $bvec_file) if $bvec_success;
}


=pod

=head3 create_dwi_nifti_bval_file($file_ref, $bval_file)

Creates the NIfTI C<.bval> file required for DWI acquisitions based on the
returned value of C<acquisition:bvalues>.

INPUTS:
- $file_ref : file hash ref
- $bval_file: path to the C<.bval> file to write into

RETURNS:
- undef if no C<acquisition:bvalues> were found (skipping the creation
of the C<.bval> file since there is nothing to write into)
- 1 after the C<.bval> file was created

=cut

sub create_dwi_nifti_bval_file {
my ($file_ref, $bval_file) = @_;

# grep bvals from the header acquisition:bvalues
my $file = $$file_ref;
my $bvals = $file->getParameter('acquisition:bvalues');

return undef unless $bvals;

# clean up the bvals string
$bvals =~ s/\.\,//g; # remove all '.,' from the string
$bvals =~ s/\.$//; # remove the last trailing '.' from the string

# print bvals into bval_file
open(FILE, '>', $bval_file) or die "Could not open file $bval_file $!";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semi-colon in error message (see corresponding message in create_dwi_nifti_bvec_file).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in the next commit!

print FILE $bvals;
close FILE;

return -e $bval_file;
}


=pod

=head3 create_dwi_nifti_bvec_file($file_ref, $bvec_file)

Creates the NIfTI C<.bvec> file required for DWI acquisitions based on the
returned value of C<acquisition:direction_x>, C<acquisition:direction_y> and
C<acquisition:direction_z>.

INPUTS:
- $file_ref : file hash ref
- $bvec_file: path to the C<.bvec> file to write into

RETURNS:
- undef if no C<acquisition:direction_x>, C<acquisition:direction_y> and
C<acquisition:direction_z> were found (skipping the creation
of the C<.bvec> file since there is nothing to write into)
- 1 after the C<.bvec> file was created

=cut

sub create_dwi_nifti_bvec_file {
my ($file_ref, $bvec_file) = @_;

# grep bvecs from headers acquisition:direction_x, y and z
my $file = $$file_ref;
my @bvecs = (
$file->getParameter('acquisition:direction_x'),
$file->getParameter('acquisition:direction_y'),
$file->getParameter('acquisition:direction_z')
);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @bvecs will always contain 3 elements and so will always evaluate to true. return undef unless @bvecs is unnecessary IMHO. Have you ever come across such a case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, for T1W acquisitions for example, those 3 elements are not there and it will return undef, skipping the bval/bvec creation since there are no fields to create them. This avoids having to add another config setting to specify the scan type for which to create bval/bvec files (which would be a config setting a bit obscure). So if those headers are present, continue in this function to create the bvec file, if they are not present, then return from the function and don't create bvec file. Does that make more sense?

return undef unless ($bvecs[0] && $bvecs[1] && $bvecs[2]);

# loop through all bvecs, clean them up and print them into the bvec file
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think opening the file, writing to it and then closing it on each iteration is not a good idea. I wouldn't even define a function to print to a file

s/^\"+|\"$//g for @bvec;
open(OUT, '>', $bvec_file) or die "Cannot write to file $bvec_file: $!\n";
print OUT map { "$_\n" } @bvec;
close(OUT);

s/^\"+|\"$//g for @bvecs;
open(OUT, '>', $bvec_file) or die "Cannot write to file $bvec_file: $!\n";
print OUT map { "$_\n" } @bvecs;
close(OUT);

return -e $bvec_file;
}


=pod

=head3 make_minc_pics($dbhr, $TarchiveSource, $profile, $minFileID, $debug, $verbose)
Expand Down