コード例 #1
0
def runOneFile(fullFilePath):

    global gNumChannels
    global gAlignBatchVersion

    if not os.path.isfile(fullFilePath):
        bPrintLog(
            '\nERROR: runOneFile() did not find file: ' + fullFilePath + '\n',
            0)
        return 0

    bPrintLog(
        time.strftime("%H:%M:%S") + ' starting runOneFile(): ' + fullFilePath,
        1)

    enclosingPath = os.path.dirname(fullFilePath)
    head, tail = os.path.split(enclosingPath)
    enclosingPath += '/'

    #make output folders
    destFolder = enclosingPath + tail + '_channels/'
    if not os.path.isdir(destFolder):
        os.makedirs(destFolder)
    destMaxFolder = destFolder + 'max/'
    if not os.path.isdir(destMaxFolder):
        os.makedirs(destMaxFolder)

    if gDoAlign:
        destAlignmentFolder = destFolder + 'alignment/'
        if not os.path.isdir(destAlignmentFolder):
            os.makedirs(destAlignmentFolder)

    if gSave8bit:
        eightBitFolder = destFolder + 'channels8/'
        if not os.path.isdir(eightBitFolder):
            os.makedirs(eightBitFolder)
        eightBitMaxFolder = eightBitFolder + 'max/'
        if not os.path.isdir(eightBitMaxFolder):
            os.makedirs(eightBitMaxFolder)

    # open image
    imp = Opener().openImage(fullFilePath)

    # get parameters of image
    (width, height, nChannels, nSlices, nFrames) = imp.getDimensions()
    bitDepth = imp.getBitDepth()
    infoStr = imp.getProperty("Info")  #get all .tif tags
    if not infoStr:
        infoStr = ''
    infoStr += 'bAlignBatch_Version=' + str(gAlignBatchVersion) + '\n'
    infoStr += 'bAlignBatch_Time=' + time.strftime(
        "%Y%m%d") + '_' + time.strftime("%H%M%S") + '\n'

    msgStr = 'w:' + str(width) + ' h:' + str(height) + ' slices:' + str(nSlices) \
       + ' channels:' + str(nChannels) + ' frames:' + str(nFrames) + ' bitDepth:' + str(bitDepth)
    bPrintLog(msgStr, 1)

    path, filename = os.path.split(fullFilePath)
    shortName, fileExtension = os.path.splitext(filename)

    #
    # look for num channels in ScanImage infoStr
    if gGetNumChanFromScanImage:
        for line in infoStr.split('\n'):
            #scanimage.SI4.channelsSave = [1;2]
            scanimage4 = find(line, 'scanimage.SI4.channelsSave =') == 0
            #state.acq.numberOfChannelsSave=2
            scanimage3 = find(line, 'state.acq.numberOfChannelsSave=') == 0
            if scanimage3:
                #print 'line:', line
                equalIdx = find(line, '=')
                line2 = line[equalIdx + 1:]
                if gGetNumChanFromScanImage:
                    gNumChannels = int(line2)
                    bPrintLog(
                        'over-riding gNumChannels with: ' + str(gNumChannels),
                        2)
            if scanimage4:
                #print '   we have a scanimage 4 file ... now i need to exptract the number of channel'
                #print 'line:', line
                equalIdx = find(line, '=')
                line2 = line[equalIdx + 1:]
                for delim in ';[]':
                    line2 = line2.replace(delim, ' ')
                if gGetNumChanFromScanImage:
                    gNumChannels = len(line2.split())
                    bPrintLog(
                        'over-riding gNumChannels with: ' + str(gNumChannels),
                        2)

    # show
    imp.show()
    # split channels if necc. and grab the original window names
    if gNumChannels == 1:
        origImpWinStr = imp.getTitle()  #use this when only one channel
        origImpWin = WindowManager.getWindow(
            origImpWinStr)  #returns java.awt.Window

    if gNumChannels == 2:
        winTitle = imp.getTitle()
        bPrintLog('Deinterleaving 2 channels...', 1)
        IJ.run('Deinterleave',
               'how=2 keep')  #makes ' #1' and ' #2', with ' #2' frontmost
        origCh1WinStr = winTitle + ' #1'
        origCh2WinStr = winTitle + ' #2'
        origCh1Imp = WindowManager.getImage(origCh1WinStr)
        origCh2Imp = WindowManager.getImage(origCh2WinStr)
        origCh1File = destFolder + shortName + '_ch1.tif'
        origCh2File = destFolder + shortName + '_ch2.tif'

    # work on a copy, mostly for alignment with cropping
    copy = Duplicator().run(imp)
    #copy.copyAttributes(imp) #don't copy attributes, it copies the name (which we do not want)
    copy.show()

    #
    # crop (on copy)
    if gDoCrop:
        bPrintLog('making cropping rectangle (left,top,width,height) ', 1)
        bPrintLog(
            str(gCropLeft) + ' ' + str(gCropTop) + ' ' + str(gCropWidth) +
            ' ' + str(gCropHeight), 2)

        roi = Roi(gCropLeft, gCropTop, gCropWidth,
                  gCropHeight)  #left,top,width,height
        copy.setRoi(roi)

        time.sleep(
            0.5
        )  # otherwise, crop SOMETIMES failes. WHAT THE F**K FIJI DEVELOPERS, REALLY, WHAT THE F**K

        #bPrintLog('cropping', 1)
        IJ.run('Crop')
        infoStr += 'bCropping=' + str(gCropLeft) + ',' + str(
            gCropTop) + ',' + str(gCropWidth) + ',' + str(gCropHeight) + '\n'

    #
    # remove calibration ( on original)
    if gRemoveCalibration:
        cal = imp.getCalibration()
        calCoeff = cal.getCoefficients()
        if calCoeff:
            msgStr = 'Calibration is y=a+bx' + ' a=' + str(
                calCoeff[0]) + ' b=' + str(calCoeff[1])
            bPrintLog(msgStr, 1)

            #remove calibration
            bPrintLog('\tRemoving Calibration', 2)
            imp.setCalibration(None)

            #without these, 8-bit conversion goes to all 0 !!! what the f**k !!!
            #bPrintLog('calling imp.resetStack() and imp.resetDisplayRange()', 2)
            imp.resetStack()
            imp.resetDisplayRange()

            #get and print out min/max
            origMin = StackStatistics(imp).min
            origMax = StackStatistics(imp).max
            msgStr = '\torig min=' + str(origMin) + ' max=' + str(origMax)
            bPrintLog(msgStr, 2)

            # 20150723, 'shift everybody over by linear calibration intercept calCoeff[0] - (magic number)
            if 1:
                # [1] was this
                #msgStr = 'Subtracting original min '+str(origMin) + ' from stack.'
                #bPrintLog(msgStr, 2)
                #subArgVal = 'value=%s stack' % (origMin,)
                #IJ.run('Subtract...', subArgVal)
                # [2] now this
                #msgStr = 'Adding calCoeff[0] '+str(calCoeff[0]) + ' from stack.'
                #bPrintLog(msgStr, 2)
                #addArgVal = 'value=%s stack' % (int(calCoeff[0]),)
                #IJ.run('Add...', addArgVal)
                # [3] subtract a magic number 2^15-2^7 = 32768 - 128
                magicNumber = gLinearShift  #2^15 - 128
                msgStr = 'Subtracting a magic number (linear shift) ' + str(
                    magicNumber) + ' from stack.'
                bPrintLog(msgStr, 2)
                infoStr += 'bLinearShift=' + str(gLinearShift) + '\n'
                subArgVal = 'value=%s stack' % (gLinearShift, )
            IJ.run(imp, 'Subtract...', subArgVal)

            # 20150701, set any pixel <0 to 0
            if 0:
                ip = imp.getProcessor()  # returns a reference
                pixels = ip.getPixels()  # returns a reference
                msgStr = '\tSet all pixels <0 to 0. This was added 20150701 ...'
                bPrintLog(msgStr, 2)
                pixels = map(lambda x: 0 if x < 0 else x, pixels)
                bPrintLog('\t\t... done', 2)

            #get and print out min/max
            newMin = StackStatistics(imp).min
            newMax = StackStatistics(imp).max
            msgStr = '\tnew min=' + str(newMin) + ' max=' + str(newMax)
            bPrintLog(msgStr, 2)

            #append calibration to info string
            infoStr += 'bCalibCoeff_a = ' + str(calCoeff[0]) + '\n'
            infoStr += 'bCalibCoeff_b = ' + str(calCoeff[1]) + '\n'
            infoStr += 'bNewMin = ' + str(newMin) + '\n'
            infoStr += 'bNewMax = ' + str(newMax) + '\n'

    #
    # set up
    if gNumChannels == 1:
        impWinStr = copy.getTitle()  #use this when only one channel
        impWin = WindowManager.getWindow(impWinStr)  #returns java.awt.Window

    if gNumChannels == 2:
        winTitle = copy.getTitle()
        bPrintLog('Deinterleaving 2 channels...', 1)
        IJ.run('Deinterleave',
               'how=2 keep')  #makes ' #1' and ' #2', with ' #2' frontmost
        ch1WinStr = winTitle + ' #1'
        ch2WinStr = winTitle + ' #2'
        ch1Imp = WindowManager.getImage(ch1WinStr)
        ch2Imp = WindowManager.getImage(ch2WinStr)
        ch1File = destFolder + shortName + '_ch1.tif'
        ch2File = destFolder + shortName + '_ch2.tif'

    #
    # alignment
    if gDoAlign and gNumChannels == 1 and copy.getNSlices() > 1:
        infoStr += 'AlignOnChannel=1' + '\n'
        #snap to middle slice
        if gAlignOnMiddleSlice:
            middleSlice = int(
                math.floor(copy.getNSlices() /
                           2))  #int() is necc., python is f*****g picky
        else:
            middleSlice = gAlignOnThisSlice
        copy.setSlice(middleSlice)

        transformationFile = destAlignmentFolder + shortName + '.txt'

        bPrintLog('MultiStackReg aligning:' + impWinStr, 1)
        stackRegParams = 'stack_1=[%s] action_1=Align file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body] save' % (
            impWin, transformationFile)
        IJ.run('MultiStackReg', stackRegParams)
        infoStr += 'AlignOnSlice=' + str(middleSlice) + '\n'

        #20150723, we just aligned on a cropped copy, apply alignment to original imp
        origImpTitle = imp.getTitle()
        stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' % (
            origImpTitle, transformationFile)
        IJ.run('MultiStackReg', stackRegParams)

    if gDoAlign and gNumChannels == 2 and ch1Imp.getNSlices(
    ) > 1 and ch2Imp.getNSlices() > 1:
        #apply to gAlignThisChannel
        alignThisWindow = ''
        applyAlignmentToThisWindow = ''
        if gAlignThisChannel == 1:
            infoStr += 'AlignOnChannel=1' + '\n'
            transformationFile = destAlignmentFolder + shortName + '_ch1.txt'
            alignThisWindow = ch1WinStr
            applyAlignmentToThisWindow = ch2WinStr
        else:
            infoStr += 'AlignOnChannel=2' + '\n'
            transformationFile = destAlignmentFolder + shortName + '_ch2.txt'
            alignThisWindow = ch2WinStr
            applyAlignmentToThisWindow = ch1WinStr

        alignThisImp = WindowManager.getImage(alignThisWindow)
        #snap to middle slice
        if gAlignOnMiddleSlice:
            middleSlice = int(
                math.floor(alignThisImp.getNSlices() /
                           2))  #int() is necc., python is f*****g picky
        else:
            middleSlice = gAlignOnThisSlice
        alignThisImp.setSlice(middleSlice)

        infoStr += 'bAlignOnSlice=' + str(middleSlice) + '\n'

        bPrintLog('MultiStackReg aligning:' + alignThisWindow, 1)
        stackRegParams = 'stack_1=[%s] action_1=Align file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body] save' % (
            alignThisWindow, transformationFile)
        IJ.run('MultiStackReg', stackRegParams)

        # 20150723, we just aligned on a copy, apply alignment to both channels of original
        # ch1
        bPrintLog('MultiStackReg applying alignment to:' + origCh1WinStr, 1)
        stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' % (
            origCh1WinStr, transformationFile)
        IJ.run('MultiStackReg', stackRegParams)
        # ch2
        bPrintLog('MultiStackReg applying alignment to:' + origCh2WinStr, 1)
        stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' % (
            origCh2WinStr, transformationFile)
        IJ.run('MultiStackReg', stackRegParams)

        #apply alignment to other window
        #bPrintLog('MultiStackReg applying alignment to:' + applyAlignmentToThisWindow, 1)
        #applyAlignThisImp = WindowManager.getImage(applyAlignmentToThisWindow)
        #stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' %(applyAlignmentToThisWindow,transformationFile)
        #IJ.run('MultiStackReg', stackRegParams)
    elif gDoAlign:
        bPrintLog('Skipping alignment, there may be only one slice?', 3)

    #
    # save
    if gNumChannels == 1:
        imp.setProperty("Info", infoStr)
        impFile = destFolder + shortName + '.tif'
        #bPrintLog('Saving:' + impFile, 1)
        bSaveStack(imp, impFile)
        #max project
        bSaveZProject(imp, destMaxFolder, shortName)

    if gNumChannels == 2:
        #ch1
        origCh1Imp.setProperty("Info", infoStr)
        #bPrintLog('Saving:' + ch1File, 1)
        bSaveStack(origCh1Imp, ch1File)
        #max project
        bSaveZProject(origCh1Imp, destMaxFolder, shortName + '_ch1')

        #ch2
        origCh2Imp.setProperty("Info", infoStr)
        #bPrintLog('Saving:' + ch2File, 1)
        bSaveStack(origCh2Imp, ch2File)
        #max project
        bSaveZProject(origCh2Imp, destMaxFolder, shortName + '_ch2')

