ブラウザ画面のボタンをクリックして写真を指定し、物体検出を行うアプリの作例です。
HTML:
<input type="file" id="input-file">
<img src="" alt="Image preview...">
<div id="image-container"></div>
CSS:
/* ページに読み込む画像用<img>要素は表示しない */
img {
display: none;
}
JavaScript:
const inputFile = document.getElementById('input-file');
// ページには表示されない<img>要素
const preview = document.querySelector('img');
// [ファイルを選択]ボタンで画像を選択したら
inputFile.addEventListener('change', (e) => {
// 取得したファイル
const imageFile = e.target.files[0];
// ファイルの読み取りに成功したら、readPromise.then()を実行する
new Promise((resolve, reject) => {
const reader = new FileReader();
// ファイルの読み取りに成功したら解決する
reader.onload = (e) => {
resolve(e.target.result);
}
// ファイルを画像として読み取る
reader.readAsDataURL(imageFile);
// 成功したら、<img>要素に画像を割り当てる
}).then((img) => {
// 画像が読み込まれたら
preview.onload = () => {
// 読み込む画像の幅と高さ用変数
const imageWidth = preview.naturalWidth;
const imageHeight = preview.naturalHeight;
// <canvas>を作成して、それに画像のイメージデータを割り当てる
const canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;
const context = canvas.getContext('2d');
// 画像に重ねて表示する矩形の色と線幅、文字の色、フォントの設定
context.strokeStyle = "lightgreen";
context.lineWidth = 2;
context.fillStyle = "red";
context.font = "30px 'MS ゴシック'";
// キャンバスに画像を描画する
context.drawImage(preview, 0, 0);
// イメージデータを取得
const imageData = context.getImageData(0, 0, imageWidth, imageHeight);
// キャンバスをページに表示 = 写真が見えるようになる。
document.getElementById('image-container').appendChild(canvas);
// モデルを読み込む
// 現在cocoSsdはcoco-ssdでオブジェクト化されているようなので、変数cocoSsd(サンプル通り)に代入している。
const cocoSsd = window['coco-ssd'];
cocoSsd.load().then(model => {
// model.detect()にイメージデータを渡し、物体検出する
model.detect(imageData).then(predictions => {
// console.log(predictions);
for (let i = 0; i < predictions.length; i++) {
// キャンバス(読み込んだ写真)の上に、物体を囲む矩形とクラス名を描画する
drawBox(context, predictions[i]);
}
});
});
}
preview.src = img;
});
}, false);
/*
{
bbox: [x, y, width, height], // 物体を囲む境界ボックスのx値、y値、幅、高さ
class: "person", // 分類名
score: 0.8380282521247864 // そうである確率
}
*/
// キャンバスの上に、物体を囲む矩形とクラス名を描画する
const drawBox = (ctx, pred) => {
//console.log(pred.bbox);
const box = pred.bbox;
// 薄緑の矩形で物体を囲む
ctx.strokeRect(box[0], box[1], box[2], box[3]);
// 赤い文字でクラス名を描く
ctx.fillText(pred.class, box[0], box[1] + 10, 80);
}
なお、上記コードを試すときには、cross-origin制約に引っかからないように、Webサーバー上で行う必要があります。