Babatunde Akande
Babatunde Akande

Reputation: 149

How to get features vector from hand image

i have a processed hand image, i need to calculate the length of each fingers and the width. please find below my code. I have attached the sample of the hand image. I've been able to convert the image to grey scale and remove the background.

import cv2
import numpy as np
import copy
import math
#import image_process_utils
#import frequency_filters

# Constants

blurValue = 41
threshold = 70

def removeBG(frame):
    fgmask = bgModel.apply(frame,learningRate=learningRate)
    # kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
    # res = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)

    kernel = np.ones((3, 3), np.uint8)
    fgmask = cv2.erode(fgmask, kernel, iterations=1)
    res = cv2.bitwise_and(frame, frame, mask=fgmask)
    return res

def calculateFingers(res,drawing):  # -> finished bool, cnt: finger count
    #  convexity defect
    hull = cv2.convexHull(res, returnPoints=False)
    if len(hull) > 3:
        defects = cv2.convexityDefects(res, hull)
        if type(defects) != type(None):  # avoid crashing.   (BUG not found)

            cnt = 0
            print(defects.shape[0])
            for i in range(defects.shape[0]):  # calculate the angle
                s, e, f, d = defects[i][0]
                start = tuple(res[s][0])
                end = tuple(res[e][0])
                far = tuple(res[f][0])
                a = math.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2)
                b = math.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2)
                c = math.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)
                angle = math.acos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c))  # cosine theorem
                if angle <= math.pi / 2:  # angle less than 90 degree, treat as fingers
                    cnt += 1
                    cv2.circle(drawing, far, 8, [211, 84, 0], -1)
            return True, cnt
    return False, 0
#Reading the image


img = cv2.imread("images/3.jpg")
img = cv2.resize(img, (0,0), fx=0.5, fy=0.5)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (blurValue, blurValue), 0)
ret, thresh = cv2.threshold(blur, threshold, 255, cv2.THRESH_BINARY)

thresh1 = copy.deepcopy(thresh)
_, contours, heirarchy = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
length = len(contours)
maxArea = -1
if length >0:
    for i in range(length):
        temp = contours[i]
        area = cv2.contourArea(temp)
        if area> maxArea:
            maxArea = area
            ci = i
    res = contours[ci]
    drawing = np.zeros(img.shape, np.uint8)
    cv2.drawContours(drawing, [res], 0, (0, 255, 0), 2)
    isFinishCal,cnt = calculateFingers(res,drawing) 

cv2.imshow('out', drawing)
cv2.waitKey(0)
cv2.destroyAllWindows()

i need to calculate each finger length in the image which will be my extracted features.

enter image description here

Upvotes: 2

Views: 288

Answers (1)

Stanislav Ivanov
Stanislav Ivanov

Reputation: 1974

You can use contour simplification by approxPolyDP instead of convexHull and convexityDefects:

import cv2
import numpy as np

img = cv2.imread('zBs8Vm.jpg',0)

#make image black and white
ret,img = cv2.threshold(img,90,255,0)

#getting max contour
_, contours, heirarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
c = max(contours, key = cv2.contourArea)

# Contnour simplification
tmp = np.zeros(img.shape, dtype = "uint8")
epsilon = 0.005*cv2.arcLength(c,True)
approx = cv2.approxPolyDP(c,epsilon,True)
cv2.drawContours(tmp, [approx], -1, 255, 3)

#Quick and dirty sharp corner detection
finger_points = []

for p in range(0,len(approx)):
    #getting next and previous point at contour
    p_pnt = approx[p-1][0] if p-1 >= 0 else approx[len(approx)-1][0]
    c_pnt = approx[p][0]
    n_pnt = approx[p+1][0] if p+1 <= len(approx)-1 else approx[0][0]

    # is left corner (and not on wrist)?
    if p_pnt[0] > c_pnt[0] and n_pnt[0] > c_pnt[0] and c_pnt[0] < img.shape[0]*0.8:
        point = list(c_pnt)

        #finger length as max of left and right side line
        length = max( ((c_pnt[0]-p_pnt[0])**2+(c_pnt[1]-p_pnt[1])**2)**0.5,
                      ((c_pnt[0]-n_pnt[0])**2+(c_pnt[1]-n_pnt[1])**2)**0.5 )

        finger_points.append(point + [length])
        cv2.circle(img, tuple(approx[p][0]), 15, 128)
        cv2.circle(tmp, tuple(approx[p][0]), 15, 128)

#sort in finger order
finger_points.sort(key=lambda x: x[1])

print(finger_points)

#Simplified contour
cv2.imwrite('simpcon.bmp', tmp)

#Finger ends points
cv2.imwrite('fp.bmp', img)

Upvotes: 1

Related Questions