本稿は「ml5-examples/p5js/SketchRNN/SketchRNN_basic」のサンプルを元に、適用するモデルをメニューから変更できるようにしたものです。
次のリンクをクリックすると、サンプルの動作を確認することができます。「ml5.js SketchRNNの基本サンプル」まずはml5.jsのSketchRNNを体験してみてください。ドロップダウンメニューをクリックして開き、描きたい項目を選択すると、そのモデルが読み込まれ、SketchRNNが線画を描きます。
以下はこのサンプルで使用しているHTMLとJavaScriptの全コードです。
HTML
<html>
<head>
<meta charset="UTF-8" />
<title>SketchRNN</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.dom.min.js"></script>
<script src="https://unpkg.com/ml5@0.1.2/dist/ml5.min.js" type="text/javascript"></script>
<!-- サンプルでは新しいml5.jsを使うようになっているが、新しいml5.jsでは
nextTensorId is not a function というエラーが発生する。サンプルで使われているml5.jsがどのバージョンが分からない
上のml5@0.1.2ではエラーは発生しない-->
<!---<script src="ml5.min.js" type="text/javascript"></script>-->
</head>
<body>
<h1>SketchRNN</h1>
<p id="status">モデルの読み込み中...</p>
<div>
<label for="model">モデルを選択:</label>
<select id="model"></select>
</div>
<script src="sketch.js"></script>
</body>
</html>
sketch.js
// SketchRNNが描ける絵の種類
const models = [
'alarm_clock',
'ambulance',
'angel',
'ant',
'antyoga',
'backpack',
'barn',
'basket',
'bear',
'bee',
'beeflower',
'bicycle',
'bird',
'book',
'brain',
'bridge',
'bulldozer',
'bus',
'butterfly',
'cactus',
'calendar',
'castle',
'cat',
'catbus',
'catpig',
'chair',
'couch',
'crab',
'crabchair',
'crabrabbitfacepig',
'cruise_ship',
'diving_board',
'dog',
'dogbunny',
'dolphin',
'duck',
'elephant',
'elephantpig',
'eye',
'face',
'fan',
'fire_hydrant',
'firetruck',
'flamingo',
'flower',
'floweryoga',
'frog',
'frogsofa',
'garden',
'hand',
'hedgeberry',
'hedgehog',
'helicopter',
'kangaroo',
'key',
'lantern',
'lighthouse',
'lion',
'lionsheep',
'lobster',
'map',
'mermaid',
'monapassport',
'monkey',
'mosquito',
'octopus',
'owl',
'paintbrush',
'palm_tree',
'parrot',
'passport',
'peas',
'penguin',
'pig',
'pigsheep',
'pineapple',
'pool',
'postcard',
'power_outlet',
'rabbit',
'rabbitturtle',
'radio',
'radioface',
'rain',
'rhinoceros',
'rifle',
'roller_coaster',
'sandwich',
'scorpion',
'sea_turtle',
'sheep',
'skull',
'snail',
'snowflake',
'speedboat',
'spider',
'squirrel',
'steak',
'stove',
'strawberry',
'swan',
'swing_set',
'the_mona_lisa',
'tiger',
'toothbrush',
'toothpaste',
'tractor',
'trombone',
'truck',
'whale',
'windmill',
'yoga',
'yogabicycle',
'everything',
];
// 最初に描画するのは目覚まし時計
let selectedModel = 'alarm_clock';
// SketchRNNモデル
let model = null;
// 現在のストロークパス
let strokePath = null;
// ペンの状態
let previous_pen = 'down';
// 現在の描画位置
let x, y;
function setup() {
// <select>要素の選択肢を設定
const selectE = select('#model');
models.forEach((elm, index) => {
let op = document.createElement("option");
op.value = models[index]; //value値
op.text = models[index]; //テキスト値
selectE.child(op);
});
// キャンバスを作成し、背景色を設定
createCanvas(640, 480);
background(220);
// 線を太くする
strokeWeight(3.0);
// <select>メニューの選択で、モデルを決める
selectE.elt.addEventListener('change', (e) => {
model = null;
selectedModel = e.target.value;
// 選択されたモデルを読み込む
model = ml5.SketchRNN(selectedModel, modelReady);
select('#status').html('モデルの読み込み中...');
}, false);
// 初期設定の'alarm_clock'モデルを読み込む
model = ml5.SketchRNN(selectedModel, modelReady);
}
function modelReady() {
select('#status').html('モデルの準備ができたので描画する');
startDrawing();
}
const startDrawing = () => {
// キャンバスをクリアし、背景色を設定
clear();
background(220);
// 線の色をランダムに決める
const r = random(255);
const g = random(255);
const b = random(255);
stroke(r, g, b);
// 描画の開始位置をキャンバスの中央にする
x = width / 2;
y = height / 2;
// モデルをリセット
model.reset();
// ストロークパスを生成
// async generate(optionsOrSeedOrCallback, seedOrCallback, cb)
model.generate(gotStroke);
}
const gotStroke = (err, s) => {
//console.log(s);
strokePath = s;
}
// 毎フレーム呼び出される
function draw() {
// ストロークパスがあれば
if (strokePath) {
console.log(strokePath.pen);
// ペンが'down'状態なら線を描く
if (previous_pen == 'down') {
line(x, y, x + strokePath.dx, y + strokePath.dy);
}
// ペンを移動
x += strokePath.dx;
y += strokePath.dy;
// ペンの状態は次のストロークのpenプロパティ
previous_pen = strokePath.pen;
// 1回の線描が終わったら
if (strokePath.pen !== 'end') {
// strokePath変数をnullにして、再度ストロークパスを生成し、次の線描に移る
strokePath = null;
model.generate(gotStroke);
}
}
}