def poreDetectionTrueColor(inputImp, inputDataset, inputRoi, ops, data, display, detectionParameters):
	
	detectionParameters.setCalibration(inputImp);
	
	# calculate area of roi 
	stats=inputImp.getStatistics()
	inputRoiArea=stats.area
	
	# get the bounding box of the active roi
	inputRec = inputRoi.getBounds()
	x1=long(inputRec.getX())
	y1=long(inputRec.getY())
	x2=x1+long(inputRec.getWidth())-1
	y2=y1+long(inputRec.getHeight())-1
	
	# crop the roi
	interval=FinalInterval( array([x1, y1 ,0], 'l'), array([x2, y2, 2], 'l') )
	cropped=ops.image().crop(inputDataset.getImgPlus(), interval ) 
	
	datacropped=data.create(cropped)
	display.createDisplay("cropped", datacropped)
	croppedPlus=IJ.getImage()
	
	# instantiate the duplicator and the substackmaker classes
	duplicator=Duplicator()
	substackMaker=SubstackMaker()
	
	# duplicate the roi
	duplicate=duplicator.run(croppedPlus)

	# separate into RGB and get the blue channel
	IJ.run(duplicate, "RGB Stack", "")
	bluePlus=substackMaker.makeSubstack(duplicate, "3-3")
	blue=ImgPlus(ImageJFunctions.wrapByte(bluePlus))
	bluePlus.setTitle("Blue")
	
	# duplicate and look for bright spots
	thresholdedLight=SpotDetection2(bluePlus)

	# duplicate and look for dark spots
	thresholdedDark=SpotDetection3(bluePlus, True)

	# convert to mask
	Prefs.blackBackground = True
	#IJ.run(thresholdedDark, "Convert to Mask", "")substackMaker

	# clear the region outside the roi
	clone=inputRoi.clone()
	clone.setLocation(0,0)
	Utility.clearOutsideRoi(thresholdedLight, clone)
	Utility.clearOutsideRoi(thresholdedDark, clone)
	roimClosedPores = RoiManager(True)
	detectionParameters.setCalibration(thresholdedDark)
	countParticles(thresholdedDark, roimClosedPores, detectionParameters.closedPoresMinSize, detectionParameters.closedPoresMaxSize, \
		detectionParameters.closedPoresMinCircularity, detectionParameters.closedPoresMaxCircularity)

	# count number of open pores
	roimOpenPores = RoiManager(True)
	detectionParameters.setCalibration(thresholdedDark)
	countParticles(thresholdedDark, roimOpenPores, detectionParameters.openPoresMinSize, detectionParameters.openPoresMaxSize, \
		detectionParameters.openPoresMinCircularity, detectionParameters.openPoresMaxCircularity)

	# count number of sebum
	roimSebum = RoiManager(True)
	detectionParameters.setCalibration(thresholdedLight)
	countParticles(thresholdedLight, roimSebum, detectionParameters.sebumMinSize, detectionParameters.sebumMaxSize, \
		detectionParameters.sebumMinCircularity, detectionParameters.sebumMaxCircularity)
	
	# create lists for open and closed pores
	closedPoresList=[]
	for roi in roimClosedPores.getRoisAsArray():
		closedPoresList.append(roi.clone())
	openPoresList=[]
	for roi in roimOpenPores.getRoisAsArray():
		openPoresList.append(roi.clone())

	# create lists for sebum
	sebumsList=[]
	for roi in roimSebum.getRoisAsArray():
		sebumsList.append(roi.clone())

	# a list of all pores
	allList=closedPoresList+openPoresList+sebumsList
	
	# calculate the stats for all pores
	detectionParameters.setCalibration(bluePlus)
	statsDict=CountParticles.calculateParticleStats(bluePlus, allList)

	poresTotalArea=0
	for area in statsDict['Areas']:
		poresTotalArea=poresTotalArea+area
		print area
	poresAverageArea=poresTotalArea/len(statsDict['Areas'])
		

	# for each roi add the offset such that the roi is positioned in the correct location for the 
	# original image
	[roi.setLocation(roi.getXBase()+x1, roi.getYBase()+y1) for roi in allList]
	
	# draw the rois on the image
	inputImp.getProcessor().setColor(Color.green)
	IJ.run(inputImp, "Line Width...", "line=3");
	inputImp.getProcessor().draw(inputRoi)
	IJ.run(inputImp, "Line Width...", "line=1");
	[CountParticles.drawParticleOnImage(inputImp, roi, Color.red) for roi in closedPoresList]
	[CountParticles.drawParticleOnImage(inputImp, roi, Color.magenta) for roi in openPoresList]
	[CountParticles.drawParticleOnImage(inputImp, roi, Color.green) for roi in sebumsList]
	
	inputImp.updateAndDraw()
	
	# close images that represent intermediate steps
	croppedPlus.changes=False
	croppedPlus.close()
	bluePlus.changes=False
	bluePlus.close()

	print "Total ROI Area: "+str(inputRoiArea)
	print "Num closed pores: "+str(len(closedPoresList))
	print "Num open pores: "+str(len(openPoresList))
	print "Num sebums: "+str(len(sebumsList))
	
	print "Total particles: "+str(len(allList))+ " total area: "+str(poresTotalArea)
	
	statslist=[inputRoiArea, len(allList), len(closedPoresList), len(openPoresList), len(sebumsList), poresAverageArea, 100*poresTotalArea/inputRoiArea]
	header=[Messages.TotalAreaMask, Messages.TotalDetectedPores, Messages.ClosedPores, Messages.OpenPores, Messages.Sebum, Messages.PoresAverageArea, Messages.PoresFractionalArea]
	
	return header,statslist

	
