Python 如何使用opencv检测手指数并添加两位数?
我不熟悉OpenCV和图像处理。我正在尝试创建一个程序,检测显示在相机前面的手指数量并添加它们。 在搜索GitHub一段时间后,我发现了一个项目,它可以检测一只手并计算其中的手指数 我在执行过程中面临的问题是,除非我的背景清楚,否则它不会显示数字。它不断地改变数字。我怎样才能稳定下来?因为我需要将屏幕前显示的数字相加,所以我无法存储该数字,除非它是稳定的Python 如何使用opencv检测手指数并添加两位数?,python,opencv,gesture-recognition,Python,Opencv,Gesture Recognition,我不熟悉OpenCV和图像处理。我正在尝试创建一个程序,检测显示在相机前面的手指数量并添加它们。 在搜索GitHub一段时间后,我发现了一个项目,它可以检测一只手并计算其中的手指数 我在执行过程中面临的问题是,除非我的背景清楚,否则它不会显示数字。它不断地改变数字。我怎样才能稳定下来?因为我需要将屏幕前显示的数字相加,所以我无法存储该数字,除非它是稳定的 import traceback import cv2 import numpy as np import math cap = cv2.
import traceback
import cv2
import numpy as np
import math
cap = cv2.VideoCapture(0)
while(1):
try: #an error comes if it does not find anything in window as it cannot find contour of max area
#therefore this try error statement
ret, frame = cap.read()
frame=cv2.flip(frame,1)
kernel = np.ones((3,3),np.uint8)
#define region of interest
roi=frame[100:300, 100:300]
cv2.rectangle(frame,(100,100),(300,300),(0,255,0),0)
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# define range of skin color in HSV
lower_skin = np.array([0,20,70], dtype=np.uint8)
upper_skin = np.array([20,255,255], dtype=np.uint8)
#extract skin colur imagw
mask = cv2.inRange(hsv, lower_skin, upper_skin)
#extrapolate the hand to fill dark spots within
mask = cv2.dilate(mask,kernel,iterations = 4)
#blur the image
mask = cv2.GaussianBlur(mask,(5,5),100)
#find contours
contours,hierarchy= cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(contours)
print(hierarchy)
#find contour of max area(hand)
cnt = max(contours, key = lambda x: cv2.contourArea(x))
#approx the contour a little
epsilon = 0.0005*cv2.arcLength(cnt,True)
approx= cv2.approxPolyDP(cnt,epsilon,True)
#make convex hull around hand
hull = cv2.convexHull(cnt)
#define area of hull and area of hand
areahull = cv2.contourArea(hull)
areacnt = cv2.contourArea(cnt)
#find the percentage of area not covered by hand in convex hull
arearatio=((areahull-areacnt)/areacnt)*100
#find the defects in convex hull with respect to hand
hull = cv2.convexHull(approx, returnPoints=False)
defects = cv2.convexityDefects(approx, hull)
# l = no. of defects
l=0
#code for finding no. of defects due to fingers
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(approx[s][0])
end = tuple(approx[e][0])
far = tuple(approx[f][0])
pt= (100,180)
# find length of all sides of triangle
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)
s = (a+b+c)/2
ar = math.sqrt(s*(s-a)*(s-b)*(s-c))
#distance between point and convex hull
d=(2*ar)/a
# apply cosine rule here
angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57
# ignore angles > 90 and ignore points very close to convex hull(they generally come due to noise)
if angle <= 90 and d>30:
l += 1
cv2.circle(roi, far, 3, [255,0,0], -1)
#draw lines around hand
cv2.line(roi,start, end, [0,255,0], 2)
l+=1
#print corresponding gestures which are in their ranges
font = cv2.FONT_HERSHEY_SIMPLEX
if l==1:
if areacnt<2000:
cv2.putText(frame,'Put hand in the box',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
else:
if arearatio<12:
cv2.putText(frame,'0',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
elif arearatio<17.5:
cv2.putText(frame,'Best of luck',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
else:
cv2.putText(frame,'1',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
elif l==2:
cv2.putText(frame,'2',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
elif l==3:
if arearatio<27:
cv2.putText(frame,'3',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
else:
cv2.putText(frame,'ok',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
elif l==4:
cv2.putText(frame,'4',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
elif l==5:
cv2.putText(frame,'5',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
elif l==6:
cv2.putText(frame,'reposition',(0,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
else :
cv2.putText(frame,'reposition',(10,50), font, 2, (0,0,255), 3, cv2.LINE_AA)
#show the windows
cv2.imshow('mask',mask)
cv2.imshow('frame',frame)
except Exception:
traceback.print_exc()
pass
# break
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
导入回溯
进口cv2
将numpy作为np导入
输入数学
cap=cv2.视频捕获(0)
而(一):
try:#如果在窗口中找不到任何内容,则会出现错误,因为它无法找到最大面积的轮廓
#因此,这个try错误语句
ret,frame=cap.read()
帧=cv2。翻转(帧,1)
内核=np.ones((3,3),np.uint8)
#定义感兴趣的区域
roi=帧[100:300,100:300]
cv2.矩形(框架,(100100),(300300),(0255,0),0)
hsv=cv2.CVT颜色(roi,cv2.COLOR\U BGR2HSV)
#定义HSV中的肤色范围
下表皮=np.数组([0,20,70],dtype=np.uint8)
上层皮肤=np.array([20255255],dtype=np.uint8)
#提取皮肤色素imagw
面罩=cv2.inRange(hsv、下皮肤、上皮肤)
#外推手部以填充内部的黑点
掩码=cv2.deflate(掩码,内核,迭代次数=4)
#模糊图像
掩模=cv2.高斯模糊(掩模,(5,5),100)
#寻找轮廓
轮廓,层次=cv2.findContours(掩码,cv2.RETR\u树,cv2.CHAIN\u近似值\u简单)
打印(等高线)
打印(层次结构)
#查找最大面积的轮廓(手)
cnt=最大值(轮廓,关键点=λx:cv2.轮廓面积(x))
#近似轮廓一点
ε=0.0005*cv2.弧长(cnt,真)
近似=cv2.approxPolyDP(cnt,ε,真)
#在手周围做凸包
外壳=cv2.凸形外壳(cnt)
#定义船体面积和手部面积
面积外壳=cv2。轮廓面积(外壳)
面积cnt=cv2。轮廓面积(cnt)
#查找凸面外壳中未手动覆盖的面积百分比
面积比=((areahull areacnt)/areacnt)*100
#找出凸壳相对于手的缺陷
外壳=cv2.凸形外壳(近似值,返回点=假)
缺陷=cv2.凸面缺陷(约为外壳)
#l=缺陷数量
l=0
#查找手指缺陷数量的代码
对于范围内的i(缺陷形状[0]):
s、 e,f,d=缺陷[i,0]
开始=元组(大约[s][0])
end=元组(约[e][0])
far=元组(约[f][0])
pt=(100180)
#求三角形所有边的长度
a=数学.sqrt((结束[0]-开始[0])**2+(结束[1]-开始[1])**2)
b=math.sqrt((远[0]-start[0])**2+(远[1]-start[1])**2)
c=数学sqrt((end[0]-far[0])**2+(end[1]-far[1])**2)
s=(a+b+c)/2
ar=数学sqrt(s*(s-a)*(s-b)*(s-c))
#点与凸包之间的距离
d=(2*ar)/a
#在这里应用余弦规则
角度=数学acos((b**2+c**2-a**2)/(2*b*c))*57
#忽略大于90的角度,忽略非常靠近凸面外壳的点(它们通常是由噪声引起的)
如果角度为30:
l+=1
cv2.圆(roi,far,3,[255,0,0],-1)
#在手周围画线
cv2.行(roi,开始,结束,[0255,0],2)
l+=1
#打印其范围内的相应手势
font=cv2.font\u HERSHEY\u SIMPLEX
如果l==1:
如果areacnt最常用的消除数据抖动的方法是收集更多的数据,并从中获取平均或最频繁的数据
你可以测量一秒钟,然后取其中出现最多的数字。例如,如果有10帧分别显示[5,3,1,5,5,4,5,4,4,3,2]个手指,则输出应为5个手指。然后将手指数添加到先前测量的手指数中,在屏幕上显示,然后继续测量
首先也是最重要的一点,我认为制作一种方法是一个好主意,它可以获取图像并返回测量的手指数量。让我们称之为检测器(图像)。您应该能够很容易地从上面的所有代码中得到这一点,因为您知道哪个变量打印手指的数量
您要添加两位数。这是另一个问题。如果你总是有两位数,这很简单,你可以测量4倍的总数,例如,5,3,4,2。那么答案是53+42。如果不总是两位数,你可以让这个人在一位数之前先举0,然后仍然测量4次
我通常在C++中工作,所以编写一个代码示例可能会出错。我以某种python风格编写了一些伪代码,希望您能够理解。让我们来编写伪代码:
//set the start time so you know how much time has passed after the first measurement
start_time = time.time()
//this is how long you want to measure the fingers
timeToMeasure = 1000
//initialize with a not possible number
previousAmountFingers = -1
prevCombinedFingers = -1
while(1):
//Get the image Mat from the camera. It can be the raw feed, or it can be preprocessed depending on how you want to display it later.
image = GetImageFromCamera()
listNrOfFingers.append(DetectNrFingers(image))
elapsed_time = time.time() - start_time
if(elapsed_time > timeToMeasure)
//this is my example above, which would return a 5 in [5, 3, 1, 5, 5, 4, 5, 4, 3, 2]
amountOfFingers = numberOccuringTheMost(listNrOfFingers)
listNrOfFingers.Clear()
if(previousAmountFingers != -1) //the initial value
//combine seperate integers to one, for example, 5 and 3 -> 53
combinedFingers = int(str(amountOfFingers) + str(previousAmountFingers))
previousAmountFingers = -1
if(prevCombinedFingers != -1)
sumFingers = combinedFingers + prevCombinedFingers
//putText sumFingers into the image on a position you like
prevCombinedFingers = combinedFingers
else //only if the previous digit was not initialized yet:
previousAmountFingers = amountOfFingers
start_time = time.time() //reset the timer for the next round of measurements.
因为你需要实时计算,所以我认为每帧1秒是不够的,但是我想你可以稍微延迟一下计算。只需打印之前计算的总和,直到计算下一个为止。因此,即使尚未计算手指,也要更多地显示帧。当然,您可以将1秒设置为更短,但您也需要时间来调整手,因此,如果您还想显示手,您需要显示比答案更多的帧。非常感谢。这很有帮助。我现在就开始写代码。好的,祝你好运。你能接受我的回答吗?如果你对这个问题还有其他问题,就把它们贴在这里:)是的,它给了我解决问题的方法。我会写代码并尽快发布。