Beispiel #1
0
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}
Beispiel #2
0
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	
Beispiel #5
0
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)
Beispiel #6
0
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)
Beispiel #12
0
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
Beispiel #13
0
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)
Beispiel #14
0
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)
Beispiel #16
0
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", "")