def poreDetectionUV(inputImp, inputDataset, inputRoi, ops, data, display, detectionParameters):
	
	title =  inputImp.getTitle()
	title=title.replace('UV', 'SD')
	
	print title
	
	#trueColorImp= WindowManager.getImage(title)
	#print type( trueColorImp)
	
	# calculate are of roi 
	stats=inputImp.getStatistics()
	inputRoiArea=stats.area
	
	print inputRoi
	
	# get the bounding box of the active roi
	inputRec = inputRoi.getBounds()
	x1=long(inputRec.getX())
	y1=long(inputRec.getY())
	x2=x1+long(inputRec.getWidth())-1
	y2=y1+long(inputRec.getHeight())-1

	print x1
	print y1
	print x2
	print y2
	
	# crop the roi
	interval=FinalInterval( array([x1, y1 ,0], 'l'), array([x2, y2, 2], 'l') )
	cropped=ops.crop(interval, None, inputDataset.getImgPlus() ) 
	
	datacropped=data.create(cropped)
	display.createDisplay("cropped", datacropped)
	croppedPlus=IJ.getImage()
	
	duplicator=Duplicator()
	substackMaker=SubstackMaker()
	
	# duplicate the roi
	duplicate=duplicator.run(croppedPlus)
	#duplicate.show()
	
	# convert duplicate of roi to HSB and get brightness
	IJ.run(duplicate, "HSB Stack", "");
	brightnessPlus=substackMaker.makeSubstack(duplicate, "3-3")
	brightness=ImgPlus(ImageJFunctions.wrapByte(brightnessPlus))
	brightnessPlus.setTitle("Brightness")
	#brightnessPlus.show()
	
	# make another duplicate, split channels and get red
	duplicate=duplicator.run(croppedPlus)
	channels=ChannelSplitter().split(duplicate)
	redPlus=channels[0]
	red=ImgPlus(ImageJFunctions.wrapByte(redPlus))
	redPlus.show()
	
	# convert to lab
	IJ.run(croppedPlus, "Color Transformer", "colour=Lab")
	IJ.selectWindow('Lab')
	labPlus=IJ.getImage()
	
	# get the A channel
	APlus=substackMaker.makeSubstack(labPlus, "2-2")
	APlus.setTitle('A')
	APlus.show()
	APlus.getProcessor().resetMinAndMax()
	APlus.updateAndDraw()
	AThresholded=threshold(APlus, -10, 50)
	
	# get the B channel
	BPlus=substackMaker.makeSubstack(labPlus, "3-3")
	BPlus.setTitle('B')
	BPlus.show()
	BPlus.getProcessor().resetMinAndMax()
	BPlus.updateAndDraw()
	BThresholded=threshold(BPlus, -10, 50)
	
	# AND the Athreshold and Bthreshold to get a map of the red pixels
	ic = ImageCalculator();
	redMask = ic.run("AND create", AThresholded, BThresholded);
	IJ.run(redMask, "Divide...", "value=255");
	#redMask.show()
	
	labPlus.close()
	
	# threshold the spots from the red channel
	thresholdedred=SpotDetectionGray(red, data, display, ops, False)
	display.createDisplay("thresholdedred", data.create(thresholdedred))
	impthresholdedred = ImageJFunctions.wrap(thresholdedred, "wrapped")
	
	# threshold the spots from the brightness channel
	thresholded=SpotDetectionGray(brightness, data, display, ops, False)
	display.createDisplay("thresholded", data.create(thresholded))
	impthresholded=ImageJFunctions.wrap(thresholded, "wrapped")
	
	# or the thresholding results from red and brightness channel
	impthresholded = ic.run("OR create", impthresholded, impthresholdedred);
	
	# convert to mask
	Prefs.blackBackground = True
	IJ.run(impthresholded, "Convert to Mask", "")
	
	# clear the region outside the roi
	clone=inputRoi.clone()
	clone.setLocation(0,0)
	Utility.clearOutsideRoi(impthresholded, clone)
	
	# create a hidden roi manager
	roim = RoiManager(True)
	
	# count the particlesimp.getProcessor().setColor(Color.green)
	countParticles(impthresholded, roim, detectionParameters.minSize, detectionParameters.maxSize, detectionParameters.minCircularity, detectionParameters.maxCircularity)
	
	# define a function to determine the percentage of pixels that are foreground in a binary image
	# inputs:
	#    imp: binary image, 0=background, 1=foreground
	#    roi: an roi
	def isRed(imp, roi):
		stats = imp.getStatistics()
	
		if (stats.mean>detectionParameters.redPercentage): return True
		else: return False
	
	def notRed(imp, roi):
		stats = imp.getStatistics()
	
		if (stats.mean>detectionParameters.redPercentage): return False
		else: return True

	allList=[]

	for roi in roim.getRoisAsArray():
		allList.append(roi.clone())
	
	# count particles that are red
	redList=CountParticles.filterParticlesWithFunction(redMask, allList, isRed)
	# count particles that are red
	blueList=CountParticles.filterParticlesWithFunction(redMask, allList, notRed)

	print "Total particles: "+str(len(allList))
	print "Filtered particles: "+str(len(redList))

	# for each roi add the offset such that the roi is positioned in the correct location for the 
	# original image
	[roi.setLocation(roi.getXBase()+x1, roi.getYBase()+y1) for roi in allList]
	
	# create an overlay and add the rois
	overlay1=Overlay()
		
	inputRoi.setStrokeColor(Color.green)
	overlay1.add(inputRoi)
	[CountParticles.addParticleToOverlay(roi, overlay1, Color.red) for roi in redList]
	[CountParticles.addParticleToOverlay(roi, overlay1, Color.cyan) for roi in blueList]
	
	def drawAllRoisOnImage(imp, mainRoi, redList, blueList):
		imp.getProcessor().setColor(Color.green)
		IJ.run(imp, "Line Width...", "line=3");
		imp.getProcessor().draw(inputRoi)
		imp.updateAndDraw()
		IJ.run(imp, "Line Width...", "line=1");
		[CountParticles.drawParticleOnImage(imp, roi, Color.magenta) for roi in redList]
		[CountParticles.drawParticleOnImage(imp, roi, Color.green) for roi in blueList]
		imp.updateAndDraw()
	
	drawAllRoisOnImage(inputImp, inputRoi, redList, blueList)
	#drawAllRoisOnImage(trueColorImp, inputRoi, redList, blueList)
	
	# draw overlay
	#inputImp.setOverlay(overlay1)
	#inputImp.updateAndDraw()
	
	statsdict=CountParticles.calculateParticleStats(APlus, BPlus, redMask, roim.getRoisAsArray())
	
	print inputRoiArea

	areas=statsdict['Areas']
	poreArea=0
	for area in areas:
		poreArea=poreArea+area

	ATotal=0
	ALevels=statsdict['ALevel']
	for A in ALevels:
		ATotal=ATotal+A

	AAverage=ATotal/len(ALevels)

	BTotal=0
	BLevels=statsdict['BLevel']
	for B in BLevels:
		BTotal=BTotal+B

	BAverage=BTotal/len(BLevels)

	redTotal=0
	redPercentages=statsdict['redPercentage']
	for red in redPercentages:
		redTotal=redTotal+red

	redAverage=redTotal/len(redPercentages)
	pixwidth=inputImp.getCalibration().pixelWidth

	inputRoiArea=inputRoiArea/(pixwidth*pixwidth)
	
	print str(len(allList))+" "+str(len(redList))+" "+str(len(blueList))+" "+str(poreArea/inputRoiArea)+" "+str(redAverage)
