一个手势就可以让你为所欲为,Python训练神经网络来检测手势!

版权声明:禁止转载至其它平台,转载至博客需带上此文链接。 https://blog.csdn.net/qq_41841569/article/details/85095051

灵感

想象一下,你正在为亲人举办生日派对。每个人都玩得很开心,音乐正在播放,派对很吵。突然间,是生日蛋糕的时候了!使用Alexa的声音太大了,而不是寻找你的手机或遥控器,如果你只是在谈话中间举起一只张开的手,你的智能家居设备会识别出这种姿势,然后关闭音乐?用同样的手势,你可以调暗灯光 - 及时看到生日蜡烛点亮了生日男孩或女孩的脸。这不是很棒吗?

学习Python中有不明白推荐加入交流群
                号:960410445
                群里有志同道合的小伙伴,互帮互助,
                群里有不错的视频学习教程和PDF!

可以在此处找到Github项目存储库中的代码,或在此处查看最终的演示文稿幻灯片。

 
https://github.com/athena15/project_kojak https://docs.google.com/presentation/d/1UY3uWE5sUjKRfV7u9DXqY0Cwk6sDNSalZoI2hbSD1o8/edit?usp=sharing 

背景

很长时间都对手势检测感到好奇。记得当第一部微软Kinect问世的时候 - 我只用一挥手就可以玩游戏并控制屏幕。随着时间的推移,谷歌主页和亚马逊Alexa等设备发布,似乎手势检测失去了支持语音的雷达。不过,我想知道它是否有可能经历复兴,现在像Facebook门户和亚马逊回声秀这样的视频设备即将问世。考虑到这一点,我想看看是否有可能构建一个能够实时识别我的手势的神经网络 - 并运行我的智能家居设备!

数据和我的早期模型

对这个想法感到很兴奋,并迅速采取行动,就像我被射出大炮一样。开始在Kaggle.com上使用手势识别数据库,并探索数据。它由20,000个标记的手势组成,如下面所示。

 
https://www.kaggle.com/benenharrington/hand-gesture-recognition-database-with-cnn 

奇怪的图像,但标签和丰富

一旦读到图像,遇到的第一个问题是我的图像是黑白的。这意味着NumPy阵列只有一个通道,而不是三个(即每个阵列的形状是(224,224,1))。因此无法将这些图像与VGG-16预训练模型一起使用,因为该模型需要RGB,3通道图像。这是通过在图像列表上使用np.stack解决的,X_data:

 
X_data = np.array(X_data, dtype = 'float32') X_data = np.stack((X_data,) * 3, axis=-1) 

一旦克服了这个障碍,就开始建立一个模型,使用一个完整地保留其中10个人中的2个人的训练测试分割。在重新运行基于VGG-16架构的模型后,模型获得了总体0.74的F1分数。这是非常好的,因为随机猜测超过10个类平均会导致10%的准确率。

但是训练模型以识别来自同质数据集的图像是一回事。训练它以识别以前从未见过的图像是另一种。尝试调整照片的光线,并使用深色背景 - 模仿模型训练过的照片。

也尝试过图像增强 - 翻转,倾斜,旋转等等。虽然这些图像比以前做得更好,但仍然无法预测 - 而且看来是不可接受的 - 结果。有一种唠叨的感觉,需要重新思考这个问题,并提出一种创造性的方法来使这个项目发挥作用。

摘要:在尽可能接近现实世界中可能看到的图像的图像上训练您的模型。

重新思考问题

决定转发并尝试新的东西。训练数据的奇怪外观与我的模型在现实生活中可能看到的图像之间存在明显的脱节。决定尝试构建自己的数据集。

一直在使用OpenCV,一个开源计算机视觉库,需要一个工程师一个解决方案,从屏幕上抓取一个图像,然后调整大小并将图像转换成我的模型可以理解的NumPy数组。用来转换数据的方法如下:

 
from keras import load_model model = load_model(path) # open saved model/weights from .h5 file def predict_image(image): image = np.array(image, dtype='float32') image /= 255 pred_array = model.predict(image) # model.predict() returns an array of probabilities - # np.argmax grabs the index of the highest probability. result = gesture_names[np.argmax(pred_array)] # A bit of magic here - the score is a float, but I wanted to # display just 2 digits beyond the decimal point. score = float("%0.2f" % (max(pred_array[0]) * 100)) print(f'Result: {result}, Score: {score}') return result, score 

