ImageJ: Wrong transferrence of Coordinates from channel to channel

Hello Community,
for my Thesis I must count cells on pictures stained with Immunofluorescence and I am writing a macro in ImageJ to do it for me. For this I coloursplit the picture, analyse particles in the red channel (my Antibody´s colour) and then I want to take the coordinates of analysed particles and only count them if at the same coordinates in the blue channel there is also a staining (DAPI - just a general cell staining).
This way I assure that there is as little dirt counted as possible.
The problem is that when I get the coordinates from the red channel out of the results table and use them to makePoint(x,y) in the blue channel the coordinates are “distorted” - usually the correct coordinates but plus 4ish, though never in exactly the same, which is why i can´t simply distract a number from the coordinates.
I had this answer on another forum: " So the issue is that the centres in the blue channel are correct but do not match the red channel? This could mean that there is a registration problem between channels or spherical aberration which is distorting things. You might be better asking on this site"
Below I first write down the critical lines of code, then the whole code.

run("Analyze Particles...", "  circularity=r1-r2 display clear in_situ");
                roiManager("deselect");
                z=nResults;

                for (j=0; j<z; j++) {   //loops through the Results table and adds to "counter" if a match is found
                    selectImage(channelsplit[2]);   //selects blue window
                    setThreshold(d,l);
                    run("Threshold...");
                    setOption("BlackBackground", true);
                    run("Convert to Mask", "method=Default background=Default black");
                    run("Coordinates...", "left=0 right=19373 top=0 bottom=13600"); //I tried to set the boundaries of the pictures equally, but it didnt work
                    makePoint(getResult("X", j)), (getResult("Y", j));
                    print ("X" + j + ": " + getResult("X",j));  //this and the following line are not to be in the program, once it works
                    print ("Y" + j + ": " + getResult("Y",j));
                    run ("Measure");
                    if (getResult("Mean", nResults-1)>100) {
                        counter++;
                    }
                } //for j
                print (i + ": " + counter);
setBatchMode(true);
if (isOpen("ROI Manager")) {
    r=roiManager("count");
} else {
    setBatchMode(false);
    exit("You need a ROI Manager open with the ROIs of all the pictures to be measured");
}

Dialog.create ("Variables")

Dialog.addCheckbox ("red", true);
Dialog.addCheckbox ("green", false);
Dialog.addCheckbox ("blue", false);
Dialog.addCheckbox ("watershed", true);

Dialog.addNumber ("Thresholddark:", 110);
Dialog.addNumber ("Thresholdlight:", 255);
Dialog.addNumber ("greenThresholddark:", 110);
Dialog.addNumber ("greenThresholdlight:", 253);
Dialog.addNumber ("pmin:", 15);
Dialog.addNumber ("pmax:", 100);
Dialog.addNumber ("roundness1:", 0.5);
Dialog.addNumber ("roundness2:", 1.0);

Dialog.addMessage("batch - select 'true' for your macro to run faster, but you will not see what it does until finished\nstack - selecht this box if you use unstacked pictures and want them stacked, deselect if you use a readied stack or a single picture\nred - select this box if you want to count red coloured cells \ngreen - select this box if you want to count green coloured cells \nblue - select this box if you want to count blue coloured cells\nall variables are the same for the colours you count. It may be better to adjust variables for each colour and count seperately\nwatershed - select this box only if you have overlapping cells in your image\nThresholdlight - particles lighter than this won't be measured/counted \nThresholddark - particles darker than this won't be measured/counted \nThresholdlight and Thresholddark can be between 0 and 255 \ntry thresholding manually at least once manually to get best results \npmin -  particles with a size smaller than this won't be counted \npmax - particles with a size greater than this won't be counted")
Dialog.show ();

cr=Dialog.getCheckbox();
cg=Dialog.getCheckbox();
cb=Dialog.getCheckbox();
w=Dialog.getCheckbox();

d=Dialog.getNumber();
l=Dialog.getNumber();
dg=Dialog.getNumber();
lg=Dialog.getNumber();
pmin=Dialog.getNumber();
pmax=Dialog.getNumber();
r1=Dialog.getNumber();
r2=Dialog.getNumber();

dir = getDirectory("Choose a Directory ");  //choose the folder with all the pictures to be measured
listFiles(dir);                 //I found this in a listFiles recursively Demo and changed it to open my pictures

