人臉、顏色追蹤

人臉追蹤並不是人臉辨識,而是純粹判斷五官而追蹤人臉 ( 畢竟如果只是「純前端」而沒有後端資料庫,要做到人臉辨識應該有難度 ),透過人臉與顏色的追蹤,將追蹤的數值套用到智慧插座裡,就可以做出許多意想不到的有趣效果。

相關 Webduino 教學參考:LED ( 人臉追蹤 )

微軟人臉辨識 API:Face API

人臉、顏色追蹤初體驗

如果是透過 Webduino Blockly 線上編輯工具 ( https://blockly.webduino.io ),可以使用現成的人臉追蹤或顏色追蹤積木,來執行相對應的動作。( 要執行的話切記一定要是「https」,因啟動相機無法在 http 的模式下進行 )

Webduino Blockly 人臉追蹤:https://goo.gl/B3Cce0

影像追蹤積木

Webduino Blockly 顏色追蹤:https://goo.gl/zJfTRv

顏色追蹤積木

顏色追蹤

使用的方法和 Webduino 一模一樣,是採用一個名為「tracking.js」的 JavaScript,它提供了人臉、顏色...等追蹤的方法。

連結:https://trackingjs.com/

tracking.js

要使用 tracking.js,首先必須載入相對應的 JavaScript,tracking.js 預設可以追蹤顏色。

<script src="https://blockly.webduino.io/lib/tracking-min.js"></script>

追蹤的方式是先透過電腦的攝影機擷取影像,透過網頁 video 的標籤顯示出來,因此 HTML 一開始要先放入 video,然後這裡可以在外層多加一個 div 作為定位。

<div id=”demo>
  <video id="demo-vedio" preload="" autoplay="" loop="" muted="" controls=""></video>
</div>

然後因為這邊要把追蹤到的顏色或是人臉,用一個對應的顏色方框顯示出來 ( 有這個顏色的區域外層用一個矩形框住,矩形邊框的顏色就是偵測到的顏色,如果是人臉也會指定一個外框顏色 ),雖然標記用的矩形是動態產生,我們仍然可以先從 CSS 設定好它的一些基本屬性,到這邊一些基本的步驟就完成了。

#demo {
  position: relative;
  width: 400px;
  height: 300px;
}

#demo-video {
  position: absolute;
  z-index:1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

#demo div{
  position:absolute;
  z-index:2;
}

首先看到顏色追蹤 ( 預設功能 ),官方範例提供三種預設可追蹤的顏色。

track.myTracker = new tracking.ColorTracker(["magenta", "cyan", "yellow"]);

不過因為只有追蹤三種顏色還是太少,可以自己添加追蹤的顏色數量,透過 .registerColor 的方法,自行添加顏色,不過這邊要注意的是,添加的顏色是用 RGB 的範圍來定義,因為雖然眼睛以為是紅色,透過攝影機的電腦卻不見得認為是紅色 ( 舉例來說,藍色的東西在紅色的光下面,看起來就偏紫色,白紙在黃光下就會變成黃色是一樣的道理 ),所以才需要定義範圍。( 不過同樣的,環境光線常會影響顏色判斷,最好是用白光測試比較準確 )

tracking.ColorTracker.registerColor("red", function(r, g, b) {
  if (r > 160 && g < 80 && b < 80) {
    return true;
  }
  return false;
});
tracking.ColorTracker.registerColor("green", function(r, g, b) {
  if (r < 80 && g > 160 && b < 80) {
    return true;
  }
  return false;
});

tracking.ColorTracker.registerColor("blue", function(r, g, b) {
  if (r < 80 && g < 80 && b > 160) {
    return true;
  }
  return false;
});

定義好顏色後,我這邊另外用了一個物件,把對應邊框的顏色寫在裡面。

track.storkColor = {
  magenta: "#f0a",
  red: "#f00",
  cyan: "#0ff",
  yellow: "#ff0",
  green: "#0c0",
  blue: "#00f"
};

接著就是要啟動攝影機。

track.trackerTask = tracking.track("#demo-video", track.myTracker, {
  camera: true
});

