0

Suppose I have a binary image and I want to do the the following in OpenCV: Given a point, measure the area and perimeter of the connected component that point belongs to ..

def areaAndPerimeter(point):
   ...do some stuff...
   return area, perimeter

I know I can use cv2.findContours() to find the perimeter and area of each connected component, but I don't know how to pair that information with input point. Which perimeter and area corresponds to the connected component of point

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
mv3
  • 469
  • 5
  • 16
  • 1
    I think you do `connectedComponentsWithStats()` and it labels all the points in each blob with the same colour. So you would find the colour (i.e. label) corresponding to your point to find which blob it belongs to. I may be hopelessly wrong! It is called `bwlabel()` in Matlab, I believe. – Mark Setchell Jan 23 '17 at 22:15
  • Yeah, I started working on a solution where I am using just plain old ``connectedComponents()`` and then extracting each component 1 by 1 and running ``findContours()`` separately on each but it seems like such a waste when I could run ``findContours()`` once on the whole image and skip connected components all together. – mv3 Jan 23 '17 at 22:18

1 Answers1

0

For this function, I would just grow a region starting from the point. Below is a pseudo-code:

 - Define a point queue Q
 - Define a foreground point vector F
 - Define a boundary point vector B
 - Put starting point in Q
 - While Q is not empty
      - p = Q.top
      - if p is foreground
          - F.push(p)
          - Q.push(neighbors of p)
      - else 
          - B.push(p)
- Return size(F), size(B)

At the end, F contains the foreground pixels and B contains the boundary pixels (black ones right outside of white ones). Thus, the size(F) gives the area and size(B) gives the perimeter.

ilke444
  • 2,641
  • 1
  • 17
  • 31
  • 1
    Are these good measures of perimeter and area? I suppose they could be taken as definitions, but when I try this they don't match the results of the opencv functions ``cv2.arcLength()`` and ``cv2.contourArea()``. The size of the contour itself matches your definition of perimeter, but the ``cv2.arclength()`` function is not equal to that and is given results closer to what I would expect. – mv3 Jan 24 '17 at 16:24
  • As there are different measures for distance (i.e., Euclidian vs. Manhattan distance), the area and arc length also depend on your approximation, as image domain is discrete. The above code gives "how many pixels are there in the foreground?" and "how many pixels are there on the boundary?". If you want to use OpenCV's approximation, then use all points in `B` and run `cv2.contourArea(B)` and `cv2.arcLength(B)`. – ilke444 Jan 24 '17 at 18:42
  • I see, I'm going to try timing this against what I am currently doing which is using ``cv2.connectedComponents()`` to find the connected components, extracting the component of my point, then using ``cv2.findContours()`` and subsequently ``cv2.contourArea()`` and ``cv2.arcLenth()``. – mv3 Jan 26 '17 at 17:23