2016年2月1日 星期一

用Node.js搭配Google Vision API與Canvas套件,做到人臉辨識功能!

Canvas是HTML5上處理2D影像的常用套件,而在node.js下,可以透過node-canvas來針對影像做一些特殊處理,例如:針對給定的座標畫各式幾何圖形、圖片縮圖等等。
Google Vision API目前是Trust Preview的階段,如果有想要試用,可以在Google的官網(http://cloud.google.com/vision/)申請唷!本篇還是以node-canvas的繪圖為主~ :D

Github

Installation

npm install node-canvas
node-canvas是需要搭配canvas相關函式庫來啟動,相關的安裝方式可以透過官方的github位置來安裝相關套件,以Mac來說,安裝如下:
$ brew install pkg-config cairo libpng jpeg giflib

範例程式

這邊搭配google-vision-api-client套件來查詢Vision API做人臉偵測的動作,並在人的臉部做方型框框標示。
#!/usr/bin/env node
var vision = require('google-vision-api-client');
var requtil = vision.requtil;
var request = require('request');
var Canvas = require('canvas')
  , Image = Canvas.Image
  , fs = require('fs')
  , sizeOf = require('image-size');

var tmpfile = '/tmp/mytmpfile';

var canvas = new Canvas(200, 200)
  , ctx = canvas.getContext('2d')

var jsonfile = '/Users/peihsinsu/.gcpkeys/itri-smart-home/itri-smart-home-33f5a755a360.json';
vision.init(jsonfile);

var outfile = process.argv[3] || '/tmp/test.jpg';

function getColor(i) {
  var list = ['red', 'yellow', 'pink', 'green', 'blue'];
  return list[i%list.length];
}

exports.draw = draw;
function draw(imgfile, outfile, opts, cb){
  fs.readFile(imgfile, function(err, squid){
    if (err) throw err;
    img = new Image;
    img.src = squid;

    if (opts && opts.filter) {
      opts.filter(ctx);
    }
    ctx.drawImage(img , 0, 0, img.width , img.height );

    ctx.globalAlpha = .5;

    var i = 0;
    function doit(vec) {
      var color = Math.random()*1000%255;
      ctx.lineWidth = 4;
      ctx.beginPath();
      ctx.moveTo(vec[0].x, vec[0].y);
      ctx.lineTo(vec[1].x, vec[1].y);
      ctx.lineTo(vec[2].x, vec[2].y);
      ctx.lineTo(vec[3].x, vec[3].y);
      ctx.closePath();
      ctx.strokeStyle = getColor(i);//'rgb(255,color,0)';
      i++;
      ctx.stroke();
      //ctx.fill();
    }

    opts.vec.forEach(function(v) {
      doit(v)
    });
    fs.writeFileSync(outfile, canvas.toBuffer());
    cb();
  });
}

function main(imgfile) {
  var d = requtil.createRequests().addRequest(
    requtil.createRequest(imgfile)
      .withFeature('FACE_DETECTION', 50)
      //.withFeature('LABEL_DETECTION', 20)
      .build());

  var imgSize = sizeOf(imgfile);
  console.log('Got the image size: %sx%s', imgSize.width, imgSize.height);

  vision.query(d, function(e, r, d){
    if(e) return console.log('ERROR:', e);
    console.log(JSON.stringify(d));

    if(!d.responses[0].faceAnnotations) return;

    //var v = d.responses[0].faceAnnotations[0].boundingPoly.vertices;
    var v = [];
    d.responses[0].faceAnnotations.forEach(function(o){
      v.push(o.boundingPoly.vertices);
    })
    console.log('-->', v);
    canvas.width = imgSize.width;
    canvas.height = imgSize.height;

    draw(imgfile, outfile, {
        vec: v,
        filter: function(ctx) {
          //ctx.strokeStyle = 'rgba(255,0,0,.5)';
        }
      },
      function(err) {
        if(err) console.log('ERROR:', err);
    });
  });
}

//Execute the process
if(process.argv[2].indexOf('http') == 0) { //from http resource
  var url = process.argv[2];
  var req = request.get(url);
  req.pipe(fs.createWriteStream(tmpfile));
  req.on('end', function(){
    main(tmpfile);
  });
} else { //from localhost
  main(process.argv[2]);
}
上面程式碼儲存成test.js並給予執行權限後,即可測試...
測試http網站圖片:
$ node test http://www.kevinparker.com.au/people/p7IGM_images/fullsize/shutterstock_48737587_fs.jpg
測試本地圖片:
$ node test /Users/peihsinsu/Pictures/Simon/simon01.jpg
執行完後,會在/tmp/test.jpg產生圖片檔案
$ open /tmp/test.jpg

Notes