#
    # post convert to 8-bit and save
    if gSave8bit:
        if bitDepth == 16:
            if gNumChannels == 1:
                bPrintLog('Converting to 8-bit:' + impWinStr, 1)
                IJ.selectWindow(impWinStr)
                #IJ.run('resetMinAndMax()')
                IJ.run("8-bit")
                impFile = eightBitFolder + shortName + '.tif'
                bPrintLog('Saving 8-bit:' + impFile, 2)
                bSaveStack(imp, impFile)
                #max project
                bSaveZProject(imp, eightBitMaxFolder, shortName)

            if gNumChannels == 2:
                #
                bPrintLog('Converting to 8-bit:' + origCh1WinStr, 1)
                IJ.selectWindow(origCh1WinStr)

                IJ.run("8-bit")
                impFile = eightBitFolder + shortName + '_ch1.tif'
                bPrintLog('Saving 8-bit:' + impFile, 2)
                bSaveStack(origCh1Imp, impFile)
                #max project
                bSaveZProject(origCh1Imp, eightBitMaxFolder,
                              shortName + '_ch1')

                #
                bPrintLog('Converting to 8-bit:' + origCh2WinStr, 1)
                IJ.selectWindow(origCh2WinStr)
                #IJ.run('resetMinAndMax()')
                IJ.run("8-bit")
                impFile = eightBitFolder + shortName + '_ch2.tif'
                bPrintLog('Saving 8-bit:' + impFile, 2)
                bSaveStack(origCh2Imp, impFile)
                #max project
                bSaveZProject(origCh2Imp, eightBitMaxFolder,
                              shortName + '_ch2')

    #
    # close original window
    imp.changes = 0
    imp.close()
    #copy
    copy.changes = 0
    copy.close()

    #
    # close ch1/ch2
    if gNumChannels == 2:
        #original
        origCh1Imp.changes = 0
        origCh1Imp.close()
        origCh2Imp.changes = 0
        origCh2Imp.close()
        #copy
        ch1Imp.changes = 0
        ch1Imp.close()
        ch2Imp.changes = 0
        ch2Imp.close()

    bPrintLog(
        time.strftime("%H:%M:%S") + ' finished runOneFile(): ' + fullFilePath,
        1)