def main():
    # define here which membrane indices will be used in the analysis, with last index the "control" index
    membrane_indices = [-1, 0, 1, 3]

    # for now, work with frontmost open image...
    imp = IJ.getImage()
    im_title = imp.getTitle()
    settings = MembraneEvolutionAnalysisSettings(
        membrane_indices=membrane_indices)
    settings.loadPersistedSettings()

    timestamp = datetime.strftime(datetime.now(), '%Y-%m-%d %H-%M-%S')
    DirectoryChooser.setDefaultDirectory((settings.output_path))
    dc = DirectoryChooser('Select the root folder for saving output')
    output_root = dc.getDirectory()
    if output_root is None:
        raise IOError('no output path chosen')
    settings.output_path = output_root

    # get calibration
    cal = imp.getCalibration()
    if cal.getTimeUnit() == "sec":
        cal.setTimeUnit('s')

    # pop up a dialog prompting for selection of zero time point, frame interval, and time step for analysis
    time_steps_not_ok = True
    while time_steps_not_ok:
        dialog = NonBlockingGenericDialog("Determine time parameters...")
        dialog.addNumericField("0 timepoint frame (1-index): ",
                               settings.zero_timepoint_frame, 0)
        dialog.addNumericField("Acquisition time step (s): ",
                               cal.frameInterval,
                               2)  # assume stored in seconds
        dialog.addNumericField(
            "Time step for analysis (s): ",
            cal.frameInterval * settings.analysis_frame_step, 2)
        dialog.showDialog()

        if dialog.wasCanceled():
            return

        zero_f = dialog.getNextNumber()
        acq_t_step = dialog.getNextNumber()
        analysis_t_step = dialog.getNextNumber()
        if acq_t_step != 0 and analysis_t_step != 0:
            analysis_frame_step = analysis_t_step / acq_t_step

            if round(analysis_frame_step) == analysis_frame_step:
                time_steps_not_ok = False
                settings.zero_timepoint_frame = zero_f
                settings.analysis_frame_step = analysis_frame_step
        if time_steps_not_ok:
            warning_dlg = GenericDialog("Error!")
            warning_dlg.addMessage(
                "Analysis time step must be an integer multiple of acquisition time steps, and neither should be zero!!"
            )
            warning_dlg.setOKLabel("Try again...")
            warning_dlg.showDialog()

            if warning_dlg.wasCanceled():
                return

    start_frame = int(((zero_f - 1) % analysis_frame_step) + 1)
    end_frame = int(imp.getNFrames() -
                    (imp.getNFrames() - zero_f) % analysis_frame_step)
    frames = [
        f + 1
        for f in range(start_frame - 1, end_frame, int(analysis_frame_step))
    ]
    print("frames = " + str(frames))
    imp.killRoi()
    analysis_imp = SubstackMaker().makeSubstack(
        imp,
        str(start_frame) + "-" + str(end_frame) + "-" +
        str(int(analysis_frame_step)))
    imp.changes = False
    imp.close()
    analysis_imp.show()
    drawn_membranes = [
        TimepointsMembranes(input_image_title=im_title,
                            time_point_s=(t - 1) * acq_t_step) for t in frames
    ]
    membranes_listener = UpdateRoiImageListener(drawn_membranes)
    analysis_imp.addImageListener(membranes_listener)

    # now attach roi listener to store all 0th membranes after showing a waitforuserdialog to prompt continuation
    IJ.setTool("freeline")
    for membrane_idx in membrane_indices:
        #		if membrane_idx>50:
        #			IJ.setTool("line");
        analysis_imp.killRoi()
        membranes_listener.resetLastFrame()
        membranes_listener.setCurrentMembraneIndex(membrane_idx)
        analysis_imp.setZ(1)
        continue_dlg = WaitForUserDialog(
            "Continue?", "Click OK once all the " + str(membrane_idx) +
            "-index membranes have been drawn")
        continue_dlg.show()
        membranes_listener.imageUpdated(analysis_imp)
        drawn_membranes = membranes_listener.getDrawnMembraneTimepointsList()
        json_path = os.path.join(output_root,
                                 "Membranes " + timestamp + ".json")
        f = open(json_path, 'w+')
        try:
            json.dump(drawn_membranes, f, default=encode_membrane)
        finally:
            f.close()
        # save csv containing mebrane measurements for current membrane index
        csv_path = os.path.join(
            output_root, ("Membrane measurements " + timestamp + ".csv"))
        if membrane_idx == membrane_indices[0]:
            try:
                f = open(csv_path, 'wb')
                writer = csv.writer(f)
                writer.writerow([
                    "Membrane index", ("Time point, " + cal.getTimeUnit()),
                    ("Membrane length, " + cal.getUnit()),
                    ("Euclidean length, " + cal.getUnit()),
                    "Membrane sinuoisty"
                ])
            finally:
                f.close()
        try:
            f = open(csv_path, 'ab')
            writer = csv.writer(f)
            for mems in drawn_membranes:
                mem = mems.getMembrane(membrane_idx)
                if mem is not None:
                    writer.writerow([
                        membrane_idx, mems.time_point_s,
                        mem.getPathLength() * cal.pixelWidth,
                        mem.getEuclidean() * cal.pixelWidth,
                        mem.getSinuosity()
                    ])
        finally:
            f.close()

    settings.persistSettings()
    settings.save_settings()
    print("Finished getting all membranes with indices " +
          str(membrane_indices))
    analysis_imp.close()
