Zenn
❄️

LangChainでGemini-2.0 APIの画像編集を実行する方法

に公開
8

はじめに

タイトルの通りです。が、LangChainからgeminiの画像編集を利用する方法の解説って、まだないと思ったので書きました。
Geminiでは画像編集が可能ですが、それをLangChainで実行するための方法を記載します。

正直、現時点では画像編集や画像生成では、Geminiモデルよりも、gpt-4oモデルの方が、性能的にはお勧めです。

しかしながら記事執筆時点では、

  • gpt-4oの画像生成はAPIで解放されていないこと
  • Geminiモデルは画像生成利用であっても無料でAPIを利用できること

から、ある程度の競争力はあると思っております。

Geminiを利用した自然言語での画像編集

簡単に試すには、Google AI Studioを利用することをお勧めします。
下記の記事などが、使い方やできることなどがまとめられていてわかりやすいです。
https://note.com/mayu_hiraizumi/n/nd643348f2e41

こちらを利用すると、下記のように自然言語での画像編集が可能です。

入力画像

プロンプト
「コーヒーカップを消去して」

生成画像

ただ、上記の画像は何回か実行した上で良かった画像を選んでいます。
失敗した画像は、下記のようにノートPCも消去されていたり、椅子が消去されていたりしています。

失敗した画像

コーヒーカップだけでなく、ノートPCも消去されている

椅子が消去されてしまっている

Google AI Studioでは、同じプロンプト+入力画像で何枚も生成するのは大変です。
そこで、APIを利用して複数枚自動で生成する需要はあると考えたため、記事にしております。

リポジトリ

下記のリポジトリをご覧ください。
https://github.com/personabb/langchain_asap_sample/tree/main/gemini_image_generation

準備

リポジトリをクローンする

下記コマンドでリポジトリをクローンしてください。

./
git clone https://github.com/personabb/langchain_asap_sample.git

この記事では、リポジトリ内の下記フォルダを利用します。

./
 cd langchain_asap_sample/gemini_image_generation

環境変数

Google AI StudioのAPIキーを準備して、.envファイルを作成し、設定してください。

APIキーの取得方法がわからない場合は下記を参考にしてください。
https://zenn.dev/asap/articles/2ad7eb5e7560cf#apiキーを設定する

取得後、下記コマンドを実行して、.envファイルを作成します

./langchain_asap_sample/gemini_image_generation
cp .env.example .env

作成した.envファイルにGoogle AI StudioのAPIキーを入力してください。

.env
GOOGLE_API_KEY="xxxxxxxxxxxxxxxxxxxxx"

編集前の画像の準備

基本的に皆様が編集したい画像を用意して、gemini_image_editing.pymain関数内のfile_pathにて指定してください。

gemini_image_editing.py
def main():
    ・・・
    # ========== 読み込む画像のパス ==========
    file_path = "inputs/sample1.png"
    #file_path = "inputs/sample2.png"

今回は下記の2枚の画像を用意しました。

inputs/sample1.png

inputs/sample2.png

編集内容を指定する

gemini_image_editing.pymain関数内のqueryにて指定してください。

gemini_image_editing.py
def main():
    ・・・
    # ========== 編集内容の指定 ==========
    query = "空を夕焼けの空に変更して、ベンチの色を赤色に変更して"
    #query = "コーヒーカップを消去して"

必要なパッケージのインストール

下記のコマンドで必要なパッケージをインストールします。

./langchain_asap_sample/gemini_image_generation
pip install -r requirements.txt

上記で動かない場合は、下記も試してみてください。
(現時点での著者のバージョン付きパッケージです)

./langchain_asap_sample/gemini_image_generation
pip install -r requirements.lock

実行

下記のコマンドで実行してください。

./langchain_asap_sample/gemini_image_generation
python gemini_image_editing.py

出力結果はoutputsフォルダに保存されています。

実行結果

最もうまく生成されたものを表示します。
こちらの画像を生成するために、同じプロンプトで5-10回生成していることをご留意ください。

inputs/sample1.png

入力画像