コード例 #2
0
class bImp:
	def __init__(self, filepath):
		"""
		Load an image or stack from filepath.

		Args:
			filepath (str): Full path to an image file. Can be .tif, .lsm, .czi, etc
		"""
		
		if not os.path.isfile(filepath):
			bPrintLog('ERROR: bImp() did not find file: ' + filepath,0)
			return 0

		self.filepath = filepath
		folderpath, filename = os.path.split(filepath)
		self.filename = filename
		self.enclosingPath = folderpath
		self.enclosingfolder = os.path.split(folderpath)[1]

		self.dateStr = ''
		self.timeStr = ''
		
		self.imp = None
		
		tmpBaseName, extension = os.path.splitext(filename)
		isZeiss = extension in ['.czi', '.lsm']
		self.islsm = extension == '.lsm'
		self.isczi = extension == '.czi'
		istif = extension == '.tif'
				
		if istif:
			# scanimage3 comes in with dimensions: [512, 512, 1, 52, 1]) = [width, height, numChannels, numSlices, numFrames]
			self.imp = Opener().openImage(filepath)
			self.imp.show()
			
		elif isZeiss:
			#open lsm using LOCI Bio-Formats
			options = ImporterOptions()
			#options.setColorMode(ImporterOptions.COLOR_MODE_GRAYSCALE)
			options.setId(filepath)
			imps = BF.openImagePlus(options)
			for imp in imps:
				self.imp = imp #WindowManager.getImage(self.windowname)
				imp.show()

		if not self.imp:
			bPrintLog('ERROR: bImp() was not able to open file: '+ filepath,0)
    				
		self.windowname = filename
		#self.imp = WindowManager.getImage(self.windowname)

		# numChannels is not correct for scanimage, corrected in readTiffHeader()
		(width, height, numChannels, numSlices, numFrames) = self.imp.getDimensions()

		self.width = width # pixelsPerLine
		self.height = height # linesPerFrame
		self.numChannels = numChannels
		self.numSlices = numSlices
		self.numFrames = numFrames

		self.infoStr = self.imp.getProperty("Info") #get all tags
				
		self.voxelx = 1
		self.voxely = 1
		self.voxelz = 1
		#self.numChannels = 1
		#self.bitsPerPixel = 8
		self.zoom = 1

		self.motorx = None
		self.motory = None
		self.motorz = None

		self.scanImageVersion = ''
		self.msPerLine = None
		self.dwellTime = None
		
		# read file headers (date, time, voxel size)
		if isZeiss:
			self.readZeissHeader(self.infoStr)
		elif istif:
			self.readTiffHeader(self.infoStr)

		self.updateInfoStr()
		
		self.channelWindows = []
		self.channelImp = []

		if self.numChannels == 1:
			self.channelWindows.append(self.windowname)
			self.channelImp.append(self.imp)
		else:
			self.deinterleave()
			
	def updateInfoStr(self):
		# Fill in infoStr with Map Manager tags		

		self.infoStr += 'Folder2MapManager=' + versionStr + '\n'

		self.infoStr += 'b_date=' + self.dateStr + '\n'
		self.infoStr += 'b_time=' + self.timeStr + '\n'
		
		# yevgeniya 20180314
		#if (self.numChannels > 3):
		#	self.numChannels = 3
		self.infoStr += 'b_numChannels=' + str(self.numChannels) + '\n'
		self.infoStr += 'b_pixelsPerline=' + str(self.width) + '\n'
		self.infoStr += 'b_linesPerFrame=' + str(self.height) + '\n'
		self.infoStr += 'b_numSlices=' + str(self.numSlices) + '\n'
		
		self.infoStr += 'b_voxelX=' + str(self.voxelx) + '\n'
		self.infoStr += 'b_voxelY=' + str(self.voxely) + '\n'
		self.infoStr += 'b_voxelZ=' + str(self.voxelz) + '\n'

		#self.infoStr += 'b_bitsPerPixel=' + str(self.bitsPerPixel) + '\n'

		self.infoStr += 'b_zoom=' + str(self.zoom) + '\n'
		
		self.infoStr += 'b_motorx=' + str(self.motorx) + '\n'
		self.infoStr += 'b_motory=' + str(self.motory) + '\n'
		self.infoStr += 'b_motorz=' + str(self.motorz) + '\n'

		self.infoStr += 'b_msPerLine=' + str(self.msPerLine) + '\n'

		self.infoStr += 'b_scanImageVersion=' + self.scanImageVersion + '\n'

	
	def readTiffHeader(self, infoStr):
		"""
		Read ScanImage 3/4 .tif headers
		"""
		logLevel = 3

		# splitting on '\r' for scanimage 3.x works
		# splitting on '\n' for scanimage 4.x works
		
		#we need to search whole infoStr to figure out scanimage 3 or 4.
		# we can't split info string because si3 uses \r and si4 uses \n
		
		infoStrDelim = '\n'
		if infoStr.find('scanimage.SI4') != -1:
			infoStrDelim = '\n'
			bPrintLog('Assuming SI4 infoStr to be delimited with backslash n', logLevel)
		elif infoStr.find('state.software.version') != -1:
			infoStrDelim = '\r'
			bPrintLog('Assuming SI3 infoStr to be delimited with backslash r', logLevel)
		else:
			bPrintLog('Splitting infoStr using backslah n', logLevel)

		# if we don't find zoom then voxel is an error (see end of function)
		foundZoom = False
		
		#for line in infoStr.split('\n'):
		for line in infoStr.split(infoStrDelim):
			#
			# ScanImage 4.x
			#
			
			# scanimage.SI4.versionMajor = 4.2
			if line.find('scanimage.SI4.versionMajor') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.scanImageVersion = rhs
			
			# scanimage.SI4.motorPosition = [-33936.5 -106316 -55308.5]
			if line.find('scanimage.SI4.motorPosition') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				rhs = rhs.replace('[','')
				rhs = rhs.replace(']','')
				floats = [float(x) for x in rhs.split()]
				self.motorx = floats[0]
				self.motory = floats[1]
				self.motorz = floats[2]

			# scanimage.SI4.channelsSave = [1;2]
			if line.find('scanimage.SI4.channelsSave') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				rhs = rhs.replace('[','')
				rhs = rhs.replace(']','')
				channels = [int(x) for x in rhs.split(';')]
				bPrintLog('reading scanimage.SI4.channelsSave inferred channels:' + str(channels), logLevel)
				self.numChannels = len(channels)

			# scanimage.SI4.scanZoomFactor = 5.9
			if line.find('scanimage.SI4.scanZoomFactor') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.zoom = float(rhs)
				foundZoom = True
				#self.voxelx = magic_scan_image_scale / self.zoom
				#self.voxely = magic_scan_image_scale / self.zoom

			# scanimage.SI4.triggerClockTimeFirst = '18-05-2015 11:58:43.788'
			if line.find('scanimage.SI4.triggerClockTimeFirst') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				rhs = rhs.replace("'","") # remove enclosing ' and '
				if rhs.startswith(' '): # if date string starts with space, remove it
					rhs = rhs[1:-1]
				datetime = rhs.split(' ')
				# 20170811, there is an extra f*****g space before datestr on the rhs
				# convert mm/dd/yyyy to yyyymmdd
				#print 'rhs:' + "'" + rhs + "'"
				#print 'datetime:', datetime
				datestr = bFixDate(datetime[0], logLevel)
				self.dateStr = datestr
				self.timeStr = datetime[1]
			
			#
			# ScanImage 3.x
			#
			
			# state.software.version = 3.8
			if line.find('state.software.version') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.scanImageVersion = rhs
			
			# state.acq.numberOfChannelsAcquire = 2
			if line.find('state.acq.numberOfChannelsAcquire') != -1:
				#print '\rDEBUG 12345'
				bPrintLog(line, logLevel)
				#print '\rDEBUG 12345'
				rhs = line.split('=')[1]
				self.numChannels = int(rhs)

			# state.acq.zoomFactor = 2.5
			if line.find('state.acq.zoomFactor') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.zoom = float(rhs)
				foundZoom = True
				# set (voxelx, voxely)
				#self.voxelx = magic_scan_image_scale / self.zoom
				#self.voxely = magic_scan_image_scale / self.zoom
				
			# state.acq.msPerLine = 2.32
			if line.find('state.acq.msPerLine') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.msPerLine = float(rhs)
			
			# state.acq.pixelTime = 3.2e-06
			if line.find('state.acq.pixelTime') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.dwellTime = float(rhs)

			# state.motor.absXPosition = -9894.4
			if line.find('state.motor.absXPosition') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.motorx = float(rhs)

			# state.motor.absYPosition = -18423.4
			if line.find('state.motor.absYPosition') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.motory = float(rhs)

			# state.motor.absZPosition = -23615.04
			if line.find('state.motor.absZPosition') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.motorz = float(rhs)

			# state.acq.zStepSize = 2
			if line.find('state.acq.zStepSize') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				self.voxelz = float(rhs)

			# state.internal.triggerTimeString = '10/2/2014 12:29:22.796'
			if line.find('state.internal.triggerTimeString') != -1:
				bPrintLog(line, logLevel)
				rhs = line.split('=')[1]
				rhs = rhs.replace("'","")
				if rhs.startswith(' '): # if date string starts with space, remove it
					rhs = rhs[1:-1]
				datetime = rhs.split(' ')
				# 20170811, there is an extra f*****g space before datestr on the rhs
				# convert mm/dd/yyyy to yyyymmdd
				#print 'rhs:' + "'" + rhs + "'"
				#print 'datetime:', datetime
				self.dateStr = bFixDate(datetime[0], logLevel)
				self.timeStr = bFixTime(datetime[1], logLevel)
				

			# state.acq.acqDelay = 0.000122
			# state.acq.bidirectionalScan = 0
			# state.acq.fillFraction = 0.706206896551724
			# state.acq.frameRate = 0.841864224137931
			# huganir lab keeps this off, image pixel intensities are 2^11 * samplesperpixel (e.g. binFactor?)
			# state.acq.binFactor = 16
			# state.internal.averageSamples = 1
			# the real image bit depth is usually inputBitDepth-1 (1 bit is not used?)
			# state.acq.inputBitDepth = 12

		if foundZoom:
			self.voxelx = magic_scan_image_scale / self.zoom * (1024 / self.width)
			self.voxely = magic_scan_image_scale / self.zoom * (1024 / self.height)
		else:
			bPrintLog('ERROR: Did not find zoom in SI header, voxel x/y will be wrong', logLevel)
			
	def readZeissHeader(self, infoStr):		
		# This is incredibly difficult to get working as (date, time, voxels) are in different obscure places in lsm and czi
		# Furthermore, just trying to read the raw ome xls is futile
		#
		# parsing ome xml as a string and searching it with regular expression(re) does not work
		# it is beyond the scope of my work to figure this out
		# the fact that it does not work and there is little documentaiton is a pretty big waste of time
		#
		# get and parse xml to find date/time
		#fi = self.imp.getOriginalFileInfo(); # returns a FileInfo object
		#omexml = fi.description #omexml is a string
		#omexml = omexml.encode('utf-8')
		#omexml = omexml.replaceAll("[^\\x20-\\x7e]", "") # see: https://stackoverflow.com/questions/2599919/java-parsing-xml-document-gives-content-not-allowed-in-prolog-error

		# (1) try and search the ome xml like a string, this gives errors
		#docsPattern = '<AcquisitionDate>.*</AcquisitionDate>'
		#searchresult = re.search(docsPattern, omexml)
		#print 'searchresult:', searchresult.group(0)
		
		# 2) treat the ome xml like any other xml (because it's xml, right?)
		# well this raises errors too
		#omexml has <AcquisitionDate>2016-08-17T15:21:50</AcquisitionDate>
		#import xml.etree.ElementTree
		#e = xml.etree.ElementTree.fromstring(omexml).getroot()		#print omexml
		#for atype in e.findall('AcquisitionDate'):
		#    print 'AcquisitionDate:', atype #.get('foobar')
		#
		#

		if self.islsm:
			# lsm have date hidden in omeMeta.getImageAcquisitionDate(0)
			# this is copied from code at: https://gist.github.com/ctrueden/6282856
			reader = ImageReader()
			omeMeta = MetadataTools.createOMEXMLMetadata() #omeMeta.getImageAcquisitionDate(0)
			reader.setMetadataStore(omeMeta)
			reader.setId(self.filepath)
			#seriesCount = reader.getSeriesCount()
			dateTimeStr = omeMeta.getImageAcquisitionDate(0) #2016-08-17T16:36:26
			reader.close()
			if dateTimeStr:
				self.dateStr, self.timeStr = dateTimeStr.toString().split('T')
				self.dateStr = bFixDate(self.dateStr)
				self.timeStr = bFixTime(self.timeStr)
				#bPrintLog('LSM date/time is: ' + self.dateStr + ' ' + self.timeStr, 3)
			else:
				bPrintLog('WARNING: did not get Zeiss date/time string')

			# lsm have voxels in infoStr
			for line in infoStr.split('\n'):
				#print line
				if line.find('VoxelSizeX') != -1:
					self.voxelx = float(line.split('=')[1])
				if line.find('VoxelSizeY') != -1:
					self.voxely = float(line.split('=')[1])
				if line.find('VoxelSizeZ') != -1:
					self.voxelz = float(line.split('=')[1])
				if line.find('SizeC') != -1:
					self.numChannels = int(line.split('=')[1])
				#if line.find('BitsPerPixel') and not line.startswith('Experiment') != -1: # 20170811, startswith is for czi
				#	self.bitsPerPixel = int(line.split('=')[1])
				if line.find('RecordingZoomX#1') != -1:
					self.zoom = int(line.split('=')[1])

		if self.isczi:
			# czi has date/time in infoStr (lsm does not)
			for line in infoStr.split('\n'):
				if line.find('CreationDate #1') != -1: # w.t.f. is #1 referring to?
					lhs, rhs = line.split('=')
					rhs = rhs.replace('  ', ' ')
					if rhs.startswith(' '):
						rhs = rhs[1:-1]
					#print "lhs: '" + lhs + "'" + "rhs: '" + rhs + "'"
					if rhs.find('T') != -1:
						self.dateStr, self.timeStr = rhs.split('T')
					else:
						self.dateStr, self.timeStr = rhs.split(' ')
					self.dateStr = bFixDate(self.dateStr)
					self.timeStr = bFixTime(self.timeStr)
					#bPrintLog('CZI date/time is: ' + self.dateStr + ' ' + self.timeStr, 3)
				# .czi
				# <Pixels BigEndian="false" DimensionOrder="XYCZT" ID="Pixels:0" Interleaved="false" PhysicalSizeX="0.20756645602494875" PhysicalSizeXUnit="µm" PhysicalSizeY="0.20756645602494875" PhysicalSizeYUnit="µm" PhysicalSizeZ="0.75" PhysicalSizeZUnit="µm" SignificantBits="8" SizeC="1" SizeT="1" SizeX="1024" SizeY="1024" SizeZ="50" Type="uint8">

			# czi have voxel in calibration
			self.voxelx = self.imp.getCalibration().pixelWidth; 
			self.voxely = self.imp.getCalibration().pixelHeight; 
			self.voxelz = self.imp.getCalibration().pixelDepth; 
			#bPrintLog('readZeissHeader() read czi scale as: ' + str(self.voxelx) + ' ' + str(self.voxely) + ' ' + str(self.voxelz), 3)

			# CLEARING self.infoStr for CZI ... it was WAY to big to parse in Map Manager
			self.infoStr = ''
			
	def printParams(self, loglevel=3): # careful, thefunction print() is already taken?
		bPrintLog('file:' + self.filepath, loglevel)
		bPrintLog("date:'" + self.dateStr + "' time:'" + self.timeStr + "'", loglevel)
		bPrintLog('channels:' + str(self.numChannels), loglevel)
		bPrintLog('zoom:' + str(self.zoom), loglevel)
		bPrintLog('pixels:' + str(self.width) + ',' + str(self.height)+ ',' + str(self.numSlices), loglevel)
		bPrintLog('voxels:' + str(self.voxelx) + ',' + str(self.voxely)+ ',' + str(self.voxelz), loglevel)

	def deinterleave(self):
		if self.numChannels == 1:
			bPrintLog('Warning: deinterleave() did not deinterleave with num channels 1', 0)
			return -1
		
		#IJ.run('Deinterleave', 'how=' + str(self.numChannels) +' keep') #makes ' #1' and ' #2', with ' #2' frontmost
		cmdStr = 'how=' + str(self.numChannels) + ' keep'
		IJ.run('Deinterleave', cmdStr) #makes ' #1' and ' #2', with ' #2' frontmost
		for i in range(self.numChannels):
			currenChannel = i + 1
			currentWindowName = self.windowname + ' #' + str(currenChannel)
			self.channelWindows.append(currentWindowName)
			
			currentImp = WindowManager.getImage(currentWindowName)
			if currentImp:
				self.channelImp.append(currentImp)
			else:
				bPrintLog('ERROR: deinterleave() did not find window names:' + currentWindowName, 0)
			
	def exportTifStack(self, destFolder=''):
		channelNumber = 1
		for imp in self.channelImp:
			if not destFolder:
				destFolder = os.path.join(self.enclosingPath, self.enclosingfolder + '_tif')
			if not os.path.isdir(destFolder):
				os.makedirs(destFolder)
			
			if not imp:
				bPrintLog("ERROR: exportTifStack() did not find an imp at channel number '" + str(channelNumber) + "'", 0)
				return -1
				
			self.updateInfoStr()
			imp.setProperty("Info", self.infoStr);

			saveFile = os.path.splitext(self.filename)[0] + '_ch' + str(channelNumber) + '.tif'
			savePath = os.path.join(destFolder, saveFile)

			# save
			fs = FileSaver(imp)
			bPrintLog('saveTifStack():' + savePath, 3)
			if imp.getNSlices()>1:
				fs.saveAsTiffStack(savePath)
			else:
				fs.saveAsTiff(savePath)

			channelNumber += 1

	def saveMaxProject(self, destFolder=''):
		channelNumber = 1
		for imp in self.channelImp:
			if not destFolder:
				destFolder = os.path.join(self.enclosingPath, self.enclosingfolder + '_tif', 'max')
			if not os.path.isdir(destFolder):
				os.makedirs(destFolder)

			# make max project
			zp = ZProjector(imp)
			zp.setMethod(ZProjector.MAX_METHOD)
			zp.doProjection()
			zimp = zp.getProjection()

			# save
			saveFile = 'max_' + os.path.splitext(self.filename)[0] + '_ch' + str(channelNumber) + '.tif'
			savePath = os.path.join(destFolder, saveFile)
			fs = FileSaver(zimp)
			bPrintLog('saveMaxProject():' + savePath, 3)
			fs.saveAsTiff(savePath)

			channelNumber += 1
			
	def closeAll(self):
		self.imp.close()
		for imp in self.channelImp:
			imp.close()
