前回「AMG8833」で温度を計測できるようにしました。ただ、対象物までの距離によって温度が変わってしまうので、このままでは人の検温に使えません。今回は一定距離を保って検温できる仕組みを作ります。
動作サンプル
シルエットに顔を合わせると、検温できます。
近すぎると高温になってしまうため、「はなれて!」と警告文がでます。
シルエットで距離を保つ
「AMG8833」で検温した場合、距離によって温度が変わってしまいます。
この問題を解決するには、距離センサーを併用して補正するか、人が動かないようにするか、どちらかです。
簡単な後者にします。
シルエットの枠を用意して、その枠に収まる距離のところでじっとします。
単純に床にラインテープを貼っても良いでしょう。
距離が一定なら、温度の補正もしやすいです。
自分の体温を別の体温計で測り、「AMG8833」で測った温度を補正して同じ値になるようにします。
37℃以上でアラート
もし37℃以上だったら、アラートが出るようにします。
画面が赤くなるようにしました。
効果音を付け加えても良いかもしれません。
距離が近すぎたら「はなれて!」
センサーが取得した8×8の温度データの中に、体温と思われる画素が多い場合は近すぎるということです。
「はなれて!」と警告文を出します。
検温に使ったコード
開発環境、サーバー側のコードは変わっていません。HTMLのみ下記コードに改修しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
<html> <head> <title>サーマルカメラ</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.0/socket.io.js"></script> <style> body { background-color: #000; } body.alert { background-color: #900; } #temp { position: absolute; top: 300px; left: 0; right: 0; margin: auto; font-size: 72px; color: #EEE; text-align: center; line-height: 1; } #thermalArea { display: flex; justify-content: center; align-items: center; } #thermalArea div { position: relative; width: 240px; height: 240px; } #thermalArea img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.8; } #canvas { position: relative; transform: scale(30); transform-origin: top left; z-index: -1; } </style> </head> <body> <main> <button type="button" id="thermalBtn">検温!</button> <span id="temp"></span><br> <div id="thermalArea"> <div> <canvas id="canvas" width="8" height="8"></canvas> <img src="img/silhouette.png" alt=""> </div> </div> </main> <script> // サーモグラフィー彩度・明度設定 const maxH = 250; const minH = 0; const stepH = 7; const maxL = 50; const minL = 20; const stepL = 7; // 体温判定 const minTemp = 36; const alertTemp = 37; const socket = io(); const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const $body = $('body'); const $thermalBtn = $('#thermalBtn'); const $temp = $('#temp'); let temp = 0; let calibration = 9; let isTemp = false; let isNear = false; let tempList = []; const init = () => { setSocket(); setBtn(); }; const setSocket = () => { let array, result = []; socket.on('thermal', (data) => { drawCanvas(data); }); }; const setBtn = () => { let timer; $thermalBtn.on('click', function(){ const emitThermal = function(){ socket.emit('msg', 'thermal'); }; isTemp = !isTemp; if(isTemp){ emitThermal(); timer = setInterval(emitThermal, 500); $thermalBtn.text('計測中…'); }else{ clearInterval(timer); $thermalBtn.text('検温!'); } return false; }); }; const drawCanvas = (data) => { let h, l, t = 0, count = 0; for (let i = 0; i < data.length; i++) { for (let j = 0; j < data[i].length; j++) { // 最大温度記録 if(data[i][j] > t){ t = data[i][j]; // 体温ヒット数をカウント if(t + calibration > minTemp){ count++; // 2画素越えると近すぎ if(count > 2){ isNear = true; }else{ isNear = false; } } } // 色相を設定 h = maxH - data[i][j] * stepH; if(maxH < h){ h = maxH; }else if(minH > h){ h = minH; } // 明度を設定 l = (data[i][j] - minL) * stepL; if(maxL < l){ l = maxL; } ctx.fillStyle = 'hsl('+ h +', 100%, '+ l +'%)'; ctx.fillRect(j, i, 1, 1); } } tempList.push(t); if(tempList.length > 10){ tempList.shift(); } // 体温中央値を取得して判定 temp = getTemp(tempList); if(isNear){ $temp.text('はなれて!'); }else if(temp < minTemp){ $temp.text(''); }else{ // 体温なら温度表示して平熱判定 $temp.text(temp.toFixed(1) + '℃'); if(temp < alertTemp){ $body.removeClass('alert'); }else{ $body.addClass('alert'); } } }; const getTemp = (tempList) => { // 中央値の温度を返す let array = tempList.slice(), val; array.sort((a, b) => { return a - b; }); let half = Math.floor(array.length / 2); if (array.length % 2) { val = array[half]; } else { val = (array[half - 1] + array[half]) / 2; } //キャリブレーション val += calibration; return val; }; init(); </script> </body> </html> |
80行目のlet calibration = 9;が、体温の補正値です。
私の環境では約9度低く出るので、+9度補正しています。
センサーまでの距離に応じて、調整が必要です。
続いて、サーモグラフィーとWebカメラの映像を重ねる予定ですが、先に解決しないといけない問題が発生しました。