Is there any way to fill the empty gap between two parts in an image?

Viewed 471

Threshold image

Mouth part

Extracted teeth

I am trying to make extraction for the teeth part only from the cropped mouth image but the threshold and mask way miss some teeth as shown in the extracted teeth image.

I am using python in do this by getting the threshold image then find contours based on the threshold image and extract the contour detected, by this code:

labels = measure.label(threshold, connectivity=2, background=0)
mask = np.zeros(threshold.shape, dtype="uint8")
for label in np.unique(labels):
    if label == 0:
        continue
    labelMask = np.zeros(threshold.shape, dtype="uint8")
    labelMask[labels == label] = 255
    numPixels = cv2.countNonZero(labelMask)
    if numPixels > 600:
        mask = cv2.add(mask, labelMask)

cv2.imshow("mask", mask)


_, contours, _ = cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(equa, contours, -1, (0, 0, 255), 2)
cv2.imshow("thre",equa)
img_contours= cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[-2]
img_contours = sorted(img_contours, key=cv2.contourArea)

for i in img_contours:

    if cv2.contourArea(i) > 1000:

        break

mask = np.zeros(mask.shape[:2], np.uint8)
cv2.drawContours(mask, [i],-1, 255, -1)
new_img = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow("Image with background removed", new_img)

So is there anyway to make extraction and get all teeth or fill the empty gap between the extracted teeth?

2 Answers

I'd suggest to use a different approach: convert to HSV colorspace and use just the Hue channel, then do some thresholding and morphing to get the mask.

img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)

Maybe you want to blur the h channel before thresholding.

h_blur = cv2.GaussianBlur(h, (5, 5), 1)

For the thresholding on the h channel I suggest you to use the GUI for some interactive adjustment

ret, thh_blur = cv2.threshold(h_blur, 9, 255, cv2.THRESH_BINARY)

You can use thh_blur as a mask and see if it is good for you or follow with some e morphing:

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
morphed_th = cv2.morphologyEx(thh_blur, cv2.MORPH_OPEN, kernel, iterations = 1)
morphed_th = cv2.morphologyEx(morphed_th, cv2.MORPH_CLOSE, kernel, iterations = 2)

Finally use morphed_th as a mask:

res = img.copy()
res[morphed_th == 0] = 0
res

I got the following image.

enter image description here

I don't know if it good for you since it misses the side teeth in the darker corners, but you can extract them from the s channel and add to the mask.

If you want to get rid of the gap between theet (darker region) you can follow more or less the same logic starting from res as input image and playing with channels, thresholding etc.


Adding the left side requires to play with parameters.

This is the code. Do the same for the opposite side.

# blur the s channel
s_blur = cv2.GaussianBlur(s, (5, 5), 1)

# custom thresholding
val1 = 240
val2 = 170
ths_blur = s_blur.copy()
ths_blur[ths_blur > val1] = 0
ths_blur[ths_blur > val2] = 255
ths_blur[ths_blur <= val2] = 0

# add to the previous and slice the left part
mask = cv2.add(morphed_th, ths_blur)
left = np.s_[:,0:70]

# apply morphology to the left slice
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
morphed_mask_left = cv2.morphologyEx(mask[left], cv2.MORPH_CLOSE, kernel, iterations = 6)

# override the mask with the morphed left part
final_mask = morphed_th.copy()
final_mask[left] = morphed_mask_left

# use the mask
res_final = img.copy()
res_final[final_mask == 0] = (0, 0, 0)
res_final

This is what I get.

enter image description here

To get a better understanding of why I did this way, plot each step. Maybe this allow you to find an even better solution.

IMO, the answer to your very question is essentially negative.

The binary image has low information content, and there is no difference between a missing tooth and normal spacing around and between teeth.

With no a priori information on what a tooth pattern looks like, no low-level vision operation (filters) can help. You might be able to get some improvement by mapping a geometric model with a teeth layout, but this would not reflect the particular anatomy at hand and would be quite difficult to implement.

You must certainly work this out before binarization.

Related