クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

画像が数になる仕組み

このレッスンのあとで: 画像が数の並びになる仕組みと、大きさとタイルが費用に与える影響を説明できます。

70分のレッスンコマンド6件AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

写真は、数の並びにすぎない

スマホで撮った写真を、コンピューターは「見る」ことができません。点の一つ一つを数にして、表のように並べて覚えています。画像を受け取るモデルは、その数を読みます。

表が大きいほど、送る費用が増えます。このレッスンでは、その表と値段を目で確かめます。

このレッスンのゴール

メモ

画像が数の並びになる仕組みと、大きさとタイルが費用に与える影響を説明できます。

キーワード

ことばいみ
画素画像の点一つ。数で覚える
チャンネル画素の色の一部。赤、緑、青
リサイズ画像の幅と高さを変えること
タイル画像を切り分けた小さな正方形
マルチモーダル文字のほかに画像など、複数の種類の入力を扱うこと

学生が入力するセルは、このプレビューでは空白です。

画像は数の表である

画像は、小さな点の行に分けられます。この点が画素です。白黒の画像では、一つの画素を 0(黒)から 255(白)の数で覚えます。

カラーの画像では、画素ごとに三つの数を持ちます。赤、緑、青のチャンネルです。だから同じ大きさなら、カラーは白黒の三倍の数になります。

白黒の画像と、カラーの画素

行画素 1画素 2画素 3
10128255
264128192
32551280
カラーの画素赤 200緑 30青 30

学生が入力するセルは、このプレビューでは空白です。

大きな画像は先に小さくする

モデルが受け取れる画像には、大きさの上限があります。大きすぎる画像は、読む前に縮めるか、断られます。

縮める一番簡単な方法は、画素のブロックを平均して一つの数にすることです。2 かける 2 の四つの画素が一つになり、幅も高さも半分になります。

よくある間違い

注意

「ファイルが小さければ、安い画像だ」と考えがちです。費用は、ディスク上のファイルの大きさではなく、画素の幅と高さに従います。小さなファイルでも巨大な表のことがあるので、必ず画素を数えます。

タイルの数が費用を決める

縮めたあと、画像は正方形のタイルに切られます。端のタイルが一部しか埋まらなくても、1 枚と数えます。

ここでは、基本料金 10 と、20 かける 20 のタイル 1 枚につき 5 という決まりを使います。これはレッスンのための架空の決まりです。本物のサービスには、そのサービスの決まりがあるので、料金表を読みます。

20 かける 20 のタイルを数える

画像横の枚数縦の枚数タイル費用
20 かける 2011115
21 かける 2021220
45 かける 3032640
60 かける 6033955

学生が入力するセルは、このプレビューでは空白です。

モデル用の補助を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// 応答に含まれるトークン数。なければ null。' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

モデル用の補助を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    const d = await res.json();' '    return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

画像のスクリプトを書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'let seed = 3;' 'function next() { seed = (seed * 29 + 17) % 256; return seed; }' 'const image = [];' 'for (let y = 0; y < 6; y++) {' '  const row = [];' '  for (let x = 0; x < 6; x++) row.push(next());' '  image.push(row);' '}' > see1.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

画像のスクリプトを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function shrink(img, f) {' '  const out = [];' '  for (let y = 0; y < img.length; y += f) {' '    const row = [];' '    for (let x = 0; x < img[0].length; x += f) {' '      let sum = 0;' '      for (let j = 0; j < f; j++) for (let i = 0; i < f; i++) sum += img[y + j][x + i];' '      row.push(Math.floor(sum / (f * f)));' '    }' '    out.push(row);' '  }' '  return out;' '}' 'function tiles(w, h, t) { return Math.ceil(w / t) * Math.ceil(h / t); }' >> see1.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

画像のスクリプトを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const small = shrink(image, 2);' '  console.log(\"元の画像 \" + image[0].length + \"x\" + image.length + \" の1行目: \" + image[0].join(\" \"));' '  console.log(\"縮小後 \" + small[0].length + \"x\" + small.length + \" の1行目: \" + small[0].join(\" \"));' '  console.log(\"2x2 のタイルの数: 元 \" + tiles(6, 6, 2) + \"、縮小後 \" + tiles(3, 3, 2));' '  const q = \"画像を小さくすると送る費用が下がる理由を、短い一文で書いてください。\";' '  const r = await ask([{ role: \"user\", content: q }], \"画像を小さくするとタイルの数が減り、費用はタイルの数で決まるからです。\", 60);' '  console.log(\"返事: \" + r.text);' '}' 'main();' >> see1.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

画像を縮めてタイルを数える

コマンド
docker exec -w /home/node/project agent node see1.js

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

出力の例

行示していること
元の画像 6x6 の1行目: 104 217 166 223 84 149作り物の画像の、最初の行の数
縮小後 3x3 の1行目: 171 101 1752 かける 2 のブロックを平均して一つの画素にした
2x2 のタイルの数: 元 9、縮小後 4縮めるとタイルが減り、値段が下がる
返事: ...モデルの一文。先に「記録済みサンプル」の行が出ることもある

学生が入力するセルは、このプレビューでは空白です。

このラボとソースについて: AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。