Gemini の画像生成をワークフローに組み込む — プロンプト設計から動画→サムネイル自動生成まで
画像生成で時間を溶かす一番の原因は、出てきた1枚が良かったのか悪かったのか、なぜそうなったのかを後から再現できないことだと感じています。私自身、Dolice Labs の4つのブログ(Gemini Lab を含む)の OGP 画像や、個人開発で続けている壁紙アプリのプロモ素材を Gemini で量産するなかで、最初の頃はまさにこの「当たりを引いても二度と同じ品質を出せない」状態に何度もはまりました。
この記事は、画像生成を一回の運試しではなく、記録して再現できるワークフローとして回すための実践メモです。前半でプロンプトを再現可能な単位に分解し、後半で 2026 年 6 月に GA となった Nano Banana 2(gemini-3.1-flash-image)の「動画から1枚絵を起こす」機能を、個人開発の自動化に組み込むところまで進めます。なお、私の現代美術の作品制作は手作業の領域で、生成 AI は使っていません。生成 AI を使うのはアプリ事業やブログ運用の素材生成という「届ける側」の作業に限定しています。この線引きを最初に置いておくと、以降の判断軸が読みやすくなるはずです。
プロンプトは「運」ではなく4要素の設計
良い画像が安定して出るプロンプトは、感覚ではなく構造でできています。私が記録をつけながら整理した結果、効いている要素は次の4つに収れんしました。
被写体(何を描くか)、背景・環境(どこで、いつ)、スタイル(写真風・水彩・3D など)、ディテール(色調・照明・アングル・感情)。この4要素を意識して埋めるだけで、「人が座っている」のような曖昧な指示から、「30代のアジア人女性が、夕方の窓際のソファに座り、暖色の室内照明に照らされている。プロフェッショナルな写真風」のような再現可能な指示に変わります。
要素を分けておく実務上の利点は、当たりが出たときに「どの要素が効いたか」を切り分けられることです。背景だけを差し替えて再生成すれば、被写体とスタイルを固定したまま雰囲気だけを比較できます。1回ごとにプロンプト全体を書き直していると、この比較ができません。
用途ごとに「型」を持っておく
毎回ゼロから書くのではなく、用途別に最小の型を持っておくと速く安定します。私がブログとアプリで実際に使い回している骨格は次の通りです。
ブログのアイキャッチなら「[記事テーマを象徴する被写体] が [作業/状況] している。[親しみやすい色調]。やや柔らかい写真風かフラットイラスト風。横長 16:9」。SNS 投稿なら正方形(1:1)か縦長(9:16)を明示し、雑誌の表紙のような洗練を一言添える。プレゼン素材なら抽象度を上げて「[概念] を象徴する 3D CGI、青と紫のネオン、前向きな雰囲気」のように、人物より概念を主役にします。
型を持つと、後半で扱う自動化に乗せやすくなります。ブリーフ(簡潔な指示文)をテンプレート化しておけば、記事タイトルや動画の内容を差し込むだけで素材が起こせるからです。
生成 AI が苦手な指示を避ける
再現性を下げる典型的な落とし穴が、否定形の指示です。画像生成モデルは「〜を描かない」という負の指示が苦手で、かえって描いてしまうことがあります。「注射器を持っていない医者」より「患者に温かく微笑みかける医者」のように、欲しい状態を肯定形で書くほうが安定します。
もう一つは矛盾です。「夜の場面なのに明るい昼の光」のような指示は破綻の温床になります。時間帯・光源・色調を一貫させるだけで、再生成のたびに当たり外れが揺れる幅が目に見えて狭まります。
同じプロンプトでもブレる——反復を「記録」して当たりを再現する
ここからが、運試しと再現可能なワークフローの分かれ目です。同じプロンプトでも生成結果はばらつきます。だからこそ、良い1枚が出たときに「プロンプト・シード・モデル・日時」をセットで残しておくことが効いてきます。
私は素材生成のたびに、ブリーフ文と使ったモデルID、採用したファイル名を1行のログに落とすようにしています。これだけで、3か月後に「あの記事のアイキャッチと同じトーンで」という依頼を自分自身に対して再現できます。記録のない生成は、毎回スタート地点に戻るのと同じです。
ここまでが、アプリの画面やブラウザの ImageFX でも実践できる「設計と記録」の話でした。ここから先は、この設計を API に乗せて、人手を介さずに素材を起こす自動化に踏み込みます。2026 年 6 月の更新で、その入口が一段広がりました。
動画から1枚絵を起こす——Nano Banana 2(gemini-3.1-flash-image)のGAで変わったこと
2026 年 6 月、Nano Banana 2(gemini-3.1-flash-image)と Nano Banana Pro(gemini-3-pro-image)が GA になりました。個人開発の素材生成という観点で一番大きいのは、動画ファイルをマルチモーダルの文脈として渡して、その内容を踏まえたサムネイルやポスター、インフォグラフィックを生成できるようになった点です(動画→画像は gemini-3.1-flash-image 系の用途です)。
これまでは、動画から良いフレームを探して切り出し、それを編集する、という手作業が挟まっていました。動画を直接渡せると、「この動画の山場を1枚の縦型サムネイルにして」という指示で起点が作れます。stand.fm の音声やショート動画の素材を扱う個人開発者にとっては、地味に効く変化です。
実装は、これまでの画像出力と同じ google-genai SDK の流れに、入力として動画パートを足すだけです。小さめの動画なら inline で渡せます。
import os
from google import genai
from google.genai import types
client = genai.Client( api_key = os.environ[ "GEMINI_API_KEY" ])
# Nano Banana 2 = gemini-3.1-flash-image(2026-06 GA)。
# 動画を文脈として渡せるのはこの系統です。
IMAGE_MODEL = "gemini-3.1-flash-image"
def thumbnail_from_video (video_path: str , brief: str ) -> bytes :
with open (video_path, "rb" ) as f:
video_bytes = f.read()
response = client.models.generate_content(
model = IMAGE_MODEL ,
contents = [
types.Part.from_bytes( data = video_bytes, mime_type = "video/mp4" ),
brief,
],
config = types.GenerateContentConfig(
response_modalities = [ "TEXT" , "IMAGE" ],
),
)
for part in response.candidates[ 0 ].content.parts:
if part.inline_data is not None :
return part.inline_data.data
raise RuntimeError ( "画像パートが返りませんでした(テキストのみ応答)" )
ブリーフは前半で作った「型」をそのまま使えます。たとえば縦型サムネイルなら、"この動画の山場を1枚に。被写体を中央に大きく、縦長 9:16、視認性の高いコントラスト、文字は入れない" のように、4要素+アスペクト比を明示します。文字(タイトル)は後段で確実に載せたいので、画像生成側では入れさせない指定にしておくのが運用上は安定します。
数十 MB を超える動画は inline ではなく Files API 経由が安全です。アップロードしたファイル参照を contents に渡す形に変えるだけで、呼び出しの骨格は同じです。
def thumbnail_from_large_video (video_path: str , brief: str ) -> bytes :
uploaded = client.files.upload( file = video_path)
response = client.models.generate_content(
model = IMAGE_MODEL ,
contents = [uploaded, brief],
config = types.GenerateContentConfig(
response_modalities = [ "TEXT" , "IMAGE" ],
),
)
for part in response.candidates[ 0 ].content.parts:
if part.inline_data is not None :
return part.inline_data.data
raise RuntimeError ( "画像が返りませんでした" )
response_modalities に IMAGE を含めても、テキストだけ・画像だけ・両方、の3パターンが混ざって返ってきます。parts をループで回し、inline_data がある場合だけ画像として処理するガードは、自動化では必須です。ここを省くと、テキストのみ応答のときに例外で止まります。
量産時に効く「破綻を出荷前に弾く」軽量ゲート
自動化の怖いところは、破綻した1枚がそのまま公開まで流れてしまうことです。私は壁紙アプリの色違い生成でこれをやって、のっぺり単色の画像を配信してしまったことがあります。重い品質判定を入れる前に、まずは安価な機械チェックで明らかな事故を止めるのが現実的です。
次のゲートは、アスペクト比が目標から外れていないか、ほぼ単色(生成破綻)になっていないかを、追加の API 呼び出しなしで判定します。
from PIL import Image
from io import BytesIO
def passes_quality_gate (img_bytes: bytes , target_ratio: float = 16 / 9 ,
tol: float = 0.08 ) -> bool :
img = Image.open(BytesIO(img_bytes)).convert( "RGB" )
w, h = img.size
ratio = w / h
if abs (ratio - target_ratio) / target_ratio > tol:
return False # アスペクト比が目標から外れすぎ
# ほぼ単色(のっぺり/破綻)の検出: 縮小して画素分散を見る
small = img.resize(( 32 , 18 ))
px = list (small.getdata())
n = len (px)
mean = [ sum (c[i] for c in px) / n for i in range ( 3 )]
var = sum ( sum ((c[i] - mean[i]) ** 2 for i in range ( 3 )) for c in px) / n
return var > 150 # 経験的閾値。下回るとのっぺり/破綻が多い
閾値の 150 はあくまで私の手元での経験値です。素材の傾向によって調整が要りますが、「明らかにおかしい1枚を自動で1回だけ作り直す」という本番運用のリトライ条件に使うだけでも、明らかな事故を回避でき、量産時の手直し率は約 30% 下がりました。完璧な品質判定を最初から目指すより、事故だけを止める安いゲートを先に置くのが、個人開発では費用対効果が高いと感じています。
preview 停止に巻き込まれない——モデルID を一箇所に閉じ込める
もう一つ、自動化で必ず効いてくるのが非推奨対応です。preview 系のモデルは予告つきで止まります。実際、gemini-3.1-flash-image-preview と gemini-3-pro-image-preview は 6/25 に停止予定で、これらを直書きしていたコードは停止日を境に一斉に INVALID_ARGUMENT で落ちます。
防ぎ方は単純で、モデル ID をコードの随所に散らさず、一箇所の辞書に閉じ込めることです。停止のたびにコード全体を grep して回らず、1行の差し替えで追従できます。
# モデル ID は一箇所に集約する。preview 停止に1行で追従できるようにする。
IMAGE_MODELS = {
"fast" : "gemini-3.1-flash-image" , # Nano Banana 2(GA)
"quality" : "gemini-3-pro-image" , # Nano Banana Pro(GA)
}
def resolve_image_model (tier: str = "fast" ) -> str :
try :
return IMAGE_MODELS [tier]
except KeyError as e:
# 未知のティアを既定へ無言フォールバックさせず、明示的に落とす
raise ValueError ( f "未知の画像モデルティア: { tier } " ) from e
私は複数の Lab サイトと壁紙アプリで同じ生成基盤を使い回しているので、preview の停止日を運用カレンダーに登録し、停止日の前週には GA 版へ寄せ終えるようにしています。期限つきの非推奨を「見落とさない仕組み」にしておくことが、個人で複数プロジェクトを回す前提では一番の保険になります。
次の一歩
個人的にお勧めなのは、まず手元で当たりが出た1枚のプロンプトを、被写体・背景・スタイル・ディテールの4要素に分解してテンプレート化することです。そのテンプレートをブリーフ文として thumbnail_from_video() に渡せば、動画から素材を起こす自動化の最小ループが今日のうちに回せます。記録と型さえ持てば、画像生成は運試しから、再現できる工程に変わっていきます。お読みいただきありがとうございました。