def poreDetectionUV(inputImp, inputDataset, inputRoi, ops, data, display, detectionParameters):

	# set calibration
	detectionParameters.setCalibration(inputImp);
	
	# calculate area of roi 
	stats=inputImp.getStatistics()
	inputRoiArea=stats.area
	
	# get the bounding box of the active roi
	inputRec = inputRoi.getBounds()
	x1=long(inputRec.getX())
	y1=long(inputRec.getY())
	x2=x1+long(inputRec.getWidth())-1
	y2=y1+long(inputRec.getHeight())-1
	
	# crop the roi
	interval=FinalInterval( array([x1, y1 ,0], 'l'), array([x2, y2, 2], 'l') )
	#cropped=ops.image().crop(interval, None, inputDataset.getImgPlus() ) 
	cropped=ops.image().crop(inputDataset.getImgPlus() , interval) 
	
	datacropped=data.create(cropped)
	display.createDisplay("cropped", datacropped)
	croppedPlus=IJ.getImage()
	
	# instantiate the duplicator and the substackmaker classes
	duplicator=Duplicator()
	substackMaker=SubstackMaker()
	
	# duplicate the roi
	duplicate=duplicator.run(croppedPlus)
	
	# convert duplicate of roi to HSB and get brightness
	IJ.run(duplicate, "HSB Stack", "");
	brightnessPlus=substackMaker.makeSubstack(duplicate, "3-3")
	brightness=ImgPlus(ImageJFunctions.wrapByte(brightnessPlus))
	brightnessPlus.setTitle("Brightness")
	#brightnessPlus.show()
	
	# make another duplicate, split channels and get red
	duplicate=duplicator.run(croppedPlus)
	channels=ChannelSplitter().split(duplicate)
	redPlus=channels[0]
	red=ImgPlus(ImageJFunctions.wrapByte(redPlus))
	
	# convert to lab
	IJ.run(croppedPlus, "Color Transformer", "colour=Lab")
	IJ.selectWindow('Lab')
	labPlus=IJ.getImage()

	croppedPlus.changes=False
	croppedPlus.close()
	
	# get the A channel
	APlus=substackMaker.makeSubstack(labPlus, "2-2")
	APlus.setTitle('A')
	#APlus.show()
	APlus.getProcessor().resetMinAndMax()
	#APlus.updateAndDraw()
	AThresholded=threshold(APlus, -10, 50)
	
	# get the B channel
	BPlus=substackMaker.makeSubstack(labPlus, "3-3")
	BPlus.setTitle('B')
	#BPlus.show()
	BPlus.getProcessor().resetMinAndMax()
	#BPlus.updateAndDraw()
	BThresholded=threshold(BPlus, -10, 50)
	
	# AND the Athreshold and Bthreshold to get a map of the red pixels
	ic = ImageCalculator();
	redMask = ic.run("AND create", AThresholded, BThresholded);
	IJ.run(redMask, "Divide...", "value=255");
	
	labPlus.close()

	fast=True
	
	# threshold the spots from the red channel
	if (fast==False):
		thresholdedred=SpotDetectionGray(red, data, display, ops, "triangle")
		impthresholdedred = ImageJFunctions.wrap(thresholdedred, "wrapped")
	else:
		impthresholdedred=SpotDetection2(redPlus)
	
	# threshold the spots from the brightness channel
	if (fast==False):
		thresholded=SpotDetectionGray(brightness, data, display, ops, "triangle")
		impthresholded=ImageJFunctions.wrap(thresholded, "wrapped")
	else:
		impthresholded=SpotDetection2(brightnessPlus)
		
	# or the thresholding results from red and brightness channel
	impthresholded = ic.run("OR create", impthresholded, impthresholdedred);
	
	roim=RoiManager(True)
	
	# convert to mask
	Prefs.blackBackground = True
	IJ.run(impthresholded, "Convert to Mask", "")
	
	def isRed(imp, roi):
		stats = imp.getStatistics()
	
		if (stats.mean>detectionParameters.porphyrinRedPercentage): return True
		else: return False
	
	def notRed(imp, roi):
		stats = imp.getStatistics()
	
		if (stats.mean>detectionParameters.porphyrinRedPercentage): return False
		else: return True


	roiClone=inputRoi.clone()
	roiClone.setLocation(0,0)
	Utility.clearOutsideRoi(impthresholded, roiClone)

	impthresholded.show()
	
	countParticles(impthresholded, roim, detectionParameters.porphyrinMinSize, detectionParameters.porphyrinMaxSize, \
		detectionParameters.porphyrinMinCircularity, detectionParameters.porphyrinMaxCircularity)
	
	uvPoreList=[]
	for roi in roim.getRoisAsArray():
		uvPoreList.append(roi.clone())

	
	#allList=uvPoreList+closedPoresList+openPoresList
	
	# count particles that are porphyrins (red)
	porphyrinList=CountParticles.filterParticlesWithFunction(redMask, uvPoreList, isRed)
	# count particles that are visible on uv but not porphyrins
	sebumList=CountParticles.filterParticlesWithFunction(redMask, uvPoreList, notRed)

	
	# for each roi add the offset such that the roi is positioned in the correct location for the 
	# original image
	[roi.setLocation(roi.getXBase()+x1, roi.getYBase()+y1) for roi in uvPoreList]
	
	# draw the ROIs on to the image
	inputImp.getProcessor().setColor(Color.green)
	IJ.run(inputImp, "Line Width...", "line=3");
	inputImp.getProcessor().draw(inputRoi)
	IJ.run(inputImp, "Line Width...", "line=1");
	[CountParticles.drawParticleOnImage(inputImp, roi, Color.magenta) for roi in porphyrinList]
	[CountParticles.drawParticleOnImage(inputImp, roi, Color.green) for roi in sebumList]	
	inputImp.updateAndDraw()

	# calculate stats for the UV visible particles
	detectionParameters.setCalibration(APlus)
	statsDictUV=CountParticles.calculateParticleStatsUV(APlus, BPlus, redMask, roim.getRoisAsArray())
	
	totalUVPoreArea=0
	for area in statsDictUV['Areas']:
		totalUVPoreArea=totalUVPoreArea+area
	averageUVPoreArea=totalUVPoreArea/len(statsDictUV['Areas'])

	poreDiameter=0
	for diameter in statsDictUV['Diameters']:
		poreDiameter=poreDiameter+diameter
	poreDiameter=poreDiameter/len(statsDictUV['Diameters'])

	redTotal=0
	for red in statsDictUV['redPercentage']:
		redTotal=redTotal+red
	redAverage=redTotal/len(statsDictUV['redPercentage'])

	statslist=[len(porphyrinList), 100*redAverage];
	statsheader=[Messages.Porphyrins,  Messages.PercentageRedPixels]

	print("Roi Area: "+str(inputRoiArea))
	print("Total Pore Area: "+str(totalUVPoreArea))
	print("Average Pore Area: "+str(averageUVPoreArea))
	print str(len(uvPoreList))+" "+str(len(porphyrinList))+" "+str(len(sebumList))+" "+str(100*totalUVPoreArea/inputRoiArea)+" "+str(100*redAverage)
	print "cp min circularity"+str(detectionParameters.closedPoresMinCircularity)+":"+str(detectionParameters.closedPoresMinSize)

	# close the thresholded image
	impthresholded.changes=False
	impthresholded.close()
	
	return uvPoreList, statslist, statsheader
