Claude 4.5 APIにおける画像入力のトークン数計算と最適化ガイド
こんにちは!
今回は、Claude 4.5 sonnet/haiku、Claude 4.1 OpusをAPIからつかうときの画像のトークン数計算方法について詳しく解説します。
画像トークン数の計算方法
Claude 4.5 APIに送信する画像は、テキストと同様にトークンとしてカウントされ、料金計算の基礎となります。画像がAPIのサイズ制限内でリサイズ不要な場合、以下の簡単な計算式でトークン数を推定できます。
基本計算式トークン数 = (横幅px × 縦幅px) ÷ 750
この計算式を使用することで、アップロード前にコストを予測し、必要に応じて画像を最適化することが可能になります。例えば、1000×1000ピクセルの画像は約1334トークンを消費し、Claude 4.5の料金体系では、画像1枚あたりのコストを事前に計算できます。1092×1092ピクセル(1.19メガピクセル)の画像であれば約1590トークンとなり、これを基準にバッチ処理のコストも見積もることが可能です。
画像サイズの制限と最適化
Claude 4.5 APIには画像サイズに関するいくつかの重要な制限があります。単一のAPIリクエストでは最大100枚の画像を送信可能ですが、画像のサイズには以下の制約が適用されます。基本的には8000×8000ピクセルを超える画像は拒否され、20枚を超える画像を同時に送信する場合は、この制限が2000×2000ピクセルに縮小されます。また、リクエスト全体のサイズは32MBを超えることはできません。
パフォーマンスの観点から、画像の長辺が1568ピクセルを超える場合、または約1600トークンを超える場合、APIは自動的にアスペクト比を保持しながら画像をスケールダウンします。この自動リサイズ処理は追加の処理時間を要するため、事前に適切なサイズに調整することで、レスポンスタイムを大幅に改善できます。
コード実装例
1. Base64エンコード形式での画像送信
最も基本的な実装方法は、画像をBase64形式にエンコードしてAPIに送信する方法です。この方法はローカルファイルやメモリ上の画像データを直接送信する際に有効です。
import base64
import anthropic
from pathlib import Path
client = anthropic.Anthropic(api_key="your-api-key")
# 画像をBase64にエンコード
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
# トークン数の事前計算
def estimate_tokens(image_path):
from PIL import Image
img = Image.open(image_path)
width, height = img.size
tokens = (width * height) / 750
return int(tokens)
image_path = "sample.jpg"
image_data = encode_image(image_path)
estimated_tokens = estimate_tokens(image_path)
print(f"推定トークン数: {estimated_tokens}")
# Claude 4.5 APIへのリクエスト
message = client.messages.create(
model="claude-3-opus-20240229", # Claude 4.5モデル指定
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": image_data
}
},
{
"type": "text",
"text": "この画像を詳しく分析してください"
}
]
}
]
)
print(message.content)
2. URL参照による画像送信
オンラインでホストされている画像を処理する場合、URLを直接指定することで、エンコーディングのオーバーヘッドを回避できます。この方法は大量の画像を処理する際や、外部サービスと連携する場合に特に効率的です。
const Anthropic = require('@anthropic-ai/sdk');
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
// 画像URLからトークン数を推定(事前にサイズ情報が必要)
async function estimateTokensFromURL(imageUrl) {
// 実際の実装では画像のメタデータを取得
const assumedWidth = 1200;
const assumedHeight = 800;
return Math.floor((assumedWidth * assumedHeight) / 750);
}
async function analyzeImageFromURL() {
const imageUrl = "https://example.com/image.jpg";
const estimatedTokens = await estimateTokensFromURL(imageUrl);
console.log(`推定トークン数: ${estimatedTokens}`);
const message = await anthropic.messages.create({
model: 'claude-3-opus-20240229', // Claude 4.5モデル
max_tokens: 1024,
messages: [{
role: 'user',
content: [
{
type: 'image',
source: {
type: 'url',
url: imageUrl
}
},
{
type: 'text',
text: '画像内のオブジェクトを識別し、その配置を説明してください'
}
]
}]
});
console.log(message.content);
}
analyzeImageFromURL();
3. 複数画像の効率的な処理とトークン最適化
複数の画像を同時に処理する場合、トークン数の合計を管理し、必要に応じて画像をリサイズすることで、コストとパフォーマンスを最適化できます。
import anthropic
from PIL import Image
import io
import base64
class ImageTokenOptimizer:
def __init__(self, api_key):
self.client = anthropic.Anthropic(api_key=api_key)
self.max_dimension = 1568 # 推奨される最大サイズ
self.target_megapixels = 1.15 # 最適なメガピクセル数
def optimize_image(self, image_path):
"""画像を最適なサイズにリサイズしてトークン数を削減"""
img = Image.open(image_path)
width, height = img.size
# 現在のトークン数を計算
current_tokens = (width * height) / 750
# リサイズが必要かチェック
if max(width, height) > self.max_dimension:
# アスペクト比を保持してリサイズ
ratio = self.max_dimension / max(width, height)
new_width = int(width * ratio)
new_height = int(height * ratio)
img = img.resize((new_width, new_height), Image.LANCZOS)
optimized_tokens = (new_width * new_height) / 750
print(f"画像リサイズ: {width}x{height} → {new_width}x{new_height}")
print(f"トークン削減: {int(current_tokens)} → {int(optimized_tokens)}")
else:
optimized_tokens = current_tokens
print(f"リサイズ不要: トークン数 {int(optimized_tokens)}")
# Base64エンコード
buffer = io.BytesIO()
img.save(buffer, format='JPEG', quality=95)
img_str = base64.b64encode(buffer.getvalue()).decode()
return img_str, int(optimized_tokens)
def batch_process_images(self, image_paths, prompt):
"""複数画像をバッチ処理"""
total_tokens = 0
image_contents = []
for path in image_paths:
img_data, tokens = self.optimize_image(path)
total_tokens += tokens
image_contents.append({
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": img_data
}
})
print(f"\n合計推定トークン数: {total_tokens}")
# テキストプロンプトを追加
image_contents.append({
"type": "text",
"text": prompt
})
# Claude 4.5 APIにリクエスト
message = self.client.messages.create(
model="claude-3-opus-20240229",
max_tokens=2048,
messages=[{
"role": "user",
"content": image_contents
}]
)
return message.content, total_tokens
# 使用例
optimizer = ImageTokenOptimizer(api_key="your-api-key")
image_files = ["image1.jpg", "image2.jpg", "image3.jpg"]
prompt = "これらの画像の共通点と相違点を分析してください"
result, total_tokens = optimizer.batch_process_images(image_files, prompt)
print(f"\n分析結果: {result}")
print(f"使用トークン数: {total_tokens}")
アスペクト比別の推奨サイズ
異なるアスペクト比の画像を処理する際は、以下の推奨サイズを参考にすることで、最適なトークン消費を実現できます。正方形(1:1)の画像では1092×1092ピクセル、縦長の画像(9:16)では819×1456ピクセル、横長の画像(16:9)では1456×819ピクセルが推奨されます。これらのサイズは、1.15メガピクセルの制限内で最大の画質を保ちながら、処理効率を最適化するように設計されています。
ベストプラクティス
Claude 4.5 APIで画像処理を行う際は、まず画像品質の確保が重要です。ぼやけた画像やピクセル化された画像は認識精度を低下させるため、鮮明な画像を使用することが推奨されます。画像内にテキストが含まれる場合は、そのテキストが読みやすいサイズであることを確認する必要があります。
コスト最適化の観点では、処理前に画像サイズを確認し、必要に応じてリサイズすることが重要です。バッチ処理を行う場合は、合計トークン数を事前に計算し、予算内で処理が完了することを確認することをお勧めします。また、頻繁に使用する画像については、Files APIを使用して一度アップロードし、複数回参照することで、エンコーディングのオーバーヘッドを削減できます。
パフォーマンスチューニングにおいては、画像を1568ピクセル以下に事前リサイズすることで、API側での自動リサイズを回避し、応答時間を短縮できます。複数の画像を処理する場合は、並列処理ではなく適切なバッチ処理を行うことで、APIレート制限を遵守しながら効率的に処理を進めることができます。
推奨される画像サイズ
最適なパフォーマンスを実現するため、Claude 4.5では画像を1.15メガピクセル以下(両辺とも1568ピクセル以内)にリサイズすることを推奨しています。
アスペクト比に応じた推奨サイズは、1:1の正方形画像であれば1092×1092ピクセル、3:4の縦長画像なら951×1268ピクセル、16:9のワイド画像の場合は819×1456ピクセルが最適です。
実装例1: Base64エンコードによる画像送信
最も基本的な画像送信方法はBase64エンコーディングを使用する方法です。この方法は画像データを直接リクエストに含めるため、外部ホスティングが不要で、セキュアな環境での利用に適しています。
import anthropic
import base64
from PIL import Image
import io
# 画像のリサイズとトークン計算
def prepare_image(image_path, max_dimension=1568):
with Image.open(image_path) as img:
# 画像サイズの取得
width, height = img.size
# トークン数の計算
estimated_tokens = (width * height) / 750
print(f"元の画像サイズ: {width}x{height}px")
print(f"推定トークン数: {estimated_tokens:.0f}")
# 必要に応じてリサイズ
if max(width, height) > max_dimension:
ratio = max_dimension / max(width, height)
new_width = int(width * ratio)
new_height = int(height * ratio)
img = img.resize((new_width, new_height), Image.LANCZOS)
# リサイズ後のトークン数を再計算
new_tokens = (new_width * new_height) / 750
print(f"リサイズ後: {new_width}x{new_height}px")
print(f"新しいトークン数: {new_tokens:.0f}")
# Base64エンコード
buffered = io.BytesIO()
img.save(buffered, format="PNG")
return base64.b64encode(buffered.getvalue()).decode()
# Claude 4.5 APIへの送信
client = anthropic.Anthropic(api_key="your-api-key")
image_base64 = prepare_image("sample.jpg")
response = client.messages.create(
model="claude-3-5-sonnet-20241022", # Claude 4.5相当のモデル
max_tokens=1000,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": image_base64
}
},
{
"type": "text",
"text": "この画像に含まれる要素を詳しく分析してください"
}
]
}
]
)
実装例2: URL参照による画像送信
公開されている画像URLを使用する方法は、大量の画像を処理する際に帯域幅を節約できる効率的な手法です。画像データがリクエストボディに含まれないため、リクエストサイズの制限を回避しやすくなります。
const Anthropic = require('@anthropic-ai/sdk');
// トークン数を事前計算する関数
async function calculateImageTokens(imageUrl) {
// 画像のメタデータを取得(実装例)
const response = await fetch(imageUrl, { method: 'HEAD' });
const contentLength = response.headers.get('content-length');
// 簡易的なサイズ推定(実際は画像を解析して正確なピクセル数を取得すべき)
const estimatedPixels = contentLength * 0.3; // 概算値
const estimatedTokens = estimatedPixels / 750;
console.log(`画像URL: ${imageUrl}`);
console.log(`推定トークン数: ${Math.round(estimatedTokens)}`);
return estimatedTokens;
}
// Claude 4.5 APIへの複数画像送信
async function analyzeMultipleImages() {
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
const imageUrls = [
'https://example.com/image1.jpg',
'https://example.com/image2.jpg'
];
// 総トークン数の計算
let totalTokens = 0;
for (const url of imageUrls) {
totalTokens += await calculateImageTokens(url);
}
console.log(`総推定トークン数: ${Math.round(totalTokens)}`);
// APIリクエストの構築
const message = await anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 1500,
messages: [{
role: 'user',
content: [
{
type: 'text',
text: 'これらの画像を比較分析してください'
},
...imageUrls.map(url => ({
type: 'image',
source: {
type: 'url',
url: url
}
}))
]
}]
});
return message;
}
実装例3: バッチ処理での最適化
大量の画像を処理する場合、バッチ処理と適切なサイズ調整を組み合わせることで、コストとパフォーマンスの両方を最適化できます。
import asyncio
import aiohttp
from typing import List, Dict
import numpy as np
from PIL import Image
import anthropic
class ImageTokenOptimizer:
def __init__(self, api_key: str):
self.client = anthropic.Anthropic(api_key=api_key)
self.token_budget = 10000 # トークン予算の設定
def calculate_optimal_size(self, original_width: int, original_height: int,
target_tokens: int = 1500) -> tuple:
"""目標トークン数に基づいて最適な画像サイズを計算"""
current_tokens = (original_width * original_height) / 750
if current_tokens <= target_tokens:
return original_width, original_height
# スケーリング係数の計算
scale_factor = np.sqrt(target_tokens * 750 / (original_width * original_height))
new_width = int(original_width * scale_factor)
new_height = int(original_height * scale_factor)
# 最大サイズ制限の確認
max_dim = 1568
if max(new_width, new_height) > max_dim:
ratio = max_dim / max(new_width, new_height)
new_width = int(new_width * ratio)
new_height = int(new_height * ratio)
return new_width, new_height
async def process_image_batch(self, image_paths: List[str]) -> Dict:
"""画像のバッチを処理し、トークン使用量を最適化"""
processed_images = []
total_tokens = 0
for path in image_paths:
with Image.open(path) as img:
width, height = img.size
# 最適サイズの計算
optimal_width, optimal_height = self.calculate_optimal_size(
width, height,
target_tokens=self.token_budget // len(image_paths)
)
# リサイズ処理
if (optimal_width, optimal_height) != (width, height):
img = img.resize((optimal_width, optimal_height), Image.LANCZOS)
# トークン数の記録
image_tokens = (optimal_width * optimal_height) / 750
total_tokens += image_tokens
processed_images.append({
'path': path,
'original_size': (width, height),
'optimized_size': (optimal_width, optimal_height),
'tokens': image_tokens,
'image': img
})
print(f"バッチ処理完了:")
print(f" 処理画像数: {len(processed_images)}")
print(f" 総トークン数: {total_tokens:.0f}")
print(f" 平均トークン/画像: {total_tokens/len(processed_images):.0f}")
return {
'images': processed_images,
'total_tokens': total_tokens,
'within_budget': total_tokens <= self.token_budget
}
async def send_optimized_batch(self, batch_data: Dict) -> str:
"""最適化された画像バッチをClaude 4.5に送信"""
# ここで実際のAPI送信処理を実装
# batch_data['images']の各画像をBase64エンコードして送信
pass
# 使用例
async def main():
optimizer = ImageTokenOptimizer(api_key="your-api-key")
image_paths = [
"image1.jpg",
"image2.jpg",
"image3.jpg"
]
# バッチ処理と最適化
batch_result = await optimizer.process_image_batch(image_paths)
# 最適化された画像をAPIに送信
if batch_result['within_budget']:
response = await optimizer.send_optimized_batch(batch_result)
print("バッチ送信成功")
else:
print("トークン予算を超過しています。画像を分割して処理してください")
# 実行
asyncio.run(main())
それでは次回またお会いしましょう!