プロンプト
「空を夕焼けの空に変更して、ベンチの色を赤色に変更して」

生成画像

inputs/sample2.png

入力画像

プロンプト
「コーヒーカップを消去して」

生成画像

コードの解説

main関数

基本的な処理はすべてmain関数に記載しているので、そちらを確認します。

gemini_image_editing.py
def main():
    # モデルの定義。APIキーは環境変数から取得
    model = ChatGoogleGenerativeAI(
        model="models/gemini-2.0-flash-exp-image-generation",
        google_api_key=api_key,
        response_modalities=[Modality.IMAGE, Modality.TEXT]
        )

    # messageを作成する
    message = [
        # 現在、gemini-2.0-flash-exp-image-generationではsystem_messageを利用できないので、HumanMessageを利用する
        HumanMessage(content= """
# 目的
あなたのタスクは画像編集です。ユーザが入力した画像を元に、ユーザが指定した内容で新しい画像を生成してください。

# ルール
ユーザが指示した内容に関係のない物体は、元の画像と全く同一にしてください。
ユーザが指示した内容だけをユーザの指示に忠実に編集して、画像を生成してください。
ユーザからの指示が変更依頼の場合は、そのオブジェクトと指定されたオブジェクトを元の画像から入れ替える形で編集してください。
ユーザからの指示が消去依頼の場合は、そのオブジェクトを元の画像から消去してください。
ユーザからの指示が追加依頼の場合は、そのオブジェクトを元の画像に追加してください。

----以下がユーザの入力です----
    """),
        HumanMessagePromptTemplate.from_template(
            [
                {
                    "type": "text",
                    "text": "{user_input}"
                },
                {
                    "image_url": {
                        "url": "data:image/png;base64,{image}"

                    }
                }
            ]
        ),
    ]

    # messageからプロンプトを作成
    prompt = ChatPromptTemplate.from_messages(message)

    # chainを作成
    chain = prompt | model


    # ========== 一度に生成する生成枚数の指定 ==========
    # RPMは10なのでそれを考慮して設定してください
    generate_images = 5


    # ========== 読み込む画像のパス ==========
    file_path = "inputs/sample1.png"
    #file_path = "inputs/sample2.png"


    # ========== 編集内容の指定 ==========
    #query = "女性の表情を溢れるくらいの笑顔に変更して"
    query = "表情を笑顔に変更して"
    #query = "空を夕焼けの空に変更して、ベンチの色を赤色に変更して"
    #query = "コーヒーカップを消去して"


    # =================================

    # 画像をbase64に変換
    file_b64 = convert_to_base64(file_path)
    print("ファイルのbase64変換が完了したので、処理を開始します。")

    for i in range(generate_images):
        print(f"画像{i+1}の生成を開始します。")
        # 画像の生成
        response = chain.invoke(
            {"user_input": query, "image": file_b64}, 
            generation_config=dict(response_modalities=["TEXT", "IMAGE"])
            )


        # LLMの出力結果が正しく画像になっているかバリデーション
        # その後、画像を保存
        try:
            image_str_dict = validate_and_extract_base64(response)
            # 画像を保存、テキストは表示
            process_dict_str_and_image(image_str_dict, file_path)

        except ValueError as e:
            print(f"エラー発生: {e}")

モデルの定義

下記にてモデルの定義をしています。画像生成や画像編集が可能なモデルはgemini-2.0-flash-exp-image-generationになりますので、そちらを指定してください。
また、画像を出力するためにresponse_modalities=[Modality.IMAGE, Modality.TEXT]の指定が必要になることに注意してください。

gemini_image_editing.py
    model = ChatGoogleGenerativeAI(
        model="models/gemini-2.0-flash-exp-image-generation",
        google_api_key=api_key,
        response_modalities=[Modality.IMAGE, Modality.TEXT]
        )

プロンプトの設定

記事執筆時点ではgemini-2.0-flash-exp-image-generationにてsystem_message設定できません。
したがって、HumanMessageを利用しています。

