Correcting brightfield illumination artifacts

imagej

#1

Hi All,

@Alex_H @haesleinhuepf @imagejan

I was wondering whether there is an ImageJ workflow already for correcting brightfield illumination?
I just tried an own attempt (median filter based) and I guess that would be OK but I also do not want to reinvent the wheel…

Input image

Gradient (Computed from downsampled and median-filtered)

Subtract gradient and then also divide by gradient


#2

Good day,

are you sure the microscope was set-up correctly?

Regards

Herbie


#3

Hi Tischi,

there are a few documented methods.
From these, I found the FFT bandpass filter to work nice and fast, but the result using your image posted above is not necessarily of better quality compared to what you already have.


#4

Good question :slight_smile:
It is low mag high throughput multi-well imaging, the gradient comes because of the well shape.


#5

Thanks for the tip! The FFT is much faster than subtracting the median. This might be helpful!


#6

What magnification?
If overall magnification is small, a normal Microscope may be sub-optimum and special illumination may be needed.

Without seeing the multi-well objects and the whole optic set-up it’s difficult to tell what’s wrong.

Regards

Herbie


#7

the BioVoxxel Pseudoflatfield correction with a radius around 10 also doesn´t look too bad and it´s super easy to use. There are some artifacts in the lower left corner which I guess are due to the jpeg format of the sample image.


#8

If you’re only after a band pass, you could also try Plugins > Integral Image Filters > Normalize Local Contrast which is even faster than the FFT bandpass. Try various block-sizes with preview checked

The integral filters are explained here:

If you have many images from the same microscope under similar settings, you can estimate the flatfield with CIDRE https://github.com/smithk/cidre.

If you have more images than CDRE can digest or you’re interested in 3D flatfields (I gues you’re not ;)), you can use our not yet published scale up of the CIDRE approach https://github.com/saalfeldlab/stitching-spark.


#9

In fact, I do have more images. My naive approach was just to compute a median projection, thereby ideally removing the objects and only being left with the flat-field. This of course does not work very robustly if there are many objects in every image. Thus, thanks for pointing out CIDRE I will check it out!


#10

@axtimwalde @igorpisarev @Kevin_Smith

CIDRE works really well! However I would need to write an other UI that enables batch-processing of many experiments and also accepts Tiff stacks as input. I guess it would make to use your new code as a starting point, rather than the original one?

Your new code (right?): https://github.com/saalfeldlab/stitching-spark/blob/42e01a6fe2751980102922513df309ba25b00f70/src/main/java/org/janelia/stitching/experimental/IlluminationCorrectionSliceParallel.java#L1452

Original code: https://github.com/smithk/cidre/blob/master/0.1/imagej/src/Cidre_Plugin.java


#11

As an alternative to CIDRE there is also BaSiC.
There is an update site available for it and you can find a bit of demo/documentation here.
If I remember correctly it does work on stacks and was quite fast.


#12

Results look good, works on stacks and is macro recordable => one can easily batch it!
Very nice!


#13

Just for the record (maybe other people will find this post interesting):
CIDRE and BaSiC are giving very similar results for my data (just different treatment of the offset due to the particular CIDRE settings that I used):


#14

Good day Christian,

unfortunately you didn’t use the provided sample image for your experiments. Furthermore, the provided sample image is JPG-compressed …

Here is what I get from your sample image (profile from left bottom to right top)

(before)

(after)

when using this little ImageJ-macro:

w = getWidth();
h = getHeight();
img = getImageID();
makeLine(0, h-1, w-1, 0);
run("Plot Profile");
selectImage(img);
run("Select None");
run("Bandpass Filter...", "filter_large=100 filter_small=0 suppress=None tolerance=0");
run("Restore Selection");
run("Plot Profile");
selectImage(img);
run("Revert");

Regards

Herbie


#15

Hi Chistian,

to me it seems you need a flat-field correction.
[https://en.wikipedia.org/wiki/Flat-field_correction]
This means, you should divide by the correction, not subtract it (also the Fourier filters do a subtraction, not a division). Otherwise the features in the dark (insufficiently illuminated) parts of the image get too weak.
You could try, e.g., the following macro:

origID=getImageID();
run("Duplicate...", "title=flat");
flatID=getImageID();
run("32-bit");
run("Gaussian Blur...", "sigma=2");
run("Subtract Background...", "rolling=500 light create sliding");
imageCalculator("Divide create 32-bit", origID,flatID);

But there are some additional problems:

  • In the dark areas, the intensity is extremely low (pixel value only 3-4), so you won’t get a reasonable result there.
  • I have the impression that the image was taken with increased contrast, so zero intensity does not correspond to a gray level of zero. Maybe there was also some nonlinear transfer curve (e.g. Gamma, https://en.wikipedia.org/wiki/Gamma_correction).
  • The features look different near the center and where you have a large gradient of the intensity. Near the center, they are mainly dark; near the edge they are bright one one side.

So I think you should definitely improve the illumination and/or alignment!


#16

Perfectly agreed, see here:
https://forum.image.sc/t/correcting-brightfield-illumination-artifacts/19940/2?u=herbie

also the Fourier filters do a subtraction, not a division

In the case in question they zero out harmonic spatial waves of large periods. Division is the way to go but improved image acquisition is superior!

Best

Herbie

PS:
Here are again results obtained from the supplied sample image. Profiles are on the image diagonal from left bottom to right top.

  1. According to Michael’s ImageJ-macro:

  2. Bandpass-filtered logarithmically transformed image after exponential re-transformation:


#17

Hi @Christian_Tischer,

did you by any chance already work on a script to batch-process your data?

I have now a similar dataset (a time-laps of 60 wells with 6x6 tiles per well in Brightfield) and it would be great if you would have code that I could use :slight_smile: Thanks!


#18

I almost finished implementing the BaSiC approach…
I still have to test the batching though…


#19

Please follow the progress in this thread: Automated batch processing


#20

Could you please test it?
Update site: EMBL-CBA
And then at the very bottom of Plugins > Restoration > Illumination > BaSiC
(I am not sure it will work immediately because I had some strange dependency issues…)