# JoyAI-Image-Edit

[JoyAI-Image](https://github.com/jd-opensource/JoyAI-Image)は、画像理解、テキストからの画像生成、および指示に基づく画像編集のための統合型マルチモーダル基盤モデルです。8Bのマルチモーダル大規模言語モデル（MLLM）と16Bのマルチモーダル拡散トランスフォーマー（MMDiT）を組み合わせています。JoyAI-Imageの中核となる原則は、理解・生成・編集の間のクローズドループな協調です。

JoyAI-Image-Editは、一般的な画像編集のほかに、オブジェクトの移動、オブジェクトの回転、カメラ制御といった空間編集機能にも対応しています。

| モデル | 説明 | ダウンロード |
|:-----:|:-----------:|:--------:|
| JoyAI-Image-Edit | 指示に基づく画像編集と、精密かつ制御可能な空間操作 | [Hugging Face](https://huggingface.co/jdopensource/JoyAI-Image-Edit-Diffusers) |

```python
import torch
from diffusers import JoyImageEditPipeline
from diffusers.utils import load_image

pipeline = JoyImageEditPipeline.from_pretrained(
    "jdopensource/JoyAI-Image-Edit-Diffusers", dtype=torch.bfloat16
)
pipeline.to("cuda")  # or "mps", "xpu", "cpu"

image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/astronaut.jpg")
prompt = "Add wings to the astronaut."

output = pipeline(
    image=image,
    prompt=prompt,
    num_inference_steps=40,
    guidance_scale=4.0,
    generator=torch.Generator("cuda").manual_seed(0),
).images[0]
output.save("joyimage_edit_output.png")
```

## 空間編集

JoyAI-Image は、**Object Move**、**Object Rotation**、**Camera Control** の 3 つの空間編集プロンプトパターンをサポートしています。最適な結果を得るには、以下のプロンプトテンプレートをできるだけ忠実に従ってください。詳細については、[SpatialEdit](https://github.com/EasonXiao-888/SpatialEdit) を参照してください。

### オブジェクトの移動

入力画像内の赤い枠で示された指定領域に、対象オブジェクトを移動します。

```text
Move the <object> into the red box and finally remove the red box.
```

### オブジェクトの回転

オブジェクトを特定の正規化ビューに回転します。サポートされている`<view>`の値: `front`、`right`、`left`、`rear`、`front right`、`front left`、`rear right`、`rear left`。

```text
Rotate the <object> to show the <view> side view.
```

### カメラコントロール

3Dシーンを変更せずに、カメラの視点を変更します。

```text
Move the camera.
- Camera rotation: Yaw {y_rotation}°, Pitch {p_rotation}°.
- Camera zoom: in/out/unchanged.
- Keep the 3D scene static; only change the viewpoint.
```

## JoyImageEditPipeline[[diffusers.JoyImageEditPipeline]]

#### diffusers.JoyImageEditPipeline[[diffusers.JoyImageEditPipeline]]

```python
diffusers.JoyImageEditPipeline(scheduler: FlowMatchEulerDiscreteScheduler, vae: AutoencoderKLWan, text_encoder: Qwen3VLForConditionalGeneration, tokenizer: Qwen2Tokenizer, transformer: JoyImageEditTransformer3DModel, processor: Qwen3VLProcessor, text_token_max_length: int = 2048)
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit.py#L100)

JoyImageアーキテクチャを使用した画像編集のためのDiffusionパイプライン。

パイプラインは、Qwen3-VL テキストエンコーダーによってテキストと画像の条件をエンコードし、3D トランスフォーマーで潜在変数をノイズ除去し、WAN VAE で結果をデコードします。

モデルのオフロード順序: text_encoder -> transformer -> vae。

#### __call__[[diffusers.JoyImageEditPipeline.__call__]]

```python
__call__(image: typing.Union[PIL.Image.Image, numpy.ndarray, torch.Tensor, list[PIL.Image.Image], list[numpy.ndarray], list[torch.Tensor], NoneType] = None, prompt: str | list[str] = None, height: int | None = None, width: int | None = None, num_inference_steps: int = 40, timesteps: typing.List[int] = None, sigmas: typing.List[float] = None, guidance_scale: float = 4.0, negative_prompt: typing.Union[str, typing.List[str], NoneType] = None, num_images_per_prompt: typing.Optional[int] = 1, generator: typing.Union[torch.Generator, typing.List[torch.Generator], NoneType] = None, latents: typing.Optional[torch.Tensor] = None, prompt_embeds: typing.Optional[torch.Tensor] = None, prompt_embeds_mask: typing.Optional[torch.Tensor] = None, negative_prompt_embeds: typing.Optional[torch.Tensor] = None, negative_prompt_embeds_mask: typing.Optional[torch.Tensor] = None, output_type: typing.Optional[str] = 'pil', return_dict: bool = True, callback_on_step_end: typing.Union[typing.Callable[[int, int, typing.Dict], NoneType], diffusers.callbacks.PipelineCallback, diffusers.callbacks.MultiPipelineCallbacks, NoneType] = None, callback_on_step_end_tensor_inputs: typing.List[str] = ['latents'], max_sequence_length: int = 4096, enable_denormalization: bool = True)
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit.py#L600)

**パラメータ:**

prompt (*str* または *List[str]*) : 生成をガイドするためのプロンプトまたはプロンプトのリスト。

height (*int*) : 生成される出力のピクセル高さ。

width (*int*) : 生成される出力の幅（ピクセル単位）。

image (*PipelineImageInput*、*optional*) : 条件付けに使用される参照画像。指定された場合、パイプラインは`num_items=2`で画像編集モードとして動作します。

num_inference_steps (*int*、*optional*、デフォルト値は40) : デノイジングのステップ数。ステップ数が多いほど、推論速度が遅くなる代わりに、一般的に品質が向上します。

timesteps (*List[int]*, *optional*) : デノイジングプロセス用のカスタムタイムステップ。指定された場合、`num_inference_steps` はリストの長さから推定されます。

sigmas (*List[float]*、*optional*) : デノイジングプロセス用のカスタムシグマ。`timesteps`とは排他的です。

guidance_scale (*float*、*optional*、デフォルト値は 4.0) : Classifier-free guidance のスケール。

negative_prompt (*str* または *List[str]*、*optional*) : 望ましくないコンテンツを抑制するために使用されるネガティブプロンプト。

num_images_per_prompt (*int*、*optional*、デフォルトは 1) : プロンプトごとに生成されるサンプルの数。

generator (*torch.Generator* または *List[torch.Generator]*、*任意*) : 決定論的なサンプリング用の乱数生成器。

latents (*torch.Tensor*, *optional*) : ターゲットスロット用の事前生成されたノイズ付き潜在変数。指定されない場合は、ガウス分布からサンプリングされます。特定の開始ノイズテンソルから生成をシードするために使用できます。

prompt_embeds (*torch.Tensor*、*optional*) : 事前計算済みのプロンプト埋め込み。指定すると、`prompt` を省略できます。

prompt_embeds_mask (*torch.Tensor*, *任意*) : `prompt_embeds`用のアテンションマスク。

negative_prompt_embeds (*torch.Tensor*, *optional*) : 事前計算されたネガティブプロンプトの埋め込み。

negative_prompt_embeds_mask (*torch.Tensor*、*optional*) : `negative_prompt_embeds`用のアテンションマスク。

output_type (*str*、*optional*、デフォルトは`"pil"`) : 出力形式。`"latent"`を渡すと、生の潜在変数を返します。

return_dict (*bool*、*optional*、デフォルトは *True*) : [JoyImageEditPipelineOutput](/docs/diffusers/main/ja/api/pipelines/joyimage_edit#diffusers.JoyImageEditPipelineOutput) を返すか、プレーンなテンソルを返すかを指定します。

callback_on_step_end (*Callable*、*PipelineCallback*、*MultiPipelineCallbacks*、*optional*) : 各デノイジングステップの終了時に呼び出されるコールバックで、シグネチャは `(self, step: int, timestep: int, callback_kwargs: Dict)` です。

callback_on_step_end_tensor_inputs (*List[str]*、*optional*、デフォルトは `["latents"]`) : `callback_on_step_end` において `callback_kwargs` に含まれる Tensor のキー。

max_sequence_length (*int*、*optional*、デフォルトは 4096) : プロンプトエンコードの最大シーケンス長。

enable_denormalization (*bool*、*optional*、デフォルトは *True*) : VAEデコードの前に、潜在変数をデノーマライズします。

**戻り値:** [*~pipelines.joyimage.JoyImageEditPipelineOutput*] または *torch.Tensor*

`return_dict` が `True` の場合、生成された画像を含むパイプライン出力オブジェクトを返します。それ以外の場合は、画像テンソルを直接返します。

参照画像とテキストプロンプトを条件として、編集された画像を生成します。

例:
```python
>>> import torch
>>> from diffusers import JoyImageEditPipeline
>>> from diffusers.utils import load_image

>>> model_id = "jdopensource/JoyAI-Image-Edit-Diffusers"
>>> pipe = JoyImageEditPipeline.from_pretrained(model_id, torch_dtype=torch.bfloat16)
>>> pipe.to("cuda")

>>> image = load_image("https://huggingface.co/datasets/diffusers/docs-images/resolve/main/astronaut.jpg")
>>> output = pipe(
...     image=image,  # pass an image for editing; omit for text-to-image generation
...     prompt="Add wings to the astronaut.",
...     num_inference_steps=40,
...     guidance_scale=4.0,
...     generator=torch.manual_seed(0),
... )
>>> output.images[0].save("joyimage_edit.png")
```

#### check_inputs[[diffusers.JoyImageEditPipeline.check_inputs]]

```python
check_inputs(prompt, height, width, negative_prompt = None, prompt_embeds = None, negative_prompt_embeds = None, prompt_embeds_mask = None, negative_prompt_embeds_mask = None, callback_on_step_end_tensor_inputs = None)
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit.py#L409)

**例外:** ``ValueError``

- ``ValueError`` -- 引数の組み合わせが無効な場合。

フォワードパスの前に、パイプラインの入力を検証します。

#### denormalize_latents[[diffusers.JoyImageEditPipeline.denormalize_latents]]

```python
denormalize_latents(latent: Tensor)
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit.py#L476)

**パラメータ:**

latent : 正規化された潜在テンソル。

**戻り値:**

`vae.decode`が期待するスケールを持つ潜在テンソル。

`normalize_latents`を逆変換して、元の潜在変数のスケールを復元します。

#### encode_prompt[[diffusers.JoyImageEditPipeline.encode_prompt]]

```python
encode_prompt(prompt: typing.Union[str, typing.List[str]], device: typing.Optional[torch.device] = None, num_images_per_prompt: int = 1, prompt_embeds: typing.Optional[torch.Tensor] = None, prompt_embeds_mask: typing.Optional[torch.Tensor] = None, max_sequence_length: int = 1024, template_type: str = 'image')
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit.py#L364)

**パラメータ:**

prompt : プロンプト文字列、またはプロンプト文字列のリスト。

device : ターゲットデバイス。

num_images_per_prompt : プロンプトごとに生成する出力の数。

prompt_embeds : 事前計算済みのプロンプト埋め込み。

prompt_embeds_mask : 事前計算済みエンベディング用のアテンションマスク。

max_sequence_length : 出力シーケンスの最大長。

template_type : プロンプトテンプレートのキー（`"image"`または`"multiple_images"`）。

**戻り値:**

(prompt_embeds, prompt_embeds_mask) のタプル。

テキストプロンプトを埋め込みベクトルにエンコードします（テキストのみパス）。

事前計算済みの`prompt_embeds`は、エンコーディングを完全にスキップします。

#### encode_prompt_multiple_images[[diffusers.JoyImageEditPipeline.encode_prompt_multiple_images]]

```python
encode_prompt_multiple_images(prompt: typing.Union[str, typing.List[str]], device: typing.Optional[torch.device] = None, num_images_per_prompt: int = 1, images: typing.Optional[torch.Tensor] = None, prompt_embeds: typing.Optional[torch.Tensor] = None, prompt_embeds_mask: typing.Optional[torch.Tensor] = None, template_type: typing.Optional[str] = 'multiple_images', max_sequence_length: typing.Optional[int] = None)
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit.py#L286)

**パラメータ:**

prompt : プロンプト文字列。必要に応じて`&amp;lt;image>\n`トークンを含むことができます。

device : ターゲットデバイス。

num_images_per_prompt : プロンプトごとに生成する出力の数。

images : インライン画像トークンに対応するピクセルテンソル。

prompt_embeds : 事前計算済みのプロンプト埋め込み。

prompt_embeds_mask : 事前計算済みエンベディング用のアテンションマスク。

template_type : `"multiple_images"` である必要があります。

max_sequence_length : 設定されている場合、出力をこの長さに切り詰めます（最後の`max_sequence_length`トークンを保持します）。

**戻り値:**

(prompt_embeds, prompt_embeds_mask) のタプル。

インラインの画像トークンを含むプロンプトを、Qwenプロセッサでエンコードします。

各プロンプト文字列内の`&amp;lt;image>\n`プレースホルダーは、マルチモーダルエンコーダーに渡される前に、Qwenのビジョン用特殊トークンに置き換えられます。

#### normalize_latents[[diffusers.JoyImageEditPipeline.normalize_latents]]

```python
normalize_latents(latent: Tensor)
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit.py#L447)

**パラメータ:**

latent : `vae.encode`からの生潜在テンソル。

**戻り値:**

正規化された潜在テンソル。

VAE設定からのチャネルごとの統計量を使用して、潜在変数を正規化します。

Uses VAE が `latents_mean` と `latents_std` を公開している場合は (latent - mean) / std を使用し、それ以外の場合は `scaling_factor` によるスケーリングにフォールバックします。

#### prepare_latents[[diffusers.JoyImageEditPipeline.prepare_latents]]

```python
prepare_latents(batch_size: int, num_channels_latents: int, height: int, width: int, video_length: int, dtype: dtype, device: device, generator: typing.Union[torch.Generator, typing.List[torch.Generator], NoneType], latents: typing.Optional[torch.Tensor] = None, image: typing.Optional[typing.List[PIL.Image.Image]] = None, enable_denormalization: bool = True)
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_joyimage_edit.py#L502)

**パラメータ:**

batch_size : バッチ内のサンプル数。

num_channels_latents : Transformer の設定から取得される潜在チャネル次元。

height : ピクセル単位の空間的な高さ。

width : ピクセル単位の空間的な幅。

video_length : フレーム数（画像推論の場合は1）。

dtype : 潜在テンソル用の浮動小数点 dtype。

device : ターゲットデバイス。

generator : 再現可能なサンプリングのためのRNGジェネレーター。

latents : ターゲットスロット用の、ユーザーが指定する任意の初期ノイズ。`None` の場合は、ランダムなノイズがサンプリングされます。

image : VAEエンコードして条件スロットとして使用するPIL参照画像の任意のリスト。

enable_denormalization : エンコードされた参照潜在変数を正規化するか。

**戻り値:**

`(latents, image_latents)` のタプル。ここで `latents` の形状は `(B, 1, C, T, H', W')`、`image_latents` の形状は `(B, N_ref, C, T, H', W')` です。参照画像が指定されない場合は `None` になります。

**例外:** `ValueError`

- `ValueError` -- `generator`が`batch_size`と長さの異なるリストの場合。

デノイジングループ用の初期ノイズ付き潜在テンソルを準備します。

## JoyImageEditPipelineOutput[[diffusers.JoyImageEditPipelineOutput]]

#### diffusers.JoyImageEditPipelineOutput[[diffusers.JoyImageEditPipelineOutput]]

```python
diffusers.JoyImageEditPipelineOutput(images: typing.Union[typing.List[PIL.Image.Image], numpy.ndarray])
```

[ソース](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/joyimage/pipeline_output.py#L11)

JoyImageEdit 生成パイプライン用の出力クラスです。

