概要
画像処理100本ノックを、TypeScriptと Canvas APIで実装しました。画像処理ライブラリを使わず、Q.1〜Q.100をブラウザ上で実行できます。
この記事は2019年に、JavaScriptとVueで40問まで実装した時点の記録として公開しました。 2026年に100問すべての実装とReact・TypeScriptへの移行が完了したため、現在の構成と アルゴリズム別の解説記事一覧へ更新しました。
実装の特徴
Canvas 2D ContextのgetImageDataでRGBAの画素配列を取得し、各アルゴリズムを適用した結果を
putImageDataでCanvasへ戻します。
const src = context.getImageData(0, 0, width, height);
const dst = context.createImageData(width, height);
for (let i = 0; i < src.data.length; i += 4) {
// src.data[i + 0] = R
// src.data[i + 1] = G
// src.data[i + 2] = B
// src.data[i + 3] = A
}
context.putImageData(dst, 0, 0);
OpenCVなどの画像処理ライブラリは使用していません。行列演算、ヒストグラム描画、HOG、 IoU、NMSもプロジェクト内で実装しています。
基礎的な画素操作
Q.1〜8は、個別の既存記事を現在のTypeScript実装へ合わせて更新しています。
| 問題 | 解説 |
|---|---|
| Q.1 チャンネル入れ替え | 画像のRGBチャンネルを入れ替える |
| Q.2 グレースケール | 画像をグレースケールに変換する |
| Q.3 二値化 | 固定閾値で画像を二値化する |
| Q.4 大津の二値化 | 大津の方法で閾値を自動決定する |
| Q.5 HSV変換 | RGBとHSVを相互変換する |
| Q.6 減色 | 固定した代表値へ減色する |
| Q.7、Q.8 プーリング | 平均・Maxプーリングを実装する |
アルゴリズム別の解説
問題番号を10問ずつ区切るのではなく、処理の目的とアルゴリズムの系統で分類しています。
画素値・空間・座標を扱う処理
| 分類 | 対象 | 解説 |
|---|---|---|
| 空間フィルタ | Q.9〜19 | 平滑化とエッジ検出 |
| ヒストグラム・濃度変換 | Q.20〜24 | 正規化、平坦化、ガンマ補正 |
| 補間・幾何変換 | Q.25〜31 | 画像補間とアフィン変換 |
| 周波数解析 | Q.32〜35 | 2次元フーリエ変換と周波数フィルタ |
| 画像圧縮 | Q.36〜40 | DCT、量子化、YCbCrとJPEG |
形状・領域・特徴を扱う処理
| 分類 | 対象 | 解説 |
|---|---|---|
| エッジから直線を検出 | Q.41〜46 | CannyとHough変換 |
| 形態学的変換 | Q.47〜55 | 膨張・収縮とモルフォロジー処理 |
| 照合・領域分割 | Q.56〜60 | テンプレートマッチングとラベリング |
| 二値図形の骨格 | Q.61〜65 | 連結数と細線化 |
| 勾配特徴 | Q.66〜69 | HOG特徴量 |
| 色による領域抽出 | Q.70〜72 | HSVカラートラッキングとマスク |
| マルチスケール処理 | Q.73〜76 | 画像ピラミッドと顕著性マップ |
| 方向・周波数特徴 | Q.77〜80 | ガボールフィルタ |
| 特徴点 | Q.81〜83 | Hessian・Harrisコーナー検出 |
認識・学習・検出
| 分類 | 対象 | 解説 |
|---|---|---|
| 教師あり画像分類 | Q.84〜87 | 色ヒストグラムとk-NN |
| 教師なし学習・減色 | Q.88〜92 | k-meansクラスタリング |
| 物体検出 | Q.93〜100 | HOG、ニューラルネットワーク、NMSと評価 |
アルゴリズムのつながり
100問は独立したサンプルの集合ではなく、前半で作った処理を後半で再利用する構成です。
グレースケール・平滑化
├─ 勾配 → Canny → Hough直線検出
├─ 勾配 → HOG ─┐
└─ 二値化 → 形態学・細線化
│
補間 → 画像ピラミッド
│
色ヒストグラム → k-NN / k-means
│
IoU + HOG + NN + NMS → 物体検出
たとえばHOGはQ.66〜69で作成し、Q.96以降の顔・非顔分類と物体検出で再利用します。 IoUは学習用クロップのラベル付け、NMS、最終評価でそれぞれ異なる役割を持ちます。
ローカルで動かす
git clone https://github.com/s-yoshiki/Gasyori100knockJS.git
cd Gasyori100knockJS
pnpm install
pnpm dev
型検査、Lint、フォーマット検査、テストは次のコマンドでまとめて実行できます。
pnpm check
まとめ
ブラウザで結果を確認しながら、画素操作、周波数解析、特徴抽出、分類、物体検出までを 段階的に追えるようにしました。解説記事は問題番号の区切りではなく、同じ考え方や共通処理を 持つアルゴリズム単位でまとめています。
学習するときの進め方
最初から100問を順番に消化するより、次の単位で結果を比較すると理解しやすくなります。
- 同じ入力に対してRGB/BGR、HSV、グレースケールの値を確認する
- 畳み込みフィルターのkernelと境界処理を変える
- 二値化からラベリング、輪郭、特徴量へ進む
- 学習データと評価データを分離して分類結果を見る
- IoU、Precision/Recall、NMSの閾値を変えて検出結果を比較する
ブラウザ実装ではCanvasの画素配列がRGBA順である一方、元のOpenCV教材はBGRを前提にする場合があります。アルゴリズムを移植するときは、チャンネル順、値域、丸め、画像端の扱いをテストで固定すると差分を追いやすくなります。
実装を利用する際の注意
これは学習用の素朴な実装です。実サービスで大きな画像を処理する場合は、メインスレッドを塞がないようWeb Worker、OffscreenCanvas、WASM/OpenCV.js、GPU処理などを検討してください。また、ユーザーが指定した画像はサイズ・MIME typeを検証し、Object URLを作った場合は不要になった時点で解放します。