"BOKU"のITな日常

興味のむくまま気の向くままに調べたり・まとめたりしてます。

JavaScriptで高速顔検出。検出した顔に任意の画像でマスクする/pico.js(2)

f:id:arakan_no_boku:20210215234003p:plain

ブラウザ上で高速に顔検出ができる「pico.js」で静止画像の人物の顔検出をやります。

3回続きの2回目です。

目次

 

検出した顔はデフォルトでは丸で囲まれます 

前回を踏まえて検出された顔を示すマークを変更します。

デフォルトだと、以下のように赤い丸です。

f:id:arakan_no_boku:20210217225114p:plain 

デフォルトの赤い丸を描いている部分はこうです。

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();

デフォルトを置き換えてみると。

f:id:arakan_no_boku:20210219200502p:plain

おー・・。いけてるいけてる。 

検出した顔の上に画像をかぶせる(マスクする) 

次は画像をかぶせます。

まず。

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])

画像を何パターンか差し替えてやってみました。 

まずは、ふつうに狐の顔。

f:id:arakan_no_boku:20210219222802p:plain

ふむふむ。

今度はパンダだけど、透過PNGを使ってみたやつ。

f:id:arakan_no_boku:20210219222949p:plain

なんか、画像を工夫したら、面白いかもです。 

検出した顔に光があたってみるような加工をする 

もうひとつ、顔の部分に光があたって、ちょっと隠れている感じをやってみます。

描画する部分を、こんな感じにしてみると。

 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();

結果はこんな風になりました。

f:id:arakan_no_boku:20210219230210p:plain

まあ・・雰囲気はいけてますかね。

 

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)です。

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

pico.jsはこちらから。

github.com