def clearScalars( trkFile1, outputFile ): ''' Copy scalars from trkFile1 to trkFile2 ''' s = io.loadTrk( trkFile1 ) tracks = s[0] origHeader = s[1] tracksHeader = numpy.copy( s[1] ) newTracks = [] for tCounter, t in enumerate( tracks ): tCoordinates = t[0] tScalars = t[1] tProperties = t[2] # clear scalars newTracks.append( ( tCoordinates, None, tProperties ) ) # write trkFile2 with update scalars io.saveTrk( outputFile, newTracks, tracksHeader, None, True ) c.info( 'Cleared scalars from ' + trkFile1 + ' and saved as ' + outputFile )
def analyze_input_data( self, input_directory, inputs ): ''' Scan an input directory for all kind of inputs. Connectome Pipeline output has higher priority than Tractography Pipeline output since the Connectome pipeline also includes the Tractography output. Returns a dictionary of found files. ''' for root, dirs, files in os.walk( input_directory ): dirs.sort() for f in files: fullpath = os.path.join( root, f ) # try to find the files for _f in inputs: # don't check if we already found this one if inputs[_f][-1] != None: continue for _mask in inputs[_f][:-1]: if fnmatch.fnmatch( fullpath, _mask ): # this matches our regex c.info( Colors.YELLOW + ' Found ' + Colors.PURPLE + f + Colors.YELLOW + '!' + Colors._CLEAR ) self.__logger.debug( 'Full path: ' + fullpath ) inputs[_f][-1] = fullpath #time.sleep( 1 ) # don't consider any other option break return inputs
def preprocessing( self, inputs, outputs ): ''' Co-Register the input files using Flirt. ''' # convert the T1.mgz to T1.nii cmd = 'ss;' cmd += 'chb-fsstable;' cmd += 'mri_convert ' + inputs['T1'][-1] + ' ' + outputs['T1'] c.info( Colors.YELLOW + ' Converting ' + Colors.PURPLE + 'T1.mgz' + Colors.YELLOW + ' to ' + Colors.PURPLE + 'T1.nii' + Colors.YELLOW + '!' + Colors._CLEAR ) sp = subprocess.Popen( ["/bin/bash", "-i", "-c", cmd], stdout=sys.stdout ) sp.communicate() # convert the aparc+aseg.mgz to aparc+aseg.nii cmd = 'ss;' cmd += 'chb-fsstable;' cmd += 'mri_convert ' + inputs['segmentation'][-1] + ' ' + outputs['segmentation'] c.info( Colors.YELLOW + ' Converting ' + Colors.PURPLE + 'aparc+aseg.mgz' + Colors.YELLOW + ' to ' + Colors.PURPLE + 'aparc+aseg.nii' + Colors.YELLOW + '!' + Colors._CLEAR ) sp = subprocess.Popen( ["/bin/bash", "-i", "-c", cmd], stdout=sys.stdout ) sp.communicate() # register B0 to T1 cmd = 'ss;' cmd += 'chb-fsstable;' flirtcmd = 'flirt -in ' + inputs['b0'][-1] + ' -ref ' + outputs['T1'] + ' -usesqform -nosearch -dof 6 -cost mutualinfo -out ' + outputs['b0_T1_space'] + '.gz -omat ' + outputs['B0toT1matrix'] + ';' cmd += flirtcmd cmd += 'gzip -d -f ' + outputs['b0_T1_space'] + '.gz;' self.__logger.debug( flirtcmd ) c.info( Colors.YELLOW + ' Registering ' + Colors.PURPLE + os.path.split( inputs['b0'][-1] )[1] + Colors.YELLOW + ' to ' + Colors.PURPLE + 'T1.nii' + Colors.YELLOW + ' and storing ' + Colors.PURPLE + os.path.split( outputs['B0toT1matrix'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) sp = subprocess.Popen( ["/bin/bash", "-i", "-c", cmd], stdout=sys.stdout ) sp.communicate() # resample all other DTI volumes to T1 space for i in inputs: if i == 'fibers' or i == 'segmentation' or i == 'T1' or i == 'b0': # we do not map these continue cmd = 'ss;' cmd += 'chb-fsstable;' flirtcmd = 'flirt -in ' + inputs[i][-1] + ' -ref ' + outputs['T1'] + ' -out ' + outputs[i + '_T1_space'] + '.gz -init ' + outputs['B0toT1matrix'] + ' -applyxfm;' cmd += flirtcmd cmd += 'gzip -d -f ' + outputs[i + '_T1_space'] + '.gz;' self.__logger.debug( flirtcmd ) c.info( Colors.YELLOW + ' Resampling ' + Colors.PURPLE + os.path.split( inputs[i][-1] )[1] + Colors.YELLOW + ' as ' + Colors.PURPLE + os.path.split( outputs[i + '_T1_space'] )[1] + Colors.YELLOW + ' using ' + Colors.PURPLE + os.path.split( outputs['B0toT1matrix'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) sp = subprocess.Popen( ["/bin/bash", "-i", "-c", cmd], stdout=sys.stdout ) sp.communicate() # resample the fibers to T1 space cmd = 'ss;' cmd += 'chb-fsstable;' transformcmd = 'track_transform ' + inputs['fibers'][-1] + ' ' + outputs['fibers'] + ' -src ' + inputs['b0'][-1] + ' -ref ' + outputs['T1'] + ' -reg ' + outputs['B0toT1matrix'] + ';' cmd += transformcmd self.__logger.debug( transformcmd ) c.info( Colors.YELLOW + ' Transforming ' + Colors.PURPLE + os.path.split( inputs['fibers'][-1] )[1] + Colors.YELLOW + ' to ' + Colors.PURPLE + os.path.split( outputs['fibers'] )[1] + Colors.YELLOW + ' using ' + Colors.PURPLE + os.path.split( outputs['B0toT1matrix'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) sp = subprocess.Popen( ["/bin/bash", "-i", "-c", cmd], stdout=sys.stdout ) sp.communicate()
def sub(master, tracks, outputFile=None, verbose=False, threadName="Global"): """ Subtract tracks from master. Both parameters are nibabel.trackvis.streamlines objects. Calculation cost: O(M*N) Returns the result as a nibabel.trackvis.streamlines object or writes it to the file system if an outputFile is specified. """ masterSizeBefore = len(master) subtractedCount = 0 # O(M*N) for t in xrange(masterSizeBefore): if subtractedCount == len(tracks): # no way we can subtract more.. stop the loop return master c.debug( threadName + ": Looking for more tracks to subtract.. [Check #" + str(t) + "/" + str(masterSizeBefore) + "]", verbose, ) if master[t] == -1: # this fiber was already removed, skip to next one continue for u in xrange(len(tracks)): if tracks[u] == -1: # this fiber was already removed, skip to next one continue # compare fiber if [p for points in master[t][0] for p in points] == [p for points in tracks[u][0] for p in points]: # fibers are equal, set them as dirty master[t] = -1 tracks[u] = -1 subtractedCount += 1 # ... and jump out break master = filter(lambda t: t != -1, master) if not outputFile: return master else: # write it out to disk io.saveTrk(outputFile, master, None, None, True)
def sub(master, tracks, outputFile=None, verbose=False, threadName='Global'): ''' Subtract tracks from master. Both parameters are nibabel.trackvis.streamlines objects. Calculation cost: O(M*N) Returns the result as a nibabel.trackvis.streamlines object or writes it to the file system if an outputFile is specified. ''' masterSizeBefore = len(master) subtractedCount = 0 # O(M*N) for t in xrange(masterSizeBefore): if subtractedCount == len(tracks): # no way we can subtract more.. stop the loop return master c.debug( threadName + ': Looking for more tracks to subtract.. [Check #' + str(t) + '/' + str(masterSizeBefore) + ']', verbose) if master[t] == -1: # this fiber was already removed, skip to next one continue for u in xrange(len(tracks)): if tracks[u] == -1: # this fiber was already removed, skip to next one continue # compare fiber if [p for points in master[t][0] for p in points ] == [p for points in tracks[u][0] for p in points]: # fibers are equal, set them as dirty master[t] = -1 tracks[u] = -1 subtractedCount += 1 # ... and jump out break master = filter(lambda t: t != -1, master) if not outputFile: return master else: # write it out to disk io.saveTrk(outputFile, master, None, None, True)
def aniso2iso(self, image, spacing, dimensions): ''' from dipy.align.aniso2iso ''' header = image.header oldspacing = header.get_zooms() olddimensions = image.shape[:3] if spacing == 'no': newspacing = (min(oldspacing), min(oldspacing), min(oldspacing)) else: newspacing = (float(spacing.split(',')[0]), float(spacing.split(',')[1]), float(spacing.split(',')[2])) if dimensions == 'no': newdimensions = olddimensions else: newdimensions = (int(dimensions.split(',')[0]), int(dimensions.split(',')[1]), int(dimensions.split(',')[2])) c.info('Resampling the master image..') c.info(' old spacing ' + str(oldspacing)) c.info(' old dimensions ' + str(olddimensions)) # work on a numpy array to resample to isotropic spacing R = numpy.diag(numpy.array(newspacing) / numpy.array(oldspacing)) new_shape = numpy.array(oldspacing) / numpy.array( newspacing) * numpy.array(newdimensions) new_shape = numpy.round(new_shape).astype('i8') newImage = affine_transform(input=image, matrix=R, offset=numpy.zeros(3, ), output_shape=tuple(new_shape), order=0) Rx = numpy.eye(4) Rx[:3, :3] = R # get the mew world-image matrix affine = numpy.dot(image.coordmap.affine, Rx) # convert to NiPy image # copy the old coordmap and replace the affine matrix newCoordMap = image.coordmap newCoordMap.affine = affine # create a new NiPy image with the resampled data and the new coordmap (including the affine matrix) nipyImage = fromarray(newImage, '', '', newCoordMap) c.info(' new spacing ' + str(newspacing)) c.info(' new dimensions ' + str(nipyImage.shape[:3])) return nipyImage
def setupGrid( self, matrix ): if self.__test: self.__rows = 101 self.__cols = 101 self.__gridWidget = GridView( self, self.__rows, self.__cols, False ) self.__layout.addWidget( self.__gridWidget, 0, 0 ) b_overwriteSpectralValue = True maxEnergy = 255 / 3 automaton = C_spectrum_CAM_RGB( maxQuanta=maxEnergy ) automaton.component_add( 'R', maxEnergy / 3, b_overwriteSpectralValue ) automaton.component_add( 'G', maxEnergy / 3, b_overwriteSpectralValue ) automaton.component_add( 'B', maxEnergy / 3, b_overwriteSpectralValue ) automaton.updateRule_changeAmount(self.__updateAmount) world = C_CAE( np.array( ( self.__rows, self.__cols ) ), automaton ) world.verbosity_set( 1 ) arr_world = np.zeros( ( self.__rows, self.__cols ) ) arr_world[0, 0] = 1 arr_world[50, 50] = maxEnergy / 3 + 1 arr_world[100, 100] = maxEnergy / 3 * 2 + 1 elif matrix: maxEnergy = 255 arr_worldRaw = np.loadtxt( matrix, float, '#', '\t' ) arr_world = misc.arr_normalize( arr_worldRaw, scale=maxEnergy ) self.__rows, self.__cols = arr_world.shape self.__gridWidget = GridView( self, self.__rows, self.__cols, False ) self.__layout.addWidget( self.__gridWidget, 0, 0 ) b_overwriteSpectralValue = True automaton = C_spectrum_CAM_RGB( maxQuanta=maxEnergy ) automaton.component_add( 'R', maxEnergy / 3, b_overwriteSpectralValue ) automaton.component_add( 'G', maxEnergy / 3, b_overwriteSpectralValue ) automaton.component_add( 'B', maxEnergy / 3, b_overwriteSpectralValue ) print "Update amount = %d" % self.__updateAmount automaton.updateRule_changeAmount(self.__updateAmount) world = C_CAE( np.array( ( self.__rows, self.__cols ) ), automaton ) world.verbosity_set( 1 ) else: c.error( 'No test mode and no matrix..' ) sys.exit() print arr_world world.initialize( arr_world ) self.__world = world
def onTick( self ): ''' ''' # update the iterations counter self.__iterations += 1 self.__iterationLabel.setText( 'Iterations: ' + str( self.__iterations ) ) self.__world.state_transition() # draw it self.draw() b_cornersDominant = False if self.__b_stopAtCorners: b_cornersDominant = self.__world.currentGridCorners_areAllDominant() if self.__iterations >= int( self.__maxIterations ) and \ int( self.__maxIterations ) != -1 or \ self.__b_stopAtCorners and b_cornersDominant: # max. iterations reached self.__timer.stop() if self.__b_stopAtCorners: self.__playButton.setText('All corners are active') else: self.__playButton.setText( 'Maximum iterations reached' ) self.__playButton.setEnabled( False ) if self.__output: # take a screenshot and exit self.save( self.__output, self.__filestem ) c.info( 'Took screenshot and saved matrix.') c.info( 'Output: ' + str( self.__output ) + os.sep + self.__filestem + '.*)' ) c.info( 'Number of iterations: %d' % self.__iterations ) c.info( 'Good-bye!' ) sys.exit()
def copyScalars( trkFile1, trkFile2, outputFile ): ''' Copy scalars from trkFile1 to trkFile2 ''' s = io.loadTrk( trkFile1 ) s2 = io.loadTrk( trkFile2 ) tracks = s[0] tracks2 = s2[0] origHeader = s[1] origHeader2 = s2[1] tracksHeader = numpy.copy( s[1] ) tracksHeader2 = numpy.copy( s2[1] ) #if tracksHeader['n_count'] != tracksHeader2['n_count']: # c.error( 'The track counts do not match!' ) # sys.exit( 2 ) # now copy tracksHeader2['n_scalars'] = tracksHeader['n_scalars'] tracksHeader2['scalar_name'] = tracksHeader['scalar_name'] newTracks2 = [] for tCounter, t in enumerate( tracks ): tCoordinates = t[0] tScalars = t[1] # copy scalars over #tracks2[tCounter][1] = numpy.copy( tScalars ) newTracks2.append( ( tracks2[tCounter][0], tScalars[:], tracks2[tCounter][2] ) ) # write trkFile2 with update scalars io.saveTrk( outputFile, newTracks2, tracksHeader2, None, True ) c.info( 'Copied Scalars from ' + trkFile1 + ' to ' + trkFile2 + ' and saved as ' + outputFile )
def run(self, input, output, mode, verbose, jobs): if len(input) < 2: c.error("Please specify at least two *.trk files as input!") sys.exit(2) if os.path.exists(output): # abort if file already exists c.error("File " + str(output) + " already exists..") c.error("Aborting..") sys.exit(2) jobs = int(jobs) if jobs < 1 or jobs > 32: jobs = 1 # load 'master' mTracks = io.loadTrk(input[0]) # copy the tracks and the header from the 'master' c.info("Master is " + input[0]) outputTracks = mTracks[0] c.info("Number of tracks: " + str(len(outputTracks))) header = mTracks[1] # remove the first input input.pop(0) if mode == "add": # # ADD # for i in input: iTracks = io.loadTrk(i) # add the tracks c.debug("Adding " + str(len(iTracks[0])) + " tracks from " + i + " to master..", verbose) outputTracks = TrackvisCalcLogic.add(outputTracks, iTracks[0]) c.debug("Number of output tracks after final addition: " + str(len(outputTracks)), verbose) elif mode == "sub": # # SUB # c.debug("Using " + str(jobs) + " threads..", verbose) mergedOutputTracks = outputTracks[:] for i in input: iTracks = io.loadTrk(i) # subtract the tracks c.info("Subtracting " + i + " (" + str(len(iTracks[0])) + " tracks) from master..") # # THREADED COMPONENT # numberOfThreads = jobs c.info("Splitting master into " + str(jobs) + " pieces..") splittedOutputTracks = u.split_list(mergedOutputTracks, numberOfThreads) # list of threads t = [None] * numberOfThreads # list of alive flags a = [None] * numberOfThreads # list of tempFiles f = [None] * numberOfThreads for n in xrange(numberOfThreads): # mark thread as alive a[n] = True # fire the thread and give it a filename based on the number tmpFile = tempfile.mkstemp(".trk", "t_calc")[1] f[n] = tmpFile t[n] = Process( target=TrackvisCalcLogic.sub, args=(splittedOutputTracks[n][:], iTracks[0][:], tmpFile, verbose, "Thread-" + str(n + 1)), ) c.info("Starting Thread-" + str(n + 1) + "...") t[n].start() allDone = False while not allDone: time.sleep(1) for n in xrange(numberOfThreads): a[n] = t[n].is_alive() if not any(a): # if no thread is alive allDone = True # # END OF THREADED COMPONENT # c.info("All Threads done!") c.info("Merging output..") # now read all the created tempFiles and merge'em to one # first thread output is the master here tmpMaster = f[0] tMasterTracks = io.loadTrk(tmpMaster) for tmpFileNo in xrange(1, len(f)): tTracks = io.loadTrk(f[tmpFileNo]) # add them mergedOutputTracks = TrackvisCalcLogic.add(tMasterTracks[0], tTracks[0]) c.info("Merging done!") # some stats c.info("Number of output tracks after final removal: " + str(len(mergedOutputTracks))) outputTracks = mergedOutputTracks # now save the outputTracks io.saveTrk(output, outputTracks, header) c.info("All done!")
def makeMatrix(inputs, outputs, no_cortex): """ Make 1/ADC, ADC, FA, FiberNumber, FiberLength, E1, E2, E3 connectivity matrices. """ s = io.loadTrk(outputs["fibers_final"]) tracks = s[0] header = s[1] scalarNames = header["scalar_name"].tolist() matrix = {} # check if the segmentation is mapped try: scalarNames.index("segmentation") except: c.error(Colors.RED) for s in scalarNames: if not s: continue print s return for i in inputs: if i == "fibers" or i == "segmentation" or i == "T1" or i == "b0": # we do not map these continue # for tCounter, t in enumerate( tracks ): try: labelIndex = scalarNames.index("segmentation") adcIndex = scalarNames.index("adc") faIndex = scalarNames.index("fa") e1Index = scalarNames.index("e1") e2Index = scalarNames.index("e2") e3Index = scalarNames.index("e3") lengthIndex = scalarNames.index("length") except: c.error("Not all scalars were found: aparc_aseg_endlabel, adc, fa, length, e1, e2, e3") sys.exit(2) m_fn = numpy.zeros([68, 68]) m_fa = numpy.zeros([68, 68]) m_adc = numpy.zeros([68, 68]) m_adcinv = numpy.zeros([68, 68]) m_len = numpy.zeros([68, 68]) m_e1 = numpy.zeros([68, 68]) m_e2 = numpy.zeros([68, 68]) m_e3 = numpy.zeros([68, 68]) fslabel_vol = [ 2012, 2019, 2032, 2014, 2020, 2018, 2027, 2028, 2003, 2024, 2017, 2026, 2002, 2023, 2010, 2022, 2031, 2029, 2008, 2025, 2005, 2021, 2011, 2013, 2007, 2016, 2006, 2033, 2009, 2015, 2001, 2030, 2034, 2035, 1012, 1019, 1032, 1014, 1020, 1018, 1027, 1028, 1003, 1024, 1017, 1026, 1002, 1023, 1010, 1022, 1031, 1029, 1008, 1025, 1005, 1021, 1011, 1013, 1007, 1016, 1006, 1033, 1009, 1015, 1001, 1030, 1034, 1035, ] for tCounter, t in enumerate(tracks): tCoordinates = t[0] tScalars = t[1] fa = numpy.mean(tScalars[:, faIndex]) adc = numpy.mean(tScalars[:, adcIndex]) e1 = numpy.mean(tScalars[:, e1Index]) e2 = numpy.mean(tScalars[:, e2Index]) e3 = numpy.mean(tScalars[:, e3Index]) len = tScalars[0, lengthIndex] firstLabel = tScalars[0, labelIndex] lastLabel = tScalars[-1, labelIndex] try: fIndex = fslabel_vol.index(firstLabel) lIndex = fslabel_vol.index(lastLabel) except: continue print "found", firstLabel, lastLabel m_fn[fIndex, lIndex] += 1 m_fa[fIndex, lIndex] += fa m_adc[fIndex, lIndex] += adc m_e1[fIndex, lIndex] += e1 m_e2[fIndex, lIndex] += e2 m_e3[fIndex, lIndex] += e3 m_adcinv[fIndex, lIndex] += 1 / adc m_len[fIndex, lIndex] += len # symmetrize matrices m_fn = m_fn + m_fn.T - numpy.diag(m_fn.diagonal()) m_fa = m_fa + m_fa.T - numpy.diag(m_fa.diagonal()) m_adc = m_adc + m_adc.T - numpy.diag(m_adc.diagonal()) m_e1 = m_e1 + m_e1.T - numpy.diag(m_e1.diagonal()) m_e2 = m_e2 + m_e2.T - numpy.diag(m_e2.diagonal()) m_e3 = m_e3 + m_e3.T - numpy.diag(m_e3.diagonal()) m_adcinv = m_adcinv + m_adcinv.T - numpy.diag(m_adcinv.diagonal()) m_len = m_len + m_len.T - numpy.diag(m_len.diagonal()) # normalize matrices m_fa[:] /= m_fn[:] m_adc[:] /= m_fn[:] m_e1[:] /= m_fn[:] m_e2[:] /= m_fn[:] m_e3[:] /= m_fn[:] m_adcinv[:] /= m_fn[:] m_len[:] /= m_fn[:] m_fa = numpy.nan_to_num(m_fa) m_e1 = numpy.nan_to_num(m_e1) m_e2 = numpy.nan_to_num(m_e2) m_e3 = numpy.nan_to_num(m_e3) m_adc = numpy.nan_to_num(m_adc) m_adcinv = numpy.nan_to_num(m_adcinv) m_len = numpy.nan_to_num(m_len) # save as .mat and .csv sio.savemat( outputDirectory + "fibmap_all_cMatrix.mat", { "m_fiberNumber": m_fn, "m_fa": m_fa, "m_adc": m_adc, "m_adcInverse": m_adcinv, "m_fiberLength": m_len, "m_e1": m_e1, "m_e2": m_e2, "m_e3": m_e3, }, ) numpy.savetxt(outputDirectory + "fibmap_fibernumber_cMatrix.csv", m_fn, delimiter=",") numpy.savetxt(outputDirectory + "fibmap_fa_cMatrix.csv", m_fa, delimiter=",") numpy.savetxt(outputDirectory + "fibmap_e1_cMatrix.csv", m_e1, delimiter=",") numpy.savetxt(outputDirectory + "fibmap_e2_cMatrix.csv", m_e2, delimiter=",") numpy.savetxt(outputDirectory + "fibmap_e3_cMatrix.csv", m_e3, delimiter=",") numpy.savetxt(outputDirectory + "fibmap_adc_cMatrix.csv", m_adc, delimiter=",") numpy.savetxt(outputDirectory + "fibmap_adcinv_cMatrix.csv", m_adcinv, delimiter=",") numpy.savetxt(outputDirectory + "fibmap_fiberlength_cMatrix.csv", m_len, delimiter=",") c.info("Connectivity matrices generated and stored.")
parser.add_argument( '-co', '--cortex_only', action='store_true', dest='cortex_only', help='Perform filtering for cortex specific analysis and skip sub-cortical structures.' ) parser.add_argument( '-s', '--stage', action='store', dest='stage', default=0, type=int, help='Start with a specific stage while skipping the ones before. E.g. --stage 3 directly starts the mapping without preprocessing, --stage 4 starts with the filtering' ) parser.add_argument( '-overwrite', '--overwrite', action='store_true', dest='overwrite', help='Overwrite any existing output. DANGER!!' ) parser.add_argument( '-v', '--verbose', action='store_true', dest='verbose', help='Show verbose output' ) # always show the help if no arguments were specified if len( sys.argv ) == 1: parser.print_help() sys.exit( 1 ) options = parser.parse_args() # validate the inputs here if not os.path.isdir( options.input ): c.error( Colors.RED + 'Could not find the input directory! Specify a valid directory using -i $PATH.' + Colors._CLEAR ) sys.exit( 2 ) if os.path.exists( options.output ) and int( options.stage ) == 0: if not options.overwrite: c.error( Colors.RED + 'The output directory exists! Add --overwrite to erase previous content!' + Colors._CLEAR ) c.error( Colors.RED + 'Or use --stage > 2 to start with a specific stage which re-uses the previous content..' + Colors._CLEAR ) sys.exit( 2 ) else: # silently delete the existing output shutil.rmtree( options.output ) if options.stage > 0 and not os.path.exists( options.output ): # we start with a specific stage so we need the output stuff c.error( Colors.RED + 'The output directory does not exist! We need it when using -s/--stage to resume the process!' + Colors._CLEAR )
def run( self, input, output, radius, length, stage, cortex_only, verbose ): ''' ''' if stage == 0: # create output directory # but not if we start with a different stage os.mkdir( output ) # activate log file self.__debug = verbose self.__logger = Logger( os.path.join( output, 'log.txt' ), verbose ) sys.stdout = self.__logger sys.stderr = self.__logger # the input data _inputs = {'adc':[ '*adc.nii', None], 'b0':[ '*b0.nii', None], 'e1':['*e1.nii', None], 'e2':[ '*e2.nii', None], 'e3':[ '*e3.nii', None], 'fa':[ '*fa.nii', None], 'fibers':['*streamline.trk', '*/final-trackvis/*.trk', None], 'segmentation': ['*aparc+aseg.mgz', None], 'T1':['*/mri/brain.mgz', None] } # the output data _outputs = {'T1':os.path.join( output, 'T1.nii' ), 'segmentation':os.path.join( output, 'aparc+aseg.nii' ), 'b0_T1_space':os.path.join( output, 'dti_b0_T1_space.nii' ), 'adc_T1_space':os.path.join( output, 'dti_adc_T1_space.nii' ), 'fa_T1_space':os.path.join( output, 'dti_fa_T1_space.nii' ), 'e1_T1_space':os.path.join( output, 'dti_e1_T1_space.nii' ), 'e2_T1_space':os.path.join( output, 'dti_e2_T1_space.nii' ), 'e3_T1_space':os.path.join( output, 'dti_e3_T1_space.nii' ), 'B0toT1matrix':os.path.join( output, 'B0-to-T1.mat' ), 'fibers':os.path.join( output, 'fybers_T1_space.trk' ), 'fibers_mapped':os.path.join( output, 'fybers_T1_space_mapped.trk' ), 'fibers_mapped_length_filtered':os.path.join( output, 'fybers_T1_space_mapped_length_filtered.trk' ), 'fibers_mapped_length_filtered_cortex_only':os.path.join( output, 'fybers_T1_space_mapped_length_filtered_cortex_only.trk' ), 'fibers_final':os.path.join( output, 'fybers_final.trk' ), 'matrix_all': os.path.join( output, 'matrix_all.mat' ), 'matrix_fibercount': os.path.join( output, 'matrix_fibercount.csv' ), 'matrix_length': os.path.join( output, 'matrix_length.csv' ), 'matrix_adc': os.path.join( output, 'matrix_adc.csv' ), 'matrix_inv_adc': os.path.join( output, 'matrix_inv_adc.csv' ), 'matrix_fa': os.path.join( output, 'matrix_fa.csv' ), 'matrix_e1': os.path.join( output, 'matrix_e1.csv' ), 'matrix_e2': os.path.join( output, 'matrix_e2.csv' ), 'matrix_e3': os.path.join( output, 'matrix_e3.csv' ), 'roi':os.path.join( output, 'roi' ) } self.intro() # 4 x beep print '\a\a\a\a\a\a\a' #time.sleep( 3 ) # stage 1 c.info( Colors.YELLOW + '>> STAGE [' + Colors.PURPLE + '1' + Colors.YELLOW + ']: ' + Colors.YELLOW + ' ANALYZING INPUT DATA' + Colors._CLEAR ) if stage <= 2: # we can never skip stage 1 without skipping stage 2 _inputs = self.analyze_input_data( input, _inputs ) else: c.info( Colors.PURPLE + ' skipping it..' + Colors._CLEAR ) # stage 2 c.info( Colors.YELLOW + '>> STAGE [' + Colors.PURPLE + '2' + Colors.YELLOW + ']: ' + Colors.YELLOW + ' PREPROCESSING' + Colors._CLEAR ) if stage <= 2: self.preprocessing( _inputs, _outputs ) else: c.info( Colors.PURPLE + ' skipping it..' + Colors._CLEAR ) # stage 3 c.info( Colors.YELLOW + '>> STAGE [' + Colors.PURPLE + '3' + Colors.YELLOW + ']: ' + Colors.YELLOW + ' MAPPING' + Colors._CLEAR ) if stage <= 3: self.mapping( _inputs, _outputs, radius ) else: c.info( Colors.PURPLE + ' skipping it..' + Colors._CLEAR ) c.info( Colors.YELLOW + '>> STAGE [' + Colors.PURPLE + '4' + Colors.YELLOW + ']: ' + Colors.YELLOW + ' FILTERING' + Colors._CLEAR ) if stage <= 4: self.filtering( _inputs, _outputs, length, cortex_only ) else: c.info( Colors.PURPLE + ' skipping it..' + Colors._CLEAR ) c.info( Colors.YELLOW + '>> STAGE [' + Colors.PURPLE + '5' + Colors.YELLOW + ']: ' + Colors.YELLOW + ' CONNECTIVITY MATRICES' + Colors._CLEAR ) if stage <= 5: self.connectivity( _inputs, _outputs, cortex_only ) else: c.info( Colors.PURPLE + ' skipping it..' + Colors._CLEAR ) c.info( Colors.YELLOW + '>> STAGE [' + Colors.PURPLE + '6' + Colors.YELLOW + ']: ' + Colors.YELLOW + ' ROI EXTRACTION' + Colors._CLEAR ) if stage <= 6: self.roi_extract( _inputs, _outputs ) else: c.info( Colors.PURPLE + ' skipping it..' + Colors._CLEAR ) self.outro() c.info( '' ) c.info( 'ALL DONE! SAYONARA..' )
def run(self, files): ''' ''' for f in files: header = io.loadTrkHeaderOnly(f) dimensions = header['dim'] spacing = header['voxel_size'] origin = header['origin'] numberOfScalars = header['n_scalars'] scalarNames = header['scalar_name'] numberOfProperties = header['n_properties'] propertyNames = header['property_name'] vox2rasMatrix = header['vox_to_ras'] voxelOrder = header['voxel_order'] pad1 = header['pad1'] pad2 = header['pad2'] imageOrientation = header['image_orientation_patient'] numberOfTracks = header['n_count'] version = header['version'] c.info('FILE: ' + f) c.info(' TRACKVIS VERSION: ' + str(version)) c.info(' NUMBER OF TRACKS: ' + str(numberOfTracks)) c.info(' DIMENSIONS: ' + str(dimensions)) c.info(' SPACING: ' + str(spacing)) c.info(' ORIGIN: ' + str(origin)) c.info(' NUMBER OF SCALARS: ' + str(numberOfScalars)) if numberOfScalars > 0: c.info(' SCALARS: ' + str(scalarNames)) c.info(' NUMBER OF PROPERTIES: ' + str(numberOfProperties)) if numberOfProperties > 0: c.info(' PROPERTIES: ' + str(propertyNames)) if version == 2: # only in trackvis v2 c.info(' VOX2RAS Matrix:') c.info(' ' + str(vox2rasMatrix[0])) c.info(' ' + str(vox2rasMatrix[1])) c.info(' ' + str(vox2rasMatrix[2])) c.info(' ' + str(vox2rasMatrix[3])) c.info(' VOXEL ORDER: ' + str(voxelOrder)) #c.info( ' IMAGE ORIENTATION: ' ) #c.info( ' ' + str( imageOrientation ) ) #c.info( ' PADDING 1: ' + str( pad1 ) ) #c.info( ' PADDING 2: ' + str( pad2 ) ) print
def run( self, input, output, matrix, jobs ): ''' ''' if os.path.exists( output ): # abort if file already exists c.error( 'File ' + str( output ) + ' already exists..' ) c.error( 'Aborting..' ) sys.exit( 2 ) if not os.path.isfile( matrix ): # abort if the matrix does not exist c.error( 'Matrix-File ' + str( matrix ) + ' does not exist..' ) c.error( 'Aborting..' ) sys.exit( 2 ) jobs = int( jobs ) if jobs < 1 or jobs > 32: jobs = 1 # read c.info( 'Loading ' + input + '..' ) t = io.loadTrk( input ) tracks = t[0] header = t[1] #.. copy the current header newHeader = numpy.copy( header ) # print old matrix in header # # WARNING: this matrix is actually never used by TrackVis (see email from Ruopeng). # We still modify it to keep it in sync with the transformations which we apply point wise. # if hasattr( header, 'vox_to_ras' ): oldMatrix = header['vox_to_ras'] c.info( 'Old transformation matrix:' ) c.info( ' ' + str( oldMatrix[0] ) ) c.info( ' ' + str( oldMatrix[1] ) ) c.info( ' ' + str( oldMatrix[2] ) ) c.info( ' ' + str( oldMatrix[3] ) ) # # load our transformation Matrix # newMatrix = numpy.loadtxt( matrix, float, '#', ' ' ) # # THREADED COMPONENT # numberOfThreads = jobs c.info( 'Splitting the input into ' + str( jobs ) + ' pieces..' ) splittedOutputTracks = u.split_list( tracks, numberOfThreads ) # list of threads t = [None] * numberOfThreads # list of alive flags a = [None] * numberOfThreads # list of tempFiles f = [None] * numberOfThreads for n in xrange( numberOfThreads ): # mark thread as alive a[n] = True # fire the thread and give it a filename based on the number tmpFile = tempfile.mkstemp( '.trk', 't_transform' )[1] f[n] = tmpFile t[n] = Process( target=TrackvisTransformLogic.transform, args=( splittedOutputTracks[n][:], newMatrix, tmpFile, False, 'Thread-' + str( n + 1 ) ) ) c.info( "Starting Thread-" + str( n + 1 ) + "..." ) t[n].start() allDone = False while not allDone: time.sleep( 1 ) for n in xrange( numberOfThreads ): a[n] = t[n].is_alive() if not any( a ): # if no thread is alive allDone = True # # END OF THREADED COMPONENT # c.info( "All Threads done!" ) c.info( "Merging output.." ) # now read all the created tempFiles and merge'em to one # first thread output is the master here tmpMaster = f[0] tMasterTracks = io.loadTrk( tmpMaster ) for tmpFileNo in xrange( 1, len( f ) ): tTracks = io.loadTrk( f[tmpFileNo] ) # add them tracks = TrackvisCalcLogic.add( tMasterTracks[0], tTracks[0] ) c.info( "Merging done!" ) # # replace the matrix in the header with a transformed one even if it will never be used by TrackVis # if hasattr( header, 'vox_to_ras' ): result = numpy.dot( oldMatrix, newMatrix ) c.info( 'New transformation matrix:' ) c.info( ' ' + str( result[0] ) ) c.info( ' ' + str( result[1] ) ) c.info( ' ' + str( result[2] ) ) c.info( ' ' + str( result[3] ) ) newHeader['vox_to_ras'] = result # write c.info( 'Saving ' + output + '..' ) io.saveTrk( output, tracks, newHeader ) c.info( 'All done!' )
def mapping( self, inputs, outputs, radius ): ''' Map all detected scalar volumes to each fiber. ''' # check if we have all required input data # we need at least: # - outputs['fibers'] == Track file in T1 space # - outputs['segmentation'] == Label Map if not os.path.exists( outputs['fibers'] ): c.error( Colors.RED + 'Could not find ' + Colors.YELLOW + outputs['fibers'] + Colors.RED + ' but we really need it to start with stage 3!!' + Colors._CLEAR ) sys.exit( 2 ) if not os.path.exists( outputs['segmentation'] ): c.error( Colors.RED + 'Could not find ' + Colors.YELLOW + outputs['segmentation'] + Colors.RED + ' but we really need it to start with stage 3!!' + Colors._CLEAR ) sys.exit( 2 ) actions = [] for i in inputs: if i == 'fibers' or i == 'segmentation' or i == 'T1' or i == 'b0': # we do not map these continue if not os.path.exists( outputs[i + '_T1_space'] ): # we can't map this since we didn't find the file continue # for normal scalars: append it to the actions actions.append( FyMapAction( i, outputs[i + '_T1_space'] ) ) c.info( Colors.YELLOW + ' Configuring mapping of ' + Colors.PURPLE + os.path.split( outputs[i + '_T1_space'] )[1] + Colors.YELLOW + ' to ' + Colors.PURPLE + os.path.split( outputs['fibers'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) # now the segmentation with the lookaround radius actions.append( FyRadiusMapAction( 'segmentation', outputs['segmentation'], radius ) ) c.info( Colors.YELLOW + ' Configuring mapping of ' + Colors.PURPLE + os.path.split( outputs['segmentation'] )[1] + Colors.YELLOW + ' to ' + Colors.PURPLE + os.path.split( outputs['fibers'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) # and also the fiber length actions.append( FyLengthAction() ) c.info( Colors.YELLOW + ' Configuring mapping of ' + Colors.PURPLE + 'fiber length' + Colors.YELLOW + ' to ' + Colors.PURPLE + os.path.split( outputs['fibers'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) # run, forest, run!! c.info( Colors.YELLOW + ' Performing configured mapping for ' + Colors.PURPLE + os.path.split( outputs['fibers'] )[1] + Colors.YELLOW + ' and storing as ' + Colors.PURPLE + os.path.split( outputs['fibers_mapped'] )[1] + Colors.YELLOW + ' (~ 30 minutes)!' + Colors._CLEAR ) if self.__debug: fyborg.fyborg( outputs['fibers'], outputs['fibers_mapped'], actions, 'debug' ) else: fyborg.fyborg( outputs['fibers'], outputs['fibers_mapped'], actions )
def run( self, files ): ''' ''' for f in files: header = io.loadTrkHeaderOnly( f ) dimensions = header['dim'] spacing = header['voxel_size'] origin = header['origin'] numberOfScalars = header['n_scalars'] scalarNames = header['scalar_name'] numberOfProperties = header['n_properties'] propertyNames = header['property_name'] vox2rasMatrix = header['vox_to_ras'] voxelOrder = header['voxel_order'] pad1 = header['pad1'] pad2 = header['pad2'] imageOrientation = header['image_orientation_patient'] numberOfTracks = header['n_count'] version = header['version'] c.info( 'FILE: ' + f ) c.info( ' TRACKVIS VERSION: ' + str( version ) ) c.info( ' NUMBER OF TRACKS: ' + str( numberOfTracks ) ) c.info( ' DIMENSIONS: ' + str( dimensions ) ) c.info( ' SPACING: ' + str( spacing ) ) c.info( ' ORIGIN: ' + str( origin ) ) c.info( ' NUMBER OF SCALARS: ' + str( numberOfScalars ) ) if numberOfScalars > 0: c.info( ' SCALARS: ' + str( scalarNames ) ) c.info( ' NUMBER OF PROPERTIES: ' + str( numberOfProperties ) ) if numberOfProperties > 0: c.info( ' PROPERTIES: ' + str( propertyNames ) ) if version == 2: # only in trackvis v2 c.info( ' VOX2RAS Matrix:' ) c.info( ' ' + str( vox2rasMatrix[0] ) ) c.info( ' ' + str( vox2rasMatrix[1] ) ) c.info( ' ' + str( vox2rasMatrix[2] ) ) c.info( ' ' + str( vox2rasMatrix[3] ) ) c.info( ' VOXEL ORDER: ' + str( voxelOrder ) ) #c.info( ' IMAGE ORIENTATION: ' ) #c.info( ' ' + str( imageOrientation ) ) #c.info( ' PADDING 1: ' + str( pad1 ) ) #c.info( ' PADDING 2: ' + str( pad2 ) ) print
def fyborg( trkFile, outputTrkFile, actions, *args ): if not actions: c.error( "We gotta do something.." ) return showDebug = 'debug' in args singleThread = 'singlethread' in args c.debug( "trkFile:" + str( trkFile ), showDebug ) c.debug( "outputTrkFile:" + str( outputTrkFile ), showDebug ) c.debug( "args:" + str( args ), showDebug ) # load trk file s = io.loadTrk( trkFile ) tracks = s[0] origHeader = s[1] tracksHeader = numpy.copy( s[1] ) numberOfScalars = origHeader['n_scalars'] scalars = origHeader['scalar_name'].tolist() numberOfTracks = origHeader['n_count'] # show some file informations printTrkInfo( tracksHeader, trkFile ) # grab the scalarNames scalarNames = [] for a in actions: if a.scalarName() != FyAction.NoScalar: scalarNames.append( a.scalarName() ) # increase the number of scalars tracksHeader['n_scalars'] += len( scalarNames ) # .. attach the new scalar names for i in range( len( scalarNames ) ): tracksHeader['scalar_name'][numberOfScalars + i] = scalarNames[i] # # THREADED COMPONENT # if singleThread: numberOfThreads = 1 else: numberOfThreads = multiprocessing.cpu_count() c.info( 'Splitting master into ' + str( numberOfThreads ) + ' pieces..' ) splittedOutputTracks = u.split_list( tracks[:], numberOfThreads ) # list of threads t = [None] * numberOfThreads # list of alive flags a = [None] * numberOfThreads # list of tempFiles f = [None] * numberOfThreads for n in xrange( numberOfThreads ): # configure actions __actions = [] for act in actions: __actions.append( act ) # mark thread as alive a[n] = True # fire the thread and give it a filename based on the number tmpFile = tempfile.mkstemp( '.trk', 'fyborg' )[1] f[n] = tmpFile t[n] = Process( target=fyborgLooper_, args=( splittedOutputTracks[n][:], tracksHeader, tmpFile, __actions, showDebug, n + 1 ) ) c.info( "Starting Thread-" + str( n + 1 ) + "..." ) t[n].start() allDone = False while not allDone: time.sleep( 1 ) for n in xrange( numberOfThreads ): a[n] = t[n].is_alive() if not any( a ): # if no thread is alive allDone = True # # END OF THREADED COMPONENT # c.info( "All Threads done!" ) # # Merging stage # c.info( "Merging tracks.." ) outputTracks = [] # now read all the created tempFiles and merge'em to one for tmpFileNo in xrange( 0, len( f ) ): tTracks = io.loadTrk( f[tmpFileNo] ) # add them outputTracks.extend( tTracks[0] ) c.info( "Merging done!" ) io.saveTrk( outputTrkFile, outputTracks, tracksHeader, None, True ) c.info( "All done!" )
def filtering( self, inputs, outputs, length, cortex_only ): ''' Filter the mapped fibers. ''' # check if we have all required input data # we need at least: # - outputs['fibers_mapped'] == Track file in T1 space with mapped scalars if not os.path.exists( outputs['fibers_mapped'] ): c.error( Colors.RED + 'Could not find ' + Colors.YELLOW + outputs['fibers_mapped'] + Colors.RED + ' but we really need it to start with stage 4!!' + Colors._CLEAR ) sys.exit( 2 ) # find the order of the mapped scalars header = io.loadTrkHeaderOnly( outputs['fibers_mapped'] ) scalars = list( header['scalar_name'] ) # split the length range length = length.split( ' ' ) min_length = int( length[0] ) max_length = int( length[1] ) # length filtering c.info( Colors.YELLOW + ' Filtering ' + Colors.PURPLE + 'fiber length' + Colors.YELLOW + ' to be ' + Colors.PURPLE + '>' + str( min_length ) + ' and <' + str( max_length ) + Colors.YELLOW + ' for ' + Colors.PURPLE + os.path.split( outputs['fibers_mapped'] )[1] + Colors.YELLOW + ' and store as ' + Colors.PURPLE + os.path.split( outputs['fibers_mapped_length_filtered'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) fyborg.fyborg( outputs['fibers_mapped'], outputs['fibers_mapped_length_filtered'], [FyFilterLengthAction( scalars.index( 'length' ), min_length, max_length )] ) header = io.loadTrkHeaderOnly( outputs['fibers_mapped_length_filtered'] ) new_count = header['n_count'] c.info( Colors.YELLOW + ' Number of tracks after ' + Colors.PURPLE + 'length filtering' + Colors.YELLOW + ': ' + str( new_count ) + Colors.YELLOW + Colors._CLEAR ) if cortex_only: # special cortex filtering c.info( Colors.YELLOW + ' Filtering for ' + Colors.PURPLE + 'valid cortex structures' + Colors.YELLOW + ' in ' + Colors.PURPLE + os.path.split( outputs['fibers_mapped_length_filtered'] )[1] + Colors.YELLOW + ' and store as ' + Colors.PURPLE + os.path.split( outputs['fibers_mapped_length_filtered_cortex_only'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) c.info( Colors.PURPLE + ' Conditions for valid fibers:' + Colors._CLEAR ) c.info( Colors.PURPLE + ' 1.' + Colors.YELLOW + ' The fiber track has to pass through the cerebral white matter. (Label values: ' + Colors.PURPLE + '[2, 41]' + Colors.YELLOW + ')' + Colors._CLEAR ) c.info( Colors.PURPLE + ' 2.' + Colors.YELLOW + ' The fiber track shall only touch sub-cortical structures not more than ' + Colors.PURPLE + '5 times' + Colors.YELLOW + '. (Label values: ' + Colors.PURPLE + '[10, 49, 16, 28, 60, 4, 43]' + Colors.YELLOW + ')' + Colors._CLEAR ) c.info( Colors.PURPLE + ' 3.' + Colors.YELLOW + ' The track shall not pass through the corpus callosum (Labels: ' + Colors.PURPLE + '[251, 255]' + Colors.YELLOW + ') and end in the same hemisphere (Labels: ' + Colors.PURPLE + '[1000-1035]' + Colors.YELLOW + ' for left, ' + Colors.PURPLE + '[2000-2035]' + Colors.YELLOW + ' for right).' + Colors._CLEAR ) fyborg.fyborg( outputs['fibers_mapped_length_filtered'], outputs['fibers_mapped_length_filtered_cortex_only'], [FyFilterCortexAction( scalars.index( 'segmentation' ) )] ) header = io.loadTrkHeaderOnly( outputs['fibers_mapped_length_filtered_cortex_only'] ) new_count = header['n_count'] c.info( Colors.YELLOW + ' Number of tracks after ' + Colors.PURPLE + 'cortex filtering' + Colors.YELLOW + ': ' + str( new_count ) + Colors.YELLOW + Colors._CLEAR ) c.info( Colors.YELLOW + ' Copied filtered tracks from ' + Colors.PURPLE + os.path.split( outputs['fibers_mapped_length_filtered_cortex_only'] )[1] + Colors.YELLOW + ' to ' + Colors.PURPLE + os.path.split( outputs['fibers_final'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) shutil.copyfile( outputs['fibers_mapped_length_filtered_cortex_only'], outputs['fibers_final'] ) else: c.info( Colors.YELLOW + ' Info: ' + Colors.PURPLE + 'Cortical _and_ sub-cortical structures ' + Colors.YELLOW + 'will be included..' + Colors._CLEAR ) c.info( Colors.YELLOW + ' Copied filtered tracks from ' + Colors.PURPLE + os.path.split( outputs['fibers_mapped_length_filtered'] )[1] + Colors.YELLOW + ' to ' + Colors.PURPLE + os.path.split( outputs['fibers_final'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) shutil.copyfile( outputs['fibers_mapped_length_filtered'], outputs['fibers_final'] )
def connectivity( self, inputs, outputs, cortex_only ): ''' Generate connectivity matrices using mapped values. ''' # check if we have all required input data # we need at least: # - outputs['fibers_mapped'] == Track file in T1 space with mapped scalars if not os.path.exists( outputs['fibers_final'] ): c.error( Colors.RED + 'Could not find ' + Colors.YELLOW + outputs['fibers_final'] + Colors.RED + ' but we really need it to start with stage 5!!' + Colors._CLEAR ) sys.exit( 2 ) s = io.loadTrk( outputs['fibers_final'] ) tracks = s[0] header = s[1] scalarNames = header['scalar_name'].tolist() matrix = {} indices = {} # check if the segmentation is mapped try: indices['segmentation'] = scalarNames.index( 'segmentation' ) except: c.error( Colors.RED + 'Could not find ' + Colors.YELLOW + 'segmentation' + Colors.RED + ' as a mapped scalar but we really need it!' ) sys.exit( 2 ) if cortex_only: labels = [2012, 2019, 2032, 2014, 2020, 2018, 2027, 2028, 2003, 2024, 2017, 2026, 2002, 2023, 2010, 2022, 2031, 2029, 2008, 2025, 2005, 2021, 2011, 2013, 2007, 2016, 2006, 2033, 2009, 2015, 2001, 2030, 2034, 2035, 1012, 1019, 1032, 1014, 1020, 1018, 1027, 1028, 1003, 1024, 1017, 1026, 1002, 1023, 1010, 1022, 1031, 1029, 1008, 1025, 1005, 1021, 1011, 1013, 1007, 1016, 1006, 1033, 1009, 1015, 1001, 1030, 1034, 1035] else: labels = [2012, 2019, 2032, 2014, 2020, 2018, 2027, 2028, 2003, 2024, 2017, 2026, 2002, 2023, 2010, 2022, 2031, 2029, 2008, 2025, 2005, 2021, 2011, 2013, 2007, 2016, 2006, 2033, 2009, 2015, 2001, 2030, 2034, 2035, 49, 50, 51, 52, 58, 53, 54, 1012, 1019, 1032, 1014, 1020, 1018, 1027, 1028, 1003, 1024, 1017, 1026, 1002, 1023, 1010, 1022, 1031, 1029, 1008, 1025, 1005, 1021, 1011, 1013, 1007, 1016, 1006, 1033, 1009, 1015, 1001, 1030, 1034, 1035, 10, 11, 12, 13, 26, 17, 18, 16] c.info( Colors.YELLOW + ' Getting ready to create connectivity matrices for the following labels: ' + Colors.PURPLE + str( labels ) + Colors._CLEAR ) c.info( Colors.YELLOW + ' Note: Mapped scalar values along the points will be averaged for each fiber track.' + Colors._CLEAR ) # create matrices for the attached scalars for i, s in enumerate( scalarNames ): if i >= header['n_scalars']: break if not s or s == 'segmentation': continue # this is a scalar value for which a matrix will be created matrix[s] = np.zeros( [len( labels ), len( labels )] ) indices[s] = scalarNames.index( s ) c.info( Colors.YELLOW + ' Preparing matrix (' + Colors.PURPLE + '[' + str( len( labels ) ) + 'x' + str( len( labels ) ) + ']' + Colors.YELLOW + ') for ' + Colors.PURPLE + s + Colors.YELLOW + ' values!' + Colors._CLEAR ) if s == 'adc': s = 'inv_adc' matrix[s] = np.zeros( [len( labels ), len( labels )] ) indices[s] = scalarNames.index( 'adc' ) c.info( Colors.YELLOW + ' Preparing matrix (' + Colors.PURPLE + '[' + str( len( labels ) ) + 'x' + str( len( labels ) ) + ']' + Colors.YELLOW + ') for ' + Colors.PURPLE + s + Colors.YELLOW + ' values!' + Colors._CLEAR ) # always create one for the fiber counts matrix['fibercount'] = np.zeros( [len( labels ), len( labels )] ) indices['fibercount'] = 0 c.info( Colors.YELLOW + ' Preparing matrix (' + Colors.PURPLE + '[' + str( len( labels ) ) + 'x' + str( len( labels ) ) + ']' + Colors.YELLOW + ') for ' + Colors.PURPLE + 'fibercount' + Colors.YELLOW + ' values!' + Colors._CLEAR ) c.info( Colors.YELLOW + ' Analyzing fibers of ' + Colors.PURPLE + os.path.split( outputs['fibers_final'] )[1] + Colors.YELLOW + '..' + Colors._CLEAR ) for tCounter, t in enumerate( tracks ): tCoordinates = t[0] tScalars = t[1] # find the segmentation labels for the start and end points start_label = tScalars[0, indices['segmentation']] end_label = tScalars[-1, indices['segmentation']] try: # now grab the index of the labels in our label list start_index = labels.index( start_label ) end_index = labels.index( end_label ) except: # this label is not monitored, so ignore this track continue # loop through all different scalars for m in matrix: # calculate the mean for each track value = np.mean( tScalars[:, indices[m]] ) if m == 'inv_adc': # invert the value since it is 1-ADC value = 1 / value elif m == 'fibercount': # in the case of fibercount, add 1 value = 1 # store value in the matrix matrix[m][start_index, end_index] += value if not start_index == end_index: matrix[m][end_index, start_index] += value # fiber loop is done, all values are stored # now normalize the matrices np.seterr( all='ignore' ) # avoid div by 0 warnings cbar = None for m in matrix: if not m == 'fibercount': # normalize it matrix[m][:] /= matrix['fibercount'] matrix[m] = np.nan_to_num( matrix[m] ) # store the matrix c.info( Colors.YELLOW + ' Storing ' + Colors.PURPLE + m + Colors.YELLOW + ' connectivity matrix as ' + Colors.PURPLE + os.path.split( outputs['matrix_' + m] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) np.savetxt( outputs['matrix_' + m], matrix[m], delimiter='\t' ) # store a picture picture_path = os.path.splitext( os.path.split( outputs['matrix_' + m] )[1] )[0] + '.png' c.info( Colors.YELLOW + ' Generating ' + Colors.PURPLE + m + ' image' + Colors.YELLOW + ' as ' + Colors.PURPLE + picture_path + Colors.YELLOW + '!' + Colors._CLEAR ) img = plot.imshow( matrix[m], interpolation='nearest' ) img.set_cmap( 'jet' ) img.set_norm( LogNorm() ) img.axes.get_xaxis().set_visible( False ) img.axes.get_yaxis().set_visible( False ) if not cbar: cbar = plot.colorbar() cbar.set_label( m ) cbar.set_ticks( [] ) plot.savefig( os.path.join( os.path.split( outputs['matrix_' + m] )[0], picture_path ) ) np.seterr( all='warn' ) # reactivate div by 0 warnings # now store the matlab version as well c.info( Colors.YELLOW + ' Storing ' + Colors.PURPLE + 'matlab data bundle' + Colors.YELLOW + ' containing ' + Colors.PURPLE + 'all matrices' + Colors.YELLOW + ' as ' + Colors.PURPLE + os.path.split( outputs['matrix_all'] )[1] + Colors.YELLOW + '!' + Colors._CLEAR ) scipy.io.savemat( outputs['matrix_all'], matrix, oned_as='row' )
def roi_extract( self, inputs, outputs ): ''' ''' # check if we have all required input data # we need at least: # - outputs['fibers_mapped'] == Track file in T1 space with mapped scalars if not os.path.exists( outputs['fibers_final'] ): c.error( Colors.RED + 'Could not find ' + Colors.YELLOW + outputs['fibers_final'] + Colors.RED + ' but we really need it to start with stage 6!!' + Colors._CLEAR ) sys.exit( 2 ) s = io.loadTrk( outputs['fibers_final'] ) tracks = s[0] header = s[1] scalarNames = header['scalar_name'].tolist() labels = {} # check if the segmentation is mapped try: seg_index = scalarNames.index( 'segmentation' ) except: c.error( Colors.RED + 'Could not find ' + Colors.YELLOW + 'segmentation' + Colors.RED + ' as a mapped scalar but we really need it!' ) sys.exit( 2 ) # create the roi subfolder if not os.path.exists( outputs['roi'] ): os.mkdir( outputs['roi'] ) # parse the color table lut = colortable.freesurfer.split( '\n' ) colors = {} for color in lut: if not color or color[0] == '#': continue splitted_line = color.split( ' ' ) splitted_line = filter( None, splitted_line ) colors[splitted_line[0]] = splitted_line[1] # loop through tracks for i, t in enumerate( tracks ): tCoordinates = t[0] tScalars = t[1] # grab the scalars for each point for scalar in tScalars: # but only the label value label_value = str( int( scalar[seg_index] ) ) if not label_value in labels: labels[label_value] = [] if not i in labels[label_value]: # store the unique fiber id for this label labels[label_value].append( i ) # now loop through all detected labels for l in labels: new_tracks = [] for t_id in labels[l]: # grab the fiber + scalars current_fiber = tracks[t_id] new_tracks.append( current_fiber ) # now store the trk file trk_outputfile = l + '_' + colors[l] + '.trk' nii_outputfile = l + '_' + colors[l] + '.nii' c.info( Colors.YELLOW + ' Creating fiber ROI ' + Colors.PURPLE + trk_outputfile + Colors.YELLOW + '!' + Colors._CLEAR ) io.saveTrk( os.path.join( outputs['roi'], trk_outputfile ), new_tracks, header, None, True ) # also create a roi label volume for this label value c.info( Colors.YELLOW + ' Creating NII ROI ' + Colors.PURPLE + nii_outputfile + Colors.YELLOW + '!' + Colors._CLEAR ) cmd = 'ss;' cmd += 'chb-fsstable;' cmd += 'mri_binarize --i ' + outputs['segmentation'] + ' --o ' + os.path.join( outputs['roi'], nii_outputfile ) + ' --match ' + l + ' --binval ' + l + ';' self.__logger.debug( cmd ) sp = subprocess.Popen( ["/bin/bash", "-i", "-c", cmd], stdout=sys.stdout ) sp.communicate()
def printTrkInfo( header, fileName ): dimensions = header['dim'] spacing = header['voxel_size'] origin = header['origin'] numberOfScalars = header['n_scalars'] scalarNames = header['scalar_name'] numberOfProperties = header['n_properties'] propertyNames = header['property_name'] voxelOrder = header['voxel_order'] pad1 = header['pad1'] pad2 = header['pad2'] imageOrientation = header['image_orientation_patient'] numberOfTracks = header['n_count'] version = header['version'] c.info( 'FILE: ' + fileName ) c.info( ' TRACKVIS VERSION: ' + str( version ) ) c.info( ' NUMBER OF TRACKS: ' + str( numberOfTracks ) ) c.info( ' DIMENSIONS: ' + str( dimensions ) ) c.info( ' SPACING: ' + str( spacing ) ) c.info( ' ORIGIN: ' + str( origin ) ) c.info( ' NUMBER OF SCALARS: ' + str( numberOfScalars ) ) if numberOfScalars > 0: c.info( ' SCALARS: ' + str( scalarNames ) ) c.info( ' NUMBER OF PROPERTIES: ' + str( numberOfProperties ) ) if numberOfProperties > 0: c.info( ' PROPERTIES: ' + str( propertyNames ) ) if version == 2: # only in trackvis v2 vox2rasMatrix = header['vox_to_ras'] c.info( ' VOX2RAS Matrix:' ) c.info( ' ' + str( vox2rasMatrix[0] ) ) c.info( ' ' + str( vox2rasMatrix[1] ) ) c.info( ' ' + str( vox2rasMatrix[2] ) ) c.info( ' ' + str( vox2rasMatrix[3] ) ) c.info( ' VOXEL ORDER: ' + str( voxelOrder ) )
def run(self, input, output, mode, verbose, jobs): if len(input) < 2: c.error('Please specify at least two *.trk files as input!') sys.exit(2) if os.path.exists(output): # abort if file already exists c.error('File ' + str(output) + ' already exists..') c.error('Aborting..') sys.exit(2) jobs = int(jobs) if jobs < 1 or jobs > 32: jobs = 1 # load 'master' mTracks = io.loadTrk(input[0]) # copy the tracks and the header from the 'master' c.info('Master is ' + input[0]) outputTracks = mTracks[0] c.info('Number of tracks: ' + str(len(outputTracks))) header = mTracks[1] # remove the first input input.pop(0) if mode == 'add': # # ADD # for i in input: iTracks = io.loadTrk(i) # add the tracks c.debug( 'Adding ' + str(len(iTracks[0])) + ' tracks from ' + i + ' to master..', verbose) outputTracks = TrackvisCalcLogic.add(outputTracks, iTracks[0]) c.debug( 'Number of output tracks after final addition: ' + str(len(outputTracks)), verbose) elif mode == 'sub': # # SUB # c.debug('Using ' + str(jobs) + ' threads..', verbose) mergedOutputTracks = outputTracks[:] for i in input: iTracks = io.loadTrk(i) # subtract the tracks c.info('Subtracting ' + i + ' (' + str(len(iTracks[0])) + ' tracks) from master..') # # THREADED COMPONENT # numberOfThreads = jobs c.info('Splitting master into ' + str(jobs) + ' pieces..') splittedOutputTracks = u.split_list(mergedOutputTracks, numberOfThreads) # list of threads t = [None] * numberOfThreads # list of alive flags a = [None] * numberOfThreads # list of tempFiles f = [None] * numberOfThreads for n in xrange(numberOfThreads): # mark thread as alive a[n] = True # fire the thread and give it a filename based on the number tmpFile = tempfile.mkstemp('.trk', 't_calc')[1] f[n] = tmpFile t[n] = Process(target=TrackvisCalcLogic.sub, args=(splittedOutputTracks[n][:], iTracks[0][:], tmpFile, verbose, 'Thread-' + str(n + 1))) c.info("Starting Thread-" + str(n + 1) + "...") t[n].start() allDone = False while not allDone: time.sleep(1) for n in xrange(numberOfThreads): a[n] = t[n].is_alive() if not any(a): # if no thread is alive allDone = True # # END OF THREADED COMPONENT # c.info("All Threads done!") c.info("Merging output..") # now read all the created tempFiles and merge'em to one # first thread output is the master here tmpMaster = f[0] tMasterTracks = io.loadTrk(tmpMaster) for tmpFileNo in xrange(1, len(f)): tTracks = io.loadTrk(f[tmpFileNo]) # add them mergedOutputTracks = TrackvisCalcLogic.add( tMasterTracks[0], tTracks[0]) c.info("Merging done!") # some stats c.info('Number of output tracks after final removal: ' + str(len(mergedOutputTracks))) outputTracks = mergedOutputTracks # now save the outputTracks io.saveTrk(output, outputTracks, header) c.info('All done!')
def run(self, masterFile, inputFiles, outputDirectory, spacing, dimensions, likefreesurfer, nii): ''' Performs the equalization ''' # sanity checks outputDirectory = os.path.normpath(outputDirectory) # prepare the output directory if os.path.exists(outputDirectory): c.error('The output directory already exists!') c.error('Aborting..') sys.exit(2) # create the output directory os.mkdir(outputDirectory) # MASTER masterFile = os.path.normpath(masterFile) # read the master master = io.readImage(masterFile) c.info('MASTER IMAGE: ' + str(masterFile)) # INPUTS for i in range(len(inputFiles)): inputFiles[i] = os.path.normpath(inputFiles[i]) c.info('INPUT IMAGE ' + str(i + 1) + ': ' + str(inputFiles[i])) # print more info c.info('OUTPUT DIRECTORY: ' + str(outputDirectory)) if likefreesurfer: spacing = '1,1,1' dimensions = '256,256,256' if spacing != 'no': c.info('SET SPACINGS: ' + str(spacing)) if dimensions != 'no': c.info('SET DIMENSIONS: ' + str(dimensions)) # re-sample master to obtain an isotropic dataset master = self.aniso2iso(master, spacing, dimensions) masterFileBasename = os.path.split(masterFile)[1] masterFileBasenameWithoutExt = os.path.splitext(masterFileBasename)[0] if not nii: masterOutputFileName = os.path.join(outputDirectory, masterFileBasename) else: masterOutputFileName = os.path.join( outputDirectory, masterFileBasenameWithoutExt) + '.nii' io.saveImage(masterOutputFileName, master) # equalize all images to the master for i in range(len(inputFiles)): currentInputFile = inputFiles[i] c.info('Equalizing ' + str(currentInputFile) + ' to ' + str(masterFile) + "...") # load the image currentImage = io.readImage(currentInputFile) currentImageHeader = currentImage.header c.info(' old spacing: ' + str(currentImageHeader.get_zooms())) c.info(' old dimensions: ' + str(currentImage.shape[:3])) # now resample resampledImage = resampler.resample_img2img(currentImage, master) # .. and save it currentInputFileBasename = os.path.split(currentInputFile)[1] currentInputFileBasenameWithoutExt = os.path.splitext( currentInputFileBasename)[0] if not nii: outputFileName = os.path.join(outputDirectory, currentInputFileBasename) else: outputFileName = os.path.join( outputDirectory, currentInputFileBasenameWithoutExt) savedImage = io.saveImage(outputFileName, resampledImage) #c.info( ' new spacing: ' + str( savedImageHeader.get_zooms() ) ) c.info(' new dimensions: ' + str(savedImage.shape[:3])) c.info('All done!')
def fyborgLooper_( tracks, tracksHeader, outputTrkFile, actions, showDebug, threadNumber ): import numpy numberOfTracks = len( tracks ) # the buffer for the new tracks newTracks = [] # now loop through the tracks for tCounter, t in enumerate( tracks ): # some debug stats c.debug( 'Thread-' + str( threadNumber ) + ': Processing ' + str( tCounter + 1 ) + '/' + str( numberOfTracks ), showDebug ) # generate a unique ID for this track uniqueId = str( threadNumber ) + str( tCounter ) tCoordinates = t[0] tScalars = t[1] # buffer for fiberScalars _fiberScalars = {} # first round: mapping per fiber # .. execute each action and buffer return value (scalar) for a in actions: value = a.scalarPerFiber( uniqueId, tCoordinates, tScalars ) _fiberScalars[a.scalarName()] = value # # Coordinate Loop # # buffer for coordinate scalars) scalars = [] # second round: mapping per coordinate for cCounter, coords in enumerate( tCoordinates ): _coordScalars = {} _mergedScalars = [] # this is the actual buffer for ordered fiber and coord scalars merged together # .. execute each action and buffer return value (scalar) for a in actions: value = a.scalarPerCoordinate( uniqueId, coords[0], coords[1], coords[2] ) # pass x,y,z _coordScalars[a.scalarName()] = value # now merge the old scalars and the fiber and coord scalars # this preserves the ordering of the configured actions if tScalars != None: _mergedScalars.extend( tScalars[cCounter] ) for a in actions: value = _fiberScalars[a.scalarName()] if value != FyAction.NoScalar: _mergedScalars.append( value ) else: # no fiber scalar, check if there is a coord scalar value = _coordScalars[a.scalarName()] if value != FyAction.NoScalar: _mergedScalars.append( value ) # attach scalars scalars.append( _mergedScalars ) # validate the fibers using the action's validate methods validator = [] for a in actions: validator.append( a.validate( uniqueId ) ) if all( validator ): # this is a valid fiber # .. add the new track with the coordinates, the new scalar array and the properties newScalars = numpy.asarray( scalars ) newTracks.append( ( t[0], newScalars, t[2] ) ) # save everything io.saveTrk( outputTrkFile, newTracks, tracksHeader, None, True )