目次
- 認識した顔はデフォルトでは丸で囲まれます
- 顔を囲む形を四角に変更する
- 認識した顔の上に画像をかぶせる(マスクする)
- 認識した顔に光があたってみるような加工をする
- JavaScript全体です
- 参考:第一回と第三回のリンクです
認識した顔はデフォルトでは丸で囲まれます
ブラウザ上で高速に顔認識ができる「pico.js」で静止画像の人物の顔認識をやります。
3回続きの2回目です。
前回を踏まえて認識された顔を示すマークを変更します。
デフォルトだと、以下のように赤い丸です。
デフォルトの赤い丸を描いている部分はこうです。
ctx.beginPath(); ctx.arc(dets[i][1], dets[i][0], dets[i][2]/2, 0, 2*Math.PI, false); ctx.lineWidth = 3; ctx.strokeStyle = 'red'; ctx.stroke();
Canvasの普通の構文で、顔の座標は「dets[i]」にはいっています。
顔を囲む形を四角に変更する
この円を四角に変更します。
dets[i]にはいっている認識した顔の位置をしめす座標の基本は円なので。
- dets[i][0]: 中心のy座標
- dets[i][1]: 中心のx座標
- dets[i][2]: 直径
となっています。
四角形を描くには、左上の視点のx,y座標に置き換えてやる必要があります。
四角形の左上のx,y座標にするには、中心から直径の1/2分ずつ、左上にずらして、こんな感じにしてやればいいわけです。
- 四角形のX座標:dets[i][1]-(dets[i][2]/2)
- 四角形のY座標:dets[i][0]-(dets[i][2]/2)
- 高さと幅:直径なので、dets[i][2] のまま。
これで四角形を描くとするとこういう感じになります。
せっかくなので、色も黄色にしてみましょう。
ctx.beginPath(); ctx.rect(dets[i][1]-(dets[i][2]/2), dets[i][0]-(dets[i][2]/2), dets[i][2], dets[i][2]); ctx.lineWidth = 3; ctx.strokeStyle = 'yellow'; ctx.stroke();
デフォルトを置き換えてみると。
おー・・。いけてるいけてる。
認識した顔の上に画像をかぶせる(マスクする)
次は画像をかぶせます。
まず。
HTML側でかぶせる画像を指定しておきます。
画面にださなくてもいいので、いったん「display:none」で、
<div style="display:none;"> <img id="mask" src="images/kitsune.png"> </div>
こいつをJavaScript側で読み込んで準備します。
var msk_img = document.getElementById('mask');
描画するのは、こう。
座標のもとめかたは、四角を描くときと同じです。
ctx.beginPath(); ctx.drawImage(msk_img, dets[i][1]-(dets[i][2]/2), dets[i][0]-(dets[i][2]/2), dets[i][2], dets[i][2])
画像を何パターンか差し替えてやってみました。
まずは、ふつうに狐の顔。
ふむふむ。
今度はパンダだけど、透過PNGを使ってみたやつ。
なんか、画像を工夫したら、面白いかもです。
認識した顔に光があたってみるような加工をする
もうひとつ、顔の部分に光があたって、ちょっと隠れている感じをやってみます。
描画する部分を、こんな感じにしてみると。
ctx.beginPath(); var grad = ctx.createRadialGradient(dets[i][1], dets[i][0],0,dets[i][1], dets[i][0],dets[i][2]/2); grad.addColorStop(0,'rgba(255,255,255,1)'); grad.addColorStop(1,'rgba(255,255,255,0)'); ctx.arc(dets[i][1], dets[i][0], dets[i][2]/2, 0, 2*Math.PI, false); ctx.fillStyle = grad; ctx.fill();
結果はこんな風になりました。
まあ・・雰囲気はいけてますかね。
JavaScript全体です
最後にJavaScript全文をのせておきます。
何パターンかやったうちの四角を描くパターンです。
var facefinder_classify_region = function(r, c, s, pixels, ldim) {return -1.0;}; var cascadeurl = 'https://raw.githubusercontent.com/nenadmarkus/pico/c2e81f9d23cc11d1a612fd21e4f9de0921a5d0d9/rnt/cascades/facefinder'; fetch(cascadeurl).then(function(response) { response.arrayBuffer().then(function(buffer) { var bytes = new Int8Array(buffer); facefinder_classify_region = pico.unpack_cascade(bytes); console.log('* cascade loaded'); }) }) //var nrow = 341; //var ncol = 512; var ctx = document.getElementById('canvas').getContext('2d'); var img = document.getElementById('image'); var msk_img = document.getElementById('mask'); img.onload = () => ctx.drawImage(img, 0, 0); function rgba_to_grayscale(rgba, nrows, ncols) { var gray = new Uint8Array(nrows*ncols); for(var r=0; r<nrows; ++r) for(var c=0; c<ncols; ++c) gray[r*ncols + c] = (2*rgba[r*4*ncols+4*c+0]+7*rgba[r*4*ncols+4*c+1]+1*rgba[r*4*ncols+4*c+2])/10; return gray; } function fnc_callback(nrow, ncol) { ctx.drawImage(img, 0, 0); var rgba = ctx.getImageData(0, 0, ncol, nrow).data; image = { "pixels": rgba_to_grayscale(rgba, nrow, ncol), "nrows": nrow, "ncols": ncol, "ldim": ncol } params = { "shiftfactor": 0.1, "minsize": 20, "maxsize": 1000, "scalefactor": 1.1 } dets = pico.run_cascade(image, facefinder_classify_region, params); dets = pico.cluster_detections(dets, 0.2); qthresh = 5.0 for(i=0; i<dets.length; ++i){ if(dets[i][3]>qthresh) { ctx.beginPath(); ctx.rect(dets[i][1]-(dets[i][2]/2), dets[i][0]-(dets[i][2]/2), dets[i][2], dets[i][2]); ctx.lineWidth = 3; ctx.strokeStyle = 'yellow'; ctx.stroke(); } } }
ではでは。
参考:第一回と第三回のリンクです
ったのが前回(1)です。
pico.jsはこちらから。