Is it that ImageJ opening bioformats with more background steps than we do programattically

I know this is not a straight forward question but for the moment I can’t figure out a way to investigate the problem. I created a java code that is applying one filter, converting it to binary and using Particle Analyzer. If there is any difference in count to what I am expecting, I always test using ImageJ Macro. Below, is the macro I run,

open("C:/.../diff result Image.tif");

run("Duplicate...", "duplicate");
run("Median...", "radius=15 stack");
imageCalculator("Subtract create stack", "diff result Image.tif","diff result Image-1.tif");
selectWindow("diff result Image.tif");
close();
selectWindow("diff result Image-1.tif");
close();
selectWindow("Result of diff result Image.tif");
run("Make Binary", "method=Default background=Default calculate black");
run("Analyze Particles...", "size=5-Infinity pixel display clear add stack");

The equivalent code in Java I am running

// Opening CZI images
ImporterOptions options = new ImporterOptions();
options.setId(imageFile.getPath());
ImagePlus[] imps = BF.openImagePlus(options);
imp = imps[0];

// Opening Tiff Images
imp = IJ.openImage(imageFile.getPath());

// Filtering and Segmenting
ImagePlus imagePlusDuplicate = new Duplicator().run(imp);
IJ.run(imagePlusDuplicate, "Median...", "radius=15 stack");
ImageCalculator imageCalculator = new ImageCalculator();
ImagePlus imagePlusFiltered = imageCalculator.run("Subtract create stack", imp, imagePlusDuplicate);
segmentedImage = new Duplicator().run(imagePlusFiltered );
IJ.run(segmentedImage, "Make Binary", "method=Default background=Dark calculate");

// Using Particle Analyzer
rt = new ResultsTable();
        ParticleAnalyzer particleAnalyzer = new ParticleAnalyzer(
        ParticleAnalyzer.INCLUDE_HOLES +
        ParticleAnalyzer.STACK_POSITION, 
        -1, rt, 5,Double.MAX_VALUE, 0, 1);
particleAnalyzer.setResultsTable(rt);

// From previous I get the x and y as follows,
double[] xDouble = rt.getColumnAsDoubles(6);
double[] yDouble = rt.getColumnAsDoubles(7);

// finally I convert them to integers as inputs to another method to be drawn
// I still don't know the decimal values in the double what it is for
(int) xDouble[i]
(int) yDouble[i]

Currently I have a case that when I opened CZI file and run my Java code, the x and y location of particles is limited to a small square on the top left of the image while in imageJ it is running correctly. Running that same Java code on different images that are not of CZI source, the x and y positions are shown correctly even with different size of images.

I still have problems with the view but seems that the markers are shown correctly with the normal image,
image

While for the CZI image,
image

I thought about Calibration to be a reason for the problem, but I am not sure if there is an automatic calibration that is done by ImageJ in the background. Any other probable reasons for this problem for me to investigate would be appreciated.

diff result Image.tif (1.0 MB)
same result Image.tif (3.0 MB)

Hi @Mourka,

for reading CZI images in Fiji you can give this script a try:

Let me know, if this works for you.

1 Like

Hi @Sebi06 thank you so much for your input.

I did read all the code and tried to implement it but still I am getting the same result. I replaced my Java code with the following.

// initialize the reader and get the OME metadata
ImageReader imageReader = new ImageReader();
IMetadata omeMeta = MetadataTools.createOMEXMLMetadata();
imageReader.setMetadataStore(omeMeta);
imageReader.setId(imageFile.getAbsolutePath());
imageReader.close();

// get the scaling for XYZ
Length physSizeX = omeMeta.getPixelsPhysicalSizeX(0);
Length physSizeY = omeMeta.getPixelsPhysicalSizeY(0);
Length physSizeZ = omeMeta.getPixelsPhysicalSizeZ(0);

float scaleX = Float.valueOf(String.format("%.3g%n", physSizeX.value()));
float scaleY = Float.valueOf(String.format("%.3g%n", physSizeY.value()));
float scaleZ = Float.valueOf(String.format("%.3g%n", physSizeZ.value()));

// check for auto stitching and possibility to read attachment
DynamicMetadataOptions metaOptions = new DynamicMetadataOptions();
metaOptions.setBoolean("zeissczi.autostitch", true);
metaOptions.setBoolean("zeissczi.attachments", false);

ZeissCZIReader zeissCZIReader = new ZeissCZIReader();
zeissCZIReader.setFlattenedResolutions(false);
zeissCZIReader.setMetadataOptions(metaOptions);
zeissCZIReader.setId(imageFile.getAbsolutePath());

// Dimensions
int sizeT = zeissCZIReader.getSizeT();
int sizeZ = zeissCZIReader.getSizeZ();
int sizeC = zeissCZIReader.getSizeC();
int sizeX = zeissCZIReader.getSizeX();
int sizeY = zeissCZIReader.getSizeY();
zeissCZIReader.close();

// read in and display ImagePlus(es) with arguments
ImporterOptions options = new ImporterOptions();
options.setOpenAllSeries(true);
options.setShowOMEXML(false);
options.setConcatenate(true);
options.setAutoscale(true);
options.setId(imageFile.getAbsolutePath());

// open the ImgPlus
ImagePlus[] imps = BF.openImagePlus(options);
imp = imps[0];
ImageStack impStack = imp.getImageStack();

// get the stack and some info
int outputSlices = impStack.getSize();
int outputSizeX = impStack.getWidth();
int outputSizeY = impStack.getHeight();

// calc scaling in case of pyramid
float scale = (float)sizeX/ (float)outputSizeX;
float scaleXOuput = scaleX * scale;
float scaleYOutput = scaleY * scale;

// set the correct scaling
// create new Calibration object
Calibration calibration = new Calibration();

// set the new parameters
calibration.pixelWidth = scaleXOuput;
calibration.pixelHeight = scaleYOutput;
calibration.pixelDepth = scaleZ;

// set the correct unit from the scaling
calibration.setXUnit("micron");
calibration.setYUnit("micron");
calibration.setZUnit("micron");

// apply the new calibration
imp.setCalibration(calibration);

Please if you noticed any thing that I am missing or doing wrong, just notify me and I will look further into it.

After comparing the imp between CZI source file saved as tiff (markers didn’t fit x,y locations) and another image that was given to me as tiff (markers fit x,y locations), I noticed the big difference in pixel sizes.
Not working case
image
image

working case
image
image

I just changed the pixel width, height and Depth to 1.0 and now I see the markers on the right places.

// set the new parameters
calibration.pixelWidth = 1.0;
calibration.pixelHeight = 1.0;
calibration.pixelDepth = 1.0;

// set the correct unit from the scaling
calibration.setXUnit("micron");
calibration.setYUnit("micron");
calibration.setZUnit("micron");

image

I am not sure if I mis interpreted the code

as now I am not setting pixel size based on the meta information but hard coded as1.0.

1 Like