また、編集元の画像を入力するために、base64に画像をエンコードして、モデルに入力します。
"{user_input}"は、ユーザからの編集指示、
{image}は編集前の画像のbase64です。これをinvoke時に指定して実行します。

gemini_image_editing.py

    # messageを作成する
    message = [
        # 現在、gemini-2.0-flash-exp-image-generationではsystem_messageを利用できないので、HumanMessageを利用する
        HumanMessage(content= """
# 目的
あなたのタスクは画像編集です。ユーザが入力した画像を元に、ユーザが指定した内容で新しい画像を生成してください。

# ルール
ユーザが指示した内容に関係のない物体は、元の画像と全く同一にしてください。
ユーザが指示した内容だけをユーザの指示に忠実に編集して、画像を生成してください。
ユーザからの指示が変更依頼の場合は、そのオブジェクトと指定されたオブジェクトを元の画像から入れ替える形で編集してください。
ユーザからの指示が消去依頼の場合は、そのオブジェクトを元の画像から消去してください。
ユーザからの指示が追加依頼の場合は、そのオブジェクトを元の画像に追加してください。

----以下がユーザの入力です----
    """),
        HumanMessagePromptTemplate.from_template(
            [
                {
                    "type": "text",
                    "text": "{user_input}"
                },
                {
                    "image_url": {
                        "url": "data:image/png;base64,{image}"

                    }
                }
            ]
        ),
    ]

    # messageからプロンプトを作成
    prompt = ChatPromptTemplate.from_messages(message)

パラメータ指定

下記にてパラメータの指定を行います。

  • generate_images
    • pythonスクリプトを実行して一度に生成する画像の枚数です
    • 無料のGemini APIの場合、10RPMになるので、それに注意して設定してください
  • file_path
    • モデルに入力する編集前の参照画像
  • query
    • モデルに入力する編集指示
gemini_image_editing.py

    # ========== 一度に生成する生成枚数の指定 ==========
    # RPMは10なのでそれを考慮して設定してください
    generate_images = 5


    # ========== 読み込む画像のパス ==========
    file_path = "inputs/sample1.png"
    #file_path = "inputs/sample2.png"


    # ========== 編集内容の指定 ==========
    #query = "女性の表情を溢れるくらいの笑顔に変更して"
    query = "表情を笑顔に変更して"
    #query = "空を夕焼けの空に変更して、ベンチの色を赤色に変更して"
    #query = "コーヒーカップを消去して"


    # =================================

モデルの実行

gemini_image_editing.py
response = chain.invoke(
        {"user_input": query, "image": file_b64}, 
        generation_config=dict(response_modalities=["TEXT", "IMAGE"])
        )

通常のLangChainと同様にinvokeメソッドにて実行できます。ここでも画像出力を行うためにgeneration_configを設定してください。
"user_input"は、ユーザからの編集指示、"image"は編集前の画像のbase64です。

まとめ

gpt-4oには現状及ばないですが、gpt-4oを除けば非常に高い性能の画像編集モデルが無料かつAPIで利用できるようになったというのは非常に喜ばしいですね。

いち早くLangChainで利用できるように実装してくださった方に感謝を。

おすすめ書籍

本記事はLangChainについては理解している前提で記載しております。私はLangChainは下記の書籍で勉強したため、おすすめとして置いておきます。
(リンクはAmazonアフィリエイトリンクです)

LangChainとLangGraphによるRAG・AIエージェント[実践]入門
ChatGPT/LangChainによるチャットシステム構築[実践]入門
今回は、さまざまなモデルを統一的に利用するために、LangChainを利用しています。
langchainに関しては、こちらの書籍を読めば大体のことはできるようになりますので、1冊目としておすすめです。

仕組みからわかる大規模言語モデル 生成AI時代のソフトウェア開発入門
最近出た本ですが、LangChainとLangGraphについてかなりのページ数を割いて説明している本です。
LangChainとLangGraphの部分だけ読んだのですが、内容しっかりしており、また細かい発展的な部分まで解説されているので、2冊目に良いのではないかなと思います。

8

Discussion

ログインするとコメントできます