Yes! I think that’s exactly what I need. Not sure how to do it, though. I have pasted below what I think is the code to get the size of the bounding box, but it would need to start from the objects already aligned to the inertia tensors. Can this be done directly from the results of the Particle analyser? Apologies if this is obvious, I don’t have much experience with coding in ImageJ
/**
* Find side lengths in pixels of the smallest stack to fit the aligned image
*
* @param E Rotation matrix
* @param imp Source image
* @param centroid 3D centroid in 3-element array {x,y,z}
* @param startSlice first slice of source image
* @param endSlice last slice of source image
* @param min minimum threshold
* @param max maximum threshold
* @return Width, height and depth of a stack that will 'just fit' the aligned image
*/
private static int[] getRotatedSize(final Matrix E, final ImagePlus imp,
final double[] centroid, final int startSlice, final int endSlice,
final double min, final double max)
{
final ImageStack stack = imp.getImageStack();
final Calibration cal = imp.getCalibration();
final double xC = centroid[0];
final double yC = centroid[1];
final double zC = centroid[2];
final Rectangle r = imp.getProcessor().getRoi();
final int rW = r.x + r.width;
final int rH = r.y + r.height;
final int rX = r.x;
final int rY = r.y;
final double vW = cal.pixelWidth;
final double vH = cal.pixelHeight;
final double vD = cal.pixelDepth;
final double[][] v = E.getArrayCopy();
final double v00 = v[0][0];
final double v10 = v[1][0];
final double v20 = v[2][0];
final double v01 = v[0][1];
final double v11 = v[1][1];
final double v21 = v[2][1];
final double v02 = v[0][2];
final double v12 = v[1][2];
final double v22 = v[2][2];
final int d = imp.getStackSize();
double[] sliceXTmax = new double[d + 1];
double[] sliceYTmax = new double[d + 1];
double[] sliceZTmax = new double[d + 1];
final AtomicInteger ai = new AtomicInteger(startSlice);
final Thread[] threads = Multithreader.newThreads();
for (int thread = 0; thread < threads.length; thread++) {
threads[thread] = new Thread(() -> {
for (int z = ai.getAndIncrement(); z <= endSlice; z = ai.getAndIncrement()) {
IJ.showStatus("Getting aligned stack dimensions...");
final ImageProcessor ip = stack.getProcessor(z);
final double zCz = z * vD - zC;
final double zCzv20 = zCz * v20;
final double zCzv21 = zCz * v21;
final double zCzv22 = zCz * v22;
double xTmax = 0;
double yTmax = 0;
double zTmax = 0;
for (int y = rY; y < rH; y++) {
final double yCy = y * vH - yC;
final double yCyv10 = yCy * v10;
final double yCyv11 = yCy * v11;
final double yCyv12 = yCy * v12;
for (int x = rX; x < rW; x++) {
final double pixel = ip.get(x, y);
if (pixel < min || pixel > max) continue;
// distance from centroid in
// original coordinate system
// xCx, yCx, zCx
final double xCx = x * vW - xC;
// now transform each coordinate
// transformed coordinate is dot product of original
// coordinates
// and eigenvectors
final double xT = xCx * v00 + yCyv10 + zCzv20;
final double yT = xCx * v01 + yCyv11 + zCzv21;
final double zT = xCx * v02 + yCyv12 + zCzv22;
// keep the biggest value to find the greatest distance
// in x, y and z
xTmax = Math.max(xTmax, Math.abs(xT));
yTmax = Math.max(yTmax, Math.abs(yT));
zTmax = Math.max(zTmax, Math.abs(zT));
}
}
sliceXTmax[z] = xTmax;
sliceYTmax[z] = yTmax;
sliceZTmax[z] = zTmax;
}
});
}