Need Help With coding a macro

Hey guys, we are highschool students trying to prototype a machine that captures images of plants and processes them to measure growthrate. We found a measure green macro online that measures the area covered by green pixels in a good picture. However, since we are measuring Maize, the stem is part purple which the macro disregards. If ya’ll would be awesome enough to help us tweak the measuregreen code so that it measures both green and purple, it would be awesome! Here’s the macro and a sample image that may not run properly with the macro but has the purple hue in it located near the base of the plant(at the start of the sheath/stem). The second image runs well with macro, turning all the green pixels black and the rest white. measuregreen.txt (1.1 KB)

Hi and welcome to the forum!

I’m sure most people here will be happy to help, but it would not be very useful to simply hand out a quick fix, which might work for these two images, but not later.

First thing you need to realize is that you might get different images from the same plant, if your camera is on auto-white balance or on changes the exposure time or if your lighting changes.

Could you please first describe the protocol you have developed to acquire the images? This will help guide you in a good direction to build a robust tool.



(FYI, the macro doesn’t work well for me . It either shows mostly black or almost fully white for both images, so it seems there some global settings in ImageJ that makes the macro not be generic (yet))


Hey Oburri, Thanks a lot for taking your time. So the bottomline is that these images were just test images. We plan to have a black backdrop with the plant and the plant only. The problem is that the macro only ‘measures green’ but if you look at the second image I initially shared, it has a slightly purplish color near the bottom of the stem which the macro won’t consider. As for your run with the macro, I initially had the same result but I rerun it a couple of times and I somehow ended up with this image:

Try running the macro on this photoshopped image and then with the original image maybe that will fix it? If not I think just waiting and the rerunning it works. I really don’t know why it works this way

Hello @Yash_Rajesh_Bhora and @oburri

well, the macro seems to be written for a very specific images, with some “magic numbers”, like min[0]=44 and max[0]=122 in line 17-18.
You can play on these numbers, but I don’t think this macro will help you. If you record clean images, with the camera at the same position over the whole experiment, uniform lighting and background, you shouldn’t have any problem segmenting the whole plant, regardless of its color (except if it’s as black as the background, but that shouldn’t happen very often for a plant). I am almost sure that the only commands you will need are “Split channels” + “Adjust threshold”, or “Color threshold”. The first test image is ok, but the second is an example of what you want to avoid.
So my advice would be that you first record a few images of your own experiment and submit them to us.
None of my business, but when you estimate the size of the plant, how do you take into account the leaves that may grow towards the camera? They will appear narrower than if they grow perpendicular…

Hey Nicolas, thanks for your feedback, since maize leaves grow outwards to the left and right only, at least in their early stages(till around the 6th leaf which is what we intend to measure up until) we can get an area of the green in the picture with pixels and also scale it up. What we are trying to extract from analyzing the image is the plant’s growth rate, that’s all. Also, I believe that the ‘magic numbers’ seem to have something to do with RGB coloration but being inexperienced with imageJ i’m not sure.

Forgive me for not mentioning earlier but the guy who gave the macro said it works by first identifying all the green pixels in the picture and then turning them black after which it identifies every other pixel and turns them white. The pixel area is calculated and that is the data significant to us.

The problem I am facing is that in the maize is a little purple near the bottom of the stem(refer to my second image) which the macro does not detect so I wish to and seek help from you guys to configure the macro so that it converts both purplish pixels and green pixels to black and the rest to white(as we will be using a black background anyways). Thanks for your concern!

If you wish to continue working with the color thresholder, there would be no other way than to run another time the thresholder on the original image to grab purple-ish things, and then combine them.

What @Nicolas and I are saying that you might run into a lot of cases where your code will not work so well and you’ll have to tweak your “magic numbers” everytime.

It would be better to think of this as a color problem and you can look at color space decompositions to do this.

 * Find green and purple-ish areas using the Lab color space.
 * By Olivier Burri for the forum

 // Get some inputs using Script Parameters:

#@ImagePlus input_image
#@Double sigma_blur( label = "Sigma for initial blurring", value = 2 )
#@String threshold( label = "Threshold Method", value = "Triangle" )

// We are blurring the image a little bit to avoid noise. 
selectImage( input_image );
run("Select None");
close( "\\Others" );
run( "Duplicate...", "title=[Lab stack]" );
run( "Gaussian Blur...", "sigma="+sigma_blur);

// This converts the image to the Lab color space:
// There is a Wikipedia page, but it's a bit more technical than I like
run( "Lab Stack" );

// Pick up the a* ad b* components
setSlice( 2 );	
run( "Duplicate...", "title=[a* Component]" );
selectImage( "Lab stack" );
setSlice( 3 );
run( "Duplicate...", "title=[b* Component]" );

// Because the stem seems to be bright in the a* component, we combine them to try and get the better plant
imageCalculator( "Max create", "a* Component","b* Component" );
rename( "Plant" );

// After this, we apply a threshold on the resulting image using an auto-method
setAutoThreshold( threshold+" dark" );
setOption( "BlackBackground", false );
run( "Convert to Mask" );

// Create a selection and overlay it on the original image
run( "Create Selection" );
selectImage( input_image );
run( "Restore Selection" );
Overlay.addSelection( "", 20, "#66ff4444" );
run("Select None");

First notice how with code like this, there are only two parameters to tweak (for now) and that the code is more readable and more straightforward than the other. It should also be more robust.

Hey Oburri, is the code you’ve attached a macro? And it returns the area of green and purplish areas in ImageJ? If that’s the case then I need nothing more!

It is a macro, but will only run with Fiji and not ImageJ probably. Give it a shot and check if the approach could be useable.

If you want to try fancier things, you could go the way of machine learning with Weka, Ilastik or LabKit.

Have fun :slight_smile:

What is the equivalent in english?
“Un rouleau compresseur pour écraser un oeuf” :wink:

1 Like

Hey Oburri, this is a little late thanks for the code but can you tell me what are the parameters of the code you put up?

There are two parameters in the code right now on the top two lines

One (sigma_blur) corresponds to the amount of blurring to perform on the image, to remove noise and small features in the image we are not interested in.

The other (threshold) corresponds to the automatic threshold method you want to use. The thresholds available are here: You get them through the dropdown in Image > Adjust > Threshold

Again this is a very simple approach. My recommendation is that you look at Image > Type > Lab Stack and try to understand what I did in the code. Then perhaps you will notice improvements you can make to this first draft.

You’re welcome :slight_smile:


You could also have a look at Hue and Chroma and check what color wheel is. It would help you to understand what is done in the macro and, if you choose to use a hard threshold (or 2), how to choose it (them).
But as @oburri said, you first have to define a protocol, to get set aquisition conditions.