Re: Help writing a macro-with pictures!

Posted by EHB2010 on
URL: http://imagej.273.s1.nabble.com/Help-writing-a-macro-with-pictures-tp3688441p3688444.html

it won't let me post this as there were too many words containing "a***" so pretend the '*' are 'a'

Hi Gabrielle,

I think it might be worth learning a little Java (or possibly macro). It's a lot simpler than you think. To get you started here is a java plug-in that I quickly wrote. I wrote it to be as short, simple and understandable as possible, but at the expense of being slow and not very user friendly. It may also have mistakes; i've only been through it with a debugger once.

There are values near the top WRITTEN_LIKE_THIS immediately below "public class SerotoninClusterAn*lyser_  implements PlugIn {". You will want to experiment to see what the best settings are (the number to the right of the '=').
apologies if this is too simple. I don't know how much programming you've ever done.
THRESHOLD_DENSITY is the really important one. This is the density of positive pixels (black circles on your pic) below which is outside of the cluster.  A value of 1 = all pixels in that ring are above threshold brightness. 0 means none. I've set it to 0.3 for no particular reason.
RADIUS_INCREMENT is the distance, in pixels, between the green circles in your picture
MAXIMUM_NUMBER_OF_RADIUS_INCREMENTS is the maximum number of green circles
THRESHOLD_FOR_POSITIVE_FLUORESCENSE. In your picture you have either black circles or white background. this is the threshold that defines a positive (black circle in your pic) pixel; it needs to be a number between 0 (black)and 255 (white).
MINIMUM_NUMBER_OF_INCREMENTS. Drawing concentric circles like in your pic is difficult with square pixels if the circle is really small. You might want to start bigger than 1 increment, although I've set the default to 1. I include that setting because it is something to think about and increasing it might need some rewriting of other parts of the code.

obviously it is a pain to change these numbers manually and recompile the file each time so you'll probably want to add a graphical interface. There's also a lot of ways of speeding up the plugin and it only uses 1 thread so lots to be worked on. (and there may be mistakes).

to run it you need to do your point selection of maxima and then press cmd+m (mac) or ?ctrl+m (pc) to measure them and open the results table. It won't work if you don't do that. You should also make sure the results table is clear before doing the measurement, otherwise you'll confuse the plugin. Then run the plugin but make sure the image you want to an*lyse is the current window or you'll end up analysing the wrong picture. Clearly you could make the whole process much slicker with better code.

There's inaccuracy at the margins of the image, because obviously we don't know how bright the pixels outside the image are. You might want to select a region of interest from which "find maxima" that doesn't include the margins of the pic.

I've included some download links for the java file and compiled plugin, but the links are not permanent.

And don't forget there may be mistakes!

------------start of plugin
import ij.plugin.PlugIn;
import ij.process.ImageProcessor;
import ij.IJ;
import ij.ImagePlus;
import ij.WindowManager;
import ij.measure.*;
 
