Areas of contours

1,065 views
Skip to first unread message

Maik Riechert

unread,
Sep 10, 2014, 5:35:29 AM9/10/14
to scikit...@googlegroups.com
Hi,

I'm currently switching from OpenCV to scikit-image and came to a point where I miss a certain feature.

In OpenCV I used findContours() and then contourArea() to calculate the area of each contour. I couldn't find this in scikit-image. If I didn't miss it somewhere, could that be added as a new function?

Thanks
Maik

Juan Nunez-Iglesias

unread,
Sep 10, 2014, 5:43:59 AM9/10/14
to scikit...@googlegroups.com
Hey Maik,

Can you be a bit more specific? The pipeline may need to be a bit different, but this seems doable. In particular, regionprops(image)[i].area will return the area of all binary-labeled regions.

If that doesn’t help, if you have an example image with code it might be easier to translate your workflow.

Note that we don’t attempt to offer feature parity with OpenCV, which has a lot of hard computer vision algorithms that we lack. But this in particular should be doable.

Juan.

Sent from Mailbox


--
You received this message because you are subscribed to the Google Groups "scikit-image" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scikit-image...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Maik Riechert

unread,
Sep 10, 2014, 8:28:36 AM9/10/14
to scikit...@googlegroups.com
My goal is to determine the biggest contour that covers 1's in the binary image and return it, therefore I thought I first use find_contours and then calculate the area of each contour to get the right one. I'm not sure if regionprops helps me here. In the meantime I adapted a function from stackoverflow:

def polygonArea(poly):
    """
    Return area of an unclosed polygon.
    
    :param poly: (n,2)-array
    """
    # we need a plain list for the following operations
    if isinstance(poly, np.ndarray):
        poly = poly.tolist()
    segments = zip(poly, poly[1:] + [poly[0]])
    return 0.5 * abs(sum(x0*y1 - x1*y0
                         for ((x0, y0), (x1, y1)) in segments))

Before using that function I un-close the returned contours.

Cheers
Maik

Juan Nunez-Iglesias

unread,
Sep 10, 2014, 9:04:27 AM9/10/14
to scikit...@googlegroups.com
Hey Maik,

But what about:

1) Do a scipy.ndimage.binary_fill_holes to ensure that objects constitute the full area from a contour
2) Do a scipy.ndimage.label to give a unique ID to each blob of 1s in the image.
3) get props = skimage.regionprops(im) to get the properties of each blob
4) you can then find the argmax of [p.area for p in props]
5) you can then compute the contour of just that object, and offset the coordinates using the .bbox property

Would this work? It all depends on your purposes, and I’m also not sure which would be most efficient.

Juan.

Sent from Mailbox

Maik Riechert

unread,
Sep 10, 2014, 9:19:57 AM9/10/14
to scikit...@googlegroups.com
Hi Juan,

how would I do step 5? Even if I know the bounding box it could still be that parts of other regions are in the box, right?

I'm not sure if all that would be a bit too slow if it worked. My images are 4000x3000 and I guess there's a noticeable performance advantage of doing all further calculations just on the contours instead of the image itself.

Cheers
Maik

Johannes Sch önberger

unread,
Sep 10, 2014, 9:24:43 AM9/10/14
to scikit...@googlegroups.com
Hi Maik,

region props let's you also get the image of the separated region (separated meaning, only containing pixels where label == i) through `prop.image` or `prop.filled_image`.

Hope it helps.

Johannes Sch önberger

Juan Nunez-Iglesias

unread,
Sep 10, 2014, 9:26:43 AM9/10/14
to scikit...@googlegroups.com
p.image contains an image of just that one region, within bbox. Note that regionprops have lazy evaluation, so the code mentioned above should be reasonably fast — possibly faster than evaluating contours for the whole image first. Also note that unless you port it to Cython, your area function on the contours will be pretty slow.

Sent from Mailbox

Maik Riechert

