今回は心拍数の取得を見ていきます。
といっても特殊な装置[ref]ユニオンツール社様のセンサなど[/ref]を使うこと無くウェブカメラを使ったWebRTC[ref]Web Real-Time Communication(W3Cによるリアルタイムコミュニケーション用API)[/ref]の映像から
心拍数を取得することを目指します。
インスタレーション作品などを制作する際は、精度良く計測出来るセンサを用いるほうがよいかと思いますが、
ウェブアプリケーションを作成する際、心拍数の計測装置を持っているユーザは
ほとんどいないと思われるため、実行環境が限られてしまいます。
精度は、ある程度ざっくりでも許容出来るアプリケーションであれば、
ウェブカメラからでも、そこそこの精度で心拍数を計測できます。
(あくまで代替手段、としてお考えいただき、精度はアプリケーションごとに検証してみてください。)
さて、どのようにウェブカメラから心拍数を計測するかですが、
心拍センサの仕組み同様、パルス酸素濃度[ref]パルスオキシメーターの概要参照[/ref]を用います。
指の先端の血中の酸素濃度の変化によって、「赤色光と赤外光の吸光度が異なるので、
センサーで透過光や反射光を測定して分析する」(wikiより)ことによりピーク値を検出することで、
心拍数を測定できます。
つまり、PCのウェブカメラに指を乗せて、後ろからライトを当てた状態で、
WebRTC経由で赤色チャンネルの明度の変化を計測する、という手順となります。
まずはWebRTCからの映像取得です。
javascript内で以下の手順で記述します。
(1) ユーザにカメラやマイクなどのメディアデバイス使用許可を尋ねる。
(2) getUserMediaでメディアソース取得。[ref]getUserMedia記述方法[/ref]
・第一引数:メディアソースに関する記述(必須)
・第二引数:メディアソース取得が成功した場合の処理(必須)
・第三引数:エラー表示オプション(オプション)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; window.URL = window.URL || window.webkitURL; if (!navigator.getUserMedia) { alert("no camera..."); } else{ navigator.getUserMedia( {audio:true,video:true}, function(stream){ var video = document.getElementById('myVideo'); video.src = URL.createObjectURL(stream); }, function(error){ console.error(error); } ); } |
上記処理で映像を取得できますので、次に以下手順で処理を続けます。
※getUserMediaのsuccess時に、下記処理を関数として呼び出すとよいかと思います。
(1) 映像のフレームごとにcanvasに静止画書き出し
(2) 静止画imageの中から赤色チャンネルの明度を計算
※各ピクセルの赤色チャンネルを合計し、ピクセル数で割る[ref]canvasのピクセル値[/ref]
※canvasの各ピクセル情報は、左上から順にR、G、B、アルファの情報、すなわり4つのデータ単位で格納されています。
(data[0]〜data[3]までで1セット、data[4]〜data[7]で次のピクセル情報の1セット)
(3) 上記をタイムスタンプ付きのコンソールログとして書き出す。
※あるいは、任意の方法でファイル出力することも考えられます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function getRedChannel(){ requestAnimationFrame(getRedChannel); var video = document.getElementById('myVideo'); var buffer = document.createElement('canvas'); var bufferContext = buffer.getContext('2d'); buffer.width = video.width; buffer.height = video.height; bufferContext.drawImage(video, 0, 0,video.width,video.height); var imagedata = bufferContext.getImageData(0, 0, video.width, video.height); var red_channel=0; for (var i = 0; i < imagedata.data.length; i += 4) { red_channel += imagedata.data[i+0] } console.log("red_channel:" + red_channel/(imagedata.data.length)); } |
上記処理を、ウェブカメラに指をあて、バックライトを当てた状態で実行すると、
コンソールログとして以下のようなタイムスタンプ付きの結果が得られます。[ref]chromeでコンソールにタイムスタンプを表示するには、ディベロッパーツールの設定ボタンから「show timestamps」を選択します[/ref]
あとは、任意の粒度で平均値をとって、均等な時間ごとのデータに整形します。
※たとえば、0.01秒桁以下は切り捨てて、0.1秒単位での平均値をとる。
整形後のログからピーク値を検出し、1分間に何回ピーク値があったか、が心拍数となります。
もし、ウェブアプリケーションとして完成させるなら、上記処理をjavascript内に記述、
ローカルデータとして分析するならコンソールログをエクセルなどで処理します。
なお、ピーク値検出は、Rを使ってもよいですが、前後任意の値よりも大きい値をピークにする、というシンプルな方法もあります。
※エクセルで最も単純にやるならば、A列にデータが入っているとしたとき、
「=IF(AND(A3>A1,A3>A2,A3>A4,A3>A5),”peak”,””)」という記述をB列にかけばよいかと思います。
(A3の前2行(A1,A2)、A3の後ろ2行(A4,A5)よりも大きいとき、A3がピーク)
ちなみに上記方法を経て得られた、私の心拍数(bpm)は72となりました。
健康診断の結果から鑑みても、特に違和感は無い数値かとおもいます。
以上、今回は心拍数のデータを取得する方法を見ていきました。