简体   繁体   中英

ImageJ - Drawing arrows linking Centroids of Two Images using a Plugin

So I'm doing a small project for my job where I'm required to take two images, one of nucleuses and one of golgi bodies and link them up by arrows with the two centroids as the endpoints. I've been wracking my brain for sometime now, and here's the source in java for my plugin. It's got some errors apparently, and I'm new to both java and imagej, so please bear with me... thanks in advance...

So the idea was that once the measurements were read into a large array, I would then proceed to find the closest corresponding nucleus per golgi body, and then link them up. To do this, I set up an array and found the minimum distance in that array, and then proceeded to draw it using a method that I found in someone else's plugin.

I should say that the results windows shows the x coordinates and y coordinates in two separate columns of a stack of images, one of which are about 1000 blue nucleuses, and 500 red golgi bodies, and the final column is the position in the stack.

I'm not quite sure what the issues are... I'm not understanding how drawing an image is done to the image processor... I've been reading some tutorials but I'm finding them relatively confusing...

import ij.*;
import ij.process.*;
import ij.gui.*; 
import java.awt.*;
import java.util.Arrays;
import java.util.Collections;
import ij.plugin.*;
import ij.plugin.filter.*;
import ij.measure.*;

public class CentroidFinder_ implements PlugInFilter {
     protected ImageStack cellstack;
     ImagePlus[] cellImages = cellstack.getImageArray();
     ImagePlus arrowImage = arrowImage.createImage("ArrayFile", 1600,1200,1);

     ResultsTable rt = Analyzer.getResultsTable();
     public int setup(String arg, ImagePlus imp) {
    cellstack = imp.getStack();

    this.imp = imp;
    return STACK_REQUIRED;
 }

public void run(ImageProcessor ip) 
{
    int[] blueCentroidsX = {};
    int[] blueCentroidsY = {};
    int[] redCentroidsX = {};
    int[] redCentroidsY = {};
    int xColumnIndex = rt.getColumnHeading("X");
    int yColumnIndex = rt.getColumnHeading("Y");
    int sliceNumberIndex = rt.getColumnHeading("Slice");


    float[] sliceCategoryPerRow = (rt.getColumn(sliceNumberIndex));

    for (int counter = 0; counter < sliceCategoryPerRow.Length; counter++)
    {
        if (sliceCategoryPerRow[counter] == 1)
        {
            blueCentroidsX[counter] = (int)(rt.getValueAsDouble(xColumnIndex, counter)); //This might be a source of error
            blueCentroidsY[counter] = (int)(rt.getValue(yColumnIndex, counter));
        }
        if (sliceCategoryPerRow[counter] == 2)
        {
            redCentroidsX[counter] = (int)rt.getValue(xColumnIndex, counter); //This might be a source of error
            redCentroidsY[counter] = (int)rt.getValue(yColumnIndex, counter);
        }
    }
    if ((blueCentroidsX.length + redCentroidsX.length) =! sliceCategoryPerRow.length)
    {
        error ("Error Message", "Something is wrong with the columns");
    }

    boolean blueIsBigger = true;

    if (blueCentroidsX.length < redCentroids.length)
        blueIsBigger = false;

    int[][] startingArrow = {};
    int[][] endingArrow = {};
    int[][] tempDistance = {};
    int counterTag;
    float[] distanceList = {};
    for (int j = 0; j < redCentroidsX.length; j++)
    {
        for (int k = 0; k < blueCentroidsX.length; k++)
        {
            tempDistance = distance (redCentroidsX[j], redCentroidsY[j], 
                                   blueCentroidsX[k], blueCentroidsY[k]);
            if (throwAwayDistance (tempDistance))
                continue;
            distanceList = distanceList.addAll({tempDistance, k});
        }
        if (distanceList.length == 0)
        {
            break;
        }
        counterTag = 0; 
        for (int l = 1; l < distanceList.length; l++)
        {
            if ((distanceList[l][0] < distanceList[l-1][0]))
                counterTag = distanceList[l][1];
        }
        startingArrow = startingArrow.addAll(({(int)blueCentroidsX[counterTag],
                                         (int)blueCentroidsY[counterTag])});
        endingArrow = add(endingArrow, {(int)redCentroidsX[j], int()redCentroidsY[j]});
    }
    if ((startingArrow.length != endingArrow.length)
        error ("Error Message", "Something has caused there not to be equal coordinates");

    for (int m = 0; m < startingArrow.length; m++)
    {
        for (int n = 0; n <endingArrow.length; n++)
        {
            drawArrow (imp, startingArrow[m][0], startingArrow[m][0],
                        endingArrow[n][0], endingArrow[n][1], 1)
        }
    }



stack.addSlice(arrowImage);

public void drawArrow(ImageProcessor ip, int x1, int y1, int x2, int y2, double size) 
{
    double dx = x2-x1;
    double dy = y2-y1;
    double ra = java.lang.Math.sqrt(dx*dx + dy*dy);
    dx /= ra;
    dy /= ra;
    int x3 = (int)Math.round(x2-dx*size);
    int y3 = (int)Math.round(y2-dy*size);
    double r = 0.3*size;
    int x4 = (int)Math.round(x3+dy*r);
    int y4 = (int)Math.round(y3-dx*r);
    int x5 = (int)Math.round(x3-dy*r);
    int y5 = (int)Math.round(y3+dx*r);
    ip.moveTo(x1, y1); ip.lineTo(x2, y2);
    ip.moveTo(x4,y4); ip.lineTo(x2,y2); ip.lineTo(x5,y5);
}
//Mathematical Functions:

public boolean throwAwayDistance (float distance)
{
    if (distance >= 25.0)
        return true;
    else return false;
}

public float distance (x1,y1,x2,y2)
{
    int length;
    return length = (((x1-x2)^2 + (y1-y2)^2)^(.5));
}   

}

Thank you all for all your help!

Since your code doesn't compile, it's hard to see what your issue is here without investing into some debugging.

Let me add some suggestions:

  • Since you say you're new to both ImageJ and Java, you should read this introduction on the Fiji wiki (Fiji is a distribution of ImageJ that includes a lot of useful plugins targeted at life sciences) as well as Albert Cardona's great tutorial .

  • You are using PlugInFilter which is designed to process single images, ie ImageProcessor s. Maybe using PlugIn would be more appropriate, since you are using multiple input images (or channels) and your output is yet in another image (although it might be in the same stack)

  • Your drawArrow method uses a low-level way to manipulate the output image (by the way you're handing over an ImagePlus where it expects an ImageProcessor , which will not work). An easier way would be to first perform your intended process within the GUI while recording the commands, then using these high-level commands in your plugin:

    • Within Fiji/ImageJ, click on Plugins > Macros > Record... and, at the 'Record:' dropdown menu, select Plugin .

    • Select the Arrow tool (right-click on the line selection tool), change the settings by double-clicking it, draw an arrow onto an open image, and finally add it to an Overlay via Image > Overlay > Add Selection... .

    • By following these steps, you end up with the following code in the Recorder window, that can easily be used in your plugin without the need of dealing with any pixel arrays:

IJ.run("Arrow Tool...", "width=2 size=10 color=black style=Filled");
        imp.setRoi(new Line(92, 184, 189, 131));
        IJ.run("Add Selection...", "");
  • You should be able to display the arrows in the overlay on top of your original image then.

Hope that helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM