小米手环心率准吗ppg方法测出的心率准吗

小米手环光感版评测:跑步实时测心率
日 00:05&&&出处:&& 作者:马景东&& 编辑:马景东 分享
外观介绍& & & 从正面来看,两款产品几乎无法分辨,小米手环光感版依然在正面设计有三颗纯白色指示灯,能够显示电量情况,腕带也依旧采用柔软的硅胶材质,佩戴的舒适度和上一代也无差别,佩戴较为舒适,这一点相比同类的百元产品来说是做的比较出色的地方。虽然小米手环光感版和前一代的小米手环在外观上差别不大,但在细微处还是能看到这两款产品的差别,在厚度上增加了0.9mm,重量也增加了0.5g,在小米手环光感版的背面还增加了光学心率传感器。新一代的小米手环支持Android 4.4 及以上版本系统,同时还支持的iOS7.0以上系统。?手环正面,指示灯依稀可见?按扣式设计,佩戴方便亲肤材质腕带,佩戴舒适& & & 这款小米手环光感版与原版在外观上最大的不同在于“米粒”背面增加了一颗光电式心率传感器,支持光电容积脉搏描记法测量,简单来说就是能够实现心率监测的功能。电池容量依旧是45mAh,但随着心率监测功能的增加,在续航时间上比小米手环的30天要略少,官方给出的数据是10天左右,根据本人使用体验,在不频繁监测心率的情况下,足够维持一周左右时间。在防水性上,支持IP67级防水,能够满足日常防水的需求。可更换表带,充电时需取下“米粒”背面增加了光学心率传感器手环专用充电线功能介绍& & & 心率监测功能是这款手环最大的亮点之一,采用的是光电式心率传感器,这种传感器的优点是监测的准确性高,并且自身体积较小,在监测心率时需要和皮肤进行直接的接触才能实现心率监测,当手环监测心率时能够看到手环背面有绿光在闪烁。为了能够直观的了解小米手环心率监测的准确性,我们选了一款千元级的TOMTOM智能手环与Apple Watch进行实时心率监测数据的对比,结果小米手环光感版在心率监测的准确度上和这两款穿戴设备非常接近,由此也可以看出小米手环光感版在心率监测的准确性上还是非常靠谱的。在单次心率监测的时间上,小米手环光感版单次手动监测心率的时间平均在19s左右,测试速度相比Apple Watch略慢了一些。小米手环光感版与Apple Watch心率监测数据对比小米手环光感版与TomTom手环心率监测数据对比(需要注意:小米手环光感版在监测时抬手臂与胸同高,手环需要避开手腕位置,将底部光学感应器贴近皮肤,同时避免移动,这样能够保证监测数据的准确性)& & & 除了心率监测功能之外,这款产品在其他方面并没有太多需要介绍的变化,虽然增加了心率监测功能,但运动监测和睡眠监测依旧是小米手环最为重要的两项功能,监测数据也更为详尽,能够直观地在小米运动APP中实时查看,而心率监测则需要在下一级菜单中查看,并且不能查看心率的变化趋势图。监测数据APP界面& & &(&小米官方在双十一当天更新了最新版的“小米运动”APP,支持跑步时实时监测心率的功能)& & & 在小米运动APP中还有一项比较重要的功能就是跑步功能,小米手环光感版能够对跑步时的配速、心率(仅光感版)、步频(需搭配李宁智能跑鞋)、卡路里等运动数据进行实时的监测,并且记录跑步时的运动轨迹,同时能够切换到地图模式进行,这个功能对于热衷跑步的人来说是非常有帮助的。优点:高性价比不用多说,增加了心率监测功能,在跑步功能下也能实时监测心率。在功能上也更加全面了,还有佩戴的舒适度依然极佳,除了材质比较柔软的因素外,在重量上也非常轻巧,比较适合全天候佩戴。待改进:在监测心率时,手环需要和手腕皮肤贴合较近,否则容易漏光而导致出现心率监测数据不准的情况。目前还无法在APP端查看心率数据的变化趋势。总结:& & & 从整体上来说,小米手环光感版是一款十分简洁又实用的智能手环,仅在原本运动监测功能的基础上,新增了心率监测功能,而价格只比小米手环普通版增加30元,相比那些动辄上千元的心率手环来说,这依旧是一款性价比极高的智能手环。& & & 关于心率监测数据的准确性问题,在保证监测方法准确的基础上,小米手环光感版在心率监测上是非常精准的。在运动监测功能上,依旧延续了上一代手环的运动监测功能,同时增加了在跑步时实时监测心率的功能,满足了用户基本的日常运动数据监测的需求,同时,亲民的价格也是这款手环最大的优势,对于想要一款入门级智能手环的朋友来说,这款小米手环无疑是非常值得推荐的。■
看过本文的人还看了
1.6万人浏览 4525人浏览 3193人浏览 3111人浏览运动手环准确率不到40%?小米:误差也就10%
[摘要]有消息称,国家体育总局对有运动监测功能的手环的评测结果,结果显示,包括国际品牌手环在内测试数据比如计步数的准确率最高的不到40%。
腾讯数码讯(李珅)11月24日消息,微电子产业专家孙昌旭微博爆料称,国家体育总局对运动手环进行检测,发现准确率最高不到40%,和小米相关人员表示不认可这一说法,小米生态链产品规划总监孙鹏则表示运动手环误差一般在10%以内。孙昌旭的微博认证信息为《国际电子商情》《电子工程专辑》《电子系统设计》首席分析师,她通过微博曝光了运动手环计步误差偏大一事,据孙昌旭表示,她在某活动中遇到了一个传感器专家,该专家向其透露了国家体育总局对有运动监测功能的手环的评测结果,结果显示,包括国际品牌手环在内测试数据比如计步数的准确率最高的不到40%,平均的准确度也就20-30%,而测心率功能误差更大,三星手表放在桌子上也可以测出桌子的心跳是78。微博一经发出,立刻吸引了广泛关注,三星和小米相关人员均表示不认可这一说法,认证信息为三星手机硬件工程师的“戈蓝V”表示,“果然是砖家!明天就用Gear S来打打脸吧!”而小米生态链产品规划总监孙鹏则表示,“正常情况下没有这么差,一般误差都在10%以内。”孙鹏也承认,“要是想故意欺骗手环,是很容易的”,但“运动数据如果是给自己看的,作假没有意义。但要是用来给别人看,防作弊就很重要了。”也有网友对孙昌旭表示支持,网友“小狐仙仙”表示,“某天早上起床我把小米手环摘下来去洗澡……后来发现这段时间变成了深度睡眠”,网友“chenshuaip”表示,“正常的日常行为也不准,你去各大手环的贴吧看看就知道了,没有哪个手环不是骂声一片的,人家都当这东西是玩具!误差百分之十?你想多了!!!要是戴在脚上我还信!”网友“西瓜炖水饺表示”,“现在的可穿戴产品基本就是个笑话”。截止发稿,小米和三星方面均未做进一步的回应,也没有发布任何相关的“打脸”评测。更新:24日晚,“戈蓝V”发表微博称,“我把alpha的HRM放在正常的桌子测量,就会出现这个界面,也证实一点~砖家说话从不经过大脑的,只经过大肠!”孙昌旭对此暂无回应。 查报价,看新品,尽在腾讯数码官方微信 扫描左侧二维码即可添加腾讯数码官方微信 您也可以在微信上搜索“腾讯数码”或“qqdigi”,获取更多数码资讯。
[责任编辑:oliverli]
还能输入140字
Copyright & 1998 - 2017 Tencent. All Rights Reserved红米手机 &
电视盒子 &
智能硬件 &
骨灰级手机控
楼主的荣誉
扫码下载App一键签到 升级加速
小米手环版块版规细则
【横向评测】小米手环光感版的心率检测到底怎么样?
扫一扫!手机看帖更爽
趁着双十一,笔者购入了99元的小米手环的光感版,仅仅比上一代小米手环贵了30元,却多了心率监测这一重要的功能,发售近一周,笔者听到了很多不一样的声音,大家褒贬不一,那么小米手环光感版的心率检测功能到底怎么样呢?他究竟采用什么样的原理,今天就来和大家聊一聊。&目前市面上带心率检测功能的腕带设备数见不鲜,而真正为大家所熟知的设备就屈指可数了,为了检测小米手环光感版的心率检测准确度,笔者特意召集了身边使用心率检测设备的小伙伴们,并且针对这一功能进行了横向对比,Apple Watch,Mio Alpha,Fitbit Charge HR(下图从左至右)&这四款手环(表)均采用了光电式心率传感器,在设备背部紧贴皮肤时,通过心率传感器二极管发出绿光,血液是红色的,反射红光,吸收绿光,传感器根据特定时间内手腕处流通的血液量来检测心率。第一轮测试&在明确了以上这几种设备的测量原理以后,我们开始进行第一轮测试,正常佩戴时的心率检测。▼&首先出场的是大家熟悉的Apple Watch。在稳定测量两次静息心率后分别得出68次/分和74次/分的结果,数值变化在正常范围内。▼&其次出场的是来自美国的知名心率表品牌—迈欧 ,Mio Alpha,佩戴在同一人的手臂上检测心率。&同样是稳定测量静息心率,随机抽取了两次结果,67次/分和69次/分,数值反馈出入不大,与前面Apple Watch所得结果较接近。▼&再次出场的是依然来自美国的知名运动手环品牌—Fitbit,此次加入对比的是Fitbit Charge HR。&经过同样的测量步骤,得出两个静息心率结果,75次/分和68次/分,与Apple Watch和Mio Alpha得出的结果基本一致。&▼&最后要出场的就是本次加入对比的新兵蛋子,小米手环光感版,由于小米手环光感版没有采用屏显,所以必须从手机App上查看测量结果,首先下载小米运动App,绑定成功后开始测量心率。&在连续使用小米手环光感版测量心率后得出一组心率区间,63次/分~68次/分,与前三种设备得出的心率结果没有明显出入,说明此次参与对比的设备在正常佩戴时都能稳定且准确地测出心率,在测量过程中可能会因为说话、呼吸节奏等因素造成轻微误差,均属正常现象!第二轮测试&在入手小米手环光感版的这几天里,笔者陆续听到了来自各方不同的声音,其中大部分是关于小米手环光感版能在非正常佩戴状态时检测到心率数据,比如在空气中空测,在液体上流测等等,于是乎笔者也尝试了下,果然会得出数据,然而其他心率检测设备怎么样呢,不妨挨个试试看!场景一:障碍物测试& & & 我们取来身边最常见的卷纸纸芯,把以上几个设备分别以最贴合的方式戴在纸芯筒上,这样就完全以固体障碍物的形式正面挡住了各自的心率传感器。分别测量,随机抽取两个结果如下。▼&Apple Watch:得出74次/分和180次/分,两次数据相差甚大!▼&Mio Alpha:测量数次均失败,无法得到数据!▼&Fitbit Charge HR:随机抽取两个数值,87次/分和97次/分,出入稍大!▼&小米手环光感版:测量两次,得出80次/分和195次/分,与Apple Watch数据差值相当!场景二:空气测试&参与测试的4部设备全部以最自然的状态侧放静止,保证背部的心率传感器正面没有任何阻挡,测试各设备在自然空气中的心率检测功能。▼&Apple Watch:得出97次/分和183次/分,数值差距依然很大!▼&Mio Alpha:抽取两个数值,165次/分和206次/分,数差明显!▼&Fitbit Charge HR:抽取两个数值,98次/分和99次/分,基本趋于稳定!▼&小米手环光感版:测量两次,分别得出75次/分和197次/分,数值差距同样与Apple Watch所得结果相当!场景三:流体测试&随手找来常用的花露水,因为花露水的瓶身直径正适合佩戴手环,于是笔者分别把四种设备佩戴在瓶身上使用心率检测功能,依然能得出数据,如下图。▼&Apple Watch:随机抽取两个数值,得出107次/分和215次/分,依然保持较大差距!▼&Mio Alpha:随机抽取两个数值,得出204次/分和120次/分,数值差距依然明显!▼&Fitbit Charge HR:随机抽取两个数值,得出104次/分和131次/分,数值差距不算太大▼&小米手环光感版:连续测量两次,得出197次/分和178次/分的结果,两次数值都较高,趋于稳定。&经过第一轮的正常佩戴测试,我们可以看出,目前市面主流腕带设备的心率检测功能均能准确检测心率,并且稳定性相当,作为心率检测设备的新生力量,小米手环光感版的表现出乎意料,希望能在功能上逐步完善。&第二轮的场景测试,也就是目前用户吐槽最多的“不佩戴”就能检测心率问题,相信也不用笔者多说了,眼见为实,耳听为虚,参与测试的设备中无一例外都能在各种场景中不同程度的“检测心率”,且能呈现不同的“数据”,关于这种现象,笔者特意查阅了很多资料,并且与光电式心率传感器的原理相结合,得出了一些个人看法,希望能与大家分享。&目前市面上的主流心率手环均采用了同理的测量方法,它的原理并不复杂,即用反射式光电测量法获得桡动脉PPG信号,对PPG信号做快速傅里叶变换,分析频域,实现人体心率的检测。简单的说,就是用一道光照到动脉上,再反射回来,根据反射回来光的变化,计算出人体的心率。&由于人体生理结构、肌肉、血液的颜色等多项因素,绿色光是人体中通过率最高的颜色,因此心率传感器的光源便使用了绿色光,以求达到最小的损耗和干扰。& & & &心率类手环检测的重点在于人体组织,非人体的物体也会读取到一些数据,这是已知和正常的现象,基于光的反射原理得到数据后心率检测会有读数,这个状况无法全部避免,于是会出现心率手环(表)在“空测”的情况下出现心率数据的问题。希望我的理解能让大家对“心率检测”有更深刻的认识!
扫描二维码,手机查看本帖
: 牺牲没什么卵用的显示屏,获得60-90天的续航,我认为值得!
: 没有显示屏,没有时间,别的厂家都做到小米手环同款了好吗
: 太棒了!用事实说话!
已有22人评分
客观,不偏不倚
真想,必须支持
去鸟吧,连个屏都没有,有啥可谈!!强列建议出个带屏的!
牺牲没什么卵用的显示屏,获得60-90天的续航,我认为值得!
没有显示屏,没有时间,别的厂家都做到小米手环同款了好吗
能不能给个运动实时测量的数据,静态手机软件都不会有偏差。
总评分: 经验 +152
米/ai粉 发表于
14:14:52为什么非生物也能测试出心跳绿光遇到物体有反射。貌似后来华米团队改进了这部分算法,不会空测了。
为什么非生物也能测试出心跳
洋洋洒洒评测了这么多,竟然没有运动中测试心率的评测。
光感版,我睡眠正常,有时5:30分起床小便后接着睡,但每天手机APP都显示我的深睡眠时间只有几十分钟,起床小便后接着睡不再能当做睡眠时间,一起床后睡眠监测就结束了,找不到办法设置改变这些不合理现象。请问谁有遇到类似问题吗?
受教了,其实我觉得还是蛮准确的
QQ: 发表于
08:09:17为什么不测体温怕烧坏了
受教了,其实我觉得还是蛮准确的,至少在正常走步的情况下是准确的,但是有时候会误判,比如摆手的时候也会被认为是在走步。正常走步,我数过,一个不差。
小米的不错
数据偏差可接受,无单独心率监测界面
感谢分享!
·来自小米手机4c
感谢分享!
·来自移动端
够牛,棒棒棒
·来自移动端
够牛,棒棒棒
智技相融 &posted on
·来自小米手机3 联通版
感谢分享。
·来自移动端
小米手环价格亲民
·来自小米Note
每次抢不到
·来自小米Note
小米手环下一代会加屏显嘛?还是直接粗暴的来一个小米手表
京ICP证110507号 京ICP备号当前位置:
小米手环2对比佳明专业手表评测 心率监测哪个准?
测试下实时心率,实时心率只有在跑步模式下可以开启,进行下设置,心率提醒是指当你的实时心率高于设置的最高心率时每隔一段时间手机会进行语音提醒,配速提醒是指低于设置的配速时手环每隔一段时间会震动提醒。
  功能测试  我们还是连接手机,看看功能吧,手环的绑定与原来没什么区别,这里就不多废话了,我们把固件升级到最新版本。  升级完进入App,看到手环还有69%的电量,距离上次充电已15天,估计续航还是不错的,抬腕亮屏功能需要通过App打开,在手环显示设置中可以看到能够显示的信息:时间、步数、里程、热量、心率、剩余电量。这里面时间的显示是无法取消的,显示顺序也无法调整。  我们在阳光下试一下,显示会变暗,但是还是可以看清时间的,还不错。对于抬腕亮屏的功能进行了一个简单测试,20次抬腕18次亮屏显示时间,其中失败的两次是因为抬腕的速度太慢,屏幕会在抬腕停止一两秒后亮起,这应该是为了避免将甩臂等动作误判为抬腕。  再测试一下主要的功能之一&&心率。与小米手环光感版不同的是小米手环2的心率可以显示在屏幕上,这里我们用佳明235来对比一下小米手环2的心率,数值差异不大,完全可以接受。这里有个问题需要注意,在如下图所示的手腕处佩戴小米手环2测试心率成功的几率非常低,原因是太靠近手腕了。所以要切记,小米手环2佩戴不要太靠近手腕,否则测试心率会失败。  我们再测试下实时心率,实时心率只有在跑步模式下可以开启,进行下设置,心率提醒是指当你的实时心率高于设置的最高心率时每隔一段时间手机会进行语音提醒,配速提醒是指低于设置的配速时手环每隔一段时间会震动提醒。因为个人身体状况不太好所以只跑了1.24公里,在这段路程里,核对手环与佳明235的数据最少20次,两者数值差距超过10的情况有1次,超过5的情况有3次,应该说这个实时心率还是比较准确的。
