# Convexhull around a diffuse binary mask

Hi,

I am new to OpenCV and am currently trying to enclose a binary mask, with fairly diffuse white/True regions in a convex hull.
Here is an example mask, and the result of the simple one liner one can use in skimage:

``````enclosed_mask = morph.convex_hull_image(mask)
``````

For reasons I won’t go into, I am trying to achieve the same with openCV, and I have spent the day spinning my wheels.

Following the tutorial in the official docs, and tweaking various resources I came across here what I have tried, with the same mask image.

``````import cv2
import tifffile as tiff
import numpy as np
import matplotlib.pylab as plt
import skimage.morphology as morphology

# Find contours: OpenCV 4.x
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

contours_poly = [None]*len(contours)
hulls = [None]*len(contours)
for i, c in enumerate(contours):
contours_poly[i] = cv2.approxPolyDP(c, 3, True)
hulls[i] = cv2.convexHull(c)

hull = cv2.drawContours(hull, hulls, -1, 255, cv2.FILLED)

fig,ax = plt.subplots(1,3,figsize=(12,4))
ax[2].imshow(hull, cmap="gray")

plt.show()
``````

I get out an image which is unchanged.

I have played about with a few variations of this, and the best I have managed is to have some smaller regions enclosed, but still a very diffuse image.

Could someone please set me on the right track on how to achieve the same result as the skimage method?

For a bonus point, is there a way within openCV to separately enclose two or more distinct (but still diffuse) regions in the same mask, perhaps separated by some arbitrary distance (like morphology.convex_hull_object()

Edit: correct image attached

basically, findcontours + convex hull (over ALL points from the contours) + drawing… is the “equivalent”

scrap the approxpolydp, it’s superfluous. that includes `contours_poly`.

the loop and associated variables merely constructs a convex hull per contour, which isn’t what you want. scrap that.

I think `cv2.convexHull(np.vstack(contours))` should work. takes all the points from all contours, and does a convex hull once.

if you need something non-convex… I don’t know if OpenCV has anything for that, but the general problem is called “alpha shapes”. idea is that a convex hull puts an infinite ruler against the points, while alpha shapes do the same with a circle of a set radius (infinite radius → convex hull).

Thanks for your quick response @crackwitz .

I’ve made some changes to my code, but it is still not quite there. As attached.

``````import cv2
import tifffile as tiff
import numpy as np
import matplotlib.pylab as plt
import skimage.morphology as morphology

# Find contours: OpenCV 4.x
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

enclosed = cv2.convexHull(np.vstack(contours))

hull = cv2.drawContours(hull, enclosed, -1, 255, cv2.FILLED)

fig,ax = plt.subplots(1,3,figsize=(12,4))
ax[2].imshow(hull, cmap="gray")
ax[2].set_title("hull")

plt.show()
`drawContours(..., [enclosed], ...)`