unread,
Sep 10, 2014, 10:05:12 AM9/10/14
to scikit...@googlegroups.com
I just did a test on a 3000x3000 image comparing both approaches. Note that I have very few (one to three) contours where there is one big that is typically 50-70% of the whole image. My contour-only way takes 0.13secs, the other one that you suggested takes 4secs where 95% of the time is spent on accessing the area property of a single region prop. Why is that so slow?

Johannes Sch önberger

unread,
Sep 10, 2014, 10:07:30 AM9/10/14
to scikit...@googlegroups.com
How do you calculate the are in case of the 0.13 seconds? Just the sum of the True pixels?

Johannes Sch önberger

Johannes Sch önberger

unread,
Sep 10, 2014, 10:08:34 AM9/10/14
to scikit...@googlegroups.com
Forget what I said, that’s certainly not the area, but can you show some code for that, please?

Johannes Sch önberger

Johannes Sch önberger

unread,
Sep 10, 2014, 10:19:01 AM9/10/14
to scikit...@googlegroups.com
Sorry for the spam, but I just found your code for calculating the area.

region props does not use the polygonal chain for calculating the area, but uses moments. So the bigger your blob is, the more time it takes to calculate the moments, and vice versa.

Johannes Sch önberger

On Sep 10, 2014, at 10:08 AM, Johannes Sch önberger <js...@demuc.de> wrote:

> Forget what I said, that's certainly not the area, but can you show some code for that, please?
>
> Johannes Sch önberger
>
> On Sep 10, 2014, at 10:07 AM, Johannes Sch önberger <js...@demuc.de> wrote:
>
>> How do you calculate the are in case of the 0.13 seconds? Just the sum of the True pixels?
>>
>> Johannes Sch önberger
>>
>> On Sep 10, 2014, at 10:05 AM, Maik Riechert <maik.r...@arcor.de> wrote:
>>
>>> I just did a test on a 3000x3000 image comparing both approaches. Note that I have very few (one to three) contours where there is one big that is typically 50-70% of the whole image. My contour-only way takes 0.13secs, the other one that you suggested takes 4secs where 95% of the time is spent on accessing the area property of a single region prop. Why is that so slow?
>>>
>>> Am Mittwoch, 10. September 2014 15:26:43 UTC+2 schrieb Juan Nunez-Iglesias:
>>> p.image contains an image of just that one region, within bbox. Note that regionprops have lazy evaluation, so the code mentioned above should be reasonably fast -- possibly faster than evaluating contours for the whole image first. Also note that unless you port it to Cython, your area function on the contours will be pretty slow.
>>> --
>>> Sent from Mailbox
>>>
>>>
>>> On Wed, Sep 10, 2014 at 11:20 PM, Maik Riechert <maik.r...@arcor.de> wrote:
>>>
>>> Hi Juan,
>>>
>>> how would I do step 5? Even if I know the bounding box it could still be that parts of other regions are in the box, right?
>>>
>>> I'm not sure if all that would be a bit too slow if it worked. My images are 4000x3000 and I guess there's a noticeable performance advantage of doing all further calculations just on the contours instead of the image itself.
>>>
>>> Cheers
>>> Maik
>>>
>>> Am Mittwoch, 10. September 2014 15:04:27 UTC+2 schrieb Juan Nunez-Iglesias:
>>> Hey Maik,
>>>
>>> But what about:
>>>
>>> 1) Do a scipy.ndimage.binary_fill_holes to ensure that objects constitute the full area from a contour
>>> 2) Do a scipy.ndimage.label to give a unique ID to each blob of 1s in the image.
>>> 3) get props = skimage.regionprops(im) to get the properties of each blob
>>> 4) you can then find the argmax of [p.area for p in props]
>>> 5) you can then compute the contour of just that object, and offset the coordinates using the .bbox property
>>>
>>> Would this work? It all depends on your purposes, and I'm also not sure which would be most efficient.
>>>
>>> Juan.
>>> --
>>> Sent from Mailbox
>>>
>>>
>>> On Wed, Sep 10, 2014 at 10:29 PM, Maik Riechert <maik.r...@arcor.de> wrote:
>>>
>>> My goal is to determine the biggest contour that covers 1's in the binary image and return it, therefore I thought I first use find_contours and then calculate the area of each contour to get the right one. I'm not sure if regionprops helps me here. In the meantime I adapted a function from stackoverflow:
>>>
>>> def polygonArea(poly):
>>> """
>>> Return area of an unclosed polygon.
>>>
>>> :see: https://stackoverflow.com/a/451482
>>> :param poly: (n,2)-array
>>> """
>>> # we need a plain list for the following operations
>>> if isinstance(poly, np.ndarray):
>>> poly = poly.tolist()
>>> segments = zip(poly, poly[1:] + [poly[0]])
>>> return 0.5 * abs(sum(x0*y1 - x1*y0
>>> for ((x0, y0), (x1, y1)) in segments))
>>>
>>> Before using that function I un-close the returned contours.
>>>
>>> Cheers
>>> Maik
>>>
>>> Am Mittwoch, 10. September 2014 11:43:59 UTC+2 schrieb Juan Nunez-Iglesias:
>>> Hey Maik,
>>>
>>> Can you be a bit more specific? The pipeline may need to be a bit different, but this seems doable. In particular, regionprops(image)[i].area will return the area of all binary-labeled regions.
>>>
>>> If that doesn't help, if you have an example image with code it might be easier to translate your workflow.
>>>
>>> Note that we don't attempt to offer feature parity with OpenCV, which has a lot of hard computer vision algorithms that we lack. But this in particular should be doable.
>>>
>>> Juan.
>>> --

