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_.classhttp://dl.dropbox.com/u/2014897/SerotoninClusterAnalyser_.java