Computer vision: Creating mask of hand using OpenCv and Python

Viewed 1700

I am trying to create the mask from hand (black - background, white - hand)

This is the first original image 1:

enter image description here

This is my code:

hand = cv2.imread('hand.jpg')

blur = cv2.GaussianBlur(hand, (3, 3), 0)

hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)

mask2 = cv2.inRange(hsv, np.array([2, 0, 0]), np.array([20, 255, 255]))

kernel = np.ones((7, 7))
dilation = cv2.dilate(mask2, kernel, iterations=1)
erosion = cv2.erode(dilation, kernel, iterations=1)

filtered = cv2.GaussianBlur(erosion, (5, 5), 0)

ret, thresh = cv2.threshold(filtered, 90, 255, 0)

cv2.imshow('Threshold', thresh)

And the result is:

enter image description here

But I need have better result - like that:

enter image description here

What should I do?

[EDIT]

second image with different background:

enter image description here

Result using @Rotem code:

enter image description here

1 Ajay Kumar. IIT Delhi Palmprint Image Database version 1.0. 2007

1 Answers

You may solve it by applying threshold on the red color channel.

The background color is dark blue and green, and the hand color is bright and tend to red color, so using only the red color channel may give better results than converting to HSV.

The solution below uses the following stages:

  • Extract red color channel - use the red channel as Grayscale image.
  • Apply binary threshold using automatically selected threshold (using cv2.THRESH_OTSU parameter).
  • Use "opening" morphological operation for clearing some small dots (noise).
    Opening is equivalent to applying erode and than dilate.
  • Use "closing" morphological operation for closing small gaps (I chose disk shaped mask).
    Closing is equivalent to applying dilate and than erode.

Here is the code:

import cv2

img = cv2.imread('hand.jpg')

# Extract red color channel (because the hand color is more red than the background).
gray = img[:, :, 2]

# Apply binary threshold using automatically selected threshold (using cv2.THRESH_OTSU parameter).
ret, thresh_gray = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# Use "opening" morphological operation for clearing some small dots (noise)
thresh_gray = cv2.morphologyEx(thresh_gray, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)))

# Use "closing" morphological operation for closing small gaps
thresh_gray = cv2.morphologyEx(thresh_gray, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9,9)))

# Display result:
cv2.imshow('thresh_gray', cv2.resize(thresh_gray, (thresh_gray.shape[1]//2, thresh_gray.shape[0]//2)))
cv2.waitKey(0)
cv2.destroyAllWindows()

Result:
enter image description here

I think you may improve the result by finding the contour of the hand, and proximate it to polygon with less vertices (but it might be an over-fitting).

Related