&&&&&&&&&&&&&&&&
责任编辑:Finn
免责声明:
本文仅代表作者个人观点,与
OFweek医疗网
无关。其原创性以及文中陈述文字和内容未经本站证实,
对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅
作参考,并请自行核实相关内容。
邮箱/用户名:
忘记密码?
用其他账号登录: QQ
请输入评论
医疗器械器械研发器械销售
广东省/深圳市
四川省/成都市
广东省/深圳市
广东省/深圳市
广东省/深圳市
广东省/深圳市
北京市/海淀区
广东省/深圳市
广东省/深圳市
广东省/惠州市
*文字标题:
*纠错内容:
联系邮箱:
*验 证 码:[前情提要]&光阴似箭,日月如梭,最近几年,支持心率检测的设备愈发常见了,大家都在各种测空气测雪碧的,如火如荼,于是我也来凑一凑热闹。[0]这段时间,我完成了一个基于iOS的心率检测Demo,只要稳定地用指尖按住手机摄像头,它就能采集你的心率数据。Demo完成后,我对心率检测组件进行了封装,并提供了默认动画和音效,能够非常方便导入到其他项目中。在这篇博客里,我将向大家分享一下我完成心率检测的过程,以及,期间我遇到的种种困难。
本文中涉及到的要点主要有:
Core Graphics
Delegate & Block
RGB -& HSV
基音标注算法(TP-Psola)
光电容积脉搏波描记法(PhotoPlethysmoGraphy, PPG)
在开始之前,我先为大家展示一下最后成品的效果:
心率检测的ViewController
上图展示的是心率检测过程中的主要界面。
在检测的过程中,应用能够实时捕捉心跳的波峰,计算相应的心率,并以Delegate或Block的形式回调,在界面上显示相应的动画和音效。
〇、剧情概览
好吧,?其实上面的前情提要都是我瞎掰的,这个Demo是我来到公司的第一天接到的任务。刚接到任务的时候其实是有点懵逼的,原本以为刚入职两天可能都是要看看文档,或者拖拖控件,写写界面什么的,结果Xcode都还没装好,突然接到一个心率检测的任务,顿时压力就大起来了?,赶紧拍拍屁股起来找资料。
心率检测的APP在我高三左右就有了,我清楚地记得当时,年少无知的我还误以为,大概又是哪个刁民闲着无聊恶搞的流氓应用,特地下载下来试了一下,没想到居然真的能测。。。
当时就震惊地打开了某度查了这类应用的原理。所以现在找起资料来还是比较有方向性的。
花了一天的时间找资料,发现在手机心率检测方面,网上相关的东西还是比较少。不过各种资料参考下来,基本的实现思路已经有了。
实现心率检测
一、整体思路
首先说一说用手机摄像头实现心率检测所用到的原理。
我们知道,现在市面上有非常多具备心率检测功能的可穿戴设备,比如各种手环以及各种Watch,其实从本质上讲,我们这次要用到的原理跟这些可穿戴设备所用到的原理并无二致,它们都是基于光电容积脉搏波描记法(PhotoPlethysmoGraphy, PPG)。
iWatch的心率传感器发出的绿光
PPG是追踪可见光(通常为绿光)在人体组织中的反射。它具备一个可见光光源来照射皮肤,再使用光电传感器采集被皮肤反射回来的光线。PPG有两种模式,透射式和反射式,像一般的手环手表这样,光源和传感器在同一侧的,就是反射式;而医院中常见的夹在指尖上的通常是透射式的,即光源和传感器在不同侧。
皮肤本身对光线的反射能力是相对稳定的,但是心脏泵血使得血管容积周期性地变化,导致反射光也呈现出周期性的波动值,特别是在指尖这种毛细血管非常丰富的部位,这种周期性的波动很容易被观察到。
使用iPhone的系统相机就可以轻易地用肉眼观察到这种波动&&在录像中打开闪光灯,然后用手指轻轻覆盖住摄像头,就能观察到满屏的红色图像会随着心跳产生一阵一阵的明暗变化,如下图(请忽略满屏的摩尔纹)。
直接用肉眼就能观察到相机图像的明暗变化
至于,为什么可穿戴设备上用的光源大多数都是绿光,我们用手机闪光灯的白光会不会有问题。这主要是因为绿光在心率检测中产生的信噪比比较大,有利于心率的检测,用白光也是完全没问题的。详情可以移步知乎:各种智能穿戴的心率检测功能 。我在这里就不细说了。
/question/
我们已经知道我们需要用闪光灯和摄像头来充当PPG的光源和传感器,那么下面就来分析一下后续整体的方案。下面是我搜集完数据之后大致画出的一个流程图。
首先我们需要采集相机的数据,这一步可以使用AVCapture;
然后按照某种算法,对每一帧图像计算出一个相应的特征值并保存到数组中,算法可以考虑取红色分量或者转换为HSV再计算;
在得到一定量的数据后,我们对这个时间段内的数据进行预处理,譬如进行滤波,过滤掉一些噪声,可以参考一篇博客:巴特沃斯滤波器;
接下来,就可以进行心率计算,这一步可能涉及到一些数字信号处理的内容,例如波峰检测,信号频率计算,可以使用Accelerate.Framework的vDSP处理框架,Accelerate框架的用法可以参考:StackOverFlow的一个回答(最终我并没有使用,原因后面会提到);
最终就可以得到心率。
二、初步实现
有了大概的方案之后,我决定着手进行实现了。
1)视频流采集
我们前面已经提到,我们要用AVCapture进行视频流的采集。在使用AVCapture的时候,需要先建立AVCaptureSession,相当于是一个传输流,用来连接数据的输入输出,然后分别建立输入和输出的连接。因此,为了更加直观,我先做了一个类似于相机的Demo,把AVCapture采集到的相机图像直接传输到一个Layer上。
1.创建AVCaptureSession
AVCaptureSession的配置过程类似于一次数据库事务的提交。开始配置前必须调用[_session beginConfiguration];来开始配置;完成所有的配置工作后,再调用[_session commitConfiguration];来提交此次配置。
因此,整个配置过程大致是这样的:
/** 建立输入输出流 */
_session = [AVCaptureSession new];
/** 开始配置AVCaptureSession */
[_session beginConfiguration];
&&* 配置session
&&* (建立输入输出流)
/** 提交配置,建立流 */
[_session commitConfiguration];
/** 开始传输数据流 */
[_session startRunning];
2.建立输入流From Camera
要从相机建立输入流,就得先获取到照相机设备,并且对它进行相应的配置。这里对照相机的配置最关键的是要打开闪光灯常亮。此外,再设置一下白平衡、对焦等参数的锁定,来保证后续的检测过程中,不会因为相机的自动调整而导致特征值不稳定。
/** 获取照相机设备并进行配置 */
AVCaptureDevice *device = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];
if ([device isTorchModeSupported:AVCaptureTorchModeOn]) {
&&&& NSError *error = nil;
&&&& /** 锁定设备以配置参数 */
&&&& [device lockForConfiguration:&error];
&&&& if (error) {
&&&&&&&& return;
&&&& [device setTorchMode:AVCaptureTorchModeOn];
&&&& [device unlockForConfiguration];//解锁
需要注意的是,照相机Device的配置过程中,需要事先锁定它,锁定成功后才能进行配置。并且,在配置闪光灯等参数前,必须事先判断当前设备是否支持相应的闪光灯模式或其他功能,确保当前设备支持才能够进行设置。
此外,对于相机的配置,还有一点非常重要:记得调低闪光灯亮度!!
长期打开闪光灯会使得电池发热,这对电池是一种伤害。在我调试的过程中,曾经无数次调着调着忘了闪光灯还没关,最后整只手机发热到烫手的程度才发现,直接进化成小米~ 所以,尽量将闪光灯的亮度降低,经过我的测试,即使闪关灯亮度开到最小也能够测得清晰的心率。
接下来就是利用配置好的device创建输入流:
/** 建立输入流 */
NSError *error = nil;
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& error:&error];
if (error) {
&&&& NSLog(@"DeviceInput error:%@", error.localizedDescription);
&&&& return;
3.建立输出流To AVCaptureVideoDataOutput
建立输出流需要用到AVCaptureVideoDataOutput类。我们需要创建一个AVCaptureVideoDataOutput类并设置它的像素输出格式为32位的BGRA格式,这似乎是iPhone相机的原始格式(经@熊皮皮提出,除了这种格式,还有两种YUV的格式)。后续我们读取图像Buffer中的像素时,也是按照这个顺序(BGRA)去读取像素点的数据。设置中需要用一个NSDictionary来作为参数。
我们还要设置AVCaptureVideoDataOutput的代理,并创建一个新的线程(FIFO)来给输出流运行。
/** 建立输出流 */
AVCaptureVideoDataOutput *videoDataOutput = [AVCaptureVideoDataOutput new];
NSNumber *BGRA32PixelFormat = [NSNumber numberWithInt:kCVPixelFormatType_32BGRA];
NSDictionary *rgbOutputSetting;
rgbOutputSetting = [NSDictionary dictionaryWithObject:BGRA32PixelFormat
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&forKey:(id)kCVPixelBufferPixelFormatTypeKey];
[videoDataOutput setVideoSettings:rgbOutputSetting];&&&&// 设置像素输出格式
[videoDataOutput setAlwaysDiscardsLateVideoFrames:YES]; // 抛弃延迟的帧
dispatch_queue_t videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
[videoDataOutput setSampleBufferDelegate:self queue:videoDataOutputQueue];
4.连接到AVCaptureSession
建立完输入输出流,就要将它们和AVCaptureSession连接起来啦!
这里需要注意的是,必须先判断是否能够添加,再进行添加操作,如下所示。
if ([_session canAddInput:deviceInput])
&&&& [_session addInput:deviceInput];
if ([_session canAddOutput:videoDataOutput])
&&&& [_session addOutput:videoDataOutput];
5.实现代理协议的方法,获取视频帧
上面的步骤中,我们将self设为AVCaptureVideoDataOutput的delegate,那么现在我们就要在self中实现AVCaptureVideoDataOutputSampleBufferDelegate的方法xxx didOutputSampleBuffer xxx,这样在视频帧到达的时候我们就能够在这个方法中获取到它。
#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate & Algorithm
- (void)captureOutput:(AVCaptureOutput *)captureOutput
&&&& didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
&&&& fromConnection:(AVCaptureConnection *)connection {
&&&& /** 读取图像Buffer */
&&&& CVPixelBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
&&&& // 我们可以在这里
&&&& // 计算这一帧的
&&&& // 特征值。。。
&&&& /** 转成位图以便绘制到Layer上 */
&&&& CGImageRef quartzImage = CGBitmapContextCreateImage(context);
&&&& /** 绘图到Layer上 */
&&&& id renderedImage = CFBridgingRelease(quartzImage);
&&&& dispatch_async(dispatch_get_main_queue(), ^(void) {
&&&&&&&& [CATransaction setDisableActions:YES];
&&&&&&&& [CATransaction begin];
&&&&&&&& _imageLayer.contents = renderedImage;
&&&&&&&& [CATransaction commit];
做到这里,我们已经获得了一个类似于相机的Demo,在屏幕上可以输出摄像头采集的画面了,接下来,我们就要在这个代理方法中对每一帧图像进行特征值的计算。
2)采样(计算特征值)
采样过程中,最关键的就是如何将一幅图像转换为一个对应的特征值。
我先将所有像素点转换为一个像素点(RGB):
累加合成一个像素点
转换成一个像素点之后,我们只剩下RGB三个数值,事情就变简单得多。在设计采样的算法的过程中,我进行了许多种尝试。
我先试着简单地使用R、G、B分量中的其中一个直接作为信号输入,结果都不理想。
& HSV色彩空间
想到之前图形学的课上有介绍过HSV色彩空间,是将颜色表示为色相、饱和度、明度(Hue, Saturation, Value)三个数值。
HSV色彩空间[5]
我想,既然肉眼都能观察到图像颜色的变化,而RGB又没有明显的反映,那HSV的三个维度中应该有某个维度是能够反映出它的变化的。我便试着转换为HSV,结果发现色相H随脉搏的变化很明显!于是,我就先确定用H值来作为特征值。
我简单地用Core Graphics直接在图像的Layer上画出H数值的折线:
色相H随脉搏的变化
3)心率计算
为了使得曲线更加直观,我对特征值稍做处理,又改变了一下横坐标的比例,得到如下截图。现在心率信号稳定以后,波峰已经比较明显了,我们开始进行心率的计算。
缩放后,稳定的时候的心率信号
最初,我想到的是利用快速傅里叶变换(FFT)对信号数组进行处理。FFT可以将时域的信号转换成频域的信号,也就得到了一段信号在各个频率上的分布,这样,我们就能通过判断占比最大的频率,就差不多能确定心率了。
但是可能由于我缺乏信号处理的相关知识,经过将近两天的研究,我还是看不懂跟高数课本一样的文档。。。
于是我决定先用暴力的方法算出心率,等能用的Demo出来之后,看看效果如何,再考虑研究算法的优化。
通过上面的曲线,我们可以看出,在信号稳定的时候,波峰还是比较清晰的。因此我想,我可以设置一个阈值,进行波峰的检测,只要信号超过阈值,就判定该帧处于一个波峰。然后再设置一个状态机,完成波峰波谷之间的状态转换,就能检测出波峰了。因为从AVCapture得到的图像帧数为30帧,也就是说,每一帧代表1/30s的时间。那么我只需要数一数从第一个波峰到最后一个波峰之间,经过了多少帧,检测到了多少波峰,那么,就能算出每个波峰间的周期,也就能算出心率了。
这个想法非常简单,但是存在一个问题,那就是,阈值的设置。波峰的凸起程度并不是恒定的,有时明显,有时微弱。因此,一个固定的阈值肯定不能满足实际检测的需求。于是我想到我们可以根据心跳曲线波动的上下范围,来实时确定一个合适的阈值。我做了如下修改:
每次进行心率计算的时候,先找出整个数组的极大和极小值,确定数据上下波动的范围。然后,根据这个范围的一个百分比,来确定阈值。
也就是说,一个特征值只有超过了整组数据的百分之多少,它才会被判定为波峰。
根据这个方法,我每隔一段时间对数据进行一遍检测,在Demo中实现了心率的计算,又对界面进行了简单的实现,大致的效果如下。
初步实现的心率检测Demo
使用的过程中还存在一定程度的误检率,不过总算是实现了心率检测~ ???
三、性能优化
在我粗略实现了心率检测的功能后,Leader提出了对性能进行优化的要求,顺便向我普及了一波Instruments的用法(以前我一直没有用过?)。
封装组件(delegate或block的形式);
提供两种默认动画;
我用Instrument分析了心率检测过程中的CPU占用,发现占用率很高,维持在50%~60%左右。不过这在我的预料中,因为我的算法确实很暴力?&&每帧的图像是尺寸的,在1/30秒内,要对这200多万个像素点进行遍历计算,还要转换成位图显示在layer上,隔一段时间还要计算一次心率。。。
我分析了CPU占用比较多的部分,归纳了几个可以考虑优化的方向
降低采样范围
降低采样率
取消AV输出
降低分辨率
改进算法,去除冗余计算
1.降低采样范围
现在的采样算法是对所有的像素点进行一次采样,我想着是否能够缩小采样的范围,例如只对中间某块区域采样,但试验后我发现,只对某块区域采样会使得检测到的波峰变得模糊,说明个别区域的采样并不具有代表性。
接着我又想到了一个新的办法。我发现图像中,临近像素点的颜色差异很小,那么我可以跳跃着采样,每隔几列、每隔几行采样一次,这样一方面可以减少工作量,一方面对采样的效果的影响也可以减少。
跳跃着采样
采样的方式就像上图展示的一样,再设置一个常量用来调节每次跳跃的间距。这样一来,理论上,每次占用的时间就可以降低为原来的1/n^2,大大减少。经过几次尝试后,可以看到,采样算法所在的函数的CPU占用比例由原来的31%降低到了14%了。
在分析CPU占用时,我发现在循环中对RGB分别累加时,第一个R的运算占用100倍以上的时间。开始时以为可能是Red分量数值较大,计算难度大,猫哥建议我使用位运算,但是我改成位运算后,瓶颈依旧存在,弄得我十分困惑。后来我试着把RGB的计算顺序换一下,结果发现,瓶颈和R无关,不论RGB,只要谁在第一位,谁就会成为瓶颈。后来我想到,这应该是CPU和内存之间的数据传输造成的瓶颈,因为像素点都存在一块很大的内存块里,在取第一个数据的时候可能速度比较慢,然后后面取临近数据的时候可能就有Cache了,所以速度回提高两个数量级。
2.降低采样率
降低采样率就是将视频的帧数降低,我记得,不知道是香农还是谁,有一个定理,大概的意思就是说,采样率只要达到频率的两倍以上,就能检测出信号的频率。
(经coderMoe童鞋指出,此处正式名称应为&耐奎斯特采样定理&~香农是参与者之一)
人的心跳上限一般是160/分钟,也就是不到3Hz,那理论上,我们的采样率只要达到6帧/秒,就能够计算出频率。
不过,由于我之前使用的算法还不是特别稳定,所以,当时我没有对采样率进行改变。
3.取消AV输出
之前我为了方便看效果,将采集到的视频图像输出到了界面上的一层Layer上,其实这个画面完全没必要显示出来。因此我去除了这部分的功能,这样一来,整体的CPU占用就降低到了33%以下。
4.降低分辨率
目前我们采集视频的大小是,其实我们并不需要分辨率这么高。降低分辨率一方面可以减少需要计算的像素点,另一方面可以减少IO的时间。
在我将分辨率降低到640&480:
if ([_session canSetSessionPreset:AVCaptureSessionPreset640x480]) {
&&&&&&/** 降低图像采集的分辨率 */
&&&&&&[_session setSessionPreset:AVCaptureSessionPreset640x480];
结果非常惊人,整体的CPU占用率直接降低到了5%左右!
5.改进算法,去除冗余计算
最后,我对算法中一些冗余的计算进行了优化,不过,由于CPU占用已经降低到了5%左右,真正的瓶颈已经消除,所以这里的改进并没有很明显的变化。
此前,我们已经完成了一个大致可用的心率监测Demo,但在此之前,我着重考虑的都是如何尽快实现心率检测的功能,对整体的结构和对象的封装都没有太多的考虑,简直把OC的面向对象用成了面向过程。
那么我们接下来的一个重要任务,就是对我们的心率检测进行封装,使它成为一个可复用的组件。
封装组件并提供合理接口(delegate或block的形式);
提供两种默认动画;
封装ViewController
最开始的时候,我想到的是对ViewController进行封装,这样别人有需要心率检测的时候,就可以弹出一个心率监测的ViewController,上面带有一些检测过程中的动画效果,检测完成后自动dismiss,并且返回检测到的心率。
我在protocol中声明了三个接口:
* 心率检测ViewController的代理协议
@protocol MTHeartBeatsCaptureViewControllerDelegate
- (void)heartBeatsCaptureViewController:(MTHeartBeatsCaptureViewController *)captureVC
&&&&&&&&&&&&&&didFinishCaptureHeartRate:(int)rate;
- (void)heartBeatsCaptureViewControllerDidCancel:(MTHeartBeatsCaptureViewController *)captureVC;
- (void)heartBeatsCaptureViewController:(MTHeartBeatsCaptureViewController *)captureVC
&&&&&&&&&&&&&&&&&&&&&& DidFailWithError:(NSError *)error;
我将三个方法都设为了optional的,因为我还在ViewController中设置了三个相应的Block供外部使用,分别对应三个方法。
@property (nonatomic, copy)void(^didFinishCaptureHeartRateHandle)(int rate);
@property (nonatomic, copy)void(^didCancelCaptureHeartRateHandle)();
@property (nonatomic, copy)void(^didFailCaptureHeartRateHandle)(NSError *error);
封装心率检测类
对ViewController进行封装之后,我们可以看到,还是比较不合理的。这意味着别人只能使用我们封装起来的界面进行心率检测,如果使用组件的人有更好的交互方案,或者有特殊的逻辑需求,那他使用起来就会很不方便。因此,我们很有必要进行更深层次的封装。
接下来,我将会剥离出心率检测的类,进行封装。
首先,我一点点剥离出心率检测的关键代码,放进新的MTHeartBeatsCapture类中。剥离的差不多之后,就发现满屏的代码都是红色的Error?,花了一个下午,才把项目恢复到能运行的状态。
我在心率检测类中设置了两个方法:启动和停止。使用起来很方便。
/** 开始检测心率 */
- (NSError *)start;
/** 停止检测心率 */
- (void)stop;
然后,我重新设计了一个心率检测器的回调接口,依旧是delegate和block并存的。新的接口如下:
* 心率检测器的代理协议;
* 可以选择Delegate或者block来获得通知,
* 因此protocol中所有方法均为可选方法
@protocol MTHeartBeatsCaptureDelegate
/** 检测到一次波峰(跳动),可通过返回值选择是否停止检测 */
- (BOOL)heartBeatsCapture:(MTHeartBeatsCapture *)capture heartBeatingWithRate:(int)rate;
/** 失去稳定信号 */
- (void)heartBeatsCaptureDidLost:(MTHeartBeatsCapture *)capture;
/** 得到新的特征值(30帧/秒) */
- (void)heartBeatsCaptureDataDidUpdata:(MTHeartBeatsCapture *)capture
我在新的接口中加入了heartBeatsCaptureDidLost:,方便在特征值波动剧烈的时候进行回调,这样外部就能提醒用户姿势不对。而第三个方法,则是为了之后外部的动画view能够做出类似于心电图一样的动画效果,而对外传出数据。
我还移除了检测成功的回调didFinishCaptureHeartRate:,换成了heartBeatingWithRate:,把成功时机的判断交给了外部,当外部的开发人员认为检测的心率足够稳定了,就可以返回YES来停止检测。
此外,我还移除了遇到错误的回调DidFailWithError:,因为我发现,几乎所有可能遇到的错误,都是发生在开始前的准备阶段,因此,我改成了在start方法中返回错误信息,并且枚举出错误类型作为code,封装成NSError。
typedef NS_OPTIONS(NSInteger, CaptureError) {
&&&&CaptureErrorNoError&&&&&&&&&&&& = 0,&&&&&&&&/**& 没有错误 */
&&&&CaptureErrorNoAuthorization&&&& = 1 && 0,&& /**& 没有照相机权限 */
&&&&CaptureErrorNoCamera&&&&&&&&&&&&= 1 && 1,&& /**& 不支持照相机设备,很可能处于模拟器上 */
&&&&CaptureErrorCameraConnectFailed = 1 && 2,&& /**& 相机出错,无法连接到照相机 */
&&&&CaptureErrorCameraConfigFailed&&= 1 && 3,&& /**& 照相机配置失败,照相机可能被其他程序锁定 */
&&&&CaptureErrorTimeOut&&&&&&&&&&&& = 1 && 4,&& /**& 检测超时,此时应提醒用户正确放置手指 */
&&&&CaptureErrorSetupSessionFailed&&= 1 && 5,&& /**& 视频数据流建立失败 */
主要的工作完成后,猫哥给我提了不少意见,主要还是封装上存在的一些问题,很多地方没有必要对外公开,应该尽可能地对外隐藏,接口也应该尽量地精简,没必要的功能要尽可能的去掉。特别是对外公开的一个特征值数组(NSMutableArray),对外应该不可变,这一点我一直没有考虑到。
封装动画&改进动画
心率检测类封装完成后,我又剥离出显示心跳波形的部分,封装成一个MTHeartBeatsWaveView,使用的时候只要将动画View赋给MTHeartBeatsCapture作为delegate,该view上就能获取到特征值数据并进行显示。
动画改进:在测试的过程中,我发现波形动画显示的波形不太理想,View的大小是初始化的时候就确定的,但是心跳波动的幅度变化是比较大的,有时候一马平川,堪比飞机场,有时候波澜壮阔,直接超出View的范围。
因此我对动画的显示做了一个改进:能够根据当前波形的范围,计算出合适的缩放比,对心跳曲线的Y坐标进行动态的缩放,使它的上下幅度适合当前的View。
这个改进大大提高了用户体验。
我们可以看到,先前得到的曲线已经能较好地反映出心脏的搏动,但是现在进行心率的计算还是存在一定的误检率。上图中展示的清晰的心跳曲线,实际上是比较理想的时候,测试中会发现,采样得到的数据经常存在较大的噪声和扰动,导致心率计算中经常会有波峰的误判。因此,我在以下两方面做了优化,来提高心率检测的准确度。
1、在预处理环节进行滤波
得到的曲线有时含有比较多的噪声
分析一下心率曲线里的噪声,我们会发现,噪声中含有一些高频噪声,这部分噪声可能是手指的细微抖动造成的,也可能是相机产生的一些噪点。因此,我找到了一个简易的实时的带通滤波器,对之前我们采样获得到的H值进行处理,滤除了一部分高频和低频的噪声。
加入滤波器处理后的心率信号
在经过滤波器的处理之后,我们得到的曲线就更加平滑啦。
2、参考TP-Psola算法,排除伪波峰
经过滤波器的处理之后,我们会发现,在每个心跳周期中,总会有一个小波峰,因为它不是真正的波峰,因此我称它为&伪波峰&,这个伪波峰非常明显,有时也会干扰到我们心率的检测,被算法误判为心跳波峰,导致心率直接翻倍。
这个伪波峰出现是因为,除了外部的噪声之外,心脏本身的跳动周期中也会出现许多的&杂波&。我们来看一次心跳的完整过程。
心电图波形产生过程的动画 [1]
上图是一次心跳周期中,心脏的状态变化以及对应产生的波段。可以看到,在心脏收缩前后,人体也会有电信号刺激心脏舒张,这在心电图上会表现出若干次的波动。而血压也会有相应的变化,我们检测到的数据的波动就是这样形成的。
正常心电周期 [2]
因此,这个伪波峰的形成是无法避免的,现有的通过阈值来判断波峰的方法很容易被欺骗,还是要考虑算法的改进,因此我又想到了快速傅里叶变换。
由于我对信号处理知之甚少,我看了两天的快速傅里叶,还是没有进展。于是我请教了部门里的前辈们,大家非常热情,推荐了不少方案和资料。其中一位实验室音频处理的博伟学长,碰巧在新人入职培训时和我分到了同一组,我就趁着闲暇的时候请教了他一些相关的问题。他觉得心率的波形比较简单,没必要用快速傅里叶变换,并且向我推荐了基音检测算法。
简单地说,这个算法会标注出可能的波峰,然后通过动态规划排除掉伪波峰,就能得到真正的波峰啦。我根据这个算法的思路,实现了一个简化版的伪波峰排除算法。经过改进后的心率检测,经测试准确度达到了和Apple watch差不多的程度。(自我感觉良好?,求轻喷~~)
实时波峰检测
我还希望提供一个实时的心跳动画,因此我还实现了一个实时的波峰检测。这样每次检测到一个波峰之后,就可以立刻通知delegate或者block,在界面上做出动画。
心率检测的ViewController
由于这一章节是歇了一阵子之后才写的,因此我把它叫做&&歇后语。
这个心率检测的项目前后一共做了三个礼拜左右,虽然第一个Demo用了三四天就完成,但是后续的封装和优化却用了两个星期的时间,嗯,感触颇深。。。
从最开始的incredible,到最后的好意思说堪比Apple Watch,真的是一个很有成就感的过程。虽然期间遇到了不少困难,甚至有那么一两次觉得自己真的无解了,但到最后总能熬过去,山重水复疑无路,柳暗花明又一村。真的忍不住要念诗了,感觉很充实,很开心。
在做这个项目的过程中,我也得到了许多人的帮助。特别是猫哥,各种指导就不用说了,在听说我们对某友好公司食堂的抱怨之后,经常带我们出去开荤,强有力地改善了我们的伙食~? 还有部门里的各位前辈、同事,在看到我的提问之后,非常热情地向我提供意见和资料。希望这篇博客会对大家有所帮助。谢谢大家~
【更新于】
经coderMoe童鞋指出,文中 [三、2.降低采样率] 提到的 &定理& 正式的名称为&奈奎斯特采样定理&。
感谢这段时间以来,大家的鼓励和支持,前阵子我写这篇文章的时候,是万万没有想到会得到这么多人的关注的,实在是受宠若惊。有很多人详细地阅读了这篇博客,并且提出了重要的意见,甚至还有几位客官打赏了我(但是简书取现要满100RMB才行,所以目前我还无法享用这笔增肥基金?哈哈),真的很感谢你们。
我当时写这篇博客也花了不少时间,只怪我语文没学好,在言辞表达上、逻辑结构上,没能做得更好,大家如果有什么意见建议、或者不同的见解,希望能不吝赐教~~大家的关注和交流会让我更有动力分享博客,要知道,写作对我这种工科生而言,真的是,&&体力活&&。?
有想要进一步关注我的朋友,可以收藏一下我正在搭建的博客,域名正在备案中,不过博客系统是已经搭起来了,有兴趣的朋友请移步:?
另外,关于许多朋友非常关心的开源的问题,这两天上班比较忙,但是我会在近期确定是否开源,届时会通过简书更新,感谢关注!
【更新于】
感谢大家的厚爱,收到Leader的回复,这个项目暂时不开源,不好意思。
但是大家如果有什么问题,欢迎继续和我探讨!?
【更新于】
我的域名审核通过啦,欢迎访问:?
另外,有朋友指出,iPhone相机支持的原始数据格式有三种,一种是文中提到的BGRA,另两种似乎是YUV的格式,我对这方面不太了解,感谢提出,详情请看文档。
此外,有个别同学,不经大脑不经谷歌,就一味指责我文中的图片造假。
说什么,文中提到的&系统相机就可以明显观察到明暗变化&的那张照片,根本不可能拍出清晰的指纹。。。
光电容积脉搏波描记法&
https://en.wikipedia.org/wiki/Photoplethysmogram
滤波:http://blog.csdn.net/shengzhadon/article/details/
Accelerate.framework:DSP处理框架(vDSP):
/questions/3398753/using-the-apple-fft-and-accelerate-framework
core Graphics画图:/info-detail-841887.html
心率检测论文:/p-9.html
通过脸部识别心率:http://people.csail.mit.edu/mrub/vidmag/
[0]: 写出&前情提要&的时候,脑子里蹦出的是:previously on marvel agents of shield?
[1]: 引用自维基百科,由Kalumet & selbst erstellt = 自己的作品,,
[2]: 引用自维基百科,由Derivative: Hazmat2Original: Hank van Helvete & 此档案源起于以下档案或由以下档案加以编辑而成: EKG Complex en.svg,,
[5]:引用自维基百科,由(3ucky(3all & Uploaded to en:File:HSV cone.png first (see associated log) by (3ucky(3 then transfered to Commons by Moongateclimber.,,
阅读(...) 评论()

我要回帖

更多关于 小米手环心率准吗 的文章

 

随机推荐