Reputation: 149
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.
Upvotes: 2
Views: 288
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