Quick and dirty Blueberry analyses

Hi all! I’m a blueberry breeder trying to learn some fiji/imagej to streamline the issues covid is causing-- namely keeping my workers separated and not having to work on site as much (we have to pay them 1.5x when they are). Our normal process is to have a bunch of people harvesting individual blueberry bushes and then take the berries inside to weigh and count. Besides weighing the entire yield of each bush, we separate out and weigh a pint of berries and then count how many berries are in that pint to give us an idea of the size and weight per berry. We also count how many berries are diseased or have stems or wounds. I’ve been playing around with fiji for a few days but I don’t feel like I’ve made satisfactory progress on getting it to recognize and count individual berries, much less measure size. There’s a program called TomatoAnalyzer that does some neat things with looking at color, shape and size, but it requires no fruit to be touching and for the background to be black. My blueberries are a pain in the butt to separate out that much, plus they’re very close to black in color already.
I’ll keep plugging away at it, but if anyone has any suggestions to easily count and size, or some improvements that could be made on my setup, please let me know!


1 Like

Hi @BerryQueen,

Welcome to the forum. Nice to read you tried a few things already to analyse your crop yield.
Did you dig in to the forum and search for berries? Then you must have found this thread on berry diameter, which might give you a few ideas on how to separate the berries.

On the other hand, your excellent sharp contrasted sample image indeed allows for ImageJ/Fiji, where you have things like perimeter/roundness/surface area ratios to play with, as well as watershed segmentation, to separate touching berries and use Analyse Particles with the appropriate constraints.

1 Like


Indeed color here is your friend. And the resolution of your images is gorgeous.

My suggestion is to look at transforming your RGB image to LAB space. the b* component really separates your berries from the background.

Then you should crop the image to avoid the background that is not your square bucket.

Finally after smoothing and thresholding, using a watershed really cuts them very neatly.

The image can be scaled down because it is already very high resolution.

Issue there is to re-scale all the regions back to the original image if you want to do some further analyses.

Here is a macro I had fun making. Read through the code and hopefully this will help you get where you want to go. I have never written ‘berry’ in a macro so much :slight_smile:

// Berry Counts by Olivier Burri
// Using simple auto threshold on LAB stack image
// Scaling applied for speed up
// Consider starting with a smaller image

// Factor to reduce the image
scale = 1/5;

// Housekeeping
run("Select None");
run("Set Measurements...", "area stack limit display redirect=None decimal=3");

// Speeds up processing slightly but hides intermediate images

original_image = getTitle();
run("Duplicate...", "title=[Lab berries]");

// Full resolution not interesting for detecting the objects
run("Scale...", "x="+scale+" y="+scale+" interpolation=Bilinear average create");
run("Lab Stack"); // Makes berries stand out

//Only the b* component is interesting
run("Duplicate...", "title=[b* berries] duplicate channels=3-3");


// here is where we segment the berries
run("Smooth"); // Smoothing to avoid small artifacts
setAutoThreshold("Default"); // Default auto threshold worked well
setOption("BlackBackground", true);
run("Convert to Mask"); // Make a binary image
run("Watershed"); // Split objects using watershed algorithm

run("Analyze Particles...", "  circularity=0.8-1.00 exclude add");

// Now we need to reapply the ROIs on the original image, so we need to scale them individually. this is very slow with the macro language but can be sped up a lot in a script (Groovy or otherwise)
nR = roiManager("count");

print("Rescaling "+nR+" berries");
for (i = 0; i < nR; i++) {
	roiManager("select", i);
	run("Scale... ", "x="+(1/scale)+" y="+(1/scale));
	// Make selection smoother
	run("Fit Spline");

	// Make a crop of the image to create an individual berry stack
	run("Duplicate...", "title=[Single Berry "+i+"]");

// Make a berry stack to see each berry individually
run("Images to Stack", "method=[Copy (center)] name=Stack title=Single use");
rename("Berry Stack");

// Show the results

// Get measurements from the berries

All the best



OMG that was magical! I’m still playing around with it- it works really great and I think if I play around with it a little more I can tweak it enough to get the measurements I need.
Another few questions-- when we measure berries with our handheld colorimeter we get Lab numbers, and we only really record the L*. I see there are some gray values you can get from the measurements, but reading further it goes into calibrating and I haven’t found anything yet about correlating with L*. Does anyone have a resource on adjusting/calibrating a picture based on a color checker and then finding the average L* in an ROI? I found a paper where someone made a plugin to calibrate RGB color with the xrite color checker I have, but for the life of me I can’t find the actual plugin.-- It was supposed to be called “ColorCal”

That ColorCal plugin seems to have been kept unpublished to the public. The supplementary data from the publication only offers some pseudocode.
You could contact the corresponding author and see if they’d share the code with you :slightly_smiling_face:

What goes into calibrating? And what is correlating with L*?

Maybe if you could explain what you are using the L* data you are collecting for, we can help out a bit.


So you may or may not know that blueberries aren’t actually blue- they have this white powder coating (“bloom”) that gives them that blue color. The number we get from the L* value gives us a good indication of the lightness of the berry. Since we’ll be doing this under different lighting conditions- outdoors, possibly indoors, cloudy or sunny, different times of day- I’m assuming the colors/light/darkness will be a little different for each picture we take, so we need to standardize the values across all the pictures (which is why I included the color checker).