透過 .on(‘track’ 的方法,就可以開始追蹤顏色,而這邊 event.data.length 表示追蹤到的顏色總數,如果你拿兩個黃色物體,長度就會是 2,你拿一個紅一個黃,長度也會是 2,也因此當數量不為 0,就表示有追蹤到顏色。

track.myTracker.on('track', function(event) {
  if (event.data.length === 0) {
    // No colors were detected in this frame.
  } else {
    event.data.forEach(function(rect) {
      // rect.x, rect.y, rect.height, rect.width, rect.color
    });
  }
});

到這邊差不多就完成顏色追蹤了,看一下完整的 JavaScript,最主要就是根據顏色的數量,產生對應數量的 div 作為方框來追蹤,當顏色數量改變或沒有追蹤到顏色時,在動態的調整 div 的數量,而 div 的顏色則是根據我們剛剛設定的邊框顏色物件來決定。

$(function(){
  var track = {};
  var $demo = $('#demo');

  tracking.ColorTracker.registerColor("red", function(r, g, b) {
    if (r > 160 && g < 80 && b < 80) {
      return true;
    }
    return false;
  });
  tracking.ColorTracker.registerColor("green", function(r, g, b) {
    if (r < 80 && g > 160 && b < 80) {
      return true;
    }
    return false;
  });

  tracking.ColorTracker.registerColor("blue", function(r, g, b) {
    if (r < 80 && g < 80 && b > 160) {
      return true;
    }
    return false;
  });

  track.myTracker = new tracking.ColorTracker(["magenta", "cyan", "yellow", "red", "green", "blue"]);
  track.storkColor = {
    magenta: "#f0a",
    red: "#f00",
    cyan: "#0ff",
    yellow: "#ff0",
    green: "#0c0",
    blue: "#00f"
  };

  track.trackerTask = tracking.track("#demo-video", track.myTracker, {
    camera: true
  });

  track.myTracker.on("track", function(event) {
    if (event.data.length === 0) {
          $('#demo div').remove(); //如果沒偵測到顏色,移除所有自動產生的追蹤方框
    } else {
      $('#demo div').remove();  //一開始搜尋到顏色時,先清空對應的追蹤方框
      var divLength = event.data.length; //獲取顏色數量
      event.data.forEach(function(e,i){
        if($('#demo .div'+i).length === 0){
          $('#demo').append('<div class="div'+i+'"></div>');  //產生對應的追蹤方框
        }
        //設定追蹤方框樣式
        $('#demo .div'+i).css({
           'border-width':'3px',
           'border-style':'solid', 
           'border-color':track.storkColor[e.color],
           'left':e.x,
           'top':e.y,
           'width':e.width,
           'height':e.height
         });
      });
    }
  });
});

完整程式碼:https://bin.webduino.io/corav/1/edit?html,css,js,output

要執行的話切記一定要是「https」,因啟動相機無法在 http 的模式下進行。

執行顏色追蹤程式

人臉追蹤

看完了顏色追蹤接著看人臉追蹤,原理其實都差不多,只是如果要追蹤人臉,必須額外載入「face-min.js」

<script src="https://blockly.webduino.io/lib/face-min.js"></script>

和顏色追蹤的差別只在於第一段,顏色追蹤是設定追蹤的顏色名稱以及範圍,而人臉追蹤則是一些預設的參數。( 官方預設是這些參數 )

track.myTracker = new tracking.ObjectTracker("face");  
tracker.setInitialScale(4);
tracker.setStepSize(2);
tracker.setEdgesDensity(0.1);

最後的程式碼長相,CSS 的部分和剛剛顏色追蹤一模一樣,JavaScript 就只是把追蹤到的人臉用紅色方框表示出來。

$(function(){
  var track = {};
  var $demo = $('#demo');

  track.myTracker = new tracking.ObjectTracker("face");
  track.myTracker.setInitialScale(4);
  track.myTracker.setStepSize(0.5); //官方預設2,數值比較小比較不會抖動,但相對較吃效能
  track.myTracker.setEdgesDensity(0.1);

  track.trackerTask = tracking.track("#demo-video", track.myTracker, {
    camera: true
  });

  track.myTracker.on("track", function(event) {
    if (event.data.length === 0) {
          $('#demo div').remove(); //如果沒偵測到人臉,移除所有自動產生的追蹤方框
    } else {
      $('#demo div').remove();  //一開始搜尋到人臉時,先清空對應的追蹤方框
      var divLength = event.data.length; //獲取人臉數量
      event.data.forEach(function(e,i){
        if($('#demo .div'+i).length === 0){
          $('#demo').append('<div class="div'+i+'"></div>');  //產生對應的追蹤方框
        }
        //設定追蹤方框樣式
        $('#demo .div'+i).css({
           'border-width':'3px',
           'border-style':'solid', 
           'border-color':'#f00',
           'left':e.x,
           'top':e.y,
           'width':e.width,
           'height':e.height
         });
      });
    }
  });
});

程式:https://bin.webduino.io/mofor/1/edit?html,css,js,output

要執行的話切記一定要是「https」,因啟動相機無法在 http 的模式下進行。

執行人臉追蹤程式

透過顏色追蹤點亮燈泡

到這邊大致上已經掌握顏色追蹤以及人臉追蹤的原理,再來就是和智慧插座結合,首先用顏色追蹤,讓追蹤到黃色的時候會開燈,追蹤到藍色的時候會熄燈。

$(function(){
  var track = {};
  var $demo = $('#demo');
  var led;

  tracking.ColorTracker.registerColor("red", function(r, g, b) {
    if (r > 160 && g < 80 && b < 80) {
      return true;
    }
    return false;
  });
  tracking.ColorTracker.registerColor("green", function(r, g, b) {
    if (r < 80 && g > 160 && b < 80) {
      return true;
    }
    return false;
  });

  tracking.ColorTracker.registerColor("blue", function(r, g, b) {
    if (r < 80 && g < 80 && b > 160) {
      return true;
    }
    return false;
  });

  track.myTracker = new tracking.ColorTracker(["magenta", "cyan", "yellow", "red", "green", "blue"]);
  track.storkColor = {
    magenta: "#f0a",
    red: "#f00",
    cyan: "#0ff",
    yellow: "#ff0",
    green: "#0c0",
    blue: "#00f"
  };

  track.trackerTask = tracking.track("#demo-video", track.myTracker, {
    camera: true
  });

  boardReady({device: '你的裝置 ID'}, function (board) {

    board.systemReset();
    board.samplingInterval = 250;
    led = getLed(board, 10);

    track.myTracker.on("track", function(event) {
      if (event.data.length === 0) {
            $('#demo div').remove(); //如果沒偵測到顏色,移除所有自動產生的追蹤方框
      } else {
        $('#demo div').remove();  //一開始搜尋到顏色時,先清空對應的追蹤方框
        var divLength = event.data.length; //獲取顏色數量
        event.data.forEach(function(e,i){
          if($('#demo .div'+i).length === 0){
            $('#demo').append('<div class="div'+i+'"></div>');  //產生對應的追蹤方框
          }
          //設定追蹤方框樣式
          $('#demo .div'+i).css({
             'border-width':'3px',
             'border-style':'solid', 
             'border-color':track.storkColor[e.color],
             'left':e.x,
             'top':e.y,
             'width':e.width,
             'height':e.height
           });
          if(e.color=='yellow'){
            console.log('yellow'); //追蹤到黃色的時候亮燈
            led.on();
          }else{
            led.off();   //不然就是都熄燈
          }
        });
      }
    });
  });

});

完整程式碼:https://bin.webduino.io/neba/1/edit?html,css,js,output

追蹤特定顏色物品啟動智慧插座燈泡

透過人臉追蹤點亮燈泡

至於人臉追蹤,這邊用人臉的 x 數值來追蹤,預設追蹤到的 x,y 數值是對應到 video 的左上角,這也是為什麼我們可以拿來作為 CSS 位置的主要原因,因為我用的 video 寬度為 360,所以我讓 x 數值大於 ( 180 - 追蹤框寬度/2 ) 的時候就亮燈,也就是臉往右邊移動超過中線的時候會開燈。

$(function(){
  var track = {};
  var $demo = $('#demo');
  var led;

  track.myTracker = new tracking.ObjectTracker("face");
  track.myTracker.setInitialScale(4);
  track.myTracker.setStepSize(0.5);
  track.myTracker.setEdgesDensity(0.1);

  track.trackerTask = tracking.track("#demo-video", track.myTracker, {
    camera: true
  });

  boardReady({device: 'evkG'}, function (board) {

    board.systemReset();
    board.samplingInterval = 250;
    led = getLed(board, 10);

    track.myTracker.on("track", function(event) {
      if (event.data.length === 0) {
            $('#demo div').remove(); //如果沒偵測到人臉,移除所有自動產生的追蹤方框
      } else {
        $('#demo div').remove();  //一開始搜尋到人臉時,先清空對應的追蹤方框
        var divLength = event.data.length; //獲取人臉數量
        event.data.forEach(function(e,i){
          if($('#demo .div'+i).length === 0){
            $('#demo').append('<div class="div'+i+'"></div>');  //產生對應的追蹤方框
          }
          //設定追蹤方框樣式
          $('#demo .div'+i).css({
             'border-width':'3px',
             'border-style':'solid', 
             'border-color':'#f00',
             'left':e.x,
             'top':e.y,
             'width':e.width,
             'height':e.height
           });
          //設定超過中線會亮燈
          if(e.x>(180-e.width/2)){
            led.on();
          }else{
            led.off();
          }
        });
      }
    });

  });
});

完整程式碼:https://bin.webduino.io/pufaqe/1/edit?html,css,js,output

偵測人臉點亮智慧插座燈泡

小結

整體而言了解智慧插座的控制後,就可以用各種方法來操控,當然人臉追蹤與顏色追蹤,都只是廣大控制方式的一部分,後續會介紹更多有趣的控制方法喔!

參考: