Example #1
0
    def __oddEvenNumberOfSlices(self, *args):
        """return a list of images that will count a odd number of slices in z direction

            If an even number of slices is found, the upper volume will be remove

        Args:
            *args: a list of images

        Returns:
             a list of images stripped

        """
        output = []
        for image in args:
            if image:
                try:
                    zDims = int(mriutil.getMriDimensions(image)[2])
                    if zDims % 2 == 1:
                        target = self.buildName(image, "subset")
                        mriutil.extractSubVolume(image, target, '+2',
                                                 "0:{}".format(zDims - 2),
                                                 self.getNTreadsMrtrix())
                        output.append(target)
                    else:
                        output.append(image)
                except ValueError:
                    output.append(image)
            else:
                output.append(False)
        return output
Example #2
0
File: 08-snr.py Project: inej/toad
    def __oddEvenNumberOfSlices(self, *args):
        """return a list of images that will count a odd number of slices in z direction

            If an even number of slices is found, the upper volume will be remove

        Args:
            *args: a list of images

        Returns:
             a list of images stripped

        """
        output = []
        for image in args:
            if image:
                try:
                    zDims = int(mriutil.getMriDimensions(image)[2])
                    if zDims%2 == 1:
                        target = self.buildName(image, "subset")
                        mriutil.extractSubVolume(image, target, '+2',"0:{}".format(zDims-2), self.getNTreadsMrtrix())
                        output.append(target)
                    else:
                        output.append(image)
                except ValueError:
                    output.append(image)
            else:
                output.append(False)
        return output
Example #3
0
    def __validateSizeAndDimension(self, *args):

        names = []
        dims = []
        sizes = []

        for source in args:
            if source:
                names.append(source)
                dimensions = mriutil.getMriDimensions(source)
                if len(dimensions) == 4:
                    dims.append([dimensions[0], dimensions[1], dimensions[2]])
                else:
                    dims.append(dimensions)
                    # sourceSize sanitization
                    sourceSize = mriutil.getMriVoxelSize(source)
                    try:
                        sourceSize = [
                            "{:.1f}".format(float(val)) for val in sourceSize
                        ]
                    except ValueError:
                        self.error("Error during sourceSize sanitization")
                    sizes.append(sourceSize)

        if not dims[1:] == dims[:-1]:
            self.error(
                "Dimension for each scale mismatch found between images: {}".
                format(", ".join(names)))

        if not sizes[1:] == sizes[:-1]:
            self.error("Voxel size mismatch found between images: {}".format(
                ", ".join(names)))
Example #4
0
    def __validateSizeAndDimension(self, *args):

        names = []
        dims = []
        sizes = []

        for source in args:
            if source:
                names.append(source)
                dimensions = mriutil.getMriDimensions(source)
                if len(dimensions) == 4:
                    dims.append([dimensions[0], dimensions[1], dimensions[2]])
                else:
                    dims.append(dimensions)
                    # sourceSize sanitization
                    sourceSize = mriutil.getMriVoxelSize(source)
                    try:
                        sourceSize = ["{:.1f}".format(float(val)) for val in sourceSize]
                    except ValueError:
                        self.error("Error during sourceSize sanitization")
                    sizes.append(sourceSize)

        if not dims[1:] == dims[:-1]:
            self.error("Dimension for each scale mismatch found between images: {}".format(", ".join(names)))

        if not sizes[1:] == sizes[:-1]:
            self.error("Voxel size mismatch found between images: {}".format(", ".join(names)))
Example #5
0
    def implement(self):

        dwi   = self.getImage(self.dependDir, 'dwi')
        b0PA  = self.getImage(self.dependDir, 'b0PA')
        b0AP  = self.getImage(self.dependDir, 'b0AP')
        bFile =  self.getImage(self.dependDir, 'grad',  None, 'b')
        bVals =  self.getImage(self.dependDir, 'grad',  None, 'bval')
        bVecs =  self.getImage(self.dependDir, 'grad',  None, 'bvec')

        #make sure the 3 images have the same voxel size and dimension scale
        self.__validateSizeAndDimension(dwi, b0PA, b0AP)

        #make sure that the z dimension contain an odd number of slices
        dwiZDims = int(mriutil.getMriDimensions(dwi)[2])

        if dwiZDims%2 == 1:
            dwi  = self.__extractZVolumes(dwi, "0:{}".format(dwiZDims-2))
            b0PA = self.__extractZVolumes(b0PA, "0:{}".format(dwiZDims-2))
            b0AP = self.__extractZVolumes(b0AP, "0:{}".format(dwiZDims-2))

        #concatenate B0 image together
        b0Image = self.__concatenateB0(b0PA, b0AP,
                            os.path.join(self.workingDir, self.get('b0s_filename')))

        #create an empty b02b0.cnf file
        #b02b0File = os.path.join(self.workingDir, self.get('b02b0_filename'))
        #open(b02b0File, 'a').close()

        #create the acquisition parameter file
        acqpTopup = self.__createAcquisitionParameterFile('topup')
        acqpEddy = self.__createAcquisitionParameterFile('eddy')

        #create an index file
        indexFile = self.__createIndexFile(mriutil.getNbDirectionsFromDWI(dwi))

        #Lauch topup on concatenate B0 image
        [topupBaseName, topupImage] = self.__topup(b0Image, acqpTopup, self.get('b02b0_filename'))

        outputFieldMask = self.__fslmaths_tmean(os.path.join(self.workingDir, topupImage))

        outputFieldMaskExtracted = self.__bet(outputFieldMask)

        outputEddyImage = self.__correction_eddy2(dwi,
                                    outputFieldMaskExtracted, topupBaseName, indexFile, acqpEddy, bVecs, bVals)

        self.info("Uncompressing eddy output image: {}".format(outputEddyImage))
        util.gunzip(outputEddyImage)

        #@TODO remove the glob and use getimage
        eddyParameterFiles = glob.glob("{}/*.eddy_parameters".format(self.workingDir))
        if len(eddyParameterFiles)>0:
            bCorrected = mriutil.applyGradientCorrection(bFile, eddyParameterFiles.pop(0), self.workingDir)
            #produce the bVal and bVec file accordingly
            mriutil.bEnc2BVec(bCorrected, self.workingDir)
            mriutil.bEnc2BVal(bCorrected, self.workingDir)
Example #6
0
    def __validateSizeAndDimension(self, dwi, b0PA, b0AP):

        dwiDim   = mriutil.getMriDimensions(dwi)
        dwiVoxel = mriutil.getMriVoxelSize(dwi)
        b0PADim   = mriutil.getMriDimensions(b0PA)
        b0PAVoxel = mriutil.getMriVoxelSize(b0PA)
        b0APDim   = mriutil.getMriDimensions(b0AP)
        b0APVoxel = mriutil.getMriVoxelSize(b0AP)

        self.info("Look if {} and {} and {} have the same voxel size".format(dwi, b0PA, b0AP))
        if len(dwiVoxel) == len(b0PAVoxel) == len(b0APVoxel) == 3:
            for i in range(0,len(dwiVoxel)):
                if not (dwiVoxel[i] == b0PAVoxel[i] == b0APVoxel[i]):
                    self.error("Voxel size mismatch found at index {} for image {} {} {}".format(i, dwi, b0PA, b0AP))
        else:
            self.error("Found Voxel size inconsistency for image {} or  {} or {}".format(dwi, b0PA, b0AP))

        self.info("Look if {} and {} and {} have the same dimension for each scale".format(dwi, b0PA, b0AP))
        for i in range(0,3):
                if not (dwiDim[i]==b0PADim[i]==b0APDim[i]):
                    self.error("Dimensions mismatch found at index {} for image {} {} {}".format(i, dwi, b0PA, b0AP))
Example #7
0
    def qaSupplier(self):
        """Create and supply images for the report generated by qa task

        """
        qaImages = Images()

        tags = (
            ('anat', self.plot3dVolume, 'High resolution anatomical image'),
            ('dwi', self.plot4dVolume, 'Diffusion weighted image'))

        tags = list(tags)

        if self.getImage('b0_pa'):
            if len(mriutil.getMriDimensions(self.getImage('b0_pa')))==4:
                tags.append(('b0_pa', self.plot4dVolume, 'B0 PA images'))
            else:
                tags.append(('b0_pa', self.plot3dVolume, 'B0 PA image'))


        if self.getImage('b0_ap'):
            if len(mriutil.getMriDimensions(self.getImage('b0_ap')))==4:
                tags.append(('b0_ap', self.plot4dVolume, 'B0 AP images'))
            else:
                tags.append(('b0_ap', self.plot3dVolume, 'B0 AP image'))

        tags.append(('mag', self.plot3dVolume, 'Magnitude image'))
        tags.append(('phase', self.plot3dVolume, 'Phase image'))

        tags = tuple(tags)

        for prefix, plotMethod, description in tags:
            source = self.getImage(prefix)
            if source:
                qaImage = plotMethod(source)
                qaImages.append((qaImage, description))

        return qaImages
