2

I want to automatically count the number of spots in this type of image where spots are very close to each other such that many are considered as a single spot:

scattered spots: very close to each other

I thought of using MATLAB's local maxima function/algorithm such as imregionalmaxima but this returns the number of pixels (ones in a binary matrix) with maximum values. I only want to measure the number of white spots contained in the black cycle.

I also found this topic here: How to count the number of spots in this image? and used ImageJ software. It cannot detect the spots, it seems to me that it also detects the pixels with maximum values.

Community
  • 1
  • 1
tselios
  • 63
  • 3

3 Answers3

5

Another simple way to count how many white spots there are in the image is to first convert your image to black and white, remove the white border, then count how many there are remaining. Use bwlabel and determine the value seen in the second output variable. To clear the white border, use imclearborder. BTW, this assumes you have the Image Processing Toolbox:

%// Read image directly from StackOverflow
im = im2bw(imread('https://i.stack.imgur.com/9hU5O.png'));

%// Remove white border surrounding image
im = imclearborder(im);

%// Count how many white spots there are
[~,num] = bwlabel(im);

I get:

>> num

num =

    18

Now in the case of your real example, you have some noisy pixels. There are several ways you can get rid of those isolated streaks. The thing that worked for me was to use morphological opening with a 5 x 5 square structuring element. Once you do this, this removes any noisy pixels that have an area of less than 5 x 5, and leaves any shape whose area is larger than 5 x 5 shape alone. Use a combination of imopen and strel to help you do this:

%// Read in the new image and convert to black and white
im = im2bw(imread('https://i.stack.imgur.com/HCvAa.png'));

%// Clear the border
im = imclearborder(im);

%// Define the structuring element
se = strel('square', 5);

%// Open the image
out = imopen(im, se);

%// Now count the objects
[~,num] = bwlabel(out);

I get:

>> num

num =

    18

Also, if you're curious, this is what the cleaned up image looks like:

>> imshow(out);

enter image description here

This processing was done on the new image you posted, and you can see that the noisy white pixels have been removed due to the opening operation.

rayryeng
  • 102,964
  • 22
  • 184
  • 193
  • 1
    plus one for imclearborder()! – lhcgeneva Nov 23 '15 at 18:55
  • the algorithm works for the black cycle with white spots but not for the cycle with the white noise I uploaded now. how can I count the spots and ignore the white noise? The algorithm gives 407 objects – tselios Nov 23 '15 at 19:22
  • 1
    @tselios You'd need to do some noise removal. I'll edit my post. It would **really** help if you posted a **real** example that you're working with. It gets annoying to keep editing my answer. – rayryeng Nov 23 '15 at 19:28
  • @tselios Edited. Check it out. – rayryeng Nov 23 '15 at 19:34
  • 1
    @rayryeng I also have a case where spots are very close to each other such that are considered as one from the software. How can avoid that? Added an example in the main question – tselios Nov 23 '15 at 21:06
  • You're on your own. Getting tired of your constant updates. – rayryeng Nov 23 '15 at 21:19
3

Try this (requires image processing toolbox):

i = imread('9hU5O.png');
bw = im2bw(i);
cc = bwconncomp(imclearborder(bw), 4);

Also see here.

Output:

cc = 

    Connectivity: 4
       ImageSize: [381 423]
      NumObjects: 18
    PixelIdxList: {1x18 cell}

Edit: now including rayryeng's imclearborder().

lhcgeneva
  • 1,981
  • 2
  • 21
  • 29
3

You need a connected-component labeling for this task.

In ImageJ, this is done using the Analyze Particles command.

Analyze Particles dialog

The result can be written to a table or displayed as particle outlines.

When working with real images, it's usually a good idea to pre-process images before segmentation, e.g. to remove noise. If that's impossible and you have a binary image that contains an imperfect segmentation, you can use morphological operations (i.e. Erode, Dilate, Open, Close) to discard the thin lines and single pixels. The following Javascript can get you started. Simply run it from the script editor.

importClass(Packages.ij.IJ);

imp = IJ.openImage("https://i.stack.imgur.com/X8Bou.png");

IJ.run(imp, "8-bit", "");
IJ.run(imp, "Open", "");
IJ.run(imp, "Watershed", "");

IJ.run(imp, "Analyze Particles...", "size=50-1000 show=Outlines display exclude clear");
imp.show();

This is the result:

Result of particle analysis

Jan Eglinger
  • 3,995
  • 1
  • 25
  • 51