コード例 #3
0
def runOneFile(fullFilePath):
	global gFileType
	global gNumChannels
	global gAlignBatchVersion
	
	if not os.path.isfile(fullFilePath):
		bPrintLog('\nERROR: runOneFile() did not find file: ' + fullFilePath + '\n',0)
		return 0

	bPrintLog(time.strftime("%H:%M:%S") + ' starting runOneFile(): ' + fullFilePath, 1)
	
	enclosingPath = os.path.dirname(fullFilePath)
	head, tail = os.path.split(enclosingPath)
	enclosingPath += '/'
	
	#make output folders
	destFolder = enclosingPath + tail + '_channels/'
	if not os.path.isdir(destFolder):
		os.makedirs(destFolder)
	destMaxFolder = destFolder + 'max/'
	if not os.path.isdir(destMaxFolder):
		os.makedirs(destMaxFolder)

	if gDoAlign:
		destAlignmentFolder = destFolder + 'alignment/'
		if not os.path.isdir(destAlignmentFolder):
			os.makedirs(destAlignmentFolder)
			
	if gSave8bit:
		eightBitFolder = destFolder + 'channels8/'
		if not os.path.isdir(eightBitFolder):
			os.makedirs(eightBitFolder)
		eightBitMaxFolder = eightBitFolder + 'max/'
		if not os.path.isdir(eightBitMaxFolder):
			os.makedirs(eightBitMaxFolder)
	
	if gFileType=='tif':
		# open .tif image
		imp = Opener().openImage(fullFilePath)
	else:
		# open .lsm
		cmdStr = 'open=%s autoscale color_mode=Default view=Hyperstack stack_order=XYCZT' % (fullFilePath,)
		IJ.run('Bio-Formats Importer', cmdStr)
		lsmpath, lsmfilename = os.path.split(fullFilePath)
		lsWindow = lsmfilename
		imp = WindowManager.getImage(lsWindow)
		
	# get parameters of image
	(width, height, nChannels, nSlices, nFrames) = imp.getDimensions()
	bitDepth = imp.getBitDepth()
	infoStr = imp.getProperty("Info") #get all .tif tags
	if not infoStr:
		infoStr = ''
	infoStr += 'bAlignBatch_Version=' + str(gAlignBatchVersion) + '\n'
	infoStr += 'bAlignBatch_Time=' + time.strftime("%Y%m%d") + '_' + time.strftime("%H%M%S") + '\n'
		
	msgStr = 'w:' + str(width) + ' h:' + str(height) + ' slices:' + str(nSlices) \
				+ ' channels:' + str(nChannels) + ' frames:' + str(nFrames) + ' bitDepth:' + str(bitDepth)
	bPrintLog(msgStr, 1)
	
	path, filename = os.path.split(fullFilePath)
	shortName, fileExtension = os.path.splitext(filename)

	#
	# look for num channels in ScanImage infoStr
	if gGetNumChanFromScanImage:
		for line in infoStr.split('\n'):
			#scanimage.SI4.channelsSave = [1;2]
			scanimage4 = find(line, 'scanimage.SI4.channelsSave =') == 0
			#state.acq.numberOfChannelsSave=2
			scanimage3 = find(line, 'state.acq.numberOfChannelsSave=') == 0
			if scanimage3:
				#print 'line:', line
				equalIdx = find(line, '=')
				line2 = line[equalIdx+1:]
				if gGetNumChanFromScanImage:
					gNumChannels = int(line2)
					bPrintLog('over-riding gNumChannels with: ' + str(gNumChannels), 2)
			if scanimage4:
				#print '   we have a scanimage 4 file ... now i need to exptract the number of channel'
				#print 'line:', line
				equalIdx = find(line, '=')
				line2 = line[equalIdx+1:]
				for delim in ';[]':
					line2 = line2.replace(delim, ' ')
				if gGetNumChanFromScanImage:
					gNumChannels = len(line2.split())
					bPrintLog('over-riding gNumChannels with: ' + str(gNumChannels), 2)

	# show
	imp.show()
	# split channels if necc. and grab the original window names
	if gNumChannels == 1:
		origImpWinStr = imp.getTitle() #use this when only one channel
		origImpWin = WindowManager.getWindow(origImpWinStr) #returns java.awt.Window
	
	if gNumChannels == 2:
		winTitle = imp.getTitle()
		bPrintLog('Deinterleaving 2 channels...', 1)
		IJ.run('Deinterleave', 'how=2 keep') #makes ' #1' and ' #2', with ' #2' frontmost
		origCh1WinStr = winTitle + ' #1'
		origCh2WinStr = winTitle + ' #2'
		origCh1Imp = WindowManager.getImage(origCh1WinStr)
		origCh2Imp = WindowManager.getImage(origCh2WinStr)
		origCh1File = destFolder + shortName + '_ch1.tif'
		origCh2File = destFolder + shortName + '_ch2.tif'

	# work on a copy, mostly for alignment with cropping
	copy = Duplicator().run(imp)
	#copy.copyAttributes(imp) #don't copy attributes, it copies the name (which we do not want)
	copy.show()
	
	#
	# crop (on copy)
	if gDoCrop:
		bPrintLog('making cropping rectangle (left,top,width,height) ',1)
		bPrintLog(str(gCropLeft) + ' ' + str(gCropTop) + ' ' +str(gCropWidth) + ' ' +str(gCropHeight), 2)
		
		roi = Roi(gCropLeft, gCropTop, gCropWidth, gCropHeight) #left,top,width,height
		copy.setRoi(roi)
		
		time.sleep(0.5) # otherwise, crop SOMETIMES failes. WHAT THE F**K FIJI DEVELOPERS, REALLY, WHAT THE F**K
		
		#bPrintLog('cropping', 1)
		IJ.run('Crop')
		infoStr += 'bCropping=' + str(gCropLeft) + ',' + str(gCropTop) + ',' + str(gCropWidth) + ',' + str(gCropHeight) + '\n'
	
	#
	# remove calibration ( on original)
	if gRemoveCalibration:
		cal = imp.getCalibration()
		calCoeff = cal.getCoefficients()
		if calCoeff:
			msgStr = 'Calibration is y=a+bx' + ' a=' + str(calCoeff[0]) + ' b=' + str(calCoeff[1])
			bPrintLog(msgStr, 1)
			
			#remove calibration
			bPrintLog('\tRemoving Calibration', 2)
			imp.setCalibration(None)
				
			#without these, 8-bit conversion goes to all 0 !!! what the f**k !!!
			#bPrintLog('calling imp.resetStack() and imp.resetDisplayRange()', 2)
			imp.resetStack()
			imp.resetDisplayRange()

			#get and print out min/max
			origMin = StackStatistics(imp).min
			origMax = StackStatistics(imp).max
			msgStr = '\torig min=' + str(origMin) + ' max=' + str(origMax)
			bPrintLog(msgStr, 2)
			
			# 20150723, 'shift everybody over by linear calibration intercept calCoeff[0] - (magic number)
			if 1:
				# [1] was this
				#msgStr = 'Subtracting original min '+str(origMin) + ' from stack.'
				#bPrintLog(msgStr, 2)
				#subArgVal = 'value=%s stack' % (origMin,)
				#IJ.run('Subtract...', subArgVal)
				# [2] now this
				#msgStr = 'Adding calCoeff[0] '+str(calCoeff[0]) + ' from stack.'
				#bPrintLog(msgStr, 2)
				#addArgVal = 'value=%s stack' % (int(calCoeff[0]),)
				#IJ.run('Add...', addArgVal)
				# [3] subtract a magic number 2^15-2^7 = 32768 - 128
				magicNumber = gLinearShift #2^15 - 128
				msgStr = 'Subtracting a magic number (linear shift) '+str(magicNumber) + ' from stack.'
				bPrintLog(msgStr, 2)
				infoStr += 'bLinearShift=' + str(gLinearShift) + '\n'
				subArgVal = 'value=%s stack' % (gLinearShift,)
			IJ.run(imp, 'Subtract...', subArgVal)
				
			# 20150701, set any pixel <0 to 0
			if 0:
				ip = imp.getProcessor() # returns a reference
				pixels = ip.getPixels() # returns a reference
				msgStr = '\tSet all pixels <0 to 0. This was added 20150701 ...'
				bPrintLog(msgStr, 2)
				pixels = map(lambda x: 0 if x<0 else x, pixels)
				bPrintLog('\t\t... done', 2)
				
			#get and print out min/max
			newMin = StackStatistics(imp).min
			newMax = StackStatistics(imp).max
			msgStr = '\tnew min=' + str(newMin) + ' max=' + str(newMax)
			bPrintLog(msgStr, 2)
			
			#append calibration to info string
			infoStr += 'bCalibCoeff_a = ' + str(calCoeff[0]) + '\n'
			infoStr += 'bCalibCoeff_b = ' + str(calCoeff[1]) + '\n'
			infoStr += 'bNewMin = ' + str(newMin) + '\n'
			infoStr += 'bNewMax = ' + str(newMax) + '\n'

	#
	# set up
	if gNumChannels == 1:
		impWinStr = copy.getTitle() #use this when only one channel
		impWin = WindowManager.getWindow(impWinStr) #returns java.awt.Window
	
	if gNumChannels == 2:
		winTitle = copy.getTitle()
		bPrintLog('Deinterleaving 2 channels...', 1)
		IJ.run('Deinterleave', 'how=2 keep') #makes ' #1' and ' #2', with ' #2' frontmost
		ch1WinStr = winTitle + ' #1'
		ch2WinStr = winTitle + ' #2'
		ch1Imp = WindowManager.getImage(ch1WinStr)
		ch2Imp = WindowManager.getImage(ch2WinStr)
		ch1File = destFolder + shortName + '_ch1.tif'
		ch2File = destFolder + shortName + '_ch2.tif'
		
	#
	# alignment
	if gDoAlign and gNumChannels == 1 and copy.getNSlices()>1:
		infoStr += 'AlignOnChannel=1' + '\n'
		#snap to middle slice
		if gAlignOnMiddleSlice:
			middleSlice = int(math.floor(copy.getNSlices() / 2)) #int() is necc., python is f*****g picky
		else:
			middleSlice = gAlignOnThisSlice
		copy.setSlice(middleSlice)
		
		transformationFile = destAlignmentFolder + shortName + '.txt'
		
		bPrintLog('MultiStackReg aligning:' + impWinStr, 1)
		stackRegParams = 'stack_1=[%s] action_1=Align file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body] save' %(impWin,transformationFile)
		IJ.run('MultiStackReg', stackRegParams)
		infoStr += 'AlignOnSlice=' + str(middleSlice) + '\n'

		#20150723, we just aligned on a cropped copy, apply alignment to original imp
		origImpTitle = imp.getTitle()
		stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' %(origImpTitle,transformationFile)
		IJ.run('MultiStackReg', stackRegParams)		
		
	if gDoAlign and gNumChannels == 2 and ch1Imp.getNSlices()>1 and ch2Imp.getNSlices()>1:
		#apply to gAlignThisChannel
		alignThisWindow = ''
		applyAlignmentToThisWindow = ''
		if gAlignThisChannel == 1:
			infoStr += 'AlignOnChannel=1' + '\n'
			transformationFile = destAlignmentFolder + shortName + '_ch1.txt'
			alignThisWindow = ch1WinStr
			applyAlignmentToThisWindow = ch2WinStr
		else:
			infoStr += 'AlignOnChannel=2' + '\n'
			transformationFile = destAlignmentFolder + shortName + '_ch2.txt'
			alignThisWindow = ch2WinStr
			applyAlignmentToThisWindow = ch1WinStr
	
		alignThisImp = WindowManager.getImage(alignThisWindow)
		#snap to middle slice
		if gAlignOnMiddleSlice:
			middleSlice = int(math.floor(alignThisImp.getNSlices() / 2)) #int() is necc., python is f*****g picky
		else:
			middleSlice = gAlignOnThisSlice
		alignThisImp.setSlice(middleSlice)

		infoStr += 'bAlignOnSlice=' + str(middleSlice) + '\n'
		
		bPrintLog('MultiStackReg aligning:' + alignThisWindow, 1)
		stackRegParams = 'stack_1=[%s] action_1=Align file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body] save' %(alignThisWindow,transformationFile)
		IJ.run('MultiStackReg', stackRegParams)
	
		# 20150723, we just aligned on a copy, apply alignment to both channels of original
		# ch1
		bPrintLog('MultiStackReg applying alignment to:' + origCh1WinStr, 1)
		stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' %(origCh1WinStr,transformationFile)
		IJ.run('MultiStackReg', stackRegParams)		
		# ch2
		bPrintLog('MultiStackReg applying alignment to:' + origCh2WinStr, 1)
		stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' %(origCh2WinStr,transformationFile)
		IJ.run('MultiStackReg', stackRegParams)		
		
		#apply alignment to other window
		#bPrintLog('MultiStackReg applying alignment to:' + applyAlignmentToThisWindow, 1)
		#applyAlignThisImp = WindowManager.getImage(applyAlignmentToThisWindow)
		#stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' %(applyAlignmentToThisWindow,transformationFile)
		#IJ.run('MultiStackReg', stackRegParams)		
	elif gDoAlign:
		bPrintLog('Skipping alignment, there may be only one slice?',3)
						
	#
	# save
	if gNumChannels == 1:
		imp.setProperty("Info", infoStr);
		impFile = destFolder + shortName + '.tif'
		#bPrintLog('Saving:' + impFile, 1)
		bSaveStack(imp, impFile)
		#max project
		bSaveZProject(imp, destMaxFolder, shortName)

	if gNumChannels == 2:
		#ch1
		origCh1Imp.setProperty("Info", infoStr);
		#bPrintLog('Saving:' + ch1File, 1)
		bSaveStack(origCh1Imp, ch1File)
		#max project
		bSaveZProject(origCh1Imp, destMaxFolder, shortName+'_ch1')

		#ch2
		origCh2Imp.setProperty("Info", infoStr);
		#bPrintLog('Saving:' + ch2File, 1)
		bSaveStack(origCh2Imp, ch2File)
 		#max project
		bSaveZProject(origCh2Imp, destMaxFolder, shortName+'_ch2')
		
 	#
	# post convert to 8-bit and save
	if gSave8bit:
		if bitDepth == 16:
			if gNumChannels == 1:
				bPrintLog('Converting to 8-bit:' + impWinStr, 1)
				IJ.selectWindow(impWinStr)
				#IJ.run('resetMinAndMax()')
				IJ.run("8-bit")
				impFile = eightBitFolder + shortName + '.tif'
				bPrintLog('Saving 8-bit:' + impFile, 2)
				bSaveStack(imp, impFile)
				#max project
				bSaveZProject(imp, eightBitMaxFolder, shortName)
				
			if gNumChannels == 2:
				#
				bPrintLog('Converting to 8-bit:' + origCh1WinStr, 1)
				IJ.selectWindow(origCh1WinStr)
				
				IJ.run("8-bit")
				impFile = eightBitFolder + shortName + '_ch1.tif'
				bPrintLog('Saving 8-bit:' + impFile, 2)
				bSaveStack(origCh1Imp, impFile)
				#max project
				bSaveZProject(origCh1Imp, eightBitMaxFolder, shortName+'_ch1')

				#
				bPrintLog('Converting to 8-bit:' + origCh2WinStr, 1)
				IJ.selectWindow(origCh2WinStr)
				#IJ.run('resetMinAndMax()')
				IJ.run("8-bit")
 				impFile = eightBitFolder + shortName + '_ch2.tif'
				bPrintLog('Saving 8-bit:' + impFile, 2)
				bSaveStack(origCh2Imp, impFile)
				#max project
				bSaveZProject(origCh2Imp, eightBitMaxFolder, shortName+'_ch2')
				
	#
	# close original window
	imp.changes = 0
	imp.close()
	#copy
	copy.changes = 0
	copy.close()

	#
	# close ch1/ch2
	if gNumChannels == 2:
		#original
		origCh1Imp.changes = 0
		origCh1Imp.close()
		origCh2Imp.changes = 0
		origCh2Imp.close()
		#copy
		ch1Imp.changes = 0
		ch1Imp.close()
		ch2Imp.changes = 0
		ch2Imp.close()

	bPrintLog(time.strftime("%H:%M:%S") + ' finished runOneFile(): ' + fullFilePath, 1)