Exemple #5
0
def poreDetectionUV(inputImp, inputDataset, inputRoi, ops, data, display,
                    detectionParameters):

    # set calibration
    detectionParameters.setCalibration(inputImp)

    # calculate area of roi
    stats = inputImp.getStatistics()
    inputRoiArea = stats.area

    # get the bounding box of the active roi
    inputRec = inputRoi.getBounds()
    x1 = long(inputRec.getX())
    y1 = long(inputRec.getY())
    x2 = x1 + long(inputRec.getWidth()) - 1
    y2 = y1 + long(inputRec.getHeight()) - 1

    # crop the roi
    interval = FinalInterval(array([x1, y1, 0], 'l'), array([x2, y2, 2], 'l'))
    #cropped=ops.image().crop(interval, None, inputDataset.getImgPlus() )
    cropped = ops.image().crop(inputDataset.getImgPlus(), interval)

    datacropped = data.create(cropped)
    display.createDisplay("cropped", datacropped)
    croppedPlus = IJ.getImage()

    # instantiate the duplicator and the substackmaker classes
    duplicator = Duplicator()
    substackMaker = SubstackMaker()

    # duplicate the roi
    duplicate = duplicator.run(croppedPlus)

    # convert duplicate of roi to HSB and get brightness
    IJ.run(duplicate, "HSB Stack", "")
    brightnessPlus = substackMaker.makeSubstack(duplicate, "3-3")
    brightness = ImgPlus(ImageJFunctions.wrapByte(brightnessPlus))
    brightnessPlus.setTitle("Brightness")
    #brightnessPlus.show()

    # make another duplicate, split channels and get red
    duplicate = duplicator.run(croppedPlus)
    channels = ChannelSplitter().split(duplicate)
    redPlus = channels[0]
    red = ImgPlus(ImageJFunctions.wrapByte(redPlus))

    # convert to lab
    IJ.run(croppedPlus, "Color Transformer", "colour=Lab")
    IJ.selectWindow('Lab')
    labPlus = IJ.getImage()

    croppedPlus.changes = False
    croppedPlus.close()

    # get the A channel
    APlus = substackMaker.makeSubstack(labPlus, "2-2")
    APlus.setTitle('A')
    #APlus.show()
    APlus.getProcessor().resetMinAndMax()
    #APlus.updateAndDraw()
    AThresholded = threshold(APlus, -10, 50)

    # get the B channel
    BPlus = substackMaker.makeSubstack(labPlus, "3-3")
    BPlus.setTitle('B')
    #BPlus.show()
    BPlus.getProcessor().resetMinAndMax()
    #BPlus.updateAndDraw()
    BThresholded = threshold(BPlus, -10, 50)

    # AND the Athreshold and Bthreshold to get a map of the red pixels
    ic = ImageCalculator()
    redMask = ic.run("AND create", AThresholded, BThresholded)
    IJ.run(redMask, "Divide...", "value=255")

    labPlus.close()

    fast = True

    # threshold the spots from the red channel
    if (fast == False):
        thresholdedred = SpotDetectionGray(red, data, display, ops, "triangle")
        impthresholdedred = ImageJFunctions.wrap(thresholdedred, "wrapped")
    else:
        impthresholdedred = SpotDetection2(redPlus)

    # threshold the spots from the brightness channel
    if (fast == False):
        thresholded = SpotDetectionGray(brightness, data, display, ops,
                                        "triangle")
        impthresholded = ImageJFunctions.wrap(thresholded, "wrapped")
    else:
        impthresholded = SpotDetection2(brightnessPlus)

    # or the thresholding results from red and brightness channel
    impthresholded = ic.run("OR create", impthresholded, impthresholdedred)

    roim = RoiManager(True)

    # convert to mask
    Prefs.blackBackground = True
    IJ.run(impthresholded, "Convert to Mask", "")

    def isRed(imp, roi):
        stats = imp.getStatistics()

        if (stats.mean > detectionParameters.porphyrinRedPercentage):
            return True
        else:
            return False

    def notRed(imp, roi):
        stats = imp.getStatistics()

        if (stats.mean > detectionParameters.porphyrinRedPercentage):
            return False
        else:
            return True

    roiClone = inputRoi.clone()
    roiClone.setLocation(0, 0)
    Utility.clearOutsideRoi(impthresholded, roiClone)

    impthresholded.show()

    countParticles(impthresholded, roim, detectionParameters.porphyrinMinSize, detectionParameters.porphyrinMaxSize, \
     detectionParameters.porphyrinMinCircularity, detectionParameters.porphyrinMaxCircularity)

    uvPoreList = []
    for roi in roim.getRoisAsArray():
        uvPoreList.append(roi.clone())

    #allList=uvPoreList+closedPoresList+openPoresList

    # count particles that are porphyrins (red)
    porphyrinList = CountParticles.filterParticlesWithFunction(
        redMask, uvPoreList, isRed)
    # count particles that are visible on uv but not porphyrins
    sebumList = CountParticles.filterParticlesWithFunction(
        redMask, uvPoreList, notRed)

    # for each roi add the offset such that the roi is positioned in the correct location for the
    # original image
    [
        roi.setLocation(roi.getXBase() + x1,
                        roi.getYBase() + y1) for roi in uvPoreList
    ]

    # draw the ROIs on to the image
    inputImp.getProcessor().setColor(Color.green)
    IJ.run(inputImp, "Line Width...", "line=3")
    inputImp.getProcessor().draw(inputRoi)
    IJ.run(inputImp, "Line Width...", "line=1")
    [
        CountParticles.drawParticleOnImage(inputImp, roi, Color.magenta)
        for roi in porphyrinList
    ]
    [
        CountParticles.drawParticleOnImage(inputImp, roi, Color.green)
        for roi in sebumList
    ]
    inputImp.updateAndDraw()

    # calculate stats for the UV visible particles
    detectionParameters.setCalibration(APlus)
    statsDictUV = CountParticles.calculateParticleStatsUV(
        APlus, BPlus, redMask, roim.getRoisAsArray())

    totalUVPoreArea = 0
    for area in statsDictUV['Areas']:
        totalUVPoreArea = totalUVPoreArea + area
    averageUVPoreArea = totalUVPoreArea / len(statsDictUV['Areas'])

    poreDiameter = 0
    for diameter in statsDictUV['Diameters']:
        poreDiameter = poreDiameter + diameter
    poreDiameter = poreDiameter / len(statsDictUV['Diameters'])

    redTotal = 0

    for red in statsDictUV['redPercentage']:
        redTotal = redTotal + red
    redAverage = redTotal / len(statsDictUV['redPercentage'])

    statslist = [len(porphyrinList), 100 * redAverage]
    statsheader = [Messages.Porphyrins, Messages.PercentageRedPixels]

    print("Roi Area: " + str(inputRoiArea))
    print("Total Pore Area: " + str(totalUVPoreArea))
    print("Average Pore Area: " + str(averageUVPoreArea))
    print str(len(uvPoreList)) + " " + str(len(porphyrinList)) + " " + str(
        len(sebumList)) + " " + str(
            100 * totalUVPoreArea / inputRoiArea) + " " + str(100 * redAverage)
    print "cp min circularity" + str(
        detectionParameters.closedPoresMinCircularity) + ":" + str(
            detectionParameters.closedPoresMinSize)

    # close the thresholded image
    impthresholded.changes = False
    impthresholded.close()

    return uvPoreList, statslist, statsheader
