zudo-paper

製品写真をNode.jsで自動生成するパイプラインを作った

Author: Takazudo | 作成: 2026/03/01

概要

Takazudo Modularで販売する製品の写真を、メーカー提供の白背景画像から自動生成するパイプラインを作った。背景除去、ファブリックテクスチャへの合成、リアルな影の付与まで全部Node.jsで完結する。当初は「初回入荷前の仮写真」ぐらいのつもりだったが、出来上がりがけっこう良くて、製品によってはこれで十分かなという感じになった。

背景

Takazudo Modularでは、製品写真をオレンジ色のファブリックテクスチャの上で撮影するスタイルで統一している。ちゃんとしたライティングで撮ると質感も出て良い写真になる。

ただ問題があって、新製品を取り扱い開始するとき、初回入荷前の段階ではそもそも実物が手元にない。メーカーから提供される製品画像はだいたい白背景。

元の製品写真(M3S)

元の製品写真(Trivium)

これをそのまま使うとショップの見た目と全然合わない。で、じゃあこの白背景を取り除いて、うちのテクスチャに載せて、影もつければそれっぽくなるのでは? と思って作り始めた。

テクスチャ背景

うちのショップで使っているファブリックテクスチャ。このオレンジのテクスチャの上に製品を合成するのがゴール。

背景のファブリックテクスチャ

背景除去とテクスチャ合成

背景除去には@imgly/background-removal-nodeを使った。ML(機械学習)ベースの背景除去ライブラリで、ローカルで動く。APIキー不要、無料。精度もかなり良い。

ただし、背景除去の精度は完璧ではなくて、製品の内部に「穴」ができることがある。たとえば黒い製品だと、背景と製品の境界をMLモデルが誤認識して、製品の一部が透明になってしまう。穴埋め処理も試みたが、うまく汎用的に対応するのが難しく、ここは諦めた。実用上は元画像の品質が良ければほぼ問題にならないので、割り切っている。

背景を除去した製品画像をsharpでテクスチャの上に合成すると、悪くはないが製品が「浮いている」。テクスチャの上に置いてある感じがしない。影がないと、ただ切り抜いて貼っただけに見える。

影なし(Trivium)

影なし(N32B Slim)

影の試行錯誤

影を追加するためにいろいろ試した。

  • Python Pillow — コンタクトシャドウ、パースシャドウ、方向性シャドウなど複数パターン
  • ImageMagick — ドロップシャドウ、パースペクティブシャドウ
  • Bria API(Replicate経由) — AIベースの影生成、強度を変えて複数パターン
  • Node.js sharp — アルファチャンネルを利用したプログラマティックな影

色々やった結果、100%プログラマティックなアプローチ(Node.js/sharp)が一番良い結果になった。

最終的な影の手法

最終的に採用したのは、5つの影レイヤーを重ねる方式。

  • ビネット — 左上光源を想定した非対称な暗がり
  • 投影影 — 製品のアルファチャンネルを縦方向に潰して製品の下に配置
  • ボトム方向のワイドシャドウ — グラデーションマスク付き、高ブラー
  • ボトム方向のミディアムシャドウ — グラデーションマスク付き、中程度のブラー
  • コンタクトシャドウ — 製品直下のタイトでシャープな影

これを全部重ねると、かなりリアルな影になる。

フローティングとグラウンデッド

Eurorackモジュール(縦長のパネル)とデスクトップ製品では影の付け方を変えている。

  • ユーロラックモジュール → フローティング(パネルが面の上に浮いているイメージ)。投影影あり
  • デスクトップ製品 → グラウンデッド(製品が面の上に置かれているイメージ)。投影影なし

ユーロラックのパネルは実際にケースに取り付けて使うもので、テーブルに「置く」製品ではない。なので浮いている表現のほうが自然。一方、N32Bのようなデスクトップ機器はテーブルに置いて使うものなので、地面に接している感じにする。

完成(Trivium)

完成(M3S)

上の2つはユーロラックモジュールなのでフローティング。下はデスクトップ製品なのでグラウンデッド。

元の製品写真(N32B Slim)

完成(N32B Slim)

--floatとグラウンデッドの使い分けは地味に大事で、製品の種類に合った影にするだけで自然さがかなり変わる。

CLIツールとして実装

パイプラインはproduct-photo-makerというCLIツールとして実装した。

# 基本的な使い方
node ./sub-packages/product-photo-maker/bin/make-product-photo.mjs photo.jpg --shadow
 
# ユーロラックモジュール用(フローティングシャドウ)
node ./sub-packages/product-photo-maker/bin/make-product-photo.mjs panel.jpg --shadow --float
 
# 端から端まで写っている製品写真(背景除去スキップ)
node ./sub-packages/product-photo-maker/bin/make-product-photo.mjs photo.jpg --no-bg-removal --shadow

出力は1600x1600のJPEG。技術的な構成は以下。

  • 背景除去: @imgly/background-removal-node(ローカル実行、無料、APIキー不要)
  • 画像処理: sharp(Node.js、高速、Raw pixelバッファで操作可能)
  • 影生成: アルファチャンネル抽出 → オフセット → ブラー → グラデーションマスク → 黒RGBAレイヤーとして合成

Claude Codeのスキルとして運用

実際の運用では、CLIを直接叩くのではなく、Claude Codeのスキル(/l-make-product-photo)として使っている。画像を渡してスキルを呼ぶと、Claude Codeが画像を見て以下を自動判断してくれる。

  • 背景除去が必要かどうか
  • トリミングするかどうか
  • フローティングかグラウンデッドか(判断がつかない場合はユーザーに確認)

複数画像を渡したとき、フラグの組み合わせが異なる画像は自動でグループ分けして別々に実行。画像を見てフラグを決めてコマンドを組み立てて実行する流れをClaude Codeに任せられるので、人間はただ画像を渡すだけで済む。

Replicateについて

試行錯誤の過程でReplicateのBria APIも試した。AIで生成された影は興味深い結果ではあったが、今回のユースケースではプログラマティックなアプローチのほうが良かった(API費用なし、ネットワーク依存なし、決定的、チューニング自由)。ただ、Replicate自体は他のAI画像処理タスクで使えそうなので、別の機会にまた何か試すかもしれない。

まとめ

「初回入荷前の仮写真」として作り始めたが、結果的にはかなり使えるレベルのものになった。全部オープンソースのツールで完結するのでコストもゼロ。--floatとグラウンデッドの使い分けは地味に大事で、製品の種類に合った影にするだけで自然さがかなり変わる。