コード例 #4
0
def runOneFile(fullFilePath):
    global gFileType
    global fileIndex

    if not os.path.isfile(fullFilePath):
        bPrintLog(
            '\nERROR: runOneFile() did not find file: ' + fullFilePath + '\n',
            0)
        return 0

    bPrintLog(
        time.strftime("%H:%M:%S") + ' starting runOneFile(): ' + fullFilePath,
        1)
    bPrintLog('inputfile is:' + fullFilePath, 1)

    enclosingPath = os.path.dirname(fullFilePath)
    head, tail = os.path.split(
        enclosingPath)  #tail is name of enclosing folder
    enclosingPath += '/'

    # make output folders
    destFolder = enclosingPath + tail + '_short/'
    if not os.path.isdir(destFolder):
        os.makedirs(destFolder)

    # open
    if gFileType == 'tif':
        # open .tif image
        imp = Opener().openImage(fullFilePath)
    else:
        # open .lsm
        cmdStr = 'open=%s autoscale color_mode=Default view=Hyperstack stack_order=XYCZT' % (
            fullFilePath, )
        IJ.run('Bio-Formats Importer', cmdStr)
        lsmpath, lsmfilename = os.path.split(fullFilePath)
        lsWindow = lsmfilename
        imp = WindowManager.getImage(lsWindow)

    # get parameters of image
    (width, height, nChannels, nSlices, nFrames) = imp.getDimensions()
    bitDepth = imp.getBitDepth()
    infoStr = imp.getProperty("Info")  #get all .tif tags
    #print 'original infoStr:', infoStr
    if not infoStr:
        infoStr = ''
    infoStr += 'ShortenNames_Version=' + str(gShortenVersion) + '\n'
    infoStr += 'ShortenNames_Time=' + time.strftime(
        "%Y%m%d") + '_' + time.strftime("%H%M%S") + '\n'

    msgStr = 'w:' + str(width) + ' h:' + str(height) + ' slices:' + str(nSlices) \
       + ' channels:' + str(nChannels) + ' frames:' + str(nFrames) + ' bitDepth:' + str(bitDepth)
    bPrintLog(msgStr, 1)

    path, filename = os.path.split(fullFilePath)
    shortName, fileExtension = os.path.splitext(filename)

    #output file name
    outFile = destFolder + tail + '_' + str(fileIndex) + '.tif'
    fileIndex += 1
    bPrintLog('output file is:' + outFile, 1)

    # put original name in header
    infoStr += 'ShortenNames_OriginalFile=' + fullFilePath + '\n'

    # put scanimage header back in
    imp.setProperty("Info", infoStr)

    #save
    bSaveStack(imp, outFile)

    #
    # close original window
    imp.changes = 0
    imp.close()