public class SerotoninClusterAn*lyser_  implements PlugIn {
        private final static double RADIUS_INCREMENT_IN_PIXELS = 1.5;//you will probably want to change the number
        private final static int MAXIMUM_NUMBER_OF_RADIUS_INCREMENTS = 25;//you will probably want to change the number
        private final static byte THRESHOLD_FOR_POSITIVE_FLUORESCENSE = 100;//you will probably want to change the number
        private final static int MINIMUM_NUMBER_OF_INCREMENTS = 1;//you may want to change the number
        private final static double THRESHOLD_DENSITY = 0.3; //you may want to change this to value between 0 (none) and 1 (all)
        private final static String AREA_COLUMN_HEADING = "area (pixels)";
        private final static String DENSITY_COLUMN_HEADING = "density (%)";
        private final static String MEAN_FLUORESCENCE_OF_CLUSTER = "Mean F";
        private ImagePlus imp = WindowManager.getCurrentImage();//get the current image
        private ResultsTable rt = ResultsTable.getResultsTable();//get the main results table
        private float[] xCoordinates;
        private float[] yCoordinates;
        private int height;
        private int width;
       
       
        public void run(String arg) {
               
               
                int xColumnNumber = rt.getColumnIndex("X");
                int yColumnNumber = rt.getColumnIndex("Y");
                if (xColumnNumber != -1 ) {//checks results table is open
                        xCoordinates = rt.getColumn(xColumnNumber);
                        yCoordinates = rt.getColumn(yColumnNumber);
                }
               
                imp = WindowManager.getCurrentImage();
                if (imp != null && imp.getBitDepth() == 8 && xCoordinates != null){//only analyse if there is an image and it is 8 bit and there are coordinates
                        doTheProcessing();//start processing
                }
        }
        private final void doTheProcessing() {
                rt.addColumns();//we need to add two new column for data
                rt.getFreeColumn(AREA_COLUMN_HEADING);
                rt.addColumns();
                rt.getFreeColumn(DENSITY_COLUMN_HEADING);
                rt.addColumns();
                rt.getFreeColumn(MEAN_FLUORESCENCE_OF_CLUSTER);
                width = imp.getWidth();//get the image width
                height = imp.getHeight();//get the image height
                ImageProcessor byteip = imp.getProcessor();//get the imageprocessor that contains the pixel data
                double previousRadius = 0;
                //this bit won't make sense unless you understand nested loops
                for (int i = 0 ; i < xCoordinates.length ; ++i) { //run through each centre point
                        int aSpecificXCoordinate = (int) xCoordinates[i];//assign the particular x coordinate
                        int aSpecificYCoordinate = (int) yCoordinates[i];//assigns the particular y coordinate
                        double currentOverallDensity = 1;//it starts as 1 as it is the peak pixel
                        int currentOverAllArea = 1;//it is 1 because of the centre pixel being positive;
                        double totalFluorescence = byteip.getPixel(aSpecificXCoordinate, aSpecificYCoordinate);
                        moveToNextCoordinate://break point for when found size
                        for (int j = MINIMUM_NUMBER_OF_INCREMENTS ; j <= MAXIMUM_NUMBER_OF_RADIUS_INCREMENTS; ++j ) { //sequentially adds more radius increments; starts at 1
                                double currentRadius = j * RADIUS_INCREMENT_IN_PIXELS;//sets current radius
                                int totalPixelsInThisRing = 0;
                                int positivePixelCountInThisRing = 0;
                                double fluorescenceInThisRing = 0;
                                for (int k = 0 ; k < width ; ++k) {//run along the columns in turn
                                        for (int l = 0 ; l < height ; ++l) {//run along the rows in turn
                                                double distanceCurrentPixelToTheCentrePixel = Math.sqrt(((aSpecificXCoordinate-k)*(aSpecificXCoordinate-k))+((aSpecificYCoordinate-l)*(aSpecificYCoordinate-l)));
                                                //now we want to see if the pixel in within the current ring
                                                if (distanceCurrentPixelToTheCentrePixel <= currentRadius && distanceCurrentPixelToTheCentrePixel > previousRadius) {
                                                        totalPixelsInThisRing = totalPixelsInThisRing + 1;//increase pixel count by 1
                                                        fluorescenceInThisRing = fluorescenceInThisRing + byteip.getPixel(k,l);
                                                        if (byteip.getPixel(k,l) > THRESHOLD_FOR_POSITIVE_FLUORESCENSE ){
                                                                positivePixelCountInThisRing = positivePixelCountInThisRing + 1;//increment positive pixel count
                                                        }
                                                }
                                        }
                                } // now calculate the density in this ring
                                double density = positivePixelCountInThisRing/(totalPixelsInThisRing*1.0);
                                if (density > THRESHOLD_DENSITY) {//if still above threshold include these pixels
                                        currentOverallDensity = ((density*totalPixelsInThisRing)+(currentOverallDensity*currentOverAllArea))/(currentOverAllArea+totalPixelsInThisRing);
                                        currentOverAllArea = currentOverAllArea + totalPixelsInThisRing;
                                        totalFluorescence = totalFluorescence + fluorescenceInThisRing;
                                } else { //else measurements in table and move to next maximum point.
                                        int currentCount = rt.getCounter();
                                    if (currentCount < i+1 ) {//just checks we are not going to go out of bounds. probably unnecessary but I don't understand the counter
                                    rt.incrementCounter();
                                    }
                                    if (currentOverAllArea == 1) { //ie there is only 1 pixel in this cluster
                                    currentOverallDensity = 1; //if there is only 1 pixel then our percentage is clearly 100
                                    }
                                        rt.setValue(AREA_COLUMN_HEADING, i, (double) currentOverAllArea);//sets the table
                                        rt.setValue(DENSITY_COLUMN_HEADING, i, currentOverallDensity*100);//sets the table
                                        rt.setValue(MEAN_FLUORESCENCE_OF_CLUSTER, i, totalFluorescence/currentOverAllArea);
                                        IJ.showProgress(i/(xCoordinates.length-1.0));
                                        break moveToNextCoordinate;
                                       
                                }
                        }
                }
                rt.show("Results");
        }
}
--------end plugin
                downloadable from :
       
http://dl.dropbox.com/u/2014897/SerotoninClusterAnalyser_.class
http://dl.dropbox.com/u/2014897/SerotoninClusterAnalyser_.java