Gradio ImageEditorチュートリアル

画像処理

このノートブックでは、GradioのパワフルなImageEditorコンポーネントを使用して、画像編集アプリケーションを作成する方法を学びます。

Gradioとは?

Gradioは、機械学習モデルや画像処理アプリケーションなどを簡単にWebインターフェースとして公開できるPythonライブラリです。特に、AIデモの作成やプロトタイピングに最適です。

環境のセットアップ

まずは必要なライブラリをインストールしましょう。

!pip install gradio pillow numpy

基本的なImageEditorアプリケーション

以下では、シンプルな画像編集アプリを構築します。このアプリでは、ユーザーは画像をアップロードして編集し、結果を保存することができます。

import gradio as gr
import time
import numpy as np
from PIL import Image
import os

def save_image(im, filename="saved_image.png"):
    """画像をファイルに保存する関数"""
    if im is not None and "composite" in im:
        # 合成画像(最終結果)を取得
        composite = im["composite"]

        # numpy配列の場合はPIL Imageに変換
        if isinstance(composite, np.ndarray):
            composite = Image.fromarray(composite)

        # 画像を保存
        composite.save(filename)
        return f"画像が正常に {filename} として保存されました"
    else:
        return "保存する画像がないか、無効な画像形式です"

# Gradio Blocksアプリケーションを作成(テーマをOceanに設定)
with gr.Blocks(theme=gr.themes.Ocean()) as demo:
    gr.Markdown("# Image Editor Demo")

    with gr.Row():
        with gr.Column():
            # 1:1の縦横比でImageEditorコンポーネントを作成
            im = gr.ImageEditor(
                type="numpy",  # 画像はnumpy配列として処理される
                crop_size="1:1",  # 正方形のトリミング比率を設定
                label="画像エディタ"
            )

        with gr.Column():
            # プレビュー表示用のImageコンポーネントを作成
            im_preview = gr.Image(label="プレビュー")

    # 各種イベントを追跡するカウンター
    with gr.Row():
        n_upload = gr.Number(0, label="アップロードイベント数", step=1)
        n_change = gr.Number(0, label="変更イベント数", step=1)
        n_input = gr.Number(0, label="入力イベント数", step=1)

    # ファイル名入力と保存ボタンを追加
    with gr.Row():
        filename_input = gr.Textbox(value="my_drawing.png", label="ファイル名")
        save_btn = gr.Button("画像を保存", variant="primary")

    # 保存操作のステータスメッセージ
    save_status = gr.Textbox(label="保存ステータス", interactive=False)

    # イベントハンドラーを定義:
    # 画像がアップロードされたらアップロードカウンターを増加
    im.upload(lambda x: x + 1, outputs=n_upload, inputs=n_upload)

    # 画像が変更されたら変更カウンターを増加(ユーザー入力または関数更新による)
    im.change(lambda x: x + 1, outputs=n_change, inputs=n_change)

    # ユーザーが画像を変更したら入力カウンターを増加
    im.input(lambda x: x + 1, outputs=n_input, inputs=n_input)

    # 画像が変更されたらプレビューエリアに合成画像を表示
    im.change(lambda im: im["composite"] if im and "composite" in im else None,
              outputs=im_preview,
              inputs=im,
              show_progress="hidden")

    # 保存ボタンクリックイベントを設定
    save_btn.click(
        fn=save_image,
        inputs=[im, filename_input],
        outputs=save_status
    )

# このスクリプトが直接実行されたときにデモを起動
if __name__ == "__main__":
    demo.launch()

コードの詳細解説

インポートと設定

import gradio as gr
import time
import numpy as np
from PIL import Image
import os

ここでは、必要なライブラリをインポートしています:

  • gradio: UIコンポーネントの作成に使用
  • time: デモンストレーション目的(必要に応じて)
  • numpy: 画像データを配列として処理
  • PIL.Image: 画像処理機能
  • os: ファイル操作

画像保存関数

def save_image(im, filename="saved_image.png"):
    """画像をファイルに保存する関数"""
    if im is not None and "composite" in im:
        # 合成画像(最終結果)を取得
        composite = im["composite"]

        # numpy配列の場合はPIL Imageに変換
        if isinstance(composite, np.ndarray):
            composite = Image.fromarray(composite)

        # 画像を保存
        composite.save(filename)
        return f"画像が正常に {filename} として保存されました"
    else:
        return "保存する画像がないか、無効な画像形式です"

この関数は以下のことを行います:

  • ImageEditorからの出力を取得し、それが有効かチェックします
  • compositeキーにアクセスして最終的な合成画像を取得します
  • 必要に応じてnumpy配列からPIL Imageに変換します
  • 指定されたファイル名で画像を保存します
  • 操作の結果に関するメッセージを返します

Gradio UIの作成

with gr.Blocks() as demo:
    with gr.Row():
        # 1:1の縦横比でImageEditorコンポーネントを作成
        im = gr.ImageEditor(
            type="numpy",  # 画像はnumpy配列として処理される
            crop_size="1:1",  # 正方形のトリミング比率を設定
            label="画像エディタ"
        )
        # プレビュー表示用のImageコンポーネントを作成
        im_preview = gr.Image(label="プレビュー")