简而言之,一旦启动并运行相机,可以抓取框架,对其进行转换,并从模型中获取预测:

 
#starts the webcam, uses it as video source camera = cv2.VideoCapture(0) #uses webcam for video while camera.isOpened(): #ret returns True if camera is running, frame grabs each frame of the video feed ret, frame = camera.read() k = cv2.waitKey(10) if k == 32: # if spacebar pressed frame = np.stack((frame,)*3, axis=-1) frame = cv2.resize(frame, (224, 224)) frame = frame.reshape(1, 224, 224, 3) prediction, score = predict_image(frame) 

在网络摄像头和模型之间连接管道取得了巨大成功。开始思考什么是理想的形象,以供我的模型。一个明显的障碍是很难将感兴趣的区域(在我们的例子中,一只手)与背景区分开来。

提取手势

采取的方法是任何熟悉Photoshop的人都熟悉的方法 - 背景减法。这是一件美好的事!从本质上讲,如果你在手中有一张场景的照片,你可以创建一个“面具”,除了你的手之外,它将删除新图像中的所有内容。

背景掩蔽和二进制图像阈值

一旦我从我的图像中减去背景,然后我使用二进制阈值使目标手势完全变白,背景完全变黑。我选择这种方法有两个原因:它使手的轮廓清晰明了,并且使得模型更容易在具有不同肤色的用户之间进行推广。这创造了我最终训练模型的照片“轮廓”般的照片。

构建新数据集

现在可以准确地检测到我的手中的图像,决定尝试新的东西。我的旧模型没有很好地概括,我的最终目标是建立一个能够实时识别我的手势的模型 - 所以我决定建立自己的数据集!

选择专注于5个手势:

策略性地选择了4个手势,这些手势也包含在Kaggle数据集中,所以可以在以后对这些图像交叉验证我的模型。我还添加了和平标志,尽管该手势在Kaggle数据集中没有类似物。

从这里开始,我通过设置我的网络摄像头来构建数据集,并在OpenCV中创建一个点击绑定来捕获和保存具有唯一文件名的图像。我试图改变帧中手势的位置和大小,这样我的模型就会更健壮。很快,我建立了一个每个包含550个轮廓图像的数据集。是的,你读得对 - 我拍摄了超过2700张图片。

训练新模型

然后使用Keras和TensorFlow构建了一个卷积神经网络。我开始使用优秀的VGG-16预训练模型,并在顶部添加了4个密集层和一个辍学层。

然后采取了不寻常的步骤,选择在我之前尝试过的原始Kaggle数据集上交叉验证我的模型。这是关键 - 如果我的新模型无法概括为之前没有训练过的其他人的手的图像,那么它并不比我原来的模型更好。

为了做到这一点,我将相同的变换应用到我应用于训练数据的每个Kaggle图像 - 背景减法和二进制阈值处理。这给了他们一个类似我的模型熟悉的“外观”。

Palm转换后的Kaggle数据集手势

结果

该模型的性能超出了我的预期。它几乎可以对测试集中的每个手势进行正确分类,最终获得98%的F1分数,以及98%的精确度和准确度分数。这是个好消息!

正如任何经验丰富的研究人员所知道的那样,在实验室中表现良好而在现实生活中表现不佳的模型并不值得。在我的初始模型遇到同样的失败后,我对这个模型在手势上实时表现良好持谨慎乐观态度。

智能家居集成

在测试模型之前,我想补充一点。我一直都是一个聪明的家庭爱好者,我的愿景一直是用我的手势控制我的Sonos和飞利浦Hue灯。为了方便地访问Philips Hue和Sonos API,我分别使用了phue和SoCo库。它们都非常简单易用,如下所示:

https://github.com/studioimaginaire/phue

https://github.com/SoCo/SoCo

 
# Philips Hue Settings bridge_ip = '192.168.0.103' b = Bridge(bridge_ip) on_command = {'transitiontime' : 0, 'on' : True, 'bri' : 254} off_command = {'transitiontime' : 0, 'on' : False, 'bri' : 254} # Turn lights on b.set_light(6, on_command) #Turn lights off b.set_light(6, off_command) 

使用SoCo通过Web API控制Sonos可以说更容易:

 
sonos_ip = '192.168.0.104' sonos = SoCo(sonos_ip) # Play sonos.play() #Pause sonos.pause() 

然后为不同的手势创建了绑定,以便使用我的智能家居设备执行不同的操作:

 
if smart_home: if prediction == 'Palm': try: action = "Lights on, music on" sonos.play() # turn off smart home actions if devices are not responding  except ConnectionError: smart_home = False pass # etc. etc. 

当最终实时测试模型时,我对结果非常满意。我的模型在绝大部分时间都准确地预测了我的手势,并且我能够使用这些手势来控制灯光和音乐。

猜你喜欢

转载自blog.csdn.net/qq_41841569/article/details/85095051