Daniel Shiffmanさんのcodingtrainのチュートリアルを参考に
特徴抽出を用いた回帰(Regression with Feature Extractor)を試してみました。
featureExtractor()メソッドを用いて実装できます。
-
ml5.js: Feature Extractor Regression
https://www.youtube.com/watch?v=aKgq0m1YjvQ&feature=youtu.be -
featureExtractor()
https://ml5js.org/docs/FeatureExtractor
ファイルは以下にアップしています。
https://www.dropbox.com/s/3cgr99lwuocugwo/03_2_featureExtractorRegression-demo.zip?dl=0
コードは以下です。
試す場合は、プロジェクトフォルダに「images」フォルダを設置し、配下に「happy.png」「sad.png」を置いてください。
ライブラリはCDNを読み込んでますのでローカルサーバー上で実行してください。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Feature Extractor Regression</title>
<style>
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
#inputContainer {
position: absolute;
top: 10px;
left: 10px;
}
input, button {
display: block;
margin: 0 10px 10px 0;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/addons/p5.dom.min.js"></script>
<script src="https://unpkg.com/ml5@0.1.1/dist/ml5.min.js"></script>
<script src="sketch.js"></script>
</head>
<body>
<div id="inputContainer"></div>
</body>
</html>
let mobilenet;
let predictor;
let video;
let happyIco;
let sadIco;
let value = 0;
let slider;
let addButton;
let trainButton;
// MobileNetモデルの準備が完了したときコールバック関数として呼ばれる
function modelReady() {
console.log('モデルが準備できた!');
}
// ビデオ入力したクラス分類機の準備が完了したときコールバック関数として呼ばれる
function videoReady() {
console.log('ビデオが準備できた!!!');
}
// トレーニング完了時に1度だけ実行される関数
function whileTraining(loss) {
if (loss == null) {
console.log('トレーニングが完了した!');
// 画像の予測を取得する
predictor.predict(gotResults);
} else {
console.log(loss);
}
}
// トレーニング完了時に再帰的に実行される関数
function gotResults(error, result) {
if (error) {
console.error(error);
} else {
// 画像の予測の値を代入する
value = result;
// 画像の予測を取得する
// 再帰的に実行
predictor.predict(gotResults);
}
}
function setup() {
// キャンバスを生成する
createCanvas(windowWidth, windowHeight);
// ウェブカメラから映像をキャプチャし、Video要素を生成
video = createCapture(VIDEO);
// Video要素を非表示にする
video.hide();
happyIco = loadImage('images/happy.png');
sadIco = loadImage('images/sad.png');
// 背景を黒で塗りつぶす
background(0);
// MobileNetで事前学習された特徴を展開
mobilenet = ml5.featureExtractor('MobileNet', modelReady);
// ビデオを入力にして、回帰のカスタム予測子を生成する
predictor = mobilenet.regression(video, videoReady);
// スライダーを生成(0 ~ 1)
slider = createSlider(0, 1, 0.5, 0.01);
slider.parent('inputContainer');
// 「サンプル画像追加」ボタンンを生成する
addButton = createButton('サンプル画像を追加する');
addButton.parent('inputContainer');
addButton.mousePressed(function() {
// 0 ~ 1の値に画像を紐づける
predictor.addImage(slider.value());
});
// 「トレーニング開始」ボタンを生成する
trainButton = createButton('トレーニング開始');
trainButton.parent('inputContainer');
// 「トレーニング開始」ボタンが押された時の処理
trainButton.mousePressed(function() {
// クラス分類機を再トレーニングする(Transfer Learning 転移学習)
predictor.train(whileTraining);
});
}
function draw() {
// 背景を黒で塗りつぶし
background(0);
// ウェブカメラからの映像をキャンバスに描画
// ミラー表示
imageMode(CORNER)
push();
translate(width,0);
scale(-1.0,1.0);
image(video, 0, 0, width, height);
pop();
// 画像の直径は横幅の1/10
let diameter = width / 10;
// 円を描画
imageMode(CENTER);
// 上下左右に画像を配置
for ( let x = 0; x < width; x += diameter) {
for ( let y = 0; y < height; y += diameter) {
if (value == 0) {
break; // value = 0(初期値)のときは表示しない
} else if (value < 0.5) {
// 楽しい顔のアイコンを表示
image(happyIco, x + diameter/2, y + diameter/2, diameter*Math.cos(value * Math.PI), diameter);
} else {
// 悲しい顔のアイコンを表示
image(sadIco, x + diameter/2, y + diameter/2, diameter*Math.cos(value * Math.PI), diameter);
}
}
}
// 線を描画しない
noStroke();
// 塗りを黒へ
fill(0);
// 矩形の描画モードを左上へ
rectMode(CORNER);
rect(0, height - 50, width, 50);
// 矩形の描画モードを中央へ
rectMode(CENTER);
// 塗りつぶしを赤へ
fill(255, 0, 0);
rect(value * width, height - 25, 50, 50);
// 塗りつぶしを白に設定
fill(255);
// テキストのサイズを設定
textSize(25);
// テキストを描画
text(value, 10, height - 10);
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
ローカルサーバーを立ち上げ、ブラウザでindex.htmlを開いたら、
以下の手順でテストしてみてください。
- スライダーを左端までドラッグし、ウェブカメラの前で前でポーズをとって、[楽しい]ボタンをクリックします。約15枚の画像を追加してみてください。
- スライダーを右端までドラッグし、ウェブカメラの前でポーズを変えて、[悲しい]ボタンをクリックします。約15枚の画像を追加してみてください。
- [トレーニング開始]をクリックして、トレーニングプロセスが完了するまで待ちます。 (コンソールログにプロセスが表示されます。)
- トレーニングが完了したら、モデルをトレーニングした2つのポーズを切り替えます。
※カメラのいろんな位置で、ポーズ画像を追加した方が精度が上がるかと思います。