How to have a batch of images with the same brightness and contrast?



Hi @iarganda,

I actually modified it a bit to have a proper optimization function:
I now have :

(getResult("Mean ",f)-stackMean)*(getResult("Mean ",f)-stackMean)/(stackMean*stackMean))).

This is an application of the least square method, with (a-b)^2/b^2 a correct unbiased estimation of my error, that enable efficient comparison.

I actually want to know which parameter (between Mean and StD) is the more accurate when I want to select an image for histogram matching. Are you sure I can determine it experimentally? I don’t think so, because I don’t know which image is the best: I’m looking for it!



Sure, but you have some intuition. For example, by visually inspecting the chosen image, you will see if the large standard deviation is due to artifacts in the image (such as bleaching, over-saturation, etc) or to real content diversity. That’s what I meant when I said “experimentally find the values”. Your script will point you to the theoretically best candidates and you will choose based on your knowledge. Does it make sense?


@iarganda Yes it does make sense, thank you so much.

I just checked and it’s not very obvious to be honest (I don’t have such artifacts, and it’s difficult to estimate what content diversity is the most valuable, since I’m working on brain sections).

So, for those who face the same problem as me, I recommend putting a higher weight on the optMean (estimation of the error of each image in relation to mean), somehow 0.9 (against 0.1 for the optStd), because often, your image with the highest diversity content isn’t the best candidate (in my case). But you have to experimentally try some values.

Thank you once more @iarganda for the help and solving this problem with me, that was cool!



Sorry @iarganda, one last question: do you know how to turn the Histogram Stack Matcher (.bsh script) into a Plugin? I’d like to integrate it to a global macro, without having to use the Script Editor.
Thank you very much,



No need to turn a script into a plugin. As long as you put the script file somewhere into your ./scripts/ (or ./plugins/Scripts/) directory, and the filename contains an underscore (_), it will appear as a menu command (in a menu corresponding to the subfolder where you put it in), and it will be recordable by the macro recorder and callable from other scripts.

See also:

Including a Beanshell Script in a Macro (.txt)

Thank you!!
I’ve been looking for this for hours …
Thank you very much.


how could i creat the reference according to your method? Many thanks


how could i creat the reference according to your method? Many thanks


You just need to select one image of the stack as reference. You should select one of the slices with more content.


Hi iarganda,

Do you know if there a youtube video on how to carryout out whole operation starting from copying the script into Fiji, loading the reference image (with final brightness & contrast) and loading all images which are to be processed. And finally the output images.
Thank you.


Dear @Pavan_Nishad,

We don’t have a video of that, but I can explain in the detail what you need to do:

  1. In Fiji go to “File > New > Script …”. Then a new window will be displayed showing the Script Editor:

  2. Copy and paste there the script I wrote in my previous post:

  3. In the Script Editor, change the language to BeanShell (under “Language > BeanShell”). That will make the text get highlighted:

  4. Using the main Fiji bar, open your images as a stack (“File > Import > Image Sequence…”). I took one of my TEM datasets as an example:

  5. In the Script Editor, click on “Run”, and a the next dialog will appear:


  6. There, choose the slice number to be used as reference and click “OK”. The script will be run an a new stack will show up at the end of the process with the result:

I hope this helps!


Hi iarganda,

Thank you very much for putting the efforts to prepare this tutorials. Let me try and check!


Hi iarganda,

I tried and it seems it worked. How do I save the newly created Histogram-matched images?


Do you mean how to save the stack as individual images? If so, “File > Save As > Image Sequence…”.


Yes, I mean saving processed stack as individual images. I tried your instruction in saving processed files and it showed me that it is saving the files in process bar, but in actual there are no files saved in that location. I tries saving in different location, but same problem occured. I am getting any error while saving the files, but it is just that files are not visible to me.


Hi iarganda,

The files appeared now. I think it take some time to copy the file to destination folder.

Thanks alot for prompt support. You are genius.


Hi iarganda,

Sorry to trouble you once again but could you please help me with one thing, I am trying to match histogram of many images with different resolution and it is giving me an error that resolution is not matching when I import the image as sequence so is there any way to bypass this match and still match the histogram?


Sorry for the late answer, @Pavan_Nishad. Are you talking about image size or image resolution? If it is resolution, I would simply set the resolution to the same values on all images before applying the histogram matching, and will re-assign it later.



When I try to run your (very promising !) script, I get this :

WARNING] Auto-imports are active, but deprecated.
Sourced file: inline evaluation of: import ini.trakem2.persistence.StaleFiles; import ini.trakem2.persistence.Cache; . . . '' : illegal use of undefined variable, class, or 'void' literal : at Line: 633 : in file: inline evaluation of:import ini.trakem2.persistence.StaleFiles; import ini.trakem2.persistence.Cache; . . . ‘’ : || referenceSlice > imp .getImageStackSize ( ) ) {

at bsh.BSHBinaryExpression.eval(
at bsh.BSHBinaryExpression.eval(
at bsh.BSHIfStatement.evaluateCondition(
at bsh.BSHIfStatement.eval(
at bsh.Interpreter.eval(
at bsh.Interpreter.eval(
at bsh.Interpreter.eval(
at org.scijava.plugins.scripting.beanshell.BeanshellScriptEngine.eval(
at org.scijava.thread.DefaultThreadService$
at java.util.concurrent.ThreadPoolExecutor.runWorker(
at java.util.concurrent.ThreadPoolExecutor$

I guess this is something related to the stacks importation ?
I just did File > Import > Image sequence…

Thank you for your help !



Now I realized that it’s probably not a importation problem but a language issue (I did not read yet your nice tutorial above !) : when I set on “BeanShell”, the reference slice dialog window does not appear. I tried (just to see) leaving the language set on “IJ1 Macro” and I got it, but then obviously an error like Baptiste ("< import > ij.IJ;")…