ここでは:

  • gr.Blocks()でUIの作成を開始
  • gr.Row()で水平レイアウトを作成
  • gr.ImageEditorを設定:
    • type="numpy": 画像をnumpy配列として処理
    • crop_size="1:1": 画像を正方形にトリミングするオプション
    • label="画像エディタ": コンポーネントのラベル
  • gr.Imageでプレビュー表示用のコンポーネントを作成

イベントカウンター

# 各種イベントを追跡するカウンター
n_upload = gr.Number(0, label="アップロードイベント数", step=1)
n_change = gr.Number(0, label="変更イベント数", step=1)
n_input = gr.Number(0, label="入力イベント数", step=1)

  • 各種のユーザーイベントを追跡するための数値カウンターを作成します
  • この例では、3種類のイベントを追跡しています:
    • アップロードイベント:新しい画像がアップロードされたとき
    • 変更イベント:画像が何らかの方法で変更されたとき
    • 入力イベント:ユーザーが直接画像を編集したとき

保存機能

# ファイル名入力と保存ボタンを追加
with gr.Row():
    filename_input = gr.Textbox(value="my_drawing.png", label="ファイル名")
    save_btn = gr.Button("画像を保存")

# 保存操作のステータスメッセージ
save_status = gr.Textbox(label="保存ステータス", interactive=False)

  • 保存機能のためのUI要素を追加:
    • ファイル名を入力するためのテキストボックス(デフォルト値付き)
    • 保存アクションを開始するボタン
    • 保存操作の結果を表示するステータステキストボックス

イベントハンドラ

# イベントハンドラーを定義:
# 画像がアップロードされたらアップロードカウンターを増加
im.upload(lambda x: x + 1, outputs=n_upload, inputs=n_upload)

# 画像が変更されたら変更カウンターを増加(ユーザー入力または関数更新による)
im.change(lambda x: x + 1, outputs=n_change, inputs=n_change)

# ユーザーが画像を変更したら入力カウンターを増加
im.input(lambda x: x + 1, outputs=n_input, inputs=n_input)

# 画像が変更されたらプレビューエリアに合成画像を表示
im.change(lambda im: im["composite"] if im and "composite" in im else None,
          outputs=im_preview,
          inputs=im,
          show_progress="hidden")

# 保存ボタンクリックイベントを設定
save_btn.click(
    fn=save_image,
    inputs=[im, filename_input],
    outputs=save_status
)

この部分ではUIのインタラクティブな動作を定義しています:

  1. イベントカウンター更新:

    • .upload().change().input()メソッドを使って各種イベントを検出
    • それぞれのイベントが発生するとカウンターを1増加
  2. プレビュー更新:

    • 画像が変更されるたびに、im.change()イベントでプレビュー画像を更新
    • compositeキーにアクセスして最終的な合成画像を取得
  3. 保存機能:

    • 保存ボタンがクリックされたときにsave_image関数を呼び出す
    • 現在の画像とユーザーが指定したファイル名を関数に渡す
    • 保存操作の結果をステータステキストボックスに表示

アプリケーションの起動

# このスクリプトが直接実行されたときにデモを起動
if __name__ == "__main__":
    demo.launch()
  • if __name__ == "__main__":は、このスクリプトが直接実行されたときだけ以下のコードを実行するPythonのイディオム
  • demo.launch()でGradioアプリケーションを起動し、ローカルのWebサーバーを開始

ImageEditorの主な特徴

編集ツール

ImageEditorコンポーネントには、以下のような編集ツールが含まれています:

  • ブラシ: 自由に描画することができます
  • 消しゴム: 描画した内容を消去できます
  • トリミング: 画像の一部を切り抜くことができます
  • レイヤー: 複数のレイヤーで作業でき、それぞれを個別に編集できます

データ構造

ImageEditorからの出力はEditorValueと呼ばれる辞書形式のオブジェクトです:

{
    'background': [背景画像データ],
    'layers': [レイヤーのリスト],
    'composite': [最終的な合成画像]
}
  • background: 編集の背景となる画像
  • layers: 追加されたレイヤーのリスト
  • composite: すべてのレイヤーを合成した最終画像

まとめ

このチュートリアルでは、GradioのImageEditorコンポーネントを使用して、以下のことを学びました:

  1. 基本的な画像編集アプリケーションの作成方法
  2. イベントハンドラを使ったインタラクティブな機能の実装
  3. 編集した画像の保存とファイル管理
  4. ImageEditorコンポーネントの主な特徴と出力データ構造

Gradioを使うと、複雑な画像処理機能を持つウェブアプリケーションを、わずか数十行のPythonコードで実装できます。これは、実用的なツール開発だけでなく、AIモデルのデモンストレーションやプロトタイピングにも非常に便利です。

さらなる学習リソース

ノートブック

Google Colab

デモアプリ

Image Editor Demo - a Hugging Face Space by MakiAi
Discover amazing ML apps made by the community

コメント

タイトルとURLをコピーしました