Example #8
0
    def __checkOddEvenNumberOfSlices(self, source):
        """return the config file b02b0

            If an even number of slices is found, b02b0_even will be used otherwise we'll b02b0_odd

        Args:
            *args: a list of images

        Returns:
             config file b02b0

        """
        zDims = int(mriutil.getMriDimensions(source)[2])
        if zDims % 2 == 1:
            return self.get('b02b0_odd')
        else:
            return self.get('b02b0_even')
Example #9
0
    def __validateSizeAndDimension(self, *args):

        names = []
        dims = []
        sizes = []

        for source in args:
            if source:
                names.append(source)
                dimensions = mriutil.getMriDimensions(source)
                if len(dimensions) == 4:
                    dims.append([dimensions[0], dimensions[1], dimensions[2]])
                else:
                    dims.append(dimensions)
                    sizes.append(mriutil.getMriVoxelSize(source))

        if not dims[1:] == dims[:-1]:
            self.error("Dimension for each scale mismatch found between images: {}".format(", ".join(names)))

        if not sizes[1:] == sizes[:-1]:
            self.error("Voxel size mismatch found between images: {}".format(", ".join(names)))
Example #10
0
    def __correctionEddy(self, source, mask, topup, index, acqp, bVecs, bVals, bEnc):
        """Performs eddy correction on a dwi file.

        Args:
            source:	File containing all the images to estimate distortions for
            mask:	Mask to indicate brain
            topup:  Base name for output files from topup
            index:	File containing indices for all volumes in --imain into --acqp and --topup
            acqp:	File containing acquisition parameters
            bvecs:	File containing the b-vectors for all volumes in --imain
            bvals:	File containing the b-values for all volumes in --imain

        Returns:
            The resulting file name

        """
        self.info("Launch eddy correction from fsl")
        tmp = self.buildName(source, "tmp")
        target = self.buildName(source, "eddy")

        cmd = "eddy_openmp_patch --imain={} --mask={} --index={} --acqp={} --bvecs={} --bvals={} --out={} " \
                    .format(source, mask, index, acqp, bVecs, bVals, tmp)

        if len(mriutil.getBValues(source, bEnc))>2:
            #cmd += " --data_is_shelled --mb={} " \
            cmd += " --data_is_shelled"
            zDims = int(mriutil.getMriDimensions(source)[2])
            if zDims % int(self.get('multiband')) == 0:
                cmd += " --mb={}".format(self.get('multiband'))
            #        .format(self.get('multiband'))

        if topup is not None:
            cmd += " --topup={}".format(topup)

        self.getNTreadsEddy()
        self.launchCommand(cmd, nice=5*60*60)
        return self.rename(tmp, target)