function listFiles(dir) {
    list = getFileList(dir);
    for (o=0; o<list.length; o++) {     //loops through the file list, opening then analysing then closing one after another
        if (endsWith(list[o], "/")) {
            listFiles(""+dir+list[i]);
        } else {
            open(dir + list[o]);
//the previous opens all pictures in a given folder in a way i do not understand
//I only use this function because I could not use the variable list.length outside of it for unknown reasons
//following is my cellcount program to be executed for each picture
//then the picture will be closed before the new one is opened
            run("Split Channels");
            channelsplit = getList("image.titles");
            if (cr==1) {
            a=0;
            }
            if (cg==1) {
            a=1;
            }

            selectImage(channelsplit[a]);   //selects red or green window, depending on input in the Dialog
            setThreshold(d,l);
            run("Threshold...");
            setOption("BlackBackground", true);
            run("Convert to Mask", "method=Default background=Default black");
            run("Coordinates...", "left=0 right=19373 top=0 bottom=13600");

            for (i=2*o; i<=((2*o)+1); i++) {    //loops through two ROIs of the ROIManager
                counter=0;
                selectImage(channelsplit[a]);
                roiManager("deselect");
                roiManager("select", i);
                if (w==1) {
                    run("Watershed", "slice");
                }   
                run("Analyze Particles...", "  circularity=r1-r2 display clear in_situ");
                roiManager("deselect");
                z=nResults;

                for (j=0; j<z; j++) {   //loops through the Results table and adds to "counter" if a match is found
                    selectImage(channelsplit[2]);   //selects blue window
                    setThreshold(d,l);
                    run("Threshold...");
                    setOption("BlackBackground", true);
                    run("Convert to Mask", "method=Default background=Default black");
                    run("Coordinates...", "left=0 right=19373 top=0 bottom=13600"); //I tried to set the boundaries of the pictures equally, but it didnt work
                    makePoint(getResult("X", j)), (getResult("Y", j));
                    print ("X" + j + ": " + getResult("X",j));  //this and the following line are not to be in the program, once it works
                    print ("Y" + j + ": " + getResult("Y",j));
                    run ("Measure");
                    if (getResult("Mean", nResults-1)>100) {
                        counter++;
                    }
                } //for j
                print (i + ": " + counter);
                close("Results");   //closes Results to get the variables in order for the next window
//              IJ.renameResults("res" + i);
            } //for i
            close("*");     //closes all image windows to save RAM
        } //else
    } //for o
} //function
setBatchMode(false);

Thank you very much in advance

These is the help I have received before

  • don’t follow exactly, but X and Y will give the centre of the particle. The run("Coordinates...") is confusing things and there is an error in syntax in the following line, should be makePoint(getResult("X", j), getResult("Y", j)); – [quantixed]

  • Thanks, I tried without the run(“Coordinates…”) but then the coordinates for the Coordinates used for the makePoint(x,y) are wrong for about 4ish and a factor of 100. Because of the print(getResult(“X”, j) I know it does get the correct coordinates. It must be distorted by thresholding or the makePoint command. – [VincentH]

The change in Syntax for the makePoint didn´t change anything – VincentH yesterday

So the issue is that the centres in the blue channel are correct but do not match the red channel? This could mean that there is a registration problem between channels or spherical aberration which is distorting things. You might be better asking on this site – [quantixed]

Hello Vincent -

First, it would be very helpful if you could post an original,
unprocessed sample image that illustrates your issue. (Please
don’t post something like a jpeg version of your image that
would be marred by compression artifacts.)

If your image is so large as to be unwieldy, you could post a
cropped version, but make sure that the cropping is identical
on all slices so that it doesn’t introduce any misregistration
artifacts.

(I generally recommend posting png images when possible, as
they are not lossy, they are accepted by this forum, and they
display as images in most browsers.)

Some clarifying questions, in line, below:

What sort of image does your microscope acquire? Is it one single
image? Or is it multiple “slices” scanned separately (for example,
with different florescence illuminations)? If it scans slices separately,
what is the likelihood that your microscope introduces misregistration?

Does this mean that you start with a single RGB image, and you use
ImageJ to split it into three (RGB) channels? Or do you start with a
three-channel (or maybe more) image “stack?”

If I were to look at your original image, would it look misregistered
to me?

How big (in pixels) are your antibodies, and how big are your cells?
As you describe it, your two channels are only off by a few pixels.

For completeness, here is the link to Vincent’s stackoverflow post:

ImageJ: Wrong transferrence of Coordinates from picture to picture

(It doesn’t really say anything that he hasn’t included here.)

As an aside (not having a sample image, it’s hard to know whether
this would work well), I would likely proceed as follows:

First, figure out how to fix or account for you registration issue.

Run Analyze Particles... on your antibody slice. Leave the
resulting ROIs in the ROI Manager. Select your DAPI slice. Run
Measure from the ROI Manager. This will measure your DAPI slice
using the ROIs obtained from the antibody slice. Go through the
results in the Results Table to determine ROIs are properly stained
(and therefore correspond to cells). If all you need is a count, just
count the appropriate rows in the Results Table.

The point is that you don’t have to write your own code to transfer
ROIs / coordinates from one slice to the next. This is one of the
things that ROIs and the ROI Manager are designed to do.

Thanks, mm

Thank you for all the help
I have found the answer.
The problem was that the makePoint(x,y) as well as getValue(x,y) and getPixel(x,y) commands use their coordinates in Pixels whereas the results table gave them in inches.
After opening a window I added a run(Set Scale…) and removed any scaling.
Works like a charm now
The code in itself was correct, the run(“Coordinates…”) didn’t do anything so i left it out.