def select_images(): """ Returns two ImagePlus objects that can be used by the drift correction. If more than two images are available a dialog is used for selection. """ if WindowManager.getImageCount() > 0: imp = WindowManager.getCurrentImage() if imp.getImageStackSize() == 2: dup = Duplicator() img1 = dup.run(imp, 1, 1) img1.setTitle("Slice1") img2 = dup.run(imp, 2, 2) img2.setTitle("Slice2") elif WindowManager.getImageCount() == 2: img1, img2 = [WindowManager.getImage(id) for id in WindowManager.getIDList()] elif WindowManager.getImageCount() > 2: image_ids = WindowManager.getIDList() image_titles = [WindowManager.getImage(id).getTitle() for id in image_ids] try: sel1, sel2 = dialogs.create_selection_dialog(image_titles, range(2)) except TypeError: return(None, None) img1 = WindowManager.getImage(image_ids[sel1]) img2 = WindowManager.getImage(image_ids[sel2]) else: IJ.error("You need two images to run the script.") return(None, None) else: IJ.error("You need two images to run the script.") return(None, None) return (img1, img2)
def getSettings(img): """This function assesses (by returning a boolean value) if the filter can be applied to the image passed as argument. Will ask the user for new values if current parameters are undefined.""" global xradius, yradius, zradius canProceed = True if not img: IJ.error("No images open.") print ">>>> No image to work with!" canProceed = False # Get new values if at least one of the parameters is 'null' if canProceed and None in (xradius, yradius, zradius): gd = GenericDialog("Median Filter") gd.addNumericField("X radius:", 2.0, 1) gd.addNumericField("Y radius:", 2.0, 1) gd.addNumericField("Z radius:", 2.0, 1) gd.showDialog() if gd.wasCanceled(): print ">>>> User canceled dialog!" canProceed = False else: xradius = gd.getNextNumber() yradius = gd.getNextNumber() zradius = gd.getNextNumber() return canProceed
def main(): # --------------------------------------------- # Loads json file, reads tiff stack filenames # runs them through the selected STORM analyser # then attempts to save the collected spot info. # --------------------------------------------- settingsFile = "" settingsFile = IJ.getFilePath(settingsFile) if settingsFile == None: return try: jsonFileObj = open(settingsFile, 'r') jsonRead = json.load(jsonFileObj) except: IJ.error("No JSON could be loaded from " + settingsFile + ". Are you certain this file is the correct format?") return directory = jsonRead['SaveDirectory'] tiledStormOutputFile = directory + os.sep + "Tiled_STORM_spots.csv" # Run analysis: for item in jsonRead['Points']: imageFile = directory + os.sep + item['Filename'] if macro == "ThunderSTORM": fileList = runThunderSTORM(imageFile) elif macro == "SomeOTHERnotimplementedSTORM": fileList = runThunderSTORM(imageFile) else: IJ.error( "The STORM method selected in the Tile_STORM macro is invalid. :(" ) # Apply offsets: applyOffsets(fileList, jsonRead, tiledStormOutputFile) return 0
def overlayImages(self, e): impBase = WindowManager.getImage( self.imageIDs[self.baseImageBox.getSelectedIndex()]) refBase = impBase.getStack().getProcessor(1) impOverlay = WindowManager.getImage( self.imageIDs[self.overlayImageBox.getSelectedIndex()]) refOverlay = impOverlay.getStack().getProcessor(1) print "Overlaying for stack sizes " + str( impBase.getStackSize()) + "/" + str( impOverlay.getStackSize()) + "..." stack = None if self.virtualStackCheckbox.isSelected(): stack = OverlayVirtualStack() stack.overlayOpacity = float( self.opacitySpinner.getValue()) / 100.0 stack.overlayColor = AWTColorToArray( self.overlayColorPreviewLabel.getBackground()) stack.base = impBase stack.overlay = impOverlay ImagePlus( "Stack Overlay from " + self.imageNames[self.baseImageBox.getSelectedIndex()] + " and " + self.imageNames[self.overlayImageBox.getSelectedIndex()], stack).show() else: IJ.error( "Not implemented yet", "Using normal stacks is not implemented yet. Please use the Virtual Stack option." )
def getCategoriesFromTable(): """ If a table is opened, this function will try to find the categories by either reading the column headers or by reading the content of a column called "Category" """ table = getTable() headings = table.getHeadings() if not headings: # empty table IJ.error("No active table") return ["Category1"] if "Category" in headings: # parse the column category to a set column = [ str(item)[1:-1] for item in table.getColumnAsVariables("Category") ] # convert from ij.macro.Variable to string + remove the " " return list(set(column)) # use set to keep single occurence else: # return columns headers except the non-category ones headings = set(headings) # use set to be able to do a difference headings = headings - nonCategory_headers # Also remove the measurement columns ? return list(headings)
def split_and_save(imp): base_title = imp.getShortTitle() base_dir = imp.getOriginalFileInfo().directory d = GenericDialog("Split Stacks") d.addMessage("Indicate the channels in your image stack, separated by commas") d.addMessage("Add the channels *in the order that you took the images*") d.addMessage("For example, \"TL, 410, 470, 410, 470\"") d.addStringField("Channels", "TL, 470, 410", 40) d.showDialog() # exit if cancelled if d.wasCanceled(): return None channels = number_duplicate_channels([x.strip() for x in d.getNextString().split(',')]) # Check that the number of images in stack is divisible by the number of channels # If not, quit. Else keep going if (imp.getNSlices() % len(channels) != 0): IJ.error("Invalid Channel Specification", "The number of slices (%d) is not divisible by the number of channels (%d). Exiting." % (imp.getNSlices(), len(channels))) return None imp.show() IJ.run("Deinterleave", "how=%d" % len(channels)) for i, img_id in enumerate(WindowManager.getIDList()): channel_i = WindowManager.getImage(img_id) channel_i.setTitle(base_title + "_" + channels[i]) IJ.saveAs(channel_i, "tif", base_dir + channel_i.getTitle()) IJ.showMessage("Saved image stacks as separate channels in %s" % base_dir)
def getSettings(img): """This function assesses (by returning a boolean value) if the filter can be applied to the image passed as argument. Will ask the user for new values if current parameters are undefined.""" global xradius, yradius, zradius canProceed = True if not img: IJ.error("No images open.") canProceed = False # Get new values if at least one of the parameters is 'null' if canProceed and None in (xradius, yradius, zradius): gd = GenericDialog("Median Filter") gd.addNumericField("X radius:", 2.0, 1) gd.addNumericField("Y radius:", 2.0, 1) gd.addNumericField("Z radius:", 2.0, 1) gd.showDialog() if gd.wasCanceled(): canProceed = False else: xradius = gd.getNextNumber() yradius = gd.getNextNumber() zradius = gd.getNextNumber() return canProceed
def checkImages(self): """ Raise error if images have changed """ current_active_IDs = WM.getIDList() if self.active_IDs != current_active_IDs: IJ.error("Change of images", "Active images have changed, please restart LinkedView") else: pass
def download_from_url(download_url, target_dir, download_file=None, download_msg=None): ''' download file in temporary location move to target_dir clean up download ''' from ij import IJ print(download_url) # open url and set up using header information u = urllib2.urlopen(download_url) headers = u.info() download_size = int(headers['Content-Length']) print(u) print(headers) if download_file == None: if headers.has_key('Content-Disposition'): download_file = re.sub(".*filename=", "", headers['Content-Disposition']) else: IJ.error( "No filename specified for download and none in http header!") if download_msg == None: download_msg = 'Downloading: %s' % (download_file) tf = tempfile.NamedTemporaryFile(suffix=download_file, delete=False) print 'Downloading ' + download_url + ' to ' + tf.name print "Download size should be %d" % (download_size) dest_file = os.path.join(target_dir, download_file) print 'Destination location %s' % (dest_file) # Now for the download block_size = 100000 if download_size > block_size: bytes_read = 0 while bytes_read < download_size: IJ.showStatus("%s (%.1f/%.1f Mb)" % (download_msg, (bytes_read / 1000000.0), (download_size / 1000000.0))) IJ.showProgress(bytes_read, download_size) tf.file.write(u.read(block_size)) bytes_read += block_size IJ.showProgress(1.0) else: tf.file.write(u.read()) u.close() tf.file.close() print('Downloaded file has size %d') % (os.path.getsize(tf.name)) tf.close() shutil.move(tf.name, dest_file) IJ.showStatus('Cleaning up!')
def __init__(self): self.active_IDs = WM.getIDList() if self.active_IDs is None: IJ.error("Error", "No images imported") if len(self.active_IDs) < 2: IJ.error("Error", "Must have at least two images open") self.Images = {ID: Image(WM.getImage(ID)) for ID in self.active_IDs} # create Images self.ref_image = self.Images.values()[ 0] # by default, ref image is first image
def run(context, imp, output_folder, analysis_ch, th_method, stroke_width, tracing_ch, dispose_snt=True): ''' **dispose_snt kwarg is not implemented. Runs the main analysis pipeline. Consists in: >Opening image >Setting up SNT plugin to trace >Wait for user to trace paths >Converts paths do ImageJ1 Rois >Applies the rois to the image analysis channel >Gets the profile plot of the roi >Save results Returns true if run succeded or false if canceled. Importantly, the orginal image is not altered in any way. ''' # Validation steps to prevent headaches along the pipeline validate_th_method(th_method) n_ch = imp.getNChannels() if n_ch < analysis_ch: raise ValueError("Analysis ch cannot be bigger than total number of channels.") rois_output, csvs_output = setup_output_folders(output_folder) imp.changes = False #imp.setC(tracing_ch) try: SNTpaths = assisted_SNTtrace(context, imp) except RuntimeError: SNTService().getPlugin().closeAndResetAllPanes() imp.close() return False if not SNTpaths: IJ.error("No paths found, reloading image.\nDid you forget to finish the trace?") return run(context, imp, output_folder, analysis_ch, th_method, stroke_width, tracing_ch, dispose_snt=dispose_snt) imp.hide() analysis_imp = get_analysis_ch(imp, analysis_ch) apply_threshold(analysis_imp, th_method) rm = get_clean_RoiManager() rois = convert_SNTpaths_to_roi(SNTpaths) profile_from_threshold(imp, analysis_ch, rois, stroke_width, th_method, csvs_output) for roi in rois: try: RoiEncoder.save(roi, os.path.join(rois_output, "{0}.roi".format(roi.getName()))) except: IJ.error("Could not save {0}".format(roi.getName())) analysis_imp.changes = False analysis_imp.close() imp.close() return True
def openImage(self, imageFile): try: images = BF.openImagePlus(imageFile) self.imp = images[0] except UnknownFormatException: return None if self.imp.getNChannels() < 2: IJ.error("Bad image format", "Image must contain at lease 2 channels!") return None if not self.pairs or \ not self.methods: self.getOptionsDialog(self.imp) title = self.imp.title self.imp.title = title[:title.rfind('.')] return self.imp
def apply_lut(cs, cmap): # type: (CellStack, str) -> None """ Apply a different Look Up Table according to the given cmap name :param cmap: Can be 'fire' """ stats = StackStatistics(cs) ll = LutLoader() if cmap == 'fire': cm = ll.open('luts/fire.lut') # print("Stats.max " + str(stats.max)) lut = LUT(cm, stats.min, stats.max) cs.setLut(lut) else: IJ.error('Invalid color map: ' + cmap + '\nDefault LUT applied')
def __init__(self): if IJ.getFullVersion() < "1.53b": message = "ImageJ with at least version 1.53b required. Update with Help > Update ImageJ..." IJ.error(message) raise Exception(message) super(TableModel, self).__init__() self.headers = ["Group", "Name"] groupNames = Roi.getGroupNames() # groupNames can be None ! groupNames = groupNames.split(",") if groupNames else [ "ExampleName-doubleClick to edit" ] # groupNames is a list self.nRows = len(groupNames) self.columns = [[], []] # 2 columns self.columns[0] = range(1, len(groupNames) + 1) self.columns[1] = groupNames
def run(): msg = "<html>" wm = WindowManager wcount = wm.getWindowCount() if wcount == 0: msg += "No windows open, nothing to do.<br/>" IJ.showMessage(PluginTitle, msg) return msg += "Number of open windows: " + str(wcount) + "<br/>" # let the User choose a directory to store the files target = DirectoryChooser("Choose target directory").getDirectory() if target is None: # User canceled the dialog msg += "<br/>No directory chosen, aborting.<br/>" IJ.showMessage(PluginTitle, msg) return msg += "Selected '" + target + "'as destination folder.<br/>" # determine padding width for filenames pad = len(str(wcount)) for i in range(wcount): # image ID lists start with 1 instead of 0, so for convenience: wid = i + 1 imp = wm.getImage(wid) imgid = wm.getNthImageID(wid) #print "window id:", wid, ", imageID:", wm.getNthImageID(wid) # Construct filename filename = 'tile_' + str(wid).zfill(pad) + '.tif' filepath = target + '/' + filename fs = FileSaver(imp) if imp.getImageStackSize() > 1: if not fs.saveAsTiffStack(filepath): IJ.error("<html>Error saving current image, stopping.") return else: if not fs.saveAsTiff(filepath): IJ.error("<html>Error saving current image, stopping.") return msg += "<br/>Successfully saved " + str(wcount) + " files.<br/>" IJ.showMessage(PluginTitle, msg)
def actionPerformed(self, event): if IJ.getFullVersion() < "1.53g": IJ.error("This plugin requires ImageJ version 1.53g minimum.\n Update using Help > Update ImageJ...") return tableWindow = WindowManager.getActiveTable() # this function requires the 1.53g (or at least not working with 1.53c) if not tableWindow: return # Get column Category table = tableWindow.getResultsTable() column = table.getColumnAsVariables("Category") columnString = [str(item) for item in column] # Plot Pie Plot for this column pieChart = PieChart("Category", columnString) pieChart.showFrame("Data-distribution")
def run(): helpText = "This program will batch convert .swc files to " + \ "SVG vector graphs.\n\n" + \ ">> Press OK to Select a directory of .swc traces." MessageDialog(IJ.getInstance(),"Batch SWC to SVG Guide", helpText) d = DirectoryChooser("Chose Traces Dir").getDirectory() if d is None: IJ.log("Choose Dir Canceled!") return swc_files = [ os.path.join(d,x) for x in os.listdir(d) if re.search('(?i)\.swc$',x) ] pafm = PathAndFillManager(10240, # width 10240, # height 1, # depth 1, # x spacing 1, # y spacing 1, # z spacing "pixel") for swc_file in swc_files: out_file = swc_file + ".svg" if not pafm.importSWC(swc_file,False): # second parameter is ignoreCalibration IJ.error("Failed to load: "+swc_file) for i in range(pafm.size()): path = pafm.getPath(i) f = open(out_file, "wb") f.write(toSvgString_polyline(path)) f.close() f = open(swc_file + "-path.svg", "wb") f.write(toSvgString_path(path)) f.close() f = open(swc_file + "-points.csv",'wb') writer = csv.writer(f) writer.writerow(["x", "y"]) writer.writerows(toListOfPoints(path)) f.close()
def filter_cellstack(cs, method, sigma): # type: (CellStack, str, float) -> None """ Perform the requested filter :param cs: CellStack :param method: name of filter, can be 'gauss', 'mean' or 'median' :param sigma: sigma value along xy axis (on the z axis it is self-computed using CellStack z scale value) """ if method == 'gauss': gaussianIJ(cs, sigma) elif method == 'mean': meanIJ(cs, sigma) elif method == 'median': medianIJ(cs, sigma) else: IJ.error('Filter not valid: ' + method + '\nImage not filtered')
def overlayImages(self, e): impBase = WindowManager.getImage(self.imageIDs[self.baseImageBox.getSelectedIndex()]) refBase = impBase.getStack().getProcessor(1) impOverlay = WindowManager.getImage(self.imageIDs[self.overlayImageBox.getSelectedIndex()]) refOverlay = impOverlay.getStack().getProcessor(1) print "Overlaying for stack sizes " + str(impBase.getStackSize()) + "/" + str(impOverlay.getStackSize()) + "..." stack = None if self.virtualStackCheckbox.isSelected(): stack = OverlayVirtualStack() stack.overlayOpacity = float(self.opacitySpinner.getValue())/100.0 stack.overlayColor = AWTColorToArray(self.overlayColorPreviewLabel.getBackground()) stack.base = impBase stack.overlay = impOverlay ImagePlus("Stack Overlay from " + self.imageNames[self.baseImageBox.getSelectedIndex()] + " and " + self.imageNames[self.overlayImageBox.getSelectedIndex()], stack).show() else: IJ.error("Not implemented yet", "Using normal stacks is not implemented yet. Please use the Virtual Stack option.")
def getCategoriesFromFile(filepath): """ Read the categories from a text file. There should be 1 cateogory per line in this text file. """ try: textFile = codecs.open(filepath, "r", "utf-8") except IOError: IJ.error("Could not open the category text file") return ["Category1"] listCategories = [line.rstrip() for line in textFile] #rstrip permettant de virer le \n textFile.close() if not listCategories: IJ.error("Empty text file") listCategories = ["Category1"] return listCategories
def updatePointRoi(self): # Surround with try/except to prevent blocking # ImageJ's stack slice updater thread in case of error. try: # Update PointRoi self.imp.killRoi() point = self.nuclei[self.imp.getFrame()] # map 1-based slices # to 0-based nuclei Z coords if len(point) == 0: return IJ.log("Cell found in frame " + str(self.imp.getFrame())) # New empty PointRoi for the current slice roi = PointRoi(point[0], point[1]) # Style: large, red dots roi.setSize(4) # ranges 1-4 roi.setPointType(2) # 2 is a dot (filled circle) roi.setFillColor(Color.red) roi.setStrokeColor(Color.red) self.imp.setRoi(roi) except: IJ.error(sys.exc_info())
def signed2unsigned16(imp): stack = imp.getStack() if stack.isVirtual(): IJ.error("Non-virtual stack required"); cal = imp.getCalibration() if not cal.isSigned16Bit(): return IJ.error("Signed 16-bit image required"); cal.disableDensityCalibration() ip = imp.getProcessor() min = ip.getMin() max = ip.getMax() stats = StackStatistics(imp) minv = stats.min for i in range(stack.getSize()): ip = stack.getProcessor(i+1) ip.add(-minv) imp.setStack(stack) ip = imp.getProcessor() ip.setMinAndMax(min-minv, max-minv) imp.updateAndDraw()
def updatePointRoi(self): # Surround with try/except to prevent blocking # ImageJ's stack slice updater thread in case of error. try: # Update PointRoi self.imp.killRoi() points = self.nuclei[ self.imp.getSlice() - 1] # map 1-based slices to 0-based nuclei Z coords if 0 == len(points): IJ.log("No points for slice " + str(self.imp.getSlice())) return roi = PointRoi() # Style: large, red dots roi.setSize(4) # ranges 1-4 roi.setPointType(2) # 2 is a dot (filled circle) roi.setFillColor(Color.red) roi.setStrokeColor(Color.red) # Add points for point in points: # points are floats roi.addPoint(self.imp, int(point[0]), int(point[1])) self.imp.setRoi(roi) except: IJ.error(sys.exc_info())
renderer.setSeriesPaint(s, Color.GREEN) plot.setFixedLegendItems(legend) frame = ChartFrame(imp.getTitle()+" Z-Normalised Intensity", chart) frame.pack() frame.setSize( Dimension(800, 800) ) frame.setLocationRelativeTo(None) frame.setVisible(True) imp = IJ.getImage() cal = imp.getCalibration() if cal.pixelWidth > 0.5: IJ.error("Bad calibration: "+str(cal.pixelWidth)+" "+cal.getUnit()) exit(0) ol = Overlay() stack = imp.getStack() W = imp.getWidth() H = imp.getHeight() Z = imp.getNSlices() T = imp.getNFrames() focusStack = getDICfocus(imp) projC1 = getC1Projection(imp, True) cells = getCells(focusStack) nuclei = getNuclei(projC1)
def myErr(err): from ij import IJ IJ.error(err) myExit(err)
import os.path from threading import Thread from Queue import Queue import ij.io.FileSaver from ij import (IJ, CompositeImage) from ij.plugin import ZProjector from IBPlib.ij.Utils.Files import (buildList, imageloader) try: from net.haesleinhuepf.clij2 import CLIJ2 clij2 = CLIJ2.getInstance() except ImportError: IJ.error("Warning: CLIJ not installed, GPU processing unavailable.") __version__ = "1.1" __threadname__ = "IBPlib.ij.Zprojector" # Threads spawned by Zprojector have this name + name of the final image. class Projector: ''' If you want to use Zprojector in opened images explicitly pass False or None to the 4 parameters. Note that by default it will generate maximum intensity projections when run as a hotkey macro. ''' def __init__(self, savefolder, imgfolder, ext, method="max", debug=False): self.debug = debug self.savefolder = savefolder self.imgfolder = imgfolder self.ext = ext
def showStackOverlayWindow(self): all = JPanel() all.setLayout(MigLayout()) self.imageIDs = WindowManager.getIDList() self.imageNames = [] if self.imageIDs is None: IJ.error( "No open images", "Stack Overlay requires at least one image to be already open." ) return for i in self.imageIDs: self.imageNames.append(WindowManager.getImage(i).getTitle()) self.baseImageBox = JComboBox(self.imageNames) baseImageBoxLabel = JLabel("Base image") self.baseImageBox.setSelectedIndex(0) all.add(baseImageBoxLabel) all.add(self.baseImageBox, "wrap") self.overlayImageBox = JComboBox(self.imageNames) overlayImageBoxLabel = JLabel("Overlay image") if len(self.imageNames) > 1: self.overlayImageBox.setSelectedIndex(1) all.add(overlayImageBoxLabel) all.add(self.overlayImageBox, "wrap") all.add(JSeparator(SwingConstants.HORIZONTAL), "span, wrap") overlayStyleFrame = JPanel() overlayStyleFrame.setLayout(MigLayout()) overlayStyleFrame.setBorder( BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder("Overlay Style"), BorderFactory.createEmptyBorder(5, 5, 5, 5))) colorLabel = JLabel("Overlay color") self.overlayColorPreviewLabel = JLabel(" ") self.overlayColorPreviewLabel.setBorder( BorderFactory.createEmptyBorder(0, 0, 1, 0)) self.overlayColorPreviewLabel.setOpaque(True) self.overlayColorPreviewLabel.setBackground(Color.red) self.overlayColor = Color.red colorPicker = JColorChooser() colorPicker.setPreviewPanel(self.overlayColorPreviewLabel) colorButton = JButton("Select color...", actionPerformed=self.showColorChooser) opacityLabel = JLabel("Overlay opacity (%)") opacitySpinnerModel = SpinnerNumberModel(100, 0, 100, 1) self.opacitySpinner = JSpinner(opacitySpinnerModel) overlayStyleFrame.add(colorLabel) overlayStyleFrame.add(self.overlayColorPreviewLabel) overlayStyleFrame.add(colorButton, "wrap") overlayStyleFrame.add(opacityLabel) overlayStyleFrame.add(self.opacitySpinner, "wrap") all.add(overlayStyleFrame, "span, wrap") self.virtualStackCheckbox = JCheckBox("Use Virtual Stack", True) all.add(self.virtualStackCheckbox, "span, wrap") # TODO: add non-thermonuclear cancel button functionality overlayCancelButton = JButton("Cancel", actionPerformed=self.onQuit) overlayStartButton = JButton("Overlay images", actionPerformed=self.overlayImages) all.add(overlayCancelButton, "gapleft push") all.add(overlayStartButton, "gapleft push") self.frame = JFrame("Stack Overlay") self.frame.getContentPane().add(JScrollPane(all)) self.frame.pack() self.frame.setLocationRelativeTo(None) self.frame.setVisible(True)
injuryLengths = [] totalLengths = [] injuryRatios = [] Xpositions = [] while stayinloop: gd = NonBlockingGenericDialog("Pick points...") gd.addMessage("Use multipoint tool to pick points along a column (Y-axis).\nAlternate points to mark injured vs uninjured area.") gd.setCancelLabel("Quit") gd.setOKLabel("Define column") gd.addCheckbox("First segment is injury?",injuryfirst) gd.showDialog() if (gd.wasOKed()): roi = theImage.getRoi() if roi is None: IJ.error("No ROI selected") else: polygon = roi.getFloatPolygon() # if len(polygon.xpoints) % 2 == 0 and is_monotonic_increasing(polygon.ypoints): if is_monotonic_increasing(polygon.ypoints): xset = average(polygon.xpoints) IJ.setForegroundColor(255,255,0) IJ.run("Draw","stack") IJ.makeLine(xset,0,xset,theImage.getHeight()) IJ.setForegroundColor(0,255,255) IJ.run("Draw","stack") injuryfirst = gd.getNextBoolean() if injuryfirst: countidx = range(0,len(polygon.xpoints)-1,2)
IJ.run(imp, "Add Selection...", "") IJ.run("Show Overlay", "") IJ.log("Number of MR+ AND NCC+ cells: " + str(len(mr_ncc_pos_idx))) def cleanup(): cells_idx = [] mr_pos_idx = [] ncc_pos_idx = [] mr_ncc_pos_idx = [] rm.reset() if not updateService.getUpdateSite("StarDist").isActive(): IJ.error( "StarDist plugin required ! Please activate the StarDist update site.") IJ.exit() else: original_image = wm.getCurrentImage().duplicate() original_image.setTitle("Original") initialize() if (original_image.isComposite()): prepareImageComposite() else: prepareImageRGB() detectNuclei("Nuclei") cells_idx = filter_nuclei()
z = [0]*len(x) # Calculate distances for all positions. Retrieve NNs distances for i in range(len(x)): minDx = sys.maxint nearest = 0 for j in range(len(x)): if i==j: continue dx = (x[i]-x[j])**2 dy = (y[i]-y[j])**2 dz = (z[i]-z[j])**2 dst = math.sqrt(dx+dy+dz) if dst>0 and dst<minDx: minDx = dst nearest = j+1 rt.setValue("NN pair", i, nearest) rt.setValue("NN distance", i, minDx); # Display appended results rt.showRowNumbers(True) rt.show("Results") # Display distributions dp = "Distribution Plotter" if dp in Menus.getCommands().keySet().toArray(): IJ.run(dp, "parameter=[NN distance] automatic=Freedman-Diaconis"); else: IJ.error("File missing", dp+" not found.\nPlease check your BAR installation.") else: IJ.error("Invalid Results Table","Data for X,Y positions not found.")
def editLUTAsText(): image = WindowManager.getCurrentImage() if image == None: IJ.error('Need an image') return ip = image.getProcessor() cm = ip.getCurrentColorModel() if not hasattr(cm, 'getMapSize'): IJ.error('Need an 8-bit color image') return size = cm.getMapSize() if size > 256: IJ.error('Need an 8-bit color image') return reds = jarray.zeros(size, 'b') greens = jarray.zeros(size, 'b') blues = jarray.zeros(size, 'b') cm.getReds(reds) cm.getGreens(greens) cm.getBlues(blues) def color(array, index): value = array[index] if value < 0: value += 256 return '% 4d' % value text = '' for i in range(0, size): text = text + color(reds, i) + ' ' + color(greens, i) + ' ' \ + color(blues, i) + "\n" editor = Editor(25, 80, 12, Editor.MONOSPACED | Editor.MENU_BAR) editor.create('Lookup Table', text) def string2byte(string): value = int(string) if value > 127: value -= 256 if value < -128: value = 128 return value class SetLookupTable(ActionListener): def actionPerformed(self, event): text = editor.getText() i = 0 for line in text.split("\n"): colors = line.split() if len(colors) < 3: continue reds[i] = string2byte(colors[0]) greens[i] = string2byte(colors[1]) blues[i] = string2byte(colors[2]) i += 1 cm = IndexColorModel(8, 256, reds, greens, blues) ip.setColorModel(cm) image.updateAndRepaintWindow() menuItem = MenuItem('Set Lookup Table') menuItem.addActionListener(SetLookupTable()) menu = Menu('Lookup Table') menu.add(menuItem) menuBar = editor.getMenuBar() for i in range(menuBar.getMenuCount() - 1, -1, -1): label = menuBar.getMenu(i).getLabel() if label == 'Macros' or label == 'Debug': menuBar.remove(i) menuBar.add(menu)
from QualiAnnotations.Charts import PieChart from ij.gui import GenericDialog from ij import IJ, WindowManager if IJ.getFullVersion() < "1.53g": IJ.error( "This plugin requires ImageJ version 1.53g minimum.\n Update using Help > Update ImageJ..." ) raise Exception("ImageJ version 1.53g minimum required") tableWindow = WindowManager.getActiveTable( ) # this function requires the 1.53g (or at least not working with 1.53c) #print tableWindow if not tableWindow: IJ.error("No open table") else: # List column headers table = tableWindow.getResultsTable() headers = table.getHeadings() # Generate dialog with dropdown for column selection dialog = GenericDialog("PieChart from table column") dialog.addChoice("Data column", headers, headers[0]) dialog.addMessage( """Hover the mouse over the plot to view absolute and relative (%) values\n Right-click to set colors, export to PNG...\n Note: BarCharts usually provide better distinction than PieCharts for sectors with similar sizes (see Help).""" )
val_high = rt.getValueAsDouble(1,0) val_bleed = rt.getValueAsDouble(1,1) val_low = rt.getValueAsDouble(1,2) val_zero = rt.getValueAsDouble(1,3) val_target = val_high - val_low # scale_target = val_target / val_bleed scale_target = val_target / (val_bleed - val_zero) print scale_target gd = GenericDialog("Scale factor") gd.addNumericField("Scale factor on subtraction:",scale_target,3) gd.showDialog() if (gd.wasCanceled()): quit() scale = gd.getNextNumber() tempImage = image2.duplicate() for i in range(tempImage.getNSlices()): tempImage.setSliceWithoutUpdate(i+1) ip = tempImage.getProcessor() ip.subtract(val_zero) ip.multiply(scale) ic = ImageCalculator() newImage = ic.run("Subtract create stack",image1,tempImage) newImage.show() else: IJ.error("No images are open.")
def show_standard_error_message(): IJ.error("There was an error.\n\ Please check the text below the script editor window.\n\ Please toggle between [Show Errors] and [Show Output], as both are relevant.")
# IJ BAR: https://github.com/tferr/Scripts#scripts # # Imports numeric values copied to the clipboard into the Results table. Useful, since # BARs that analyze tabular data can only read values from the main IJ "Results" table # # Requirements: Requires BAR_-XX.jar to be installed in the plugins folder of IJ # # NB: When copying data from withing IJ (e.g., lists from histograms or plot profiles), # Use Edit>Options>Input/Output... to specify if column headers/row numbers should be # copied to the clipboard import os, sys, tempfile from bar import Utils as barUtils from ij import IJ from ij.plugin.filter import Analyzer import ij.measure.ResultsTable as RT fd, path = tempfile.mkstemp() try: os.write(fd, barUtils.getClipboardText()) os.close(fd) rt = RT.open(path) #IOException if getClipboardText()=="" if Analyzer.resetCounter(): rt.show("Results") except: IJ.error("Could not place clipboard into Results table.") finally: os.remove(path)
# Process list of images for (counter, f) in enumerate(files): # Display progress IJ.showStatus("Processing file "+ str(counter+1) +"/"+ str(len(files))) # Open each image and process it imp = IJ.openImage(f) myRoutines(imp) # Save processed image in out_dir (enforcing .tif extension) newpath = os.path.splitext(out_dir + imp.getTitle())[0] +".tif" IJ.saveAsTiff(imp, newpath) imp.close() # Log paths of processed files csvWriter.writerow([f, newpath]) # Display CSV log csvFile.close() rt = ResultsTable.open(csvPath) rt.show("_ProcessedFileList.csv") # Proudly inform that processing terminated if IJ.showMessageWithCancel("All done","Reveal output directory?"): Utils.revealFile(out_dir); else: # Inform no filtered files were found IJ.error("No matches for the selected extension(s).")
Requirements : - IJ-OpenCV (from the updater) TO DO : - Images with overlay in Stack : change to the easier ij.plugin.ImagesToStack that use a list to make the stack. No need to precise the size.. ''' # Python from __future__ import division # ImageJ from ij import IJ,ImagePlus, ImageStack from ij.plugin.filter import MaximumFinder #from ij.gui import Roi, PointRoi if IJ.getFullVersion()<"1.52o": IJ.error("Please update ImageJ to min v1.52o. Help>Update ImageJ...") # OpenCV try: from org.bytedeco.javacpp.opencv_imgproc import matchTemplate, threshold, CV_THRESH_TOZERO from org.bytedeco.javacpp.opencv_core import Mat, Scalar, Point, minMaxLoc, subtract # UNUSED normalize, NORM_MINMAX, CV_8UC1, CV_32FC1 from org.bytedeco.javacpp import DoublePointer except: IJ.error("Missing OpenCV dependencies. Make sure to activate 'IJ-OpenCV plugins' update site.") # Java from java.lang import Float #used to convert BytesToFloat # Home-made module in jars/Lib sent with Acquifer update site
def showStackOverlayWindow(self): all = JPanel() all.setLayout(MigLayout()) self.imageIDs = WindowManager.getIDList() self.imageNames = [] if self.imageIDs is None: IJ.error("No open images", "Stack Overlay requires at least one image to be already open.") return for i in self.imageIDs: self.imageNames.append(WindowManager.getImage(i).getTitle()) self.baseImageBox = JComboBox(self.imageNames) baseImageBoxLabel = JLabel("Base image") self.baseImageBox.setSelectedIndex(0) all.add(baseImageBoxLabel) all.add(self.baseImageBox, "wrap") self.overlayImageBox = JComboBox(self.imageNames) overlayImageBoxLabel = JLabel("Overlay image") if len(self.imageNames) > 1: self.overlayImageBox.setSelectedIndex(1) all.add(overlayImageBoxLabel) all.add(self.overlayImageBox, "wrap") all.add(JSeparator(SwingConstants.HORIZONTAL), "span, wrap") overlayStyleFrame = JPanel() overlayStyleFrame.setLayout(MigLayout()) overlayStyleFrame.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Overlay Style"), BorderFactory.createEmptyBorder(5,5,5,5))) colorLabel = JLabel("Overlay color") self.overlayColorPreviewLabel = JLabel(" ") self.overlayColorPreviewLabel.setBorder(BorderFactory.createEmptyBorder(0,0,1,0)) self.overlayColorPreviewLabel.setOpaque(True) self.overlayColorPreviewLabel.setBackground(Color.red) self.overlayColor = Color.red colorPicker = JColorChooser() colorPicker.setPreviewPanel(self.overlayColorPreviewLabel) colorButton = JButton("Select color...", actionPerformed=self.showColorChooser) opacityLabel = JLabel("Overlay opacity (%)") opacitySpinnerModel = SpinnerNumberModel(100, 0, 100, 1) self.opacitySpinner = JSpinner(opacitySpinnerModel) overlayStyleFrame.add(colorLabel) overlayStyleFrame.add(self.overlayColorPreviewLabel) overlayStyleFrame.add(colorButton, "wrap") overlayStyleFrame.add(opacityLabel) overlayStyleFrame.add(self.opacitySpinner, "wrap") all.add(overlayStyleFrame, "span, wrap") self.virtualStackCheckbox = JCheckBox("Use Virtual Stack", True) all.add(self.virtualStackCheckbox, "span, wrap") # TODO: add non-thermonuclear cancel button functionality overlayCancelButton = JButton("Cancel", actionPerformed=self.onQuit) overlayStartButton = JButton("Overlay images", actionPerformed=self.overlayImages) all.add(overlayCancelButton, "gapleft push") all.add(overlayStartButton, "gapleft push") self.frame = JFrame("Stack Overlay") self.frame.getContentPane().add(JScrollPane(all)) self.frame.pack() self.frame.setLocationRelativeTo(None) self.frame.setVisible(True)
from ij.plugin import ImageCalculator, Duplicator, ZProjector, RoiEnlarger, Straightener, Selection from ij.plugin.filter import GaussianBlur, MaximumFinder, ThresholdToSelection, Binary, EDM from ij.process import ImageStatistics, Blitter, ImageProcessor, ShortProcessor, ByteProcessor, AutoThresholder, FloodFiller from ij.measure import ResultsTable, Measurements from ij.gui import Roi, ShapeRoi, TextRoi, Overlay from fiji.process3d import SEDT MINA = 5 #cell area range, µm² MAXA = 100 if ((channel_sca1 + channel_hoescht + channel_opn + channel_gfp != 10) or channel_sca1 < 1 or channel_hoescht < 1 or channel_opn < 1 or channel_gfp < 1 or channel_sca1 > 4 or channel_hoescht > 4 or channel_opn > 4 or channel_gfp > 4): IJ.error("Invalid channels") exit(0) def maxProject(image, chan): proj = ShortProcessor(image.getWidth(), image.getHeight()) stack = image.getStack() for z in range(1, imp.getNSlices() + 1): ip = stack.getProcessor(image.getStackIndex(chan, z, 1)) proj.copyBits(ip, 0, 0, Blitter.MAX) return proj def fillHoles(mask): width = mask.getWidth() height = mask.getHeight()
default_config = 'config.txt' # Get directory of open image or prompt user to choose. folder = IJ.getDirectory('image') if not folder: folder = IJ.getDirectory('Select a folder') config_filename = get_config_file(folder) if config_filename: config_filepath = os.path.join(folder, config_filename) # Load the config file or abort. try: config = open(config_filepath) except: IJ.error('Could not open config file %s' % config_filepath) config = None else: IJ.error('No config file was specified, aborting...') config = None # Only run if config file was successfully loaded. if config: # Get all raw datafiles from a folder. datafiles = import_datafiles(folder) # Extract data from text files and store in Image instances. images = parse_data(datafiles) # Parse config file and create Aspect instances. aspects = parse_config(images)
def main(): try: # Retrieve valid data rt = Utils.getTable(); start = time.time() # Retrive x,y,t positions (all in unc. units) x = getColumn(rt, X_POS_HEADING) y = getColumn(rt, Y_POS_HEADING) t = getColumn(rt, T_POS_HEADING) # Retrieve the total n. of tracks track_ids = getColumn(rt, ID_HEADING) track_ids = [int(i) for i in track_ids] n_tracks = track_ids[-1] log("Tracks to be analyzed: ", n_tracks) except: IJ.error("Invalid Results Table") return # Create "nan"-padded tables to hold results detail_rt = new_Table() # Extract individual tracks and determine the track with the # largest data (i.e., the one with the highest number of rows) track_row = 0 max_track_row = 0 for i in range(0, rt.getCounter()-1): track_label = str(track_ids[i]) if (track_ids[i]==track_ids[i+1]): dx = (x[i+1]-x[i])**2 dy = (y[i+1]-y[1])**2 dt = t[i+1]-t[i] dis = math.sqrt(dx+dy) vel = dis/dt if (track_row>max_track_row): max_track_row = track_row # Log to "detailed" table if (i<=max_track_row): detail_rt.incrementCounter() detail_rt.setValue("Dis_" + track_label, track_row, dis) detail_rt.setValue("Vel_" + track_label, track_row, vel) detail_rt.setValue("Dur_" + track_label, track_row, dt) detail_rt.setValue("Flag_" + track_label, track_row, RESTING_FLAG if vel < restingVelocity else MOVING_FLAG) track_row += 1 else: # Analyzed track just ended: Reset loop variables and create column # to hold bout flags track_row = 0 detail_rt.setValue("BoutFlag_" + track_label, 0, float("nan")) detail_rt.setValue("Mov_Dur_" + track_label, 0, float("nan")) detail_rt.setValue("Rest_Dur_" + track_label, 0, float("nan")) log("Extracting track ", track_label) listOfRasterPaths = [] # List holding raster tracks # Loop through individual tracks and tag each datapoint (i.e., each row) for track in range(0, n_tracks): durHeading = "Dur_" + str(track) fFlagHeading = "Flag_" + str(track) bFlagHeading = "BoutFlag_" + str(track) mDurHeading = "Mov_Dur_" + str(track) rDurHeading = "Rest_Dur_" + str(track) durations = getColumn(detail_rt, durHeading) fFlags = getColumn(detail_rt, fFlagHeading) bFlags = getColumn(detail_rt, bFlagHeading) nDataPoints = findLastNonNumberIdx(durations) + 1 log("Tagging track ", track, ": ", nDataPoints , " positions") for row in range(0, nDataPoints): # Define the boundaries of the moving window. "Stopping flags" # within this window will be monitoried to define a motionless bout # NB: Boundaries are defined from the rows of the input table. This # works only when the time elapsed betwen two rows is a single frame. # So we'll have to monitor the actual time that has elapsed within the # bounderies of the window lower_bound = max(0, row - neighborhood + 1) upper_bound = min(nDataPoints, row+neighborhood) sum_of_flags = 0 sum_of_frames = 0 neighborhood_sum = upper_bound - lower_bound for i in xrange(lower_bound, upper_bound): if isNumber(durations[i]) and isNumber(fFlags[i]): sum_of_flags += (fFlags[i] * durations[i]) sum_of_frames += durations[i] if sum_of_frames >= neighborhood_sum: break # Assign this tracked point to its bout moving_bout_duration = float("nan") resting_bout_duration = float("nan") bout_flag = float("nan") if sum_of_flags >= neighborhood_sum: bout_flag = MOVING_FLAG moving_bout_duration = durations[row] else: bout_flag = RESTING_FLAG resting_bout_duration = durations[row] detail_rt.setValue(bFlagHeading, row, bout_flag) detail_rt.setValue(mDurHeading, row, moving_bout_duration) detail_rt.setValue(rDurHeading, row, resting_bout_duration) if generateRasterTracks: # Generate raster column if path is long enough if nDataPoints > shortestRasterTrack: # Retrieve updated column of bout flags bFlags = getColumn(detail_rt, bFlagHeading) # Generate raster column (motion-flags temporally aligned, all 1 # frame apart) until the path duration reaches the maximum limit keepGrowingRasterPath = True for idx, duration in enumerate(durations): if (keepGrowingRasterPath): flag = bFlags[idx] for insertIdx in range(1, int(duration)): if (len(bFlags)==longestRasterTrack): keepGrowingRasterPath = False break bFlags.insert(idx+insertIdx, flag) # Store only lists without NaN values listOfRasterPaths.append(bFlags[:findLastNonNumberIdx(bFlags)]) # Allow analysis to be interrupted if IJ.escapePressed(): break # Display table. Displaying it now may ensure all tracks are padded with "NaN" if (displayDetailedTable): detail_rt.show("Track_Details["+ str(restingVelocity) +"-"+ str(neighborhood) +"]") # Now that all paths are contained in listOfRasterPaths. Sort them by length of track listOfRasterPaths = sorted(listOfRasterPaths, key = len) # Create Image of analysis. We'll create it from a ResultsTable. It would be much # more efficient to generate a text image directly, but this allows the table to be # processed elsewhere if needed. In IJ1, column headings of a ResultsTable must be # unique, so we will use distinct identifiers if generateRasterTracks: raster_rt = new_Table() log('Tracks to be rendered:', len(listOfRasterPaths)) for rasterPath in xrange(len(listOfRasterPaths)): log("Rendering track ", rasterPath) for row, raster_flag in enumerate(listOfRasterPaths[rasterPath]): if not isNumber(raster_flag): break if (row>raster_rt.getCounter()-1): raster_rt.incrementCounter() # Create upper border: 1 px-wide bColor = borderColor if isNumber(raster_flag) else backgroundColor raster_rt.setValue("Delim1_" + str(rasterPath), row, bColor) # Create raster path: 18 px wide raster_flag_color = colorizeFlag(raster_flag) for i in 'abcdefghijklmnopq': raster_rt.setValue("Raster_" + str(rasterPath) + str(i), row, raster_flag_color) # Create lower border: 1 px-wide raster_rt.setValue("Delim2_" + str(rasterPath), row, bColor) # Append padding space between tracks: 10px wide for j in 'abcdefghij': raster_rt.setValue("Space_" + str(rasterPath) + str(j), row, backgroundColor) # Allow analysis to be interrupted if IJ.escapePressed(): break # Display table of rasterized tracks if displayRasterTable: raster_rt.show("RasterTracks["+ str(restingVelocity) +"-"+ str(neighborhood ) +"]") # Display image of rasterized tracks ip = raster_rt.getTableAsImage().rotateLeft() paintNaNpixels(ip, backgroundColor) ip = ip.convertToByte(False) imp = ImagePlus("RasterTracks["+ str(restingVelocity) +"-"+ str(neighborhood ) +"]", ip) imp.show() ## Add scale-bar for time IJ.run(imp, "Set Scale...", "distance=1 known="+ str(frameCal[0]) +" unit="+ frameCal[1]); IJ.run(imp, "Scale Bar...", "width=10 color=Black location=[Lower Right] overlay"); # Loop through individual tracks and extract some basic statistics. Most of these parameters # are already retrieved by Trackmate. We calculate them here just for convenience track_ids = [] # List holding the track identifier sum_distances = [] # List holding the track's total distance sum_durations = [] # List holding the track's total duration max_speeds = [] # List holding the track's Max speed min_speeds = [] # List holding the track's Min speed sum_n_rests = [] # List holding the number of resting bouts in each track sum_n_moves = [] # List holding the number of moving bouts in each track sum_dur_rests = [] # List holding the total resting time of each tracked object sum_dur_moves = [] # List holding the total moving time of each tracked object log("Logging Summaries...") summary_rt = new_Table() for track in range(0, n_tracks): # Retrieve and store the track identifier track_id = str(track) track_ids.insert(track, "Track_"+track_id) # Retrive tracking data distances = getColumn(detail_rt, "Dis_" + track_id) durations = getColumn(detail_rt, "Dur_" + track_id) velocities = getColumn(detail_rt, "Vel_" + track_id) mov_durations = getColumn(detail_rt, "Mov_Dur_" + track_id) rest_durations = getColumn(detail_rt, "Rest_Dur_" + track_id) # Reset stats for this track track_sum_dis = 0 track_sum_dur = 0 track_max_vel = 0 track_min_vel = sys.maxint track_sum_move = 0 track_sum_rest = 0 track_n_moves = 0 track_n_rests = 0 # Compute basic stats and store them in dedicated lists nDataPoints = findLastNonNumberIdx(distances) + 1 for row in xrange(nDataPoints): track_sum_dis += distances[row] track_sum_dur += durations[row] if (velocities[row]>track_max_vel): track_max_vel = velocities[row] if (velocities[row]<track_min_vel): track_min_vel = velocities[row] if isNumber(mov_durations[row]): track_sum_move += mov_durations[row] if isNumber(rest_durations[row]): track_sum_rest += rest_durations[row] sum_distances.insert(track, track_sum_dis) sum_durations.insert(track, track_sum_dur) max_speeds.insert(track, track_max_vel) min_speeds.insert(track, track_min_vel) sum_dur_moves.insert(track, track_sum_move) sum_dur_rests.insert(track, track_sum_rest) # Assess the number of moving/resting bouts in this track for row in xrange(nDataPoints-1): if isNumber(mov_durations[row]) and not isNumber(mov_durations[row+1]): track_n_moves += 1 if isNumber(rest_durations[row]) and not isNumber(rest_durations[row+1]): track_n_rests += 1 # Predict cases in which bouts lasted entire track duration if track_n_moves==0 and track_sum_dur==track_sum_move: track_n_moves += 1 if track_n_rests==0 and track_sum_dur==track_sum_rest: track_n_rests += 1 sum_n_moves.insert(track, track_n_moves) sum_n_rests.insert(track, track_n_rests) # Log summary data for i in range(0, n_tracks): # Ignore tracks shorter than neighborhood if hideShortTracks and sum_durations[i]<neighborhood: continue row = summary_rt.getCounter() summary_rt.incrementCounter() summary_rt.setLabel(track_ids[i], row) summary_rt.setValue("Total dx", row, sum_distances[i]) summary_rt.setValue("Duration", row, sum_durations[i]) summary_rt.setValue("Max speed", row, max_speeds[i]) summary_rt.setValue("Min speed", row, min_speeds[i]) summary_rt.setValue("Moving dur", row, sum_dur_moves[i]) summary_rt.setValue("Resting dur", row, sum_dur_rests[i]) summary_rt.setValue("Resting %", row, 100 * sum_dur_rests[i] / sum_durations[i]) summary_rt.setValue("Moving bouts", row, sum_n_moves[i]) summary_rt.setValue("Resting bouts", row, sum_n_rests[i]) if sum_n_moves[i]!=0: summary_rt.setValue("Avg moving bout dur", row, sum_dur_moves[i] / sum_n_moves[i]) if sum_n_rests[i]!=0: summary_rt.setValue("Avg resting bout dur", row, sum_dur_rests[i] / sum_n_rests[i]) summary_rt.show("Track_Summaries["+ str(restingVelocity) +"-"+ str(neighborhood) +"]") log("Finished: ", time.time()-start, " seconds")
directory = tempFileArray[i].getParent() name = tempFileArray[i].getName() tempUi = nrims.UI() tempUi.openFile(tempFileArray[i]) tempImage = tempUi.getOpener() image = ui.getOpener() images = ui.getOpenMassImages() mimStack = ui.getmimsStackEditing() for j in range(len(images)): images[j].setTitle(name) if ui.getOpener().getNMasses() == tempImage.getNMasses(): if mimStack.sameResolution(image, tempImage): if mimStack.sameSpotSize(image, tempImage): mimStack.concatImages(False, tempUi) else: IJ.error("Images do not have the same spot size.") else: IJ.error("Images are not the same resolution.") else: IJ.error("Two images with the same\nnumber of masses must be open.") #kill the temp images and temp ui, then delete the temp file tempImages = tempUi.getMassImages() for j in range(len(tempImages)): if tempImages[j] != None: tempImages[j].setAllowClose(True) tempImages[j].close() ui.getMimsData().setHasStack(True) tempUi = None; tempFileArray[i].delete() nw = nrimsData.Nrrd_Writer(ui) images = ui.getOpenMassImages()