コード例 #5
0
def runOneFile(fullFilePath):

	global gNumChannels
	
	if not os.path.isfile(fullFilePath):
		bPrintLog('\nERROR: runOneFile() did not find file: ' + fullFilePath + '\n',0)
		return 0

	bPrintLog(time.strftime("%H:%M:%S") + ' starting runOneFile(): ' + fullFilePath, 1)
	
	enclosingPath = os.path.dirname(fullFilePath)
	head, tail = os.path.split(enclosingPath)
	enclosingPath += '/'
	
	#make output folders
	destFolder = enclosingPath + tail + '_channels/'
	if not os.path.isdir(destFolder):
		os.makedirs(destFolder)
	destMaxFolder = destFolder + 'max/'
	if not os.path.isdir(destMaxFolder):
		os.makedirs(destMaxFolder)

	if gDoAlign:
		destAlignmentFolder = destFolder + 'alignment/'
		if not os.path.isdir(destAlignmentFolder):
			os.makedirs(destAlignmentFolder)
			
	if gSave8bit:
		eightBitFolder = destFolder + 'channels8/'
		if not os.path.isdir(eightBitFolder):
			os.makedirs(eightBitFolder)
		eightBitMaxFolder = eightBitFolder + 'max/'
		if not os.path.isdir(eightBitMaxFolder):
			os.makedirs(eightBitMaxFolder)
	
	# open image
	imp = Opener().openImage(fullFilePath)

	# get parameters of image
	(width, height, nChannels, nSlices, nFrames) = imp.getDimensions()
	bitDepth = imp.getBitDepth()
	infoStr = imp.getProperty("Info") #get all .tif tags
	if not infoStr:
		infoStr = ''
		
	msgStr = 'w:' + str(width) + ' h:' + str(height) + ' slices:' + str(nSlices) \
				+ ' channels:' + str(nChannels) + ' frames:' + str(nFrames) + ' bitDepth:' + str(bitDepth)
	bPrintLog(msgStr, 1)
	
	path, filename = os.path.split(fullFilePath)
	shortName, fileExtension = os.path.splitext(filename)

	#this is too much work for ScanImage4
	#try and guess channels if it is a scanimage file
	#scanImage3 = string.find(infoStr, 'scanimage') != -1
	#scanimage4 = find(infoStr, 'scanimage.SI4.channelSave = ')
	#print 'scanimage4:', scanimage4
	
	#
	# look for num channels in ScanImage infoStr
	if gGetNumChanFromScanImage:
		for line in infoStr.split('\n'):
			#scanimage.SI4.channelsSave = [1;2]
			scanimage4 = find(line, 'scanimage.SI4.channelsSave =') == 0
			#state.acq.numberOfChannelsSave=2
			scanimage3 = find(line, 'state.acq.numberOfChannelsSave=') == 0
			if scanimage3:
				#print 'line:', line
				equalIdx = find(line, '=')
				line2 = line[equalIdx+1:]
				if gGetNumChanFromScanImage:
					gNumChannels = int(line2)
					bPrintLog('over-riding gNumChannels with: ' + str(gNumChannels), 2)
			if scanimage4:
				#print '   we have a scanimage 4 file ... now i need to exptract the number of channel'
				#print 'line:', line
				equalIdx = find(line, '=')
				line2 = line[equalIdx+1:]
				for delim in ';[]':
					line2 = line2.replace(delim, ' ')
				if gGetNumChanFromScanImage:
					gNumChannels = len(line2.split())
					bPrintLog('over-riding gNumChannels with: ' + str(gNumChannels), 2)

	# show
	imp.show()

	infoStr += 'bAlignBatch6=' + time.strftime("%Y%m%d") + '\n'
	#
	# crop
	if gDoCrop:
		bPrintLog('making cropping rectangle (left,top,width,height) ',1)
		bPrintLog(str(gCropLeft) + ' ' + str(gCropTop) + ' ' +str(gCropWidth) + ' ' +str(gCropHeight), 2)
		roi = Roi(gCropLeft, gCropTop, gCropWidth, gCropHeight) #left,top,width,height
		imp.setRoi(roi)
		
		#time.sleep(1)
		
		#bPrintLog('cropping', 1)
		IJ.run('Crop')
		infoStr += 'cropping=' + str(gCropLeft) + ',' + str(gCropTop) + ',' + str(gCropWidth) + ',' + str(gCropHeight) + '\n'
	
	#
	# remove negative (<0) pixel values
	#ip = imp.getProcessor()
	#pixels = ip.getPixels()  # this returns a reference (not a copy)
	#for i in xrange(len(pixels)):  
	#	if pixels[i] < 0:  
	#		pixels[i] = 0
	# or this, for each pixel 'x', if  x<0 then 0 else x
	#pixels = map(lambda x: 0 if x<0 else x, pixels)
	
	#set our new values (without pixels <0) back into original (I hope this handles stacks and channels???)
	#ip.setPixels(pixels)
	
	#
	# remove calibration
	if gRemoveCalibration:
		cal = imp.getCalibration()
		calCoeff = cal.getCoefficients()
		if calCoeff:
			msgStr = 'Calibration is y=a+bx' + ' a=' + str(calCoeff[0]) + ' b=' + str(calCoeff[1])
			bPrintLog(msgStr, 1)
			
			#remove calibration
			bPrintLog('\tRemoving Calibration', 2)
			imp.setCalibration(None)
				
			#get and print out min/max
			origMin = StackStatistics(imp).min
			origMax = StackStatistics(imp).max
			msgStr = '\torig min=' + str(origMin) + ' max=' + str(origMax)
			bPrintLog(msgStr, 2)
			
			#msgStr = 'adding calCoeff[0]='+str(calCoeff[0]) + ' to stack.'
			#bPrintLog(msgStr, 2)
			#subArgVal = 'value=%s stack' % (calCoeff[0],)
			#IJ.run('Add...', subArgVal)

			# 20150701, 'shift everybody over by linear calibration intercept calCoeff[0]'
			if 1:
				# [1] was this
				#msgStr = 'Subtracting original min '+str(origMin) + ' from stack.'
				#bPrintLog(msgStr, 2)
				#subArgVal = 'value=%s stack' % (origMin,)
				#IJ.run('Subtract...', subArgVal)
				# [2] now this
				#msgStr = 'Adding calCoeff[0] '+str(calCoeff[0]) + ' from stack.'
				#bPrintLog(msgStr, 2)
				#addArgVal = 'value=%s stack' % (int(calCoeff[0]),)
				#IJ.run('Add...', addArgVal)
				# [3] subtract a magic number 2^15-2^7 = 32768 - 128
				magicNumber = 32768 - 128
				msgStr = 'Subtracting a magic number '+str(magicNumber) + ' from stack.'
				bPrintLog(msgStr, 2)
				subArgVal = 'value=%s stack' % (origMin,)
				IJ.run('Subtract...', subArgVal)
				
			# 20150701, set any pixel <0 to 0
			if 0:
				ip = imp.getProcessor() # returns a reference
				pixels = ip.getPixels() # returns a reference
				msgStr = '\tSet all pixels <0 to 0. This was added 20150701 ...'
				bPrintLog(msgStr, 2)
				pixels = map(lambda x: 0 if x<0 else x, pixels)
				bPrintLog('\t\t... done', 2)
				
			#get and print out min/max
			newMin = StackStatistics(imp).min
			newMax = StackStatistics(imp).max
			msgStr = '\tnew min=' + str(newMin) + ' max=' + str(newMax)
			bPrintLog(msgStr, 2)
			
			#without these, 8-bit conversion goes to all 0 !!! what the f**k !!!
			#bPrintLog('calling imp.resetStack() and imp.resetDisplayRange()', 2)
			imp.resetStack()
			imp.resetDisplayRange()

			#append calibration to info string
			infoStr += 'calibCoeff_a = ' + str(calCoeff[0]) + '\n'
			infoStr += 'calibCoeff_b = ' + str(calCoeff[1]) + '\n'
			infoStr += 'origMin = ' + str(origMin) + '\n'
			infoStr += 'origMax = ' + str(origMax) + '\n'

	#
	# set up
	if gNumChannels == 1:
		impWinStr = imp.getTitle() #use this when only one channel
		impWin = WindowManager.getWindow(impWinStr) #returns java.awt.Window
	
	if gNumChannels == 2:
		winTitle = imp.getTitle()
		bPrintLog('Deinterleaving 2 channels...', 1)
		IJ.run('Deinterleave', 'how=2 keep') #makes ' #1' and ' #2', with ' #2' frontmost
		ch1WinStr = winTitle + ' #1'
		ch2WinStr = winTitle + ' #2'
		ch1Imp = WindowManager.getImage(ch1WinStr)
		ch2Imp = WindowManager.getImage(ch2WinStr)
		ch1File = destFolder + shortName + '_ch1.tif'
		ch2File = destFolder + shortName + '_ch2.tif'
		
	#
	# alignment
	if gDoAlign and gNumChannels == 1 and imp.getNSlices()>1:
		infoStr += 'AlignOnChannel=1' + '\n'
		#snap to middle slice
		if gAlignOnMiddleSlice:
			middleSlice = int(math.floor(imp.getNSlices() / 2)) #int() is necc., python is f*****g picky
		else:
			middleSlice = gAlignOnThisSlice
		imp.setSlice(middleSlice)
		
		transformationFile = destAlignmentFolder + shortName + '.txt'
		
		bPrintLog('MultiStackReg aligning:' + impWinStr, 1)
		stackRegParams = 'stack_1=[%s] action_1=Align file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body] save' %(impWin,transformationFile)
		IJ.run('MultiStackReg', stackRegParams)
		infoStr += 'AlignOnSlice=' + str(middleSlice) + '\n'
	if gDoAlign and gNumChannels == 2 and ch1Imp.getNSlices()>1 and ch2Imp.getNSlices()>1:
		#apply to gAlignThisChannel
		alignThisWindow = ''
		applyAlignmentToThisWindow = ''
		if gAlignThisChannel == 1:
			infoStr += 'AlignOnChannel=1' + '\n'
			transformationFile = destAlignmentFolder + shortName + '_ch1.txt'
			alignThisWindow = ch1WinStr
			applyAlignmentToThisWindow = ch2WinStr
		else:
			infoStr += 'AlignOnChannel=2' + '\n'
			transformationFile = destAlignmentFolder + shortName + '_ch2.txt'
			alignThisWindow = ch2WinStr
			applyAlignmentToThisWindow = ch1WinStr
	
		alignThisImp = WindowManager.getImage(alignThisWindow)
		#snap to middle slice
		if gAlignOnMiddleSlice:
			middleSlice = int(math.floor(alignThisImp.getNSlices() / 2)) #int() is necc., python is f*****g picky
		else:
			middleSlice = gAlignOnThisSlice
		alignThisImp.setSlice(middleSlice)

		infoStr += 'AlignOnSlice=' + str(middleSlice) + '\n'
		
		bPrintLog('MultiStackReg aligning:' + alignThisWindow, 1)
		stackRegParams = 'stack_1=[%s] action_1=Align file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body] save' %(alignThisWindow,transformationFile)
		IJ.run('MultiStackReg', stackRegParams)
	
		#apply alignment to other window
		bPrintLog('MultiStackReg applying alignment to:' + applyAlignmentToThisWindow, 1)
		applyAlignThisImp = WindowManager.getImage(applyAlignmentToThisWindow)
		stackRegParams = 'stack_1=[%s] action_1=[Load Transformation File] file_1=[%s] stack_2=None action_2=Ignore file_2=[] transformation=[Rigid Body]' %(applyAlignmentToThisWindow,transformationFile)
		IJ.run('MultiStackReg', stackRegParams)		
	elif gDoAlign:
		bPrintLog('Skipping alignment, there may be only one slice?',3)
						
	#
	# save
	if gNumChannels == 1:
		imp.setProperty("Info", infoStr);
		impFile = destFolder + shortName + '.tif'
		#bPrintLog('Saving:' + impFile, 1)
		bSaveStack(imp, impFile)
		#max project
		bSaveZProject(imp, destMaxFolder, shortName)

	if gNumChannels == 2:
		#ch1
		ch1Imp.setProperty("Info", infoStr);
		#bPrintLog('Saving:' + ch1File, 1)
		bSaveStack(ch1Imp, ch1File)
		#max project
		bSaveZProject(ch1Imp, destMaxFolder, shortName+'_ch1')

		#ch2
		ch2Imp.setProperty("Info", infoStr);
		#bPrintLog('Saving:' + ch2File, 1)
		bSaveStack(ch2Imp, ch2File)
 		#max project
		bSaveZProject(ch2Imp, destMaxFolder, shortName+'_ch2')
		
 	#
	# post convert to 8-bit and save
	if gSave8bit:
		if bitDepth == 16:
			if gNumChannels == 1:
				bPrintLog('Converting to 8-bit:' + impWinStr, 1)
				IJ.selectWindow(impWinStr)
				#IJ.run('resetMinAndMax()')
				IJ.run("8-bit")
				impFile = eightBitFolder + shortName + '.tif'
				bPrintLog('Saving 8-bit:' + impFile, 2)
				bSaveStack(imp, impFile)
				#max project
				bSaveZProject(imp, eightBitMaxFolder, shortName)
				
			if gNumChannels == 2:
				#
				bPrintLog('Converting to 8-bit:' + ch1WinStr, 1)
				IJ.selectWindow(ch1WinStr)
				#IJ.run('resetMinAndMax()')
				
				#ch1Imp.resetStack()
				#ch1Imp.resetDisplayRange()
				
				IJ.run("8-bit")
				impFile = eightBitFolder + shortName + '_ch1.tif'
				bPrintLog('Saving 8-bit:' + impFile, 2)
				bSaveStack(ch1Imp, impFile)
				#max project
				bSaveZProject(ch1Imp, eightBitMaxFolder, shortName+'_ch1')

				#
				bPrintLog('Converting to 8-bit:' + ch2WinStr, 1)
				IJ.selectWindow(ch2WinStr)
				#IJ.run('resetMinAndMax()')
				IJ.run("8-bit")
 				impFile = eightBitFolder + shortName + '_ch2.tif'
				bPrintLog('Saving 8-bit:' + impFile, 2)
				bSaveStack(ch2Imp, impFile)
				#max project
				bSaveZProject(ch2Imp, eightBitMaxFolder, shortName+'_ch2')
				
	#
	# close original window
	imp.changes = 0
	imp.close()

	#
	# close ch1/ch2
	if 1 and gNumChannels == 2:
		ch1Imp.changes = 0
		ch1Imp.close()
		ch2Imp.changes = 0
		ch2Imp.close()

	bPrintLog(time.strftime("%H:%M:%S") + ' finished runOneFile(): ' + fullFilePath, 1)
