'Find maximum inscribed circle in a non convex hull

By "non convex hull" I mean something like

enter image description here

the black portion of the image (my apologies if this is not "non convex hull", I do not have a better word to describe it).

What I am trying to get is a maximum inscribed circle within the black portion, like the red circle below. enter image description here

In other words, I would like to know the circle in a vacant space. Is this possible using opencv? When I try to get the circle using the following code

dist_map = cv2.distanceTransform(src_mask, cv2.DIST_L2, cv2.DIST_MASK_PRECISE)
_, radius, _, center = cv2.minMaxLoc(dist_map)
result = cv2.cvtColor(src_mask, cv2.COLOR_GRAY2BGR)
cv2.circle(result, tuple(center), int(radius), (0, 0, 255), 2, cv2.LINE_8, 0)

I got this instead. enter image description here As you can see, the circle goes out of bound. I'm happy to hear any suggestions and pointers. Thank you!

EDIT: I added a minimal example to reproduce this. Here is the script, and the outcome is attached below

import cv2
import numpy as np


##########
# create mask
# 0 if background, 255 if foreground
##########
src_mask = np.zeros((281, 500))
src_mask[100:170, 200:400] = 255
src_mask[127:143, 150:440] = 255
src_mask[213: 244, 30:59] = 255
src_mask[239: 279, 360:460] = 255
src_mask = src_mask.astype("uint8")
result = cv2.cvtColor(src_mask, cv2.COLOR_GRAY2BGR)
cv2.imwrite("mask.png", result)

##########
# draw contours
# the reason for 255-src_mask is that I want to have a circle in black portion instead of white portion 
##########
dist_map = cv2.distanceTransform(255 - src_mask, cv2.DIST_L2, cv2.DIST_MASK_PRECISE)
contours, _ = cv2.findContours(255 - src_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:]
result = cv2.cvtColor(src_mask, cv2.COLOR_GRAY2BGR)
cv2.drawContours(result, contours, -1, (255, 0, 0))
cv2.imwrite('contour.png', result)

##########
# circle
##########
dist_map = cv2.distanceTransform(255 - src_mask, cv2.DIST_L2, cv2.DIST_MASK_PRECISE)
_, radius, _, center = cv2.minMaxLoc(dist_map)
result = cv2.cvtColor(src_mask, cv2.COLOR_GRAY2BGR)
cv2.circle(result, tuple(center), int(radius), (0, 0, 255), 2, cv2.LINE_8, 0)
cv2.imwrite('circle.png', result)

and the output is enter image description here Again, the circle goes out of bound.



Solution 1:[1]

This can do the magic. Mask also your frame boundaries, like:

src_mask[:, 0 ] = 255
src_mask[:, -1 ] = 255
src_mask[0, : ] = 255
src_mask[-1, : ] = 255

That way, the calculated distances would take the frame's boundaries into account. (If you further need the mask copy it before changes)

I got with your example:

enter image description here

Solution 2:[2]

There’s some cases of occurring it:

case 1: set the variable center wrongly ;-;

case 2: because of cv2 coords ( 0, 0 ) is the top left of the screen, so that if center is correct, then make sure that you’ve made the the cv2 screen as your screen size, else that happens

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Dharman