Maik Riechert

unread,
Sep 10, 2014, 10:27:29 AM9/10/14
to scikit...@googlegroups.com
If you still want to see the code, here it is: https://gist.github.com/neothemachine/64c70e6916eccf70464d

You can directly run it and see some execution times.

Johannes Sch önberger

unread,
Sep 10, 2014, 10:43:31 AM9/10/14
to scikit...@googlegroups.com
Thanks for sharing this.

regionprops is definitely missing a feature to extract the polygonal chain of the region boundary… this would be a very welcome feature.

Nevertheless, for big regions you are for now better of using the approximation with find_contours and then using the polygon area.

Johannes Sch önberger

Stéfan van der Walt

unread,
Sep 10, 2014, 8:03:56 PM9/10/14
to scikit-image
Hi Mike

On Wed, Sep 10, 2014 at 10:35 AM, Maik Riechert <maik.r...@arcor.de> wrote:
> In OpenCV I used findContours() and then contourArea() to calculate the area
> of each contour. I couldn't find this in scikit-image. If I didn't miss it
> somewhere, could that be added as a new function?

I happened to run into very similar problems this week. I see no
reason to include its calculation, especially if we can also implement
additional contour finding algorithms (at the moment, we just have
constant-value contours via marching squares). We can implement it as
a helper method for regionprops, and then update regionprops to use it
once it supports proper region boundary detection.

Would you be interested in helping with this? My standard reference
for polygons is

http://paulbourke.net/geometry/polygonmesh/

If not, let me know and I'll give it a shot.

Stéfan

Maik Riechert

unread,
Sep 11, 2014, 8:01:24 AM9/11/14
to scikit...@googlegroups.com
Hi Stefan,

I happened to run into very similar problems this week.  I see no
reason to include its calculation, especially if we can also implement
additional contour finding algorithms (at the moment, we just have
constant-value contours via marching squares).  We can implement it as
a helper method for regionprops, and then update regionprops to use it
once it supports proper region boundary detection.

Would you be interested in helping with this?  My standard reference
for polygons is

http://paulbourke.net/geometry/polygonmesh/


I'm afraid I currently don't have enough time but I'm happy to help test it etc.

Cheers
Maik
Reply all
Reply to author
Forward
0 new messages