📱会話のきっかけに!名札×画像認識×自己紹介
私の会社では中途採用が活発で、今月は同じチームに 1 名の新しい仲間が加わりました👏
業務説明をしていたとき「フリーデスクで、オンラインの自己紹介だと、名前や担当がなかなか一致しないんですよね」とポロッと言われ、「それ、私のときもそうだった!」と気づきました。
特に私の部署は、新しいシステムの企画・営業を担当しています。
複数案件を半年ごとに分担し直すため、今誰が何を担当しているのか、長くいるメンバー同士でも迷子になることがあります。
そこで、名札をスマホでスキャンするだけで、その人の情報がパッと表示できる
担当業務・得意分野・経歴・趣味がすぐにわかるツールを作ってみました。
こんなときに便利!
- 新メンバーとの会話のきっかけに
- 「この件、誰に聞けばいい?」の相談相手探しに
- 半期ごとの担当変更にも対応します!
1️⃣準備するもの
-
Teachable Machine https://teachablemachine.withgoogle.com/
Googleが提供する、ブラウザだけで機械学習モデルを作れるサービス。
名札の画像を学習させ、誰かを判定します。 -
CodePen https://codepen.io/
HTML / CSS / JavaScript をブラウザ上で書いてすぐ動作確認できるオンラインエディタ。
Teachable Machineのモデルを使った判定用Webアプリを作成します。 -
GitHub https://github.com/
ソースコードやドキュメントをオンラインで保存・共有できるサービス。
今回は作成したWebアプリを他者へ共有するため、GitHubに置いたファイルをGitHub Pages機能でWebサイトとして公開しました。 -
ChatGPT
CodePenに書く HTML / CSS / JS のソースコードの生成に使用。
2️⃣Teachable Machine で画像認識のモデルを作る
名札の写真を使って、5人(Aさん〜Eさん)を判別する機械学習モデルを作成します。
➊Image Project
(画像プロジェクト) → 標準の画像モデル
を選択
➋クラスの追加
class1、class2と書かれたボックスがあるので、クラス名をアプリで表示させたい文章に修正し、人数分を+作成
➌名札の画像をアップロード
各名札の画像を条件を変えて100枚程度撮る
➍モデルをトレーニング
を押します
➎モデルを保存しURLを取得
Export Model(モデルをエクスポートする
→ Upload my model(モデルをアップロード)
をクリック → 共有可能なリンク欄にモデルのURL
が表示されます
➏プロジェクトの保存
左上メニューからドライブにプロジェクトを保存
またはプロジェクトをファイルとしてダウンロード
で保存
➎で取得したモデルURLはこのあと3️⃣ JS(javascript) で使います!
📌 実践から学んだコツ:画像認識の精度アップ
名札を選んだのは、最初は「顔にカメラを向けるのはちょっと失礼かも」という配慮からでしたが、
自社の名札は苗字がひらがなで書かれたとてもシンプルなデザインで、グループ内各社で同じ形式を使っているため(標準化)、学習データがぶれにくく、結果的に画像判別にもぴったりな対象でした。
【画像判別の精度を高めるのに効果的だった4つの工夫】
- 背景の色や模様を変えて撮影する
- 撮影する角度を変える(正面・斜め・上からなど)
- 名札との距離を変えて撮る(近距離・中距離)
- 明るい場所/逆光気味の場所など光の条件を変える
ぜひ試してみてください。
3️⃣ CodePen でWebアプリを作成
ChatGPTを使ってHTML / CSS / JS のコードを作成し、Codepenへ貼り付けて、Teachable Machineのモデルを読み込んで動くWebアプリが完成
🚀完成コード(CodePen) このまま使えます
【HTML】CodePenの左部分
Webページの骨組みを作る。文章や画像、ボタンなどの配置を定義
<!DOCTYPE html> <!-- HTML文書であることを宣言 -->
<html lang="ja">
<head>
<meta charset="UTF-8"> <!-- 文字コード設定(日本語対応) -->
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- スマホ表示対応 -->
<meta name="description" content="Teachable Machine with Separate HTML, CSS, and JS">
<title>Teachable Machine - Separate Files</title>
<link rel="stylesheet" href="styles.css"> <!-- 外部CSS読み込み -->
</head>
<body>
<h1>Name Scan</h1>
<h2 class="subtitle">名札から広がる、会話のきっかけ</h2>
<!-- 操作用ボタン -->
<button onclick="init()">カメラ起動</button>
<button onclick="predict()">撮影&判定</button>
<button onclick="stopWebcam()">カメラ停止</button>
<!-- カメラ映像と結果表示領域 -->
<div id="webcam-container"></div>
<div id="status-label">カメラ待機中...</div>
<div id="result-label">判定結果待機中...</div>
<div id="snapshot-container"></div>
<!-- Teachable Machine用ライブラリ -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/image@latest/dist/teachablemachine-image.min.js"></script>
<!-- 外部JavaScript読み込み -->
<script src="script.js"></script>
</body>
</html>
【CSS】CodePenの中央部分
Webページの見た目を装飾する。文字の色や大きさ、背景、余白などを指定
/* ---------- 基本設定 ---------- */
:root {
--bg: #f0f0f5; /* 背景色 */
--fg: #333; /* 文字色 */
--accent: #007bff; /* メインボタン色 */
--accent-dark: #0056b3; /* ボタンホバー色 */
--card-radius: 10px; /* 角丸の半径 */
}
body {
font-family: Arial, sans-serif;
color: var(--fg);
background: var(--bg);
margin: 0;
padding: 16px; /* 端の余白 */
text-align: center; /* 中央寄せ */
}
/* ---------- 見出し ---------- */
h1 { font-size: 24px; margin: 0 0 15px; }
h2.subtitle { font-size: 14px; color: #666; margin: 6px 0 18px; }
/* ---------- ボタン ---------- */
button {
padding: 12px 16px; /* クリックしやすいサイズ */
margin: 6px;
font-size: 16px;
cursor: pointer;
background: var(--accent);
color: #fff;
border: none;
border-radius: 8px;
transition: background .2s; /* ホバー時の色変化 */
}
button:hover { background: var(--accent-dark); }
/* ---------- カメラ映像・判定結果 ---------- */
#webcam-container, #snapshot-container { margin-top: 15px; }
#webcam-container canvas,
#webcam-container video,
#snapshot-container img {
max-width: 92vw; /* 画面幅に収める */
height: auto;
border-radius: var(--card-radius);
}
#status-label { margin-top: 10px; font-size: 16px; color: #444; }
#result-label { margin-top: 15px; font-size: 18px; font-weight: bold; }
【JS(javascript)】CodePenの中央部分
Webページの動きや処理を設定。ボタンを押したら判定を実行するなど、動的な機能を追加
ポイント1:機械学習モデルを更新した後のアプリ側のキャッシュクリア
ポイント2:スマホは自動でアウトカメラを優先
ポイント3:判定結果は最も確率が高い1件のみ表示(配列をソート → 先頭1件だけ表示)
下記 JS コードの、先頭の注意コメント部分のURLは必ずご自身のモデルURLに差し替えて使用してください。
2️⃣Teachable Machine➎で取得した"モデルのURL
"
const URL="https://teachablemachine.withgoogle.com/models/あなたのモデルID/";
// ====== Teachable Machine(キャッシュ回避つき) ======
// ★ 注意:下記URLは必ずご自身のモデルURLに差し替えて使用してください。 "" で囲むこと ★
const URL = "https://teachablemachine.withgoogle.com/models/あなたのモデルID/";
// キャッシュ回避用(ポイント1)
const VER = Date.now();
const MODEL_URL = `${URL}model.json?v=${VER}`;
const METADATA_URL = `${URL}metadata.json?v=${VER}`;
let model, webcam, maxPredictions;
let cameraActive = false;
// 簡易DOMヘルパー
const $ = (id) => document.getElementById(id);
const log = (t) => { $("status-label").textContent = t; console.log(t); };
/* ====== 初期化 ======
- モデル読み込み
- カメラ起動(スマホはアウトカメラ優先/ポイント2)
*/
async function init() {
try {
log("モデル読込中…");
model = await tmImage.load(MODEL_URL, METADATA_URL); // ← 両方ともキャッシュ回避URL
maxPredictions = model.getTotalClasses();
log("モデル読み込み完了。カメラを起動中…");
// スマホはアウトカメラを優先(失敗時は自動でフォールバック)
const isMobile = /Mobi|Android/i.test(navigator.userAgent);
const flip = !isMobile; // イン/アウトで左右反転の要否が変わる想定
webcam = new tmImage.Webcam(320, 240, flip);
try {
// ポイント2: アウトカメラを要求
await webcam.setup({ facingMode: "environment" });
} catch {
// PCや未対応端末は通常設定で
await webcam.setup();
}
await webcam.play();
cameraActive = true;
$("webcam-container").innerHTML = "";
$("webcam-container").appendChild(webcam.canvas);
log("カメラ起動中…");
requestAnimationFrame(updateCameraView);
} catch (e) {
console.error(e);
log("❌ モデル読み込みに失敗しました。Ctrl+F5で再読み込みを試してください。");
}
}
// ====== カメラ描画ループ(任意:停止中は抜ける) ======
function updateCameraView() {
if (!cameraActive) return; // 省略可:安全ガード
webcam.update();
requestAnimationFrame(updateCameraView);
}
/* ====== 撮影&判定(ポイント3) ======
- 予測結果を確率で降順ソート
- 最上位(1件)のみ表示
*/
async function predict() {
if (!webcam || !cameraActive) {
log("カメラが起動していません");
return;
}
const preds = await model.predict(webcam.canvas);
preds.sort((a, b) => b.probability - a.probability);
const top = preds[0]; // ← もっとも確率が高い1件のみ
const percent = (top.probability * 100).toFixed(2);
$("result-label").innerHTML =
`<h3>判定結果</h3><div style="font-size:1.1rem;"><b>${top.className}</b>:${percent}%</div>`;
}
// ====== カメラ停止(任意:結果は保持) ======
function stopWebcam() {
if (webcam) webcam.stop();
cameraActive = false;
$("webcam-container").innerHTML = "";
log("カメラ停止中(結果は保持されます)");
}
4️⃣ GitHubでアプリを共有
完成したHTML/CSS/JSをまとめて index.html
として保存し、GitHubリポジトリにアップロード。
GitHub Pagesを有効化すると、以下のようなURLで誰でもアクセスできるようになります。
例:https://ユーザー名.github.io/リポジトリ名/
(※手順詳細は折りたたみ)
ここをクリック👉【初心者向け】GitHub Pages 公開手順
🌐GitHub 公開手順
①GitHubにログイン
アカウントを持っていない場合はGitHub公式サイトで無料登録。
②新しいリポジトリを作成
- 右上の「+」→「New repository」
-
Repository name
に好きな名前を入力(例:namescan
) - 公開設定は Public を選択
- 「Create repository」をクリック
③ファイルをアップロード
- 作成したリポジトリ画面で「Add file」→「Upload files」
-
index.html
(HTML、CSS、JSをまとめたファイル)をドラッグ&ドロップ - 下にスクロールして「Commit changes」をクリック
④GitHub Pagesを有効化
- リポジトリ画面で「Settings」タブを開く
- 左メニューから「Pages」を選択
- 「Source」を Deploy from a branch に変更
- 「Branch」で
main
/root
を選択し「Save」 - 数十秒〜数分後、上部に公開URLが表示されます
⑤動作確認
- 表示されたURL(例:
https://ユーザー名.github.io/リポジトリ名/
)を開いて、Webアプリが表示されれば成功!
🎉今後の応用アイデア
-
社内イベントのアイスブレイク
名札やイベントで使う席札をスキャン → お互いのプロフィールやイベント内で使う情報を共有できる -
他部署とのコミュニケーション
名札をスキャン → 部署・業務内容・社歴・趣味などを表示し、会話のきっかけに♪