I have a bunch of images similar to the following: enter image description here

As you can see, there are faint grains in a roughly ellipse-shaped area, along with a few bright ones. I need to identify the location and density of these. For example, in the marked area, in an ideal case the algorithm would detect approximately the following "blobs": enter image description here

But... I have no idea what method or algorithm should I use. Blob detection algorithms usually assume the blobs are bright and are the main feature of the image, not something close to the level of background noise. The ones I have tried so far did not work. How would you approach this issue?

I don't need the algorithm to be exact or even very accurate - I'd already be very happy with a solution that gives like 80% good result. I have little image processing background. Regarding implementation, something usable in Python is preferred, but I'm interested in any implementation.

  • 1
    $\begingroup$ typically, you'd want to base this on a model of how these dots are shaped – typically a function of your optics/detector. $\endgroup$ Nov 16, 2023 at 16:02
  • $\begingroup$ "I have little image processing background." Without irony, and with apologies if this sounds sarcastic -- congratulations, you'll have a lot more when you're done. "Regarding implementation, something usable in Python is preferred." While you may luck out and get an answer that actually implements what you need, keep in mind that this site is mostly about giving you a theoretical basis. On the plus side, if there's a popular package in one of C or Fortran, it's usually available soon after in a wrapper for the other, and in Python to boot. $\endgroup$
    – TimWescott
    Nov 16, 2023 at 19:03

1 Answer 1


You want to segment the image into "grain" and "non-grain" areas.

Then you want to label the "grain" areas.

Segmentation is easy in principle: you process the image into a mask where all the "interesting" pixels are non-zero values (traditionally 1) and all the "non-interesting" pixels are zero.

Labeling is a matter of working through the segmented image and replacing each non-zero value with an ID for the cluster that it is in -- so the resulting image has zero-valued pixels (boring), and each cluster (in your case, each grain) with values 1, 2, 3, and so on.

I kinda like scikit-image; to label pixels with that you use skimage.morphology.label. Then if you want to operate on each individual grain (e.g., you want to find its centroid) you just mask the image on the label.

Segmentation is easy in principle, but difficult in practice. If you're really lucky, you can segment the image by comparing to some very dark but non-zero value, global to the image. "Objects" will be brighter than the threshold, "non-objects" will be darker. In the scikit-image environment, you should be able to use the code binary = image > threshold -- then display binary to see if it looks good.

If that doesn't work then start digging -- there are various ways to threshold an image. The simplest involve low-pass filtering the image, dividing that by some constant, and taking that as the threshold. This has the upside that gradual shading in the image (i.e., brighter on one side than the other) will be filtered out -- but it has the downside that large bright features, like your image has -- will suppress detection around them.

Ultimately, you need to experiment with your image(s) to find the best segmentation method. Find one that works, test it on some images, and run with it.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.