def poreDetectionTrueColor(inputImp, inputDataset, inputRoi, ops, data,
                           display, detectionParameters):

    detectionParameters.setCalibration(inputImp)

    # calculate area of roi
    stats = inputImp.getStatistics()
    inputRoiArea = stats.area

    # get the bounding box of the active roi
    inputRec = inputRoi.getBounds()
    x1 = long(inputRec.getX())
    y1 = long(inputRec.getY())
    x2 = x1 + long(inputRec.getWidth()) - 1
    y2 = y1 + long(inputRec.getHeight()) - 1

    # crop the roi
    interval = FinalInterval(array([x1, y1, 0], 'l'), array([x2, y2, 2], 'l'))
    cropped = ops.crop(interval, None, inputDataset.getImgPlus())

    datacropped = data.create(cropped)
    display.createDisplay("cropped", datacropped)
    croppedPlus = IJ.getImage()

    duplicator = Duplicator()
    substackMaker = SubstackMaker()
    # duplicate the roi
    duplicate = duplicator.run(croppedPlus)

    # separate into RGB and get the blue channel
    IJ.run(duplicate, "RGB Stack", "")
    bluePlus = substackMaker.makeSubstack(duplicate, "3-3")
    blue = ImgPlus(ImageJFunctions.wrapByte(bluePlus))
    bluePlus.setTitle("Blue")

    # duplicate and look for bright spots
    thresholdedLight = SpotDetection2(bluePlus)

    # duplicate and look for dark spots
    thresholdedDark = SpotDetection3(bluePlus, True)

    # convert to mask
    Prefs.blackBackground = True
    #IJ.run(thresholdedDark, "Convert to Mask", "")

    # clear the region outside the roi
    clone = inputRoi.clone()
    clone.setLocation(0, 0)
    Utility.clearOutsideRoi(thresholdedLight, clone)
    Utility.clearOutsideRoi(thresholdedDark, clone)
    roimClosedPores = RoiManager(True)
    detectionParameters.setCalibration(thresholdedDark)
    countParticles(thresholdedDark, roimClosedPores, detectionParameters.closedPoresMinSize, detectionParameters.closedPoresMaxSize, \
     detectionParameters.closedPoresMinCircularity, detectionParameters.closedPoresMaxCircularity)

    # count number of open pores
    roimOpenPores = RoiManager(True)
    detectionParameters.setCalibration(thresholdedDark)
    countParticles(thresholdedDark, roimOpenPores, detectionParameters.openPoresMinSize, detectionParameters.openPoresMaxSize, \
     detectionParameters.openPoresMinCircularity, detectionParameters.openPoresMaxCircularity)

    # count number of sebum
    roimSebum = RoiManager(True)
    detectionParameters.setCalibration(thresholdedLight)
    countParticles(thresholdedLight, roimSebum, detectionParameters.sebumMinSize, detectionParameters.sebumMaxSize, \
     detectionParameters.sebumMinCircularity, detectionParameters.sebumMaxCircularity)

    # create lists for open and closed pores
    closedPoresList = []
    for roi in roimClosedPores.getRoisAsArray():
        closedPoresList.append(roi.clone())
    openPoresList = []
    for roi in roimOpenPores.getRoisAsArray():
        openPoresList.append(roi.clone())

    # create lists for sebum
    sebumsList = []
    for roi in roimSebum.getRoisAsArray():
        sebumsList.append(roi.clone())

    # a list of all pores
    allList = closedPoresList + openPoresList + sebumsList

    # calculate the stats for all pores
    detectionParameters.setCalibration(bluePlus)
    statsDict = CountParticles.calculateParticleStats(bluePlus, allList)

    poresTotalArea = 0
    for area in statsDict['Areas']:
        poresTotalArea = poresTotalArea + area
        print area
    poresAverageArea = poresTotalArea / len(statsDict['Areas'])

    # for each roi add the offset such that the roi is positioned in the correct location for the
    # original image
    [
        roi.setLocation(roi.getXBase() + x1,
                        roi.getYBase() + y1) for roi in allList
    ]

    # draw the rois on the image
    inputImp.getProcessor().setColor(Color.green)
    IJ.run(inputImp, "Line Width...", "line=3")
    inputImp.getProcessor().draw(inputRoi)
    IJ.run(inputImp, "Line Width...", "line=1")
    [
        CountParticles.drawParticleOnImage(inputImp, roi, Color.red)
        for roi in closedPoresList
    ]
    [
        CountParticles.drawParticleOnImage(inputImp, roi, Color.magenta)
        for roi in openPoresList
    ]
    [
        CountParticles.drawParticleOnImage(inputImp, roi, Color.green)
        for roi in sebumsList
    ]

    inputImp.updateAndDraw()

    # close images that represent intermediate steps
    croppedPlus.changes = False
    croppedPlus.close()
    bluePlus.changes = False
    bluePlus.close()

    print "Total ROI Area: " + str(inputRoiArea)
    print "Num closed pores: " + str(len(closedPoresList))
    print "Num open pores: " + str(len(openPoresList))
    print "Num sebums: " + str(len(sebumsList))

    print "Total particles: " + str(
        len(allList)) + " total area: " + str(poresTotalArea)

    statslist = [
        inputRoiArea,
        len(allList),
        len(closedPoresList),
        len(openPoresList),
        len(sebumsList), poresAverageArea, 100 * poresTotalArea / inputRoiArea
    ]
    header = [
        Messages.TotalAreaMask, Messages.TotalDetectedPores,
        Messages.ClosedPores, Messages.OpenPores, Messages.Sebum,
        Messages.PoresAverageArea, Messages.PoresFractionalArea
    ]

    return header, statslist