Example #11
0
    def implement(self):

        dwi = self.getDenoisingImage('dwi', 'denoise')
        if not dwi:
            dwi = self.getPreparationImage('dwi')

        b0AP = self.getPreparationImage('b0_ap')
        b0PA = self.getPreparationImage('b0_pa')
        bEnc = self.getPreparationImage('grad', None, 'b')
        bVals = self.getPreparationImage('grad', None, 'bvals')
        bVecs = self.getPreparationImage('grad', None, 'bvecs')
        norm = self.getParcellationImage('norm')
        parcellationMask = self.getParcellationImage('mask')

        # Fieldmap only
        mag = self.getPreparationImage("mag")
        phase = self.getPreparationImage("phase")
        freesurferAnat = self.getParcellationImage('anat', 'freesurfer')

        self.info("extract b0 image from the dwi")
        b0 = os.path.join(self.workingDir,
                          os.path.basename(dwi).replace(self.get("prefix", 'dwi'), self.get("prefix", 'b0')))

        # Extract first n b0s from DWI
        self.info(mriutil.extractFirstB0sFromDWI(dwi, b0, bVals, self.getNTreadsMrtrix()))

        # Get number of b0s extracted from DWI
	tDims = int(mriutil.getMriDimensions(b0)[3])

        self.info("look if all images have the same voxel size and dimension scale")
        self.__validateSizeAndDimension(dwi, b0, b0AP, b0PA)

        # Generate a missing b0 image if we could. --> 0 = P>>A, 1 = A>>P
        if self.get("phase_enc_dir") == "0" and b0AP and b0PA is False:
            b0PA = b0
            # Extract same number of volumes b0PA
	    try:
	        b0APDim = int(mriutil.getMriDimensions(b0AP)[3])
        	target = os.path.join(self.workingDir,
               	         os.path.basename(dwi).replace(self.get("prefix", 'dwi'), self.get("prefix", 'b0_ap')))
            	self.info(mriutil.extractSubVolume(b0AP, target, '+3', "{}:{}".format(b0APDim-tDims, b0APDim-1 ), self.getNTreadsMrtrix()))
            	b0AP = target
	    except:
		b0APDim = 1

        if self.get("phase_enc_dir") == "1" and b0PA and b0AP is False:
            b0AP = b0
            # Extract same number of volumes b0PA
            try:
		b0PADim = int(mriutil.getMriDimensions(b0PA)[3])
		target = os.path.join(self.workingDir,
                          os.path.basename(dwi).replace(self.get("prefix", 'dwi'), self.get("prefix", 'b0_pa')))
	        self.info(mriutil.extractSubVolume(b0PA, target, '+3', "{}:{}".format(b0PADim-tDims, b0PADim-1), self.getNTreadsMrtrix()))
		b0PA = target
	    except:
		b0PADim = 1

        topupConfigFile = self.__checkOddEvenNumberOfSlices(dwi)

        self.set('method', None)


        if b0AP is False or b0PA is False:
            topupBaseName = None
            b0Image = b0
            self.set('method', 'fieldmap')
        else:
            # Concatenate B0 image together
            if self.get("phase_enc_dir") == "0":
                concatenateB0Image = self.__concatenateB0(b0PA, b0AP, self.buildName("b0pa_b0ap", None, "nii.gz"))
                self.dimB0s = [mriutil.getNbDirectionsFromDWI(b0PA), mriutil.getNbDirectionsFromDWI(b0AP)]
            elif self.get("phase_enc_dir") == "1":
                concatenateB0Image = self.__concatenateB0(b0AP, b0PA, self.buildName("b0ap_b0pa", None, "nii.gz"))
                self.dimB0s = [mriutil.getNbDirectionsFromDWI(b0AP), mriutil.getNbDirectionsFromDWI(b0PA)]

            if int(mriutil.getMriDimensions(dwi)[2]) % 2 == 1: # Number of slice in z axis
                if 'force' not in self.get('crop'): # Use odd number
                    [dwi, b0, b0AP, b0PA, concatenateB0Image] = self.__cropNumberOfSlices(dwi, b0, b0AP, b0PA, concatenateB0Image)

            # Select config File for topup
            topupConfigFile = self.__checkOddEvenNumberOfSlices(dwi)

            # Create the acquisition parameter file
            acqpTopup = self.__createAcquisitionParameterFile('topup')

            # Run topup on concatenate B0 image
            [topupBaseName, topupImage] = self.__topup(concatenateB0Image, acqpTopup, topupConfigFile)
            b0Image = self.__fslmathsTmean(os.path.join(self.workingDir, topupImage))
            self.set('method', 'topup')

        self.info("create a suitable mask for the dwi")
        extraArgs = " -dof 6 "  # same subject

        if self.get("methodology", "intrasession"):
            extraArgs += " -usesqform "

        mask, _notUsed_a, _notUsed_b = mriutil.computeDwiMaskFromFreesurfer(b0Image,
                                                    norm,
                                                    parcellationMask,
                                                    self.buildName(parcellationMask, 'temporary'),
                                                    extraArgs)

        # Create the acquisition parameter file for eddy
        acqpEddy = self.__createAcquisitionParameterFile('eddy')

        # Create an index file
        indexFile = self.__createIndexFile(mriutil.getNbDirectionsFromDWI(dwi))

        outputImage = self.__correctionEddy(dwi, mask, topupBaseName, indexFile, acqpEddy, bVecs, bVals, bEnc)

        eddyParameterFiles = self.getImage('dwi', None, 'eddy_parameters')

        if eddyParameterFiles:
            self.info("Apply eddy movement correction to gradient encodings directions")
            bEnc = mriutil.applyGradientCorrection(bEnc, eddyParameterFiles, self.buildName(outputImage, None, 'b'))
            self.info(mriutil.mrtrixToFslEncoding(outputImage,
                                                  bEnc,
                                                  self.buildName(outputImage, None, 'bvecs'),
                                                  self.buildName(outputImage, None, 'bvals')))
        # Proceed with fieldmap if provided
        if mag and phase and not self.__topupCorrection:
            # OutputImage is now used for fieldmap correction
            outputImage = self.__computeFieldmap(outputImage, bVals, mag, phase, norm, parcellationMask, freesurferAnat)
            self.set('method', 'fieldmap')

        # Produce a valid b0 and mask for QA
        b0Corrected = self.buildName(b0, 'corrected')
        self.info(mriutil.extractFirstB0FromDwi(outputImage, b0Corrected, bVals))
        maskCorrected = mriutil.computeDwiMaskFromFreesurfer(b0Corrected,
                                                             norm,
                                                             parcellationMask,
                                                             self.buildName(parcellationMask, 'corrected'),
                                                             extraArgs)

        self.rename(outputImage, self.buildName(outputImage, 'corrected'))