def thresh(sum_prj, thresh, roi, method): # threshold signal based percent of max_pixel and returns ROI # If you use thresh=1 it returns the brightest pixel. from ij import ImagePlus from ij.measure import Measurements as mm from ij.process import ImageProcessor from ij.plugin.filter import ThresholdToSelection from ij.gui import Roi, PointRoi imp = sum_prj.duplicate() max_pix = max_pix(imp, roi) ip = imp.getProcessor() ip.setValue(0) ip.fillOutside(roi) if method == "boundary": ip.setThreshold(max_pix * thresh, max_pix, ImageProcessor.NO_LUT_UPDATE) bndry_roi = ThresholdToSelection.run(imp) return bndry_roi elif method == "point": ip.setThreshold(max_pix, max_pix, ImageProcessor.NO_LUT_UPDATE) bndry_roi = ThresholdToSelection.run(imp) bounds = bndry_roi.getBounds() mask = bndry_roi.getMask() mask.invert() impt = ImagePlus("d", mask) stats = impt.getStatistics(mm.CENTROID) xl, yl = stats.xCentroid + bounds.x, stats.yCentroid + bounds.y return {"x": xl, "y": yl}
def create_mask_selection(movie, sigma=0, thresh_method='Huang', threshold=None): ''' If threshold is *None* use selected AutoThreshold, otherwise use fixed *threshold* ''' C = movie.getC() S = movie.getSlice() NFrames = movie.getNFrames() maxThresh = 2**movie.getBitDepth() tts = ThresholdToSelection() ov = Overlay() # to save the rois for frame in range(1, NFrames + 1): movie.setPosition(C, S, frame) ip = movie.getProcessor().duplicate() # imp = ImagePlus('Blurred', ip) if sigma != 0: ip.blurGaussian(sigma) # manual thresholding if threshold: ip.setThreshold(threshold, maxThresh, 0) # no LUT update # automatic thresholding else: ip.setAutoThreshold(thresh_method, True, False) tts.setup("", movie) shape_roi = tts.convert(ip) # only one connected roi present if type(shape_roi) == ij.gui.PolygonRoi: mask_roi = shape_roi else: # for disconnected regions.. take the shape_roi as is # rois = shape_roi.getRois() # splits into sub rois # mask_roi = get_largest_roi(rois) # sort out smaller Rois mask_roi = shape_roi mask_roi.setPosition(frame) ov.add(mask_roi) return ov
def getNuclei(stack): nuclei = [ [] for t in range(T+1) ] minNucleusA = 50.0 #µm² maxNucleusA = 500.0 sigma = 0.5 * maths.sqrt(minNucleusA/maths.pi) / cal.pixelWidth #px k = 5 for t in range(1,T+1): proc = stack.getProcessor(t).duplicate() sub = proc.duplicate() proc.blurGaussian(sigma) sub.blurGaussian(sigma*k) proc.copyBits(sub, 0,0, Blitter.SUBTRACT) hist = proc.getHistogram(256) stats = proc.getStatistics() thresh = AutoThresholder().getThreshold( AutoThresholder.Method.MaxEntropy, hist ) thresh = (thresh/float(255)) * (stats.max-stats.min) + stats.min proc.setThreshold(thresh, 99999999, ImageProcessor.NO_LUT_UPDATE) composite = ThresholdToSelection().convert(proc) rois = ShapeRoi(composite).getRois() for nuc in rois: proc.setRoi(nuc) if proc.getStatistics().mean < thresh: continue #exclude composite holes area = nuc.getStatistics().area * cal.pixelWidth * cal.pixelHeight if area >= minNucleusA and area <= maxNucleusA: circ = 4*maths.pi*(area/pow(nuc.getLength()*cal.pixelWidth, 2)) if circ >= 0.65: nuclei[t].append(nuc) nuclei[t] = sorted( list(nuclei[t]), key=lambda nuc:nuc.getLength(), reverse=True ) #largest to smallest return nuclei
def feret(sum_prj,thresh,roi,pixel_size): ''' CAlculates feret diameter (longest line that can be fitted) of a feature. sum_prj: sum projected image. thresh: threshold for making the binary image. roi: ROI to perform the action on. pixel_size: pixel x_y pixel size to calculate microns from pixels. ''' from ij import ImagePlus from ij.measure import Measurements as mm from ij.process import ImageProcessor from ij.plugin.filter import ThresholdToSelection from ij.gui import Roi,PointRoi def max_pix(sum_prj,roi): # Get sum_prj image and an roi as input and output max signal in roi imp=sum_prj.duplicate() #copy the array as float imp.setRoi(roi) stats = imp.getStatistics() return stats.max imp=sum_prj.duplicate() max_pix=max_pix(imp,roi) ip=imp.getProcessor() ip.setValue(0) ip.fillOutside(roi) ip.setThreshold(max_pix*thresh,max_pix,ImageProcessor.NO_LUT_UPDATE) bndry_roi= ThresholdToSelection.run(imp) imp.setRoi(bndry_roi) stats = imp.getStatistics() loci_area=stats.area*(pixel_size**2) loci_feret=bndry_roi.getFeretsDiameter()*pixel_size return bndry_roi, loci_feret, loci_area
def binarize_upper_lower_threshold(imp, thr_low, thr_hi): """ binarize_upper_lower_threshold Binarize an image using an upper & lower threshold Adapted from the python_imagej_cookbook """ imp.getProcessor().setThreshold(thr_low, thr_hi, ImageProcessor.NO_LUT_UPDATE) roi = ThresholdToSelection.run(imp) imp.setRoi(roi) imp_mask = ImagePlus("Mask", imp.getMask()) # maskimp.show() # comment out for headless return (imp_mask)
def SegmentMask(ip): ''' Returns a Region of Interest (ROI) that contains a proposed segmentation for the input image processor imp Binarization: Find the GaussianBlur with minimum radius necessary to perform a Minimum Autothreshold ''' minThresholdValue=-1 radius=GaussianBlurParam['initialRadius'] #Initial Radius os the Gaussian Blur contador=0 while (minThresholdValue==-1 and contador<6): contador=contador+1 #Make a copy of the image impThres = ImagePlus() ipThres = ip.duplicate() impThres.setProcessor("Copy for thresholding", ipThres) GaussianBlur().blurGaussian( impThres.getProcessor(), radius, radius,GaussianBlurParam['accuracy']) #impThres.show() try: IJ.setAutoThreshold(impThres, "Minimum dark") minThresholdValue = impThres.getProcessor().getMinThreshold() except: print("No threshold found for segmentation") if minThresholdValue !=-1: #Check thresholded image contains at least 50% of the original stats = impThres.getStatistics() histogram = stats.histogram binSize=(stats.max-stats.min)/256 ThresholdBin=int(round((minThresholdValue-stats.min)/binSize)) CumulativeValues=0 for i in range(ThresholdBin): CumulativeValues+=histogram[i] ImageAboveThreshold=1-float(CumulativeValues)/(ip.width*ip.height) #(ImageAboveThreshold) #ImageAboveThreshold must be above 50% if ImageAboveThreshold < 0.5: minThresholdValue=-1 radius=radius+1 impThres.getProcessor().setThreshold(minThresholdValue, stats.max, ImageProcessor.NO_LUT_UPDATE) boundRoi = ThresholdToSelection.run(impThres) return boundRoi
def Weka_Segm(dirs): """ Loads trained classifier and segments cells """ """ in aligned images according to training. """ # Define reference image for segmentation (default is timepoint000). w_train = os.path.join(dirs["Composites_Aligned"], "Timepoint000.tif") trainer = IJ.openImage(w_train) weka = WekaSegmentation() weka.setTrainingImage(trainer) # Select classifier model. weka.loadClassifier(str(classifier)) weka.applyClassifier(False) segmentation = weka.getClassifiedImage() segmentation.show() # Convert image to 8bit ImageConverter(segmentation).convertToRGB() ImageConverter(segmentation).convertToGray8() # Threshold segmentation to soma only. hist = segmentation.getProcessor().getHistogram() lowth = Auto_Threshold.IJDefault(hist) segmentation.getProcessor().threshold(lowth) segmentation.getProcessor().setThreshold(0, 0, ImageProcessor.NO_LUT_UPDATE) segmentation.getProcessor().invert() segmentation.show() # Run Watershed Irregular Features plugin, with parameters. IJ.run(segmentation, "Watershed Irregular Features", "erosion=20 convexity_treshold=0 separator_size=0-Infinity") # Make selection and add to RoiManager. RoiManager() rm = RoiManager.getInstance() rm.runCommand("reset") roi = ThresholdToSelection.run(segmentation) segmentation.setRoi(roi) rm.addRoi(roi) rm.runCommand("Split")
def mask2D(ip, sigmaPx, k, method, minimum, doFillHoles, doWatershed): mask = ip.duplicate() sub = mask.duplicate() mask.blurGaussian(sigmaPx) if k > 0: sub.blurGaussian(k * sigmaPx) mask.copyBits(sub, 0, 0, Blitter.SUBTRACT) stats = mask.getStatistics() hist = mask.getStatistics().histogram thresh = AutoThresholder().getThreshold(method, hist) thresh = (thresh / float(255)) * (stats.max - stats.min) + stats.min mask.threshold(int(thresh)) mask = mask.convertToByte(False) if doFillHoles: fillHoles(mask) if doWatershed: floatEdm = EDM().makeFloatEDM(mask, 0, False) maxIp = MaximumFinder().findMaxima(floatEdm, 0.5, ImageProcessor.NO_THRESHOLD, MaximumFinder.SEGMENTED, False, True) if (maxIp != None): mask.copyBits(maxIp, 0, 0, Blitter.AND) mask.dilate() mask.erode() mask.setThreshold(255, 255, ImageProcessor.NO_LUT_UPDATE) roi = ThresholdToSelection().convert(mask) ip.setRoi(roi) mean = ip.getStatistics().mean if mean < minimum: #if the mask area intensity mean in the original image is less than the minimum required mask = ByteProcessor(ip.getWidth(), ip.getHeight()) #return empty mask return mask
def getRoi(mask): mask.setThreshold(255, 255, ImageProcessor.NO_LUT_UPDATE) roi = ThresholdToSelection().convert(mask) return roi
def getRois(mask): mask.setThreshold(255, 255, ImageProcessor.NO_LUT_UPDATE) composite = ThresholdToSelection().convert(mask) rois = ShapeRoi(composite).getRois() return rois
def process(subFolder, outputDirectory, filename): imp = IJ.openImage(inputDirectory + subFolder + '/' + rreplace(filename, "_ch00.tif", ".tif")) IJ.run( imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=0.8777017 pixel_height=0.8777017 voxel_depth=25400.0508001" ) ic = ImageConverter(imp) ic.convertToGray8() IJ.setThreshold(imp, 2, 255) IJ.run(imp, "Convert to Mask", "") IJ.run(imp, "Remove Outliers...", "radius=5" + " threshold=50" + " which=Dark") IJ.run(imp, "Remove Outliers...", "radius=5" + " threshold=50" + " which=Bright") imp.getProcessor().invert() rm = RoiManager(True) imp.getProcessor().setThreshold(0, 0, ImageProcessor.NO_LUT_UPDATE) boundroi = ThresholdToSelection.run(imp) rm.addRoi(boundroi) if not displayImages: imp.changes = False imp.close() images = [None] * 5 intensities = [None] * 5 blobsarea = [None] * 5 blobsnuclei = [None] * 5 bigAreas = [None] * 5 for chan in channels: v, x = chan images[x] = IJ.openImage(inputDirectory + subFolder + '/' + rreplace(filename, "_ch00.tif", "_ch0" + str(x) + ".tif")) imp = images[x] for roi in rm.getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.MEAN | Measurements.AREA) intensities[x] = stats.mean bigAreas[x] = stats.area rm.close() # Opens the ch00 image and sets default properties imp = IJ.openImage(inputDirectory + subFolder + '/' + filename) IJ.run( imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=0.8777017 pixel_height=0.8777017 voxel_depth=25400.0508001" ) # Sets the threshold and watersheds. for more details on image processing, see https://imagej.nih.gov/ij/developer/api/ij/process/ImageProcessor.html ic = ImageConverter(imp) ic.convertToGray8() IJ.run(imp, "Remove Outliers...", "radius=2" + " threshold=50" + " which=Dark") IJ.run(imp, "Gaussian Blur...", "sigma=" + str(blur)) IJ.setThreshold(imp, lowerBounds[0], 255) if displayImages: imp.show() IJ.run(imp, "Convert to Mask", "") IJ.run(imp, "Watershed", "") if not displayImages: imp.changes = False imp.close() # Counts and measures the area of particles and adds them to a table called areas. Also adds them to the ROI manager table = ResultsTable() roim = RoiManager(True) ParticleAnalyzer.setRoiManager(roim) pa = ParticleAnalyzer(ParticleAnalyzer.ADD_TO_MANAGER, Measurements.AREA, table, 15, 9999999999999999, 0.2, 1.0) pa.setHideOutputImage(True) #imp = impM # imp.getProcessor().invert() pa.analyze(imp) areas = table.getColumn(0) # This loop goes through the remaining channels for the other markers, by replacing the ch00 at the end with its corresponding channel # It will save all the area fractions into a 2d array called areaFractionsArray areaFractionsArray = [None] * 5 for chan in channels: v, x = chan # Opens each image and thresholds imp = images[x] IJ.run( imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=0.8777017 pixel_height=0.8777017 voxel_depth=25400.0508001" ) ic = ImageConverter(imp) ic.convertToGray8() IJ.setThreshold(imp, lowerBounds[x], 255) if displayImages: imp.show() WaitForUserDialog("Title", "Adjust Threshold for Marker " + v).show() IJ.run(imp, "Convert to Mask", "") # Measures the area fraction of the new image for each ROI from the ROI manager. areaFractions = [] for roi in roim.getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.AREA_FRACTION) areaFractions.append(stats.areaFraction) # Saves the results in areaFractionArray areaFractionsArray[x] = areaFractions roim.close() for chan in channels: v, x = chan imp = images[x] imp.deleteRoi() roim = RoiManager(True) ParticleAnalyzer.setRoiManager(roim) pa = ParticleAnalyzer(ParticleAnalyzer.ADD_TO_MANAGER, Measurements.AREA, table, 15, 9999999999999999, 0.2, 1.0) pa.analyze(imp) blobs = [] for roi in roim.getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.AREA) blobs.append(stats.area) blobsarea[x] = sum(blobs) blobsnuclei[x] = len(blobs) if not displayImages: imp.changes = False imp.close() roim.reset() roim.close() # Creates the summary dictionary which will correspond to a single row in the output csv, with each key being a column summary = {} summary['Image'] = filename summary['Directory'] = subFolder # Adds usual columns summary['size-average'] = 0 summary['#nuclei'] = 0 summary['all-negative'] = 0 summary['too-big-(>' + str(tooBigThreshold) + ')'] = 0 summary['too-small-(<' + str(tooSmallThreshold) + ')'] = 0 # Creates the fieldnames variable needed to create the csv file at the end. fieldnames = [ 'Name', 'Directory', 'Image', 'size-average', 'too-big-(>' + str(tooBigThreshold) + ')', 'too-small-(<' + str(tooSmallThreshold) + ')', '#nuclei', 'all-negative' ] # Adds the columns for each individual marker (ignoring Dapi since it was used to count nuclei) summary["organoid-area"] = bigAreas[x] fieldnames.append("organoid-area") for chan in channels: v, x = chan summary[v + "-positive"] = 0 fieldnames.append(v + "-positive") summary[v + "-intensity"] = intensities[x] fieldnames.append(v + "-intensity") summary[v + "-blobsarea"] = blobsarea[x] fieldnames.append(v + "-blobsarea") summary[v + "-blobsnuclei"] = blobsnuclei[x] fieldnames.append(v + "-blobsnuclei") # Adds the column for colocalization between first and second marker if len(channels) > 2: summary[channels[1][0] + '-' + channels[2][0] + '-positive'] = 0 fieldnames.append(channels[1][0] + '-' + channels[2][0] + '-positive') # Adds the columns for colocalization between all three markers if len(channels) > 3: summary[channels[1][0] + '-' + channels[3][0] + '-positive'] = 0 summary[channels[2][0] + '-' + channels[3][0] + '-positive'] = 0 summary[channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive'] = 0 fieldnames.append(channels[1][0] + '-' + channels[3][0] + '-positive') fieldnames.append(channels[2][0] + '-' + channels[3][0] + '-positive') fieldnames.append(channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive') # Loops through each particle and adds it to each field that it is True for. areaCounter = 0 for z, area in enumerate(areas): log.write(str(area)) log.write("\n") if area > tooBigThreshold: summary['too-big-(>' + str(tooBigThreshold) + ')'] += 1 elif area < tooSmallThreshold: summary['too-small-(<' + str(tooSmallThreshold) + ')'] += 1 else: summary['#nuclei'] += 1 areaCounter += area temp = 0 for chan in channels: v, x = chan if areaFractionsArray[x][z] > areaFractionThreshold[ 0]: #theres an error here im not sure why. i remember fixing it before summary[chan[0] + '-positive'] += 1 if x != 0: temp += 1 if temp == 0: summary['all-negative'] += 1 if len(channels) > 2: if areaFractionsArray[1][z] > areaFractionThreshold[1]: if areaFractionsArray[2][z] > areaFractionThreshold[2]: summary[channels[1][0] + '-' + channels[2][0] + '-positive'] += 1 if len(channels) > 3: if areaFractionsArray[1][z] > areaFractionThreshold[1]: if areaFractionsArray[3][z] > areaFractionThreshold[3]: summary[channels[1][0] + '-' + channels[3][0] + '-positive'] += 1 if areaFractionsArray[2][z] > areaFractionThreshold[2]: if areaFractionsArray[3][z] > areaFractionThreshold[3]: summary[channels[2][0] + '-' + channels[3][0] + '-positive'] += 1 if areaFractionsArray[1][z] > areaFractionThreshold[1]: summary[channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive'] += 1 # Calculate the average of the particles sizes if float(summary['#nuclei']) > 0: summary['size-average'] = round(areaCounter / summary['#nuclei'], 2) # Opens and appends one line on the final csv file for the subfolder (remember that this is still inside the loop that goes through each image) with open(outputDirectory + "/" + outputName + ".csv", 'a') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore', lineterminator='\n') if os.path.getsize(outputDirectory + "/" + outputName + ".csv") < 1: writer.writeheader() writer.writerow(summary)
def getCells(dicStack): outStack = ImageStack(W,H) cells = [None for t in range(T+1)] for t in range(1,T+1): mapp = dicStack.getProcessor(t).convertToFloatProcessor() mapp.subtract( mapp.getStatistics().mean ) mapp.abs() RankFilters().rank(mapp, 1.0, RankFilters.VARIANCE) mapp.sqrt() mapp.blurGaussian(5) hist = mapp.getHistogram(256) stats = mapp.getStatistics() thresh = AutoThresholder().getThreshold( AutoThresholder.Method.Otsu, hist ) thresh = (thresh/float(255)) * (stats.max-stats.min) + stats.min mask = ByteProcessor(W,H) for i in range(W*H): value = mapp.getf(i) bite = 255 if value>=thresh else 0 mask.set(i, bite) fillHoles(mask) ed = 3 for e in range(ed): mask.erode(1, 0) for d in range(ed): mask.dilate(1, 0) watershed(mask) minA = 5000 #px² mask.setThreshold(255,255, ImageProcessor.NO_LUT_UPDATE) composite = ThresholdToSelection().convert(mask) rois = ShapeRoi(composite).getRois() keep = [] for roi in rois: if roi.getStatistics().area >= minA: if not onEdge(roi): keep.append(roi) else: edgeRoi = ShapeRoi(roi) edgeRoi.setPosition(0,0,t) edgeRoi.setStrokeColor(Color.YELLOW) ol.add(edgeRoi) print("T"+str(t)+" using "+str(len(keep))+"/"+str(len(rois))+" ROIs") rois = keep #rois = [ roi for roi in rois if roi.getStatistics().area >= minA and not onEdge(roi) ] #keep big enough and not on edges # if there is only one Roi, cut it along the fitted ellipse minor axis if len(rois)==1: el = EllipseFitter() mask.setRoi(rois[0]) el.fit(mask, None) el.makeRoi(mask) theta = el.angle * (maths.pi/180.0) length = el.major/2.0 dy = maths.sin(theta)* length dx = maths.cos(theta)* length #major axis lineX0 = el.xCenter - dx lineY0 = el.yCenter + dy lineX1 = el.xCenter + dx lineY1 = el.yCenter - dy line = Line(lineX0, lineY0, lineX1, lineY1) line.setStrokeColor(Color.BLUE) line.setStrokeWidth(1) line.setPosition(0,0,t) ol.add(line) #minor axis scaled length to make sure cut ends are outside Roi cutX0 = el.xCenter + dy*100 cutY0 = el.xCenter + dx*100 cutX1 = el.yCenter - dy*100 cutY1 = el.yCenter - dx*100 cut = Line(cutX0,cutY0, cutX1, cutY1) cut.setStrokeWidth(2) cut = PolygonRoi( cut.getFloatPolygon(), PolygonRoi.POLYGON ) mask.setColor(0) mask.fill(cut) composite = ThresholdToSelection().convert(mask) rois = ShapeRoi(composite).getRois() rois = [ roi for roi in rois if roi.getStatistics().area >= minA ] print(str(t) + ":" + str(len(rois))) rois = [ PolygonRoi(roi.getInterpolatedPolygon(20, True), PolygonRoi.POLYGON) for roi in rois ] rois = [ PolygonRoi(roi.getConvexHull(), PolygonRoi.POLYGON) for roi in rois ] rois = sorted(list(rois), key=lambda roi:roi.getLength() ) #size order rois = rois[-2:] #keep 2 biggest rois = sorted(list(rois), key=lambda roi:roi.getStatistics().xCentroid+roi.getStatistics().yCentroid ) #top left to bottom right order if len(rois)>0: rois[0].setStrokeColor(Color.RED) rois[0].setPosition(0, 0, t) ol.add(rois[0]) if len(rois)>1: rois[1].setStrokeColor(Color.GREEN) rois[1].setPosition(0, 0, t) ol.add(rois[1]) cells[t] = (rois[0], rois[1]) return cells
def process(subFolder, outputDirectory, filename): imp = IJ.openImage(inputDirectory + subFolder + '/' + filename) imp.show() IJ.run( imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=0.8777017 pixel_height=0.8777017 voxel_depth=25400.0508001" ) ic = ImageConverter(imp) dup = imp.duplicate() dup_title = dup.getTitle() ic.convertToGray8() imp.updateAndDraw() IJ.run("Threshold...") IJ.setThreshold(218, 245) IJ.run(imp, "Convert to Mask", "") rm = RoiManager() imp.getProcessor().setThreshold(0, 0, ImageProcessor.NO_LUT_UPDATE) boundroi = ThresholdToSelection.run(imp) rm.addRoi(boundroi) imp.changes = False imp.close() images = [None] * 5 intensities = [None] * 5 blobsarea = [None] * 5 blobsnuclei = [None] * 5 cells = [None] * 5 bigareas = [None] * 5 IJ.run(dup, "Colour Deconvolution", "vectors=[H DAB]") images[0] = getImage(dup_title + "-(Colour_1)") images[1] = getImage(dup_title + "-(Colour_2)") images[2] = getImage(dup_title + "-(Colour_3)") images[2].close() for chan in channels: v, x = chan imp = images[x] imp.show() for roi in rm.getRoiManager().getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.MEAN | Measurements.AREA) intensities[x] = stats.mean bigareas[x] = stats.area rm.runCommand(imp, "Show None") rm.close() # Opens the ch00 image and sets default properties imp = images[0].duplicate() IJ.run( imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=0.8777017 pixel_height=0.8777017 voxel_depth=25400.0508001" ) # Sets the threshold and watersheds. for more details on image processing, see https://imagej.nih.gov/ij/developer/api/ij/process/ImageProcessor.html imp.show() setTempCurrentImage(imp) ic = ImageConverter(imp) imp.updateAndDraw() IJ.run(imp, "Gaussian Blur...", "sigma=" + str(blur)) imp.updateAndDraw() imp.show() IJ.run("Threshold...") IJ.setThreshold(30, lowerBounds[0]) if displayImages: imp.show() WaitForUserDialog( "Title", "Adjust threshold for nuclei. Current region is: " + region).show() IJ.run(imp, "Convert to Mask", "") # Counts and measures the area of particles and adds them to a table called areas. Also adds them to the ROI manager table = ResultsTable() roim = RoiManager() pa = ParticleAnalyzer(ParticleAnalyzer.ADD_TO_MANAGER, Measurements.AREA, table, 5, 9999999999999999, 0.05, 1.0) pa.setHideOutputImage(True) imp = IJ.getImage() # imp.getProcessor().invert() pa.analyze(imp) imp.changes = False imp.close() areas = table.getColumn(0) # This loop goes through the remaining channels for the other markers, by replacing the ch00 at the end with its corresponding channel # It will save all the area fractions into a 2d array called areaFractionsArray areaFractionsArray = [None] * 5 maxThresholds = [] for chan in channels: v, x = chan # Opens each image and thresholds imp = images[x] IJ.run( imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=0.8777017 pixel_height=0.8777017 voxel_depth=25400.0508001" ) imp.show() setTempCurrentImage(imp) ic = ImageConverter(imp) ic.convertToGray8() imp.updateAndDraw() rm.runCommand(imp, "Show None") rm.runCommand(imp, "Show All") rm.runCommand(imp, "Show None") imp.show() IJ.selectWindow(imp.getTitle()) IJ.run("Threshold...") IJ.setThreshold(20, lowerBounds[x]) if displayImages: WaitForUserDialog( "Title", "Adjust threshold for " + v + ". Current region is: " + region).show() ip = imp.getProcessor() maxThresholds.append(ip.getMaxThreshold()) IJ.run(imp, "Convert to Mask", "") # Measures the area fraction of the new image for each ROI from the ROI manager. areaFractions = [] for roi in roim.getRoiManager().getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.AREA_FRACTION) areaFractions.append(stats.areaFraction) # Saves the results in areaFractionArray areaFractionsArray[x] = areaFractions roim.close() for chan in channels: v, x = chan imp = images[x] imp.deleteRoi() imp.updateAndDraw() setTempCurrentImage(imp) roim = RoiManager() pa = ParticleAnalyzer(ParticleAnalyzer.ADD_TO_MANAGER, Measurements.AREA, table, 15, 9999999999999999, 0.2, 1.0) pa.analyze(imp) blobs = [] cell = [] for roi in roim.getRoiManager().getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.AREA) blobs.append(stats.area) if stats.area > tooSmallThresholdDAB and stats.area < tooBigThresholdDAB: cell.append(stats.area) blobsarea[x] = sum(blobs) blobsnuclei[x] = len(blobs) cells[x] = len(cell) imp.changes = False imp.close() roim.reset() roim.close() # Creates the summary dictionary which will correspond to a single row in the output csv, with each key being a column summary = {} summary['Image'] = filename summary['Directory'] = subFolder # Adds usual columns summary['size-average'] = 0 summary['#nuclei'] = 0 summary['all-negative'] = 0 summary['too-big-(>' + str(tooBigThreshold) + ')'] = 0 summary['too-small-(<' + str(tooSmallThreshold) + ')'] = 0 # Creates the fieldnames variable needed to create the csv file at the end. fieldnames = [ 'Directory', 'Image', 'size-average', 'too-big-(>' + str(tooBigThreshold) + ')', 'too-small-(<' + str(tooSmallThreshold) + ')', '#nuclei', 'all-negative' ] for row in info: if row['Animal ID'] == filename.replace('s', '-').replace( 'p', '-').split('-')[0]: for key, value in row.items(): fieldnames.insert(0, key) summary[key] = value # Adds the columns for each individual marker (ignoring Dapi since it was used to count nuclei) summary["tissue-area"] = bigareas[0] fieldnames.append("tissue-area") for chan in channels: v, x = chan summary[v + "-HEMO-cells"] = 0 fieldnames.append(v + "-HEMO-cells") summary[v + "-intensity"] = intensities[x] fieldnames.append(v + "-intensity") summary[v + "-area"] = blobsarea[x] fieldnames.append(v + "-area") summary[v + "-area/tissue-area"] = blobsarea[x] / bigareas[0] fieldnames.append(v + "-area/tissue-area") summary[v + "-particles"] = blobsnuclei[x] fieldnames.append(v + "-particles") summary[v + "-cells"] = cells[x] fieldnames.append(v + "-cells") summary[v + "-particles/tissue-area"] = blobsnuclei[x] / bigareas[0] fieldnames.append(v + "-particles/tissue-area") fieldnames.append(v + "-HEMO-Cells/tissue-area") # Adds the column for colocalization between first and second marker if len(channels) > 2: summary[channels[1][0] + '-' + channels[2][0] + '-positive'] = 0 fieldnames.append(channels[1][0] + '-' + channels[2][0] + '-positive') # Adds the columns for colocalization between all three markers if len(channels) > 3: summary[channels[1][0] + '-' + channels[3][0] + '-positive'] = 0 summary[channels[2][0] + '-' + channels[3][0] + '-positive'] = 0 summary[channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive'] = 0 fieldnames.append(channels[1][0] + '-' + channels[3][0] + '-positive') fieldnames.append(channels[2][0] + '-' + channels[3][0] + '-positive') fieldnames.append(channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive') # Loops through each particle and adds it to each field that it is True for. areaCounter = 0 for z, area in enumerate(areas): if area > tooBigThreshold: summary['too-big-(>' + str(tooBigThreshold) + ')'] += 1 elif area < tooSmallThreshold: summary['too-small-(<' + str(tooSmallThreshold) + ')'] += 1 else: summary['#nuclei'] += 1 areaCounter += area temp = 0 for chan in channels: v, x = chan if areaFractionsArray[x][z] > areaFractionThreshold[0]: summary[chan[0] + '-HEMO-cells'] += 1 if x != 0: temp += 1 if temp == 0: summary['all-negative'] += 1 if len(channels) > 2: if areaFractionsArray[1][z] > areaFractionThreshold[1]: if areaFractionsArray[2][z] > areaFractionThreshold[2]: summary[channels[1][0] + '-' + channels[2][0] + '-positive'] += 1 if len(channels) > 3: if areaFractionsArray[1][z] > areaFractionThreshold[1]: if areaFractionsArray[3][z] > areaFractionThreshold[3]: summary[channels[1][0] + '-' + channels[3][0] + '-positive'] += 1 if areaFractionsArray[2][z] > areaFractionThreshold[2]: if areaFractionsArray[3][z] > areaFractionThreshold[3]: summary[channels[2][0] + '-' + channels[3][0] + '-positive'] += 1 if areaFractionsArray[1][z] > areaFractionThreshold[1]: summary[channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive'] += 1 # Calculate the average of the particles sizes for chan in channels: v, x = chan summary[v + "-cells/tissue-area"] = summary[v + "-cells"] / bigareas[0] if float(summary['#nuclei']) > 0: summary['size-average'] = round(areaCounter / summary['#nuclei'], 2) if displayImages: fieldnames = ["Directory", "Image"] for chan in channels: v, x = chan summary[v + "-threshold"] = maxThresholds[x] fieldnames.append(v + "-threshold") allMaxThresholds[v + "-" + region].append(maxThresholds[x]) # Opens and appends one line on the final csv file for the subfolder (remember that this is still inside the loop that goes through each image) with open(outputName, 'a') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore', lineterminator='\n') if os.path.getsize(outputName) < 1: writer.writeheader() writer.writerow(summary)
resrt = ResultsTable() for i in range(regionedimp.getStackSize()): aregion = regionedimp.getStack().getProcessor(i+1) particleAnalysis(i, ImagePlus("extract", aregion), resrt) #resrt.show("data") rm = RoiManager() for i in range(resrt.getCounter()): cc = resrt.getValue("counts", i) if cc == 2: print "row", i x1 = resrt.getValue("c1x", i) y1 = resrt.getValue("c1y", i) x2 = resrt.getValue("c2x", i) y2 = resrt.getValue("c2y", i) resrt.setValue("Distance", i, distance(x1, y1, x2, y2)) print "points", x1, y1, x2, y2 aroi = Line(x1, y1, x2, y2) rm.addRoi(aroi) rm.runCommand("Show All") rm.runCommand("Labels") resrt.show("results" + imgtitle) segimp.getProcessor().setThreshold(0, 0, ImageProcessor.NO_LUT_UPDATE) boundroi = ThresholdToSelection.run(segimp) rm.addRoi(boundroi) #perRegionlist[11].show()
def process(subFolder, outputDirectory, filename): roim = RoiManager() roim.close() imp = IJ.openImage(inputDirectory + subFolder + '/' + filename.replace("_ch00.tif", ".tif")) IJ.run( imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=0.8777017 pixel_height=0.8777017 voxel_depth=25400.0508001" ) ic = ImageConverter(imp) ic.convertToGray8() imp.updateAndDraw() IJ.setThreshold(imp, 2, 255) IJ.run(imp, "Convert to Mask", "") IJ.run(imp, "Remove Outliers...", "radius=5" + " threshold=50" + " which=Dark") IJ.run(imp, "Remove Outliers...", "radius=5" + " threshold=50" + " which=Bright") imp.getProcessor().invert() imp.changes = False imp.close() x_amount = 10 y_amount = 10 l = 0 j = 0 while l < x_amount: k = 0 while k < y_amount: copy = IJ.openImage(inputDirectory + subFolder + '/' + filename.replace("_ch00.tif", ".tif")) Xposition = (int)(round((imp.width / x_amount) * l)) Yposition = (int)(round((imp.width / y_amount) * k)) Width = (int)(round(imp.width / x_amount)) Height = (int)(round(imp.height / y_amount)) roi = Roi(Xposition, Yposition, Width, Height) copy.setRoi(roi) IJ.run(copy, "Crop", "") FileSaver(copy).saveAsTiff(outputDirectory + '/' + filename + "_crop_" + str(j) + ".tif") copy.changes = False copy.close() for chan in channels: v, x = chan image = IJ.openImage(inputDirectory + subFolder + '/' + filename.replace("ch00.tif", "ch0" + str(x) + ".tif")) roi = Roi(Xposition, Yposition, Width, Height) image.setRoi(roi) IJ.run(image, "Crop", "") FileSaver(image).saveAsTiff(outputDirectory + '/' + filename + "_crop_" + str(j) + "_ch0" + str(x) + ".tif") image.changes = False image.close() roim.close() k = k + 1 j = j + 1 l = l + 1 imp.getProcessor().setThreshold(0, 0, ImageProcessor.NO_LUT_UPDATE) boundroi = ThresholdToSelection.run(imp) rm = RoiManager() rm.addRoi(boundroi) images = [None] * 5 intensities = [None] * 5 blobsarea = [None] * 5 blobsnuclei = [None] * 5 areas = [None] * 5 for chan in channels: v, x = chan images[x] = IJ.openImage(inputDirectory + subFolder + '/' + filename.replace("ch00.tif", "ch0" + str(x) + ".tif")) imp = images[x] for roi in rm.getRoiManager().getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.MEAN | Measurements.AREA) intensities[x] = stats.mean areas[x] = stats.area rm.close() # Creates the summary dictionary which will correspond to a single row in the output csv, with each key being a column summary = {} summary['Image'] = filename summary['Directory'] = subFolder # Creates the fieldnames variable needed to create the csv file at the end. fieldnames = ['Name', 'Directory', 'Image'] # Adds the columns for each individual marker (ignoring Dapi since it was used to count nuclei) summary["organoid-area"] = areas[x] fieldnames.append("organoid-area") for chan in channels: v, x = chan summary[v + "-intensity"] = intensities[x] fieldnames.append(v + "-intensity") # Opens and appends one line on the final csv file for the subfolder (remember that this is still inside the loop that goes through each image) with open(outputDirectory + "/" + outputName + ".csv", 'a') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore', lineterminator='\n') if os.path.getsize(outputDirectory + "/" + outputName + ".csv") < 1: writer.writeheader() writer.writerow(summary)
def process(subFolder, outputDirectory, filename): #IJ.close() imp = IJ.openImage(inputDirectory + subFolder + '/' + rreplace(filename, "_ch00.tif", ".tif")) imp.show() # Finds the pixel length in microns from the xml metadata file file_list = [file for file in os.listdir(inputDirectory + subFolder) if file.endswith('.xml')] if len(file_list) > 0: xml = os.path.join(inputDirectory + subFolder, file_list[0]) element_tree = ET.parse(xml) root = element_tree.getroot() for dimensions in root.iter('DimensionDescription'): num_pixels = int(dimensions.attrib['NumberOfElements']) if dimensions.attrib['Unit'] == "m": length = float(dimensions.attrib['Length']) * 1000000 else: length = float(dimensions.attrib['Length']) pixel_length = length / num_pixels else: pixel_length = 0.877017 log.write("Pixel Length:" + str(pixel_length) + "\n") IJ.run(imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=" + str(pixel_length) + " pixel_height=" + str(pixel_length) + " voxel_depth=25400.0508001") ic = ImageConverter(imp); ic.convertToGray8(); #IJ.setThreshold(imp, 2, 255) # If wand tool is enabled, then this will prompt that to be used if enableWand: # Call threshold function to adjust threshold and select Organoid ROI IJ.run("Threshold...") WaitForUserDialog("Adjust Threshold to create mask").show() IJ.setTool("Wand") WaitForUserDialog("Click on Organoid Area for it to be selected. Best selection will be at the edge of the organoid to get entire organoid shape.").show() IJ.run("Clear Outside") if not enableWand: IJ.setAutoThreshold(imp, "Mean dark no-reset") IJ.run(imp, "Convert to Mask", "") IJ.run(imp, "Analyze Particles...", "size=100000-Infinity add select") rm = RoiManager.getInstance() imp = getCurrentImage() rm.select(imp, 0) IJ.setBackgroundColor(0, 0, 0) IJ.run(imp, "Clear Outside", "") IJ.run(imp, "Convert to Mask", "") IJ.run(imp, "Remove Outliers...", "radius=5" + " threshold=50" + " which=Dark") IJ.run(imp, "Remove Outliers...", "radius=5" + " threshold=50" + " which=Bright") # #Save the mask and open it IJ.saveAs("tiff", inputDirectory + '/mask') mask = IJ.openImage(inputDirectory + '/mask.tif') if enableWand: #Select ROI again to add it to the the ROI manager so that intensities and area is saved #IJ.run("Threshold...") IJ.setTool("Wand") WaitForUserDialog("Select Organoid area again for it to register within the ROI manager").show() rm = RoiManager() boundroi = ThresholdToSelection.run(mask) rm.addRoi(boundroi) if not displayImages: imp.changes = False imp.close() images = [None] * 5 intensities = [None] * 5 blobsarea = [None] * 5 blobsnuclei = [None] * 5 bigAreas = [None] * 5 imp.close() #Loop to open all the channel images for chan in channels: v, x = chan images[x] = IJ.openImage( inputDirectory + subFolder + '/' + rreplace(filename, "_ch00.tif", "_ch0" + str(x) + ".tif")) # Apply Mask on all the images and save them into an array apply_mask = ImageCalculator() images[x] = apply_mask.run("Multiply create 32 bit", mask, images[x]) ic = ImageConverter(images[x]) ic.convertToGray8() imp = images[x] # Calculate the intensities for each channel as well as the organoid area for roi in rm.getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.MEAN | Measurements.AREA) intensities[x] = stats.mean bigAreas[x] = stats.area rm.close() # Opens the ch00 image and sets default properties apply_mask = ImageCalculator() imp = IJ.openImage(inputDirectory + subFolder + '/' + filename) imp = apply_mask.run("Multiply create 32 bit", mask, imp) IJ.run(imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=" + str(pixel_length) + " pixel_height=" + str(pixel_length) + " voxel_depth=25400.0508001") # Sets the threshold and watersheds. for more details on image processing, see https://imagej.nih.gov/ij/developer/api/ij/process/ImageProcessor.html ic = ImageConverter(imp); ic.convertToGray8(); IJ.run(imp, "Remove Outliers...", "radius=2" + " threshold=50" + " which=Dark") IJ.run(imp, "Gaussian Blur...", "sigma=" + str(blur)) IJ.setThreshold(imp, lowerBounds[0], 255) if displayImages: imp.show() IJ.run(imp, "Convert to Mask", "") IJ.run(imp, "Watershed", "") if not displayImages: imp.changes = False imp.close() # Counts and measures the area of particles and adds them to a table called areas. Also adds them to the ROI manager table = ResultsTable() roim = RoiManager(True) ParticleAnalyzer.setRoiManager(roim); pa = ParticleAnalyzer(ParticleAnalyzer.ADD_TO_MANAGER, Measurements.AREA, table, 15, 9999999999999999, 0.2, 1.0) pa.setHideOutputImage(True) # imp = impM # imp.getProcessor().invert() pa.analyze(imp) areas = table.getColumn(0) # This loop goes through the remaining channels for the other markers, by replacing the ch00 at the end with its corresponding channel # It will save all the area fractions into a 2d array called areaFractionsArray areaFractionsArray = [None] * 5 for chan in channels: v, x = chan # Opens each image and thresholds imp = images[x] IJ.run(imp, "Properties...", "channels=1 slices=1 frames=1 unit=um pixel_width=" + str(pixel_length) + " pixel_height=" + str(pixel_length) + " voxel_depth=25400.0508001") ic = ImageConverter(imp); ic.convertToGray8(); IJ.setThreshold(imp, lowerBounds[x], 255) if displayImages: imp.show() WaitForUserDialog("Title", "Adjust Threshold for Marker " + v).show() IJ.run(imp, "Convert to Mask", "") # Measures the area fraction of the new image for each ROI from the ROI manager. areaFractions = [] for roi in roim.getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.AREA_FRACTION) areaFractions.append(stats.areaFraction) # Saves the results in areaFractionArray areaFractionsArray[x] = areaFractions roim.close() for chan in channels: v, x = chan imp = images[x] imp.deleteRoi() roim = RoiManager(True) ParticleAnalyzer.setRoiManager(roim); pa = ParticleAnalyzer(ParticleAnalyzer.ADD_TO_MANAGER, Measurements.AREA, table, 15, 9999999999999999, 0.2, 1.0) pa.analyze(imp) blobs = [] for roi in roim.getRoisAsArray(): imp.setRoi(roi) stats = imp.getStatistics(Measurements.AREA) blobs.append(stats.area) blobsarea[x] = sum(blobs) #take this out and use intial mask tissue area from the beginning blobsnuclei[x] = len(blobs) if not displayImages: imp.changes = False imp.close() roim.reset() roim.close() imp.close() # Creates the summary dictionary which will correspond to a single row in the output csv, with each key being a column summary = {} summary['Image'] = filename summary['Directory'] = subFolder # Adds usual columns summary['size-average'] = 0 summary['#nuclei'] = 0 summary['all-negative'] = 0 summary['too-big-(>' + str(tooBigThreshold) + ')'] = 0 summary['too-small-(<' + str(tooSmallThreshold) + ')'] = 0 # Creates the fieldnames variable needed to create the csv file at the end. fieldnames = ['Name', 'Directory', 'Image', 'size-average', 'too-big-(>' + str(tooBigThreshold) + ')', 'too-small-(<' + str(tooSmallThreshold) + ')', '#nuclei', 'all-negative'] # Adds the columns for each individual marker (ignoring Dapi since it was used to count nuclei) summary["organoid-area"] = bigAreas[x] fieldnames.append("organoid-area") for chan in channels: v, x = chan summary[v + "-positive"] = 0 fieldnames.append(v + "-positive") summary[v + "-intensity"] = intensities[x] fieldnames.append(v + "-intensity") summary[v + "-blobsarea"] = blobsarea[x] fieldnames.append(v + "-blobsarea") summary[v + "-blobsnuclei"] = blobsnuclei[x] fieldnames.append(v + "-blobsnuclei") # Adds the column for colocalization between first and second marker if len(channels) > 2: summary[channels[1][0] + '-' + channels[2][0] + '-positive'] = 0 fieldnames.append(channels[1][0] + '-' + channels[2][0] + '-positive') # Adds the columns for colocalization between all three markers if len(channels) > 3: summary[channels[1][0] + '-' + channels[3][0] + '-positive'] = 0 summary[channels[2][0] + '-' + channels[3][0] + '-positive'] = 0 summary[channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive'] = 0 fieldnames.append(channels[1][0] + '-' + channels[3][0] + '-positive') fieldnames.append(channels[2][0] + '-' + channels[3][0] + '-positive') fieldnames.append(channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive') # Loops through each particle and adds it to each field that it is True for. areaCounter = 0 for z, area in enumerate(areas): log.write(str(area)) log.write("\n") if area > tooBigThreshold: summary['too-big-(>' + str(tooBigThreshold) + ')'] += 1 elif area < tooSmallThreshold: summary['too-small-(<' + str(tooSmallThreshold) + ')'] += 1 else: summary['#nuclei'] += 1 areaCounter += area temp = 0 for chan in channels: v, x = chan if areaFractionsArray[x][z] > areaFractionThreshold[ 0]: # theres an error here im not sure why. i remember fixing it before summary[chan[0] + '-positive'] += 1 if x != 0: temp += 1 if temp == 0: summary['all-negative'] += 1 if len(channels) > 2: if areaFractionsArray[1][z] > areaFractionThreshold[1]: if areaFractionsArray[2][z] > areaFractionThreshold[2]: summary[channels[1][0] + '-' + channels[2][0] + '-positive'] += 1 if len(channels) > 3: if areaFractionsArray[1][z] > areaFractionThreshold[1]: if areaFractionsArray[3][z] > areaFractionThreshold[3]: summary[channels[1][0] + '-' + channels[3][0] + '-positive'] += 1 if areaFractionsArray[2][z] > areaFractionThreshold[2]: if areaFractionsArray[3][z] > areaFractionThreshold[3]: summary[channels[2][0] + '-' + channels[3][0] + '-positive'] += 1 if areaFractionsArray[1][z] > areaFractionThreshold[1]: summary[channels[1][0] + '-' + channels[2][0] + '-' + channels[3][0] + '-positive'] += 1 # Calculate the average of the particles sizes if float(summary['#nuclei']) > 0: summary['size-average'] = round(areaCounter / summary['#nuclei'], 2) # Opens and appends one line on the final csv file for the subfolder (remember that this is still inside the loop that goes through each image) with open(outputDirectory + "/" + outputName + ".csv", 'a') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore', lineterminator='\n') if os.path.getsize(outputDirectory + "/" + outputName + ".csv") < 1: writer.writeheader() writer.writerow(summary) IJ.run(imp, "Close All", "")