First of all, I am so happy that we’re getting more and more members. Thank you all for joining!
I’m going to post the first question on here. Ideally, we should always try to post example images when asking a question, but I’m hypocritically not doing it mainly because I think it’s a straightforward question.
I’m trying to do some analysis on histology images using ImageJ macro scripting (IJM language), and at some point in the script I have the coordinates of an approximate center of a cell, derived from it’s cell body center of mass. However, my downstream quantification requires that I skeletonize. But now the coords may or may not fall on the 1-pixel wide skeleton. I need it to fall on it for subsequent analysis, so I want to find the nearest non-zero pixel to these coords on the skeleton image.
I did come up with an approach, and the script is enclosed below. But… it’s a bit slow, and it needs to be much faster because the script is gigantic.
The approach simply makes a circle centered on the coords I have, and the circle is only 10 pixels in radius, because it appears that’s enough to capture the skeleton’s nearest white pixel in all cases. Then I iterate through every pixel in this circular ROI computing its euclidean distance from my coords only if it’s non-zero (white).
Question: So you see how it’s not a quick approach, and if there is a plugin to do this instead, it would be so much faster because it’s skipping the wrapping. For context, this is part of a nested for loop for many many objects in many many regions in hundreds of images.
Here is the code:
// Making a circular 10-px radius ROI centered on coords
makeEllipse(CoordX-10, CoordY, CoordX+10, CoordY, 1);
Roi.getContainedPoints(containedX, containedY);
// Iterating through all pixels contained in the search circle
// Euclidean distance is calculated for non-zero pixels and tabulated
Table.create("Non-Zero Contained Pixels");
for (p = 0; p < containedX.length; p++) {
value = getPixel(containedX[p], containedY[p]);
selectWindow("Non-Zero Contained Pixels");
// Keeping indexing for the table independent of the loop as many pixels will be skipped
outOfLoopSize = Table.size;
if (value == 255) {
distance = sqrt(pow(containedX[p]-CoordX, 2)+pow(containedY[p]-CoordY, 2));
Table.set("CoordIndex", outOfLoopSize, p);
Table.set("Distance", outOfLoopSize, distance);
}
}
selectWindow("Non-Zero Contained Pixels");
// Sorting by distance and setting new coordinates
Table.sort("Distance");
Table.update;
nearestNeighbor = Table.get("CoordIndex", 0);
// Setting the new seed pixel for downstream quantification
seedX = containedX[nearestNeighbor];
seedY = containedY[nearestNeighbor];
close("Non-Zero Contained Pixels");
// Add computed seed for Sholl analysis
// i refers to a much larger for loop, just writing this for contextual information for this script excerpt
selectWindow("Skeleton" + i);
run("Select None");
Overlay.clear
updateDisplay();
makePoint(seedX, seedY, "small yellow hybrid");
Thanks a lot! And keep spreading the word :D
Okay, so I solved the issue for anyone curious. The improvement is a 59% faster computation, so days/over a week saved in terms of the big picture.
The new approach: I simply create a Euclidean distance map where each non zero pixel is now value-encoded with it’s distance from my coords. I do that with just two ramps, the Euclidean distance equation, and image arithmetic. And then simply threshold the image after getting min and max. Of course a few things to resolve equidistant pixels and such, but all good.