5

I'm trying to find similar or equivalent function of Matlabs "Bwareaopen" function in OpenCV?

In MatLab Bwareaopen(image,P) removes from a binary image all connected components (objects) that have fewer than P pixels.

In my 1 channel image I want to simply remove small regions that are not part of bigger ones? Is there any trivial way to solve this?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Miha
  • 57
  • 1
  • 5

4 Answers4

4

Take a look at the cvBlobsLib, it has functions to do what you want. In fact, the code example on the front page of that link does exactly what you want, I think. Essentially, you can use CBlobResult to perform connected-component labeling on your binary image, and then call Filter to exclude blobs according to your criteria.

tzaman
  • 46,925
  • 11
  • 90
  • 115
  • thanks tzaman for quick answer and ur right cvBlobsLib is exactly what i need. but now the thing is Im not shure i can import those cvBlobsLib in my Xcode project (iPhone) libraries and i already had a lot of work even with importing opencv libs. Do you think i can just copy parts of code out of libs that i'll be needing? – Miha Feb 27 '10 at 18:40
  • I haven't actually used cvBlobsLib myself (or Xcode!), but it's distributed as source, so you should be able to just add all the `.cpp` and `.h` files to your project, `#include` the appropriate headers, and take it from there. – tzaman Feb 27 '10 at 19:29
  • Also, don't forget to accept / upvote the answer if it was helpful! :) – tzaman Feb 27 '10 at 19:35
  • No go for just including .cpp and .h files to project :( I guess i need version for mac though! – Miha Feb 27 '10 at 23:26
3

There is not such a function, but you can 1) find contours 2) Find contours area 3) filter all external contours with area less then threshhold 4) Create new black image 5) Draw left contours on it 6) Mask it with a original image

yehuda
  • 75
  • 1
  • 6
  • I would not recommend working with contours because OpenCV isn't terribly accurate in the definition of those. *connected components* (with stats, and some masking) serve the same purpose, but better. – Christoph Rackwitz Jul 28 '22 at 14:38
1

I had the same problem and came up with a function that uses connectedComponentsWithStats():

    def bwareaopen(img, min_size, connectivity=8):
        """Remove small objects from binary image (approximation of 
        bwareaopen in Matlab for 2D images).
    
        Args:
            img: a binary image (dtype=uint8) to remove small objects from
            min_size: minimum size (in pixels) for an object to remain in the image
            connectivity: Pixel connectivity; either 4 (connected via edges) or 8 (connected via edges and corners).
    
        Returns:
            the binary image with small objects removed
        """
    
        # Find all connected components (called here "labels")
        num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(
            img, connectivity=connectivity)
        
        # check size of all connected components (area in pixels)
        for i in range(num_labels):
            label_size = stats[i, cv2.CC_STAT_AREA]
            
            # remove connected components smaller than min_size
            if label_size < min_size:
                img[labels == i] = 0
                
        return img

For clarification regarding connectedComponentsWithStats(), see:

How to remove small connected objects using OpenCV
https://www.programcreek.com/python/example/89340/cv2.connectedComponentsWithStats https://python.hotexamples.com/de/examples/cv2/-/connectedComponentsWithStats/python-connectedcomponentswithstats-function-examples.html

Thodor
  • 23
  • 4
0

The closest OpenCV solution to your question is the morphological closing or opening.

Say you have white regions in your image that you need to remove. You can use morphological opening. Opening is erosion + dilation, in that order. Erosion is when the white regions in your image are shrunk. Dilation is (the opposite) where white regions in your image are enlarged. When you perform an opening operation, your small white region is eroded until it vanishes. Larger white features will not vanish but will be eroded from the boundary. The subsequent dilation step restores their original size. However, since the small element(s) vanished during the erosion step, they will not appear in the final image after dilation.

For example consider this image where we want to remove the small white regions but retain the 3 large white ellipses. Running the following code removes the white regions and displays the clean image

import cv2
im = cv2.imread('sample.png')
clean = cv2.morphologyEx(im, cv2.MORPH_OPEN, np.ones((10, 10)))
cv2.imshwo("Clean image", clean)

The clean image output would be like this.

The command above uses a square block of size 10 as the kernel. You can modify this to suit your requirement. You can even generate a more advanced kernel using the function getStructuringElement().

Note that if your image is inverted, i.e., with black noise on a white background, you simply need to use the morphological closing operation (cv2.MORPH_CLOSE method) instead of opening. This reverses the order of operation - first the image is eroded and then dilated.

coderam
  • 1
  • 1
  • caveat: open/close morphology can and will change the shapes of blobs, even those it doesn't remove. it's better to work with connected components. I would not recommend working with contours because OpenCV isn't terribly accurate in the definition of those. – Christoph Rackwitz Jul 28 '22 at 14:37