How do I detect distinct objects when their edges touch each other?

I need to find all the contours in an image retrieved from the camera. So I first use the canny edge detector to find the edges and then find the contours. Pretty simple.

However, my contours get "merged". For example, in the image below, I clearly have 4 different objects. The edges are slightly touching at some points though, so I get one big contour instead of four separate ones. I tried changing around the thresholds, eroding, morphology operations and similar things but the edges keep slightly touching. Does anyone have any suggestions on how to get separate contours in images similar to the one below? (The image below is obviously just an example, my actual images are much more complex, but have the same basic problem).

• Watershed segmentation can work. Commented Jul 23, 2013 at 11:58
• So, you should also consider cases where the contact is a line and not just a point too (touching but not overlapping) Commented Aug 13, 2019 at 14:11

Detecting different components:

If you're trying to detect the different components, there probably are other approaches to do them than detecting the contours. Here's an example in Mathematica. An erosion followed by dilation is used to close the gap in the second component before detection (if you don't do this, it won't detect it).

img = Binarize@Import["https://i.sstatic.net/yqDyu.png"];
Colorize[MorphologicalComponents[Dilation[Erosion[img,1],1]]]


The figure on the left below, shows imperfect object detection (without closing the gap) and on the right, shows the correct detection (running the above code).

Detecting the different contours:

However, if you indeed want to separate only the contours, here's an example. The erosion and dilation are performed as before to close the gap and the resulting image is run through a Canny edge detector. I've made the default options explicit, so that you can see what's being used.

img2 = EdgeDetect[Dilation[Erosion[img, 1], 1], Method -> "Canny"]


This will give you both the inside and the outside edge (see figure on the left below), since the pixel width is greater than 1 all around. I haven't had much luck trying to get it thinner, as the performance degrades (may be different for your other images). The inner contours are the ones you want, and the outer contour is just the combined contour of all 4 components. Now all we need to do is drop the outermost one with:

SelectComponents[img2, "EnclosingComponentCount", # > 0 &]


which gives you just the inner contours (see bottom right). In other words, it only picks those contours that are enclosed by at least one other contour, which automatically disqualifies the outermost one. I do not know the equivalent of these commands/operations in openCV.

Note that the apparent breaks in the figure are due to saving to jpeg in a smaller size. It does not look that way on my screen.

Try pre-processing your images with a morphological filter like erosion. This will allow touching contours to be separated. After detecting your contours, you can apply a dilation operation to complete lattices.

• I tried that, but the results showed no improvement.
Commented Dec 3, 2011 at 22:12
• Can you show a real example image?
– fmorency
Commented Dec 4, 2011 at 0:07

It's not an answer to your question, but contour analysis is error-prone. You cannot do much about it and it works only on very simple scenarios.

If you have trouble using it, you should look for a completely different algorithm. There are more complex and more robust ways to solve things, but it depends on what you want to achieve (object detection, tracking, etc...)

• Thank You. My program is used for hand detection, so I would think it would be very similar to object detection. Do you gave any suggestions for more complex and robust algorithms? Haar Features, SURF and similar machine learning algorithms are not something I can do.