大規模なECモールや複数プラットフォームを横断する出品チームにおいて、商品登録時の画像処理は深刻な運用ボトルネックになりがちです。各サプライヤーから納品される元画像は、解像度、アスペクト比、背景の雑音、照明条件がバラバラです。デスクトップ向けの一括レタッチツールは手作業が介在するため社内ERP、PIM(商品情報管理)、CMSとの自動連携が難しく、デザイナーによる手動切り抜き作業は24〜72時間の出品遅延とSKUあたりの人件費高騰を招きます。
Cutout.proが提供する開発者向けREST APIを活用すれば、商品画像の背景透過(切り抜き)、トリミング、白抜き背景生成を自動化できます。このAPIをバックエンドの非同期画像処理パイプラインに組み込むことで、入荷した生データを数秒でAmazonやShopifyの出品基準に適合した純白背景(#FFFFFF)、統一マージン、自然な接地シャドウ(コンタクトシャドウ)付きの標準画像へと一括変換できます。
1. Cutout.pro APIの仕様と認証フロー
Cutout.proの機能はHTTPSエンドポイント経由で提供されます。認証はシンプルで、すべてのリクエストのHTTPヘッダーに発行されたAPIキーを付与します。
APIKEY: your_cutout_pro_api_key_here
パイプライン実行前のクレジット残高確認
セール期やシーズン切り替え時の商品一括登録では、数万枚の画像が一括処理されます。処理途中でクレジットが枯渇するとエラーコード 4001(残高不足)が発生し、後続タスクが停止してしまいます。そのため、バッチ処理開始前にアカウント残高を事前確認する設計が不可欠です。
Cutout.proには残高確認専用のエンドポイントが用意されています。
- エンドポイント:
GET https://www.cutout.pro/api/v1/mySubscription - ヘッダー:
APIKEY: <YOUR_API_KEY>,Accept: application/json
レスポンス例:
{
"code": 0,
"data": {
"monthBalance": 1250,
"imageBalance": 5000,
"videoBalance": 0,
"monthStartDate": "2026-10-01 00:00:00",
"monthExpireDate": "2026-11-01 00:00:00"
},
"msg": null,
"time": 1728729600000
}
タスクオーケストレーターに事前チェックを組み込むことで、残高不足時にジョブを安全に一時停止し、運用チームへアラートを通知できます。
2. エンドポイントの選定と必須パラメータ
EC商品の切り抜き処理には、汎用オブジェクト向けモデルである mattingType=6 または mattingType=1 を指定します。画像の保存場所やアーキテクチャに応じて3つの呼び出しモードが選択可能です。
| モード | エンドポイント | メソッド & Content-Type | レスポンス形式 | 推奨ユースケース |
|---|---|---|---|---|
| モード1: バイナリ直接取得 | https://www.cutout.pro/api/v1/matting | POST / multipart/form-data | 生画像バイナリ(image/png) | ローカルディスク書き込みやインメモリ処理 |
| モード2: Base64 JSON | https://www.cutout.pro/api/v1/matting2 | POST / multipart/form-data | data.imageBase64 含むJSON | JSON-RPCベースのマイクロサービス間連携 |
| モード3: URL指定 | https://www.cutout.pro/api/v1/mattingByUrl | GET / クエリパラメータ | data.imageBase64 含むJSON | S3、Cloudflare R2、CDN上に元画像がある場合 |
EC標準化に重要なリクエストパラメータ
mattingType(整数、必須): EC商品・グッズ切り抜きは6を指定。crop(真偽値、任意):trueに設定すると、商品外周の透明余白を自動カットし、バウンディングボックスに密着トリミング。cropMargin(文字列、任意):crop=true時に商品外周へ付与する余白。"30px"や"10%"などの絶対値・割合、または上下左右の個別指定が可能。bgcolor(16進数文字列、任意): 背景の指定色塗りつぶし(例: 白抜きならFFFFFF、#は含めない)。特殊値'blur'で背景ぼかしも可能。outputFormat(文字列、任意): 出力フォーマット(png、webp、jpg_<品質>例:jpg_85)。preview(真偽値、任意):trueにすると最大解像度500x500に制限され、消費クレジットが通常1枚1点から 0.25点 に削減。出品前のドラフトプレビューに最適。通常解像度(最大4096x4096px、15MB以下)は 1点 消費。
3. 大量バッチ処理とレートリミット対策(非同期キュー設計)
Cutout.proのAPIは同期型HTTP通信であり、1枚ごとのリクエストに対して即時推論が行われます。しかし、標準プランでは 秒間最大5リクエスト(5 QPS) という同時実行制限が存在します。
無制限なマルチスレッドで並行送信を行うと、エラーコード 5005(Too many requests in the queue, please wait)が頻発します。数万SKUを安定処理するためには、非同期メッセージキューによる流量制御が必要です。
本番環境向けアーキテクチャ
[ERP / PIM 一括商品登録]
│ (SKUバッチ投入)
▼
[メッセージブローカー: Redis / RabbitMQ]
│
▼
[Workerクラスタ (Celery / BullMQ)]
├── トークンバケット流量制御 (クラスタ全体で <= 4.5 QPS に制御)
├── Cutout.pro API呼び出し (POST /api/v1/matting?mattingType=6)
│ └── 5005エラー時の指数バックオフ+ジッター
├── 画像標準化エンジン (Pillow / Sharp)
│ ├── 正方形キャンバスへの配置 (2000x2000px)
│ ├── 85%比率でのセンタリングリサイズ
│ └── 自然な接地シャドウ (Contact Shadow) の合成
├── クラウドストレージ保存 (AWS S3 / Cloudflare R2)
└── ERPへのWebhook通知 (処理完了・画像URL更新)
リトライとエラー処理方針
- トークンバケットによる流量制御: ワーカープール全体からの外部送信レートを秒間4.5回以下に制限し、Cutout.proの5 QPS制限超過を防ぎます。
- エラーコードごとの分岐:
5005(キュー超過・頻度制限): 指数バックオフ(待機時間: 1.5秒、3秒、6秒+ランダムジッター)で再試行。1002(15MB超過)/5008(不正画像): デッドレターキュー(DLQ)に転送し、ERPダッシュボードで手動確認フラグを付与。4001(残高不足): ワーカーの消費を全停止し、即座にSlackやメールで運用担当者へ高優先度アラートを通知。
4. 画像標準化パイプラインの実装(サイズ、マージン、接地シャドウ)
APIの bgcolor=FFFFFF オプションで単純な白背景化は可能ですが、主要ECプラットフォームの出品基準を満たすには以下の調整が必要です。
- キャンバスを厳密な正方形(アスペクト比 1:1、例: 2000x2000px)にする。
- 商品がキャンバス全体の80%〜85%を占めるように自動スケールする。
- 純白背景にそのまま商品を載せると浮遊感(シール感)が出るため、底面に柔らかい接地シャドウ(コンタクトシャドウ)を生成して立体感を出す。
推奨される構成は、Cutout.proから透過PNG(crop=true、bgcolor なし)を取得し、ワーカー内の画像ライブラリ(Python PillowやNode.js Sharp)でキャンバス調整と影の合成を行う方式です。
本番用実装コード(Python + Pillow)
import io
import time
import requests
from PIL import Image, ImageFilter
CUTOUT_API_KEY = "YOUR_API_KEY_HERE"
API_URL = "https://www.cutout.pro/api/v1/matting?mattingType=6&crop=true"
def remove_background(image_bytes: bytes, max_retries: int = 3) -> bytes:
"""Cutout.pro APIを呼び出し、5005制限時の指数バックオフを備えた切り抜き処理"""
headers = {"APIKEY": CUTOUT_API_KEY}
files = {"file": ("product.jpg", image_bytes, "image/jpeg")}
for attempt in range(max_retries):
response = requests.post(API_URL, headers=headers, files=files, timeout=30)
if response.status_code == 200 and response.headers.get("Content-Type", "").startswith("image/"):
return response.content
try:
err = response.json()
code = err.get("code")
msg = err.get("msg")
if code == 5005: # キュー制限
time.sleep((2 ** attempt) + 0.5)
continue
elif code == 4001:
raise RuntimeError("Cutout.proのAPIクレジットが不足しています。")
else:
raise ValueError(f"Cutout.pro処理失敗: {code} - {msg}")
except requests.exceptions.JSONDecodeError:
response.raise_for_status()
raise TimeoutError("Cutout.proへのリトライ上限に達しました。")
def standardize_product_image(
transparent_png_bytes: bytes,
target_canvas_size: int = 2000,
fill_ratio: float = 0.85
) -> Image.Image:
"""
正方形純白キャンバスへリサイズ・配置し、占有率85%と自然な接地シャドウを合成。
"""
# 1. 切り抜かれた透過PNGを読み込み
product = Image.open(io.BytesIO(transparent_png_bytes)).convert("RGBA")
prod_w, prod_h = product.size
# 2. 占有率に合わせたアスペクト比保持スケーリング
max_dim = int(target_canvas_size * fill_ratio)
scale = min(max_dim / prod_w, max_dim / prod_h)
new_w, new_h = int(prod_w * scale), int(prod_h * scale)
product_resized = product.resize((new_w, new_h), Image.Resampling.LANCZOS)
# 3. 正方形純白キャンバスを作成
canvas = Image.new("RGBA", (target_canvas_size, target_canvas_size), (255, 255, 255, 255))
# 4. 接地シャドウ(コンタクトシャドウ)の生成
alpha = product_resized.split()[3]
shadow_height = max(10, int(new_h * 0.08))
# アルファチャンネルを縦方向に縮小して接地マスクを作成
shadow_mask = alpha.resize((new_w, shadow_height), Image.Resampling.BILINEAR)
shadow_mask = shadow_mask.filter(ImageFilter.GaussianBlur(radius=15))
# 濃いグレーの半透明レイヤーを作成(不透明度最大35%)
shadow_layer = Image.new("RGBA", (new_w, shadow_height), (40, 40, 40, 0))
shadow_layer.putalpha(shadow_mask.point(lambda p: int(p * 0.35)))
# 5. 各レイヤーをキャンバスに合成
pos_x = (target_canvas_size - new_w) // 2
pos_y = (target_canvas_size - new_h) // 2
# 影を商品の最下部付近に配置
shadow_y = pos_y + new_h - int(shadow_height * 0.6)
canvas.paste(shadow_layer, (pos_x, shadow_y), shadow_layer)
# 商品本体を合成
canvas.paste(product_resized, (pos_x, pos_y), product_resized)
# 出力用RGB画像へ変換
return canvas.convert("RGB")
def run_pipeline(input_path: str, output_path: str):
with open(input_path, "rb") as f:
raw_bytes = f.read()
# ステップ1: クラウドAPIによる透過切り抜き
cutout_bytes = remove_background(raw_bytes)
# ステップ2: ローカルでの画像標準化と接地シャドウ合成
final_img = standardize_product_image(cutout_bytes)
# ステップ3: 最適化JPEGとして保存
final_img.save(output_path, "JPEG", quality=90, optimize=True)
5. 運用上のベストプラクティスとコスト削減策
mattingByUrlによる転送帯域とI/Oの削減: 登録元画像がすでにS3などのオブジェクトストレージにある場合、mattingByUrlモードを活用して公開URLを渡します。サーバーからの画像再アップロード処理が不要となり、ネットワーク負荷とレイテンシを大幅に削減できます。- 2段階の画像審査ワークフロー: 出品ドラフト作成時は
preview=true(0.25クレジット)で処理し、出品承認・本番公開時にフル解像度(1クレジット)で本番処理を実行する設計にすることで、無駄なクレジット消費を防止できます。 - 透過PNGマスクの長期保存: APIから取得した透過PNGはアーカイブ用ストレージに保管しておくことを推奨します。将来的に背景色をライトグレーに変更したり、余白比率の規定が変わった場合でも、有料APIを再実行することなくローカル合成スクリプトのみで全商品を再生成できます。