コード例 #6
0
def runOneFile(fullFilePath):
	global gFileType
	global fileIndex
	
	if not os.path.isfile(fullFilePath):
		bPrintLog('\nERROR: runOneFile() did not find file: ' + fullFilePath + '\n',0)
		return 0

	bPrintLog(time.strftime("%H:%M:%S") + ' starting runOneFile(): ' + fullFilePath, 1)
	bPrintLog('inputfile is:' + fullFilePath, 1)
	
	enclosingPath = os.path.dirname(fullFilePath)
	head, tail = os.path.split(enclosingPath) #tail is name of enclosing folder
	enclosingPath += '/'
	
	# make output folders
	destFolder = enclosingPath + tail + '_short/'
	if not os.path.isdir(destFolder):
		os.makedirs(destFolder)

	# open
	if gFileType=='tif':
		# open .tif image
		imp = Opener().openImage(fullFilePath)
	else:
		# open .lsm
		cmdStr = 'open=%s autoscale color_mode=Default view=Hyperstack stack_order=XYCZT' % (fullFilePath,)
		IJ.run('Bio-Formats Importer', cmdStr)
		lsmpath, lsmfilename = os.path.split(fullFilePath)
		lsWindow = lsmfilename
		imp = WindowManager.getImage(lsWindow)

	# get parameters of image
	(width, height, nChannels, nSlices, nFrames) = imp.getDimensions()
	bitDepth = imp.getBitDepth()
	infoStr = imp.getProperty("Info") #get all .tif tags
	#print 'original infoStr:', infoStr
	if not infoStr:
		infoStr = ''
	infoStr += 'ShortenNames_Version=' + str(gShortenVersion) + '\n'
	infoStr += 'ShortenNames_Time=' + time.strftime("%Y%m%d") + '_' + time.strftime("%H%M%S") + '\n'
		
	msgStr = 'w:' + str(width) + ' h:' + str(height) + ' slices:' + str(nSlices) \
				+ ' channels:' + str(nChannels) + ' frames:' + str(nFrames) + ' bitDepth:' + str(bitDepth)
	bPrintLog(msgStr, 1)
	
	path, filename = os.path.split(fullFilePath)
	shortName, fileExtension = os.path.splitext(filename)

	#output file name
	outFile = destFolder + tail + '_' + str(fileIndex) + '.tif'
	fileIndex += 1
	bPrintLog('output file is:' + outFile, 1)
	
	# put original name in header
	infoStr += 'ShortenNames_OriginalFile=' + fullFilePath + '\n'
	
	# put scanimage header back in
	imp.setProperty("Info", infoStr);

	#save
	bSaveStack(imp, outFile)

	#
	# close original window
	imp.changes = 0
	imp.close()
コード例 #7
0
def main():

    Interpreter.batchMode = True

    if (lambda_flat == 0) ^ (lambda_dark == 0):
        print ("ERROR: Both of lambda_flat and lambda_dark must be zero,"
               " or both non-zero.")
        return
    lambda_estimate = "Automatic" if lambda_flat == 0 else "Manual"

    print "Loading images..."
    filenames = enumerate_filenames(pattern)
    if len(filenames) == 0:
        return
    # This is the number of channels inferred from the filenames. The number
    # of channels in an individual image file will be determined below.
    num_channels = len(filenames)
    num_images = len(filenames[0])
    image = Opener().openImage(filenames[0][0])
    if image.getNDimensions() > 3:
        print "ERROR: Can't handle images with more than 3 dimensions."
    (width, height, channels, slices, frames) = image.getDimensions()
    # The third dimension could be any of these three, but the other two are
    # guaranteed to be equal to 1 since we know NDimensions is <= 3.
    image_channels = max((channels, slices, frames))
    image.close()
    if num_channels > 1 and image_channels > 1:
        print (
            "ERROR: Can only handle single-channel images with {channel} in"
            " the pattern, or multi-channel images without {channel}. The"
            " filename patterns imply %d channels and the images themselves"
            " have %d channels." % (num_channels, image_channels)
        )
        return
    if image_channels == 1:
        multi_channel = False
    else:
        print (
            "Detected multi-channel image files with %d channels"
            % image_channels
        )
        multi_channel = True
        num_channels = image_channels
        # Clone the filename list across all channels. We will handle reading
        # the individual image planes for each channel below.
        filenames = filenames * num_channels

    # The internal initialization of the BaSiC code fails when we invoke it via
    # scripting, unless we explicitly set a the private 'noOfSlices' field.
    # Since it's private, we need to use Java reflection to access it.
    Basic_noOfSlices = Basic.getDeclaredField('noOfSlices')
    Basic_noOfSlices.setAccessible(True)
    basic = Basic()
    Basic_noOfSlices.setInt(basic, num_images)

    # Pre-allocate the output profile images, since we have all the dimensions.
    ff_image = IJ.createImage("Flat-field", width, height, num_channels, 32);
    df_image = IJ.createImage("Dark-field", width, height, num_channels, 32);

    print("\n\n")

    # BaSiC works on one channel at a time, so we only read the images from one
    # channel at a time to limit memory usage.
    for channel in range(num_channels):
        print "Processing channel %d/%d..." % (channel + 1, num_channels)
        print "==========================="

        stack = ImageStack(width, height, num_images)
        opener = Opener()
        for i, filename in enumerate(filenames[channel]):
            print "Loading image %d/%d" % (i + 1, num_images)
            # For multi-channel images the channel determines the plane to read.
            args = [channel + 1] if multi_channel else []
            image = opener.openImage(filename, *args)
            stack.setProcessor(image.getProcessor(), i + 1)
        input_image = ImagePlus("input", stack)

        # BaSiC seems to require the input image is actually the ImageJ
        # "current" image, otherwise it prints an error and aborts.
        WindowManager.setTempCurrentImage(input_image)
        basic.exec(
            input_image, None, None,
            "Estimate shading profiles", "Estimate both flat-field and dark-field",
            lambda_estimate, lambda_flat, lambda_dark,
            "Ignore", "Compute shading only"
        )
        input_image.close()

        # Copy the pixels from the BaSiC-generated profile images to the
        # corresponding channel of our output images.
        ff_channel = WindowManager.getImage("Flat-field:%s" % input_image.title)
        ff_image.slice = channel + 1
        ff_image.getProcessor().insert(ff_channel.getProcessor(), 0, 0)
        ff_channel.close()
        df_channel = WindowManager.getImage("Dark-field:%s" % input_image.title)
        df_image.slice = channel + 1
        df_image.getProcessor().insert(df_channel.getProcessor(), 0, 0)
        df_channel.close()

        print("\n\n")

    template = '%s/%s-%%s.tif' % (output_dir, experiment_name)
    ff_filename = template % 'ffp'
    IJ.saveAsTiff(ff_image, ff_filename)
    ff_image.close()
    df_filename = template % 'dfp'
    IJ.saveAsTiff(df_image, df_filename)
    df_image.close()

    print "Done!"