# JoyAI-Image-Edit

[JoyAI-Image](https://github.com/jd-opensource/JoyAI-Image) é um modelo de fundação multimodal unificado para compreensão de imagens, geração de imagens a partir de texto e edição de imagens guiada por instruções. Ele combina um Modelo de Linguagem Multimodal (MLLM) de 8B com um Transformer de Difusão Multimodal (MMDiT) de 16B. Um princípio central do JoyAI-Image é a colaboração em ciclo fechado entre compreensão, geração e edição.

O JoyAI-Image-Edit suporta edição geral de imagens, bem como capacidades de edição espacial, incluindo mover objetos, rotacionar objetos e controle de câmera.

| Model | Descrição | Download |
|:-----:|:-----------:|:--------:|
| JoyAI-Image-Edit | Edição de imagens guiada por instruções com manipulação espacial precisa e controlável | [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")
```

## Edição espacial

O JoyAI-Image suporta três padrões de prompt de edição espacial: **Object Move**, **Object Rotation** e **Camera Control**. Para obter os melhores resultados, siga os modelos de prompt abaixo o mais fielmente possível. Para mais informações, consulte [SpatialEdit](https://github.com/EasonXiao-888/SpatialEdit).

### Mover Objeto

Mova um objeto de destino para uma região especificada, marcada por uma caixa vermelha, na imagem de entrada.

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

### Rotação de Objeto

Gire um objeto para uma vista canônica específica. Valores de `<view>` suportados: `front`, `right`, `left`, `rear`, `front right`, `front left`, `rear right`, `rear left`.

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

### Controle da Câmera

Alterne o ponto de vista da câmera mantendo a cena 3D inalterada.

```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)
```

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

Pipeline de difusão para edição de imagens usando a arquitetura JoyImage.

O pipeline codifica o condicionamento de texto e imagem por meio de um codificador de texto Qwen3-VL, remove o ruído dos latentes com um transformador 3-D e decodifica o resultado com um WAN VAE.

Ordem de offloading do modelo: 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)
```

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

**Parâmetros:**

prompt (*str* ou *List[str]*) : O prompt ou os prompts para orientar a geração.

height (*int*) : Altura da saída gerada em pixels.

width (*int*) : Largura da saída gerada em pixels.

image (*PipelineImageInput*, *opcional*) : Imagem de referência usada para condicionamento. Quando fornecida, o pipeline opera no modo de edição de imagem com `num_items=2`.

num_inference_steps (*int*, *optional*, padrão 40) : Número de etapas de remoção de ruído. Mais etapas geralmente melhoram a qualidade, mas aumentam o tempo de inferência.

timesteps (*List[int]*, *opcional*) : Passos de tempo personalizados para o processo de desruidamento. Quando fornecidos, `num_inference_steps` é inferido a partir do comprimento da lista.

sigmas (*List[float]*, *opcional*) : Sigmas personalizados para o processo de desruidamento. Mutuamente exclusivo com `timesteps`.

guidance_scale (*float*, *optional*, padrão 4.0) : Escala de orientação sem classificador.

negative_prompt (*str* ou *List[str]*, *opcional*) : Prompt(s) negativo(s) usado(s) para suprimir conteúdo indesejado.

num_images_per_prompt (*int*, *opcional*, padrão 1) : Número de amostras geradas por prompt.

generator (*torch.Generator* ou *List[torch.Generator]*, *opcional*) : gerador(es) de RNG para amostragem determinística.

latents (*torch.Tensor*, *opcional*) : Latentes ruidosos pré-gerados para o slot de destino. Amostras de uma distribuição gaussiana quando não fornecidos. Pode ser usado para iniciar a geração a partir de um tensor de ruído específico.

prompt_embeds (*torch.Tensor*, *opcional*) : Embebidos de prompt pré-computados. Quando fornecidos, `prompt` pode ser omitido.

prompt_embeds_mask (*torch.Tensor*, *opcional*) : Máscara de atenção para `prompt_embeds`.

negative_prompt_embeds (*torch.Tensor*, *opcional*) : Embeddings de prompt negativo pré-computados.

negative_prompt_embeds_mask (*torch.Tensor*, *opcional*) : Máscara de atenção para `negative_prompt_embeds`.

output_type (*str*, *opcional*, padrão `"pil"`) : Formato de saída. Passe `"latent"` para retornar os latentes brutos.

return_dict (*bool*, *opcional*, padrão *True*) : Se deve retornar um [JoyImageEditPipelineOutput](/docs/diffusers/main/pt/api/pipelines/joyimage_edit#diffusers.JoyImageEditPipelineOutput) ou um tensor simples.

callback_on_step_end (*Callable*, *PipelineCallback*, *MultiPipelineCallbacks*, *opcional*) : Callback chamado no final de cada etapa de remoção de ruído com a assinatura `(self, step: int, timestep: int, callback_kwargs: Dict)`.

callback_on_step_end_tensor_inputs (*List[str]*, *opcional*, padrão `["latents"]`) : Chaves de Tensor incluídas em `callback_kwargs` para `callback_on_step_end`.

max_sequence_length (*int*, *opcional*, padrão 4096) : Comprimento máximo da sequência para a codificação do prompt.

enable_denormalization (*bool*, *opcional*, padrão *True*) : Desnormaliza os latentes antes da decodificação pelo VAE.

**Retorna:** [*~pipelines.joyimage.JoyImageEditPipelineOutput*] ou *torch.Tensor*

Se `return_dict` for `True`, retorna um objeto de saída do pipeline contendo a(s) imagem(ns) gerada(s). Caso contrário, retorna o tensor da imagem diretamente.

Gere uma imagem editada condicionada a uma imagem de referência e a um prompt de texto.

Exemplos:
```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)
```

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

**Exceções:** ``ValueError``

- ``ValueError`` -- Em qualquer combinação inválida de argumentos.

Valide as entradas do pipeline antes da passagem direta.

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

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

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

**Parâmetros:**

latent : Tensor latente normalizado.

**Retorna:**

Tensor latente na escala esperada por `vae.decode`.

Inverta `normalize_latents` para recuperar a escala latente original.

#### 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')
```

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

**Parâmetros:**

prompt : String de prompt ou lista de strings de prompt.

device : Dispositivo de destino.

num_images_per_prompt : Número de saídas a gerar por prompt.

prompt_embeds : Embeddings de prompt pré-computados.

prompt_embeds_mask : Máscara de atenção para incorporações pré-computadas.

max_sequence_length : Comprimento máximo da sequência de saída.

template_type : Chave do modelo de prompt (`"image"` ou `"multiple_images"`).

**Retorna:**

Tupla de (prompt_embeds, prompt_embeds_mask).

Codifique um prompt de texto em embeddings (caminho apenas de texto).

`prompt_embeds` pré-computados contornam completamente a codificação.

#### 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)
```

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

**Parâmetros:**

prompt : String(s) de prompt, opcionalmente contendo tokens `&amp;lt;image>\n`.

device : Dispositivo de destino.

num_images_per_prompt : Número de saídas a gerar por prompt.

images : Tensores de pixels correspondentes aos tokens de imagem inline.

prompt_embeds : Embeddings de prompt pré-computados.

prompt_embeds_mask : Máscara de atenção para incorporações pré-computadas.

template_type : Deve ser `"multiple_images"`.

max_sequence_length : Se definido, trunca a saída para esse comprimento (mantendo os últimos `max_sequence_length` tokens).

**Retorna:**

Tupla de (prompt_embeds, prompt_embeds_mask).

Codifique prompts que contêm tokens de imagem inline por meio do processador Qwen.

Os placeholders `&amp;lt;image>\n` em cada string de prompt são substituídos pelos tokens especiais de visão do Qwen antes de serem enviados ao codificador multimodal.

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

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

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

**Parâmetros:**

latent : Tensor latente bruto de `vae.encode`.

**Retorna:**

Tensor latente normalizado.

Normalize os latentes usando estatísticas por canal da configuração do VAE.

Uses (latent - mean) / std quando o VAE expõe `latents_mean` e `latents_std`; caso contrário, recorre à escala por `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)
```

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

**Parâmetros:**

batch_size : Número de amostras no lote.

num_channels_latents : Dimensão do canal latente da configuração do transformer.

height : Altura espacial em pixels.

width : Largura espacial em pixels.

video_length : Número de quadros (1 para inferência de imagem).

dtype : dtype de ponto flutuante para o tensor latente.

device : Dispositivo de destino.

generator : gerador(es) de RNG para amostragem reprodutível.

latents : Ruído inicial opcional fornecido pelo usuário para o slot de destino. Quando `None`, um ruído aleatório é amostrado.

image : Lista opcional de imagens de referência em PIL para codificar com VAE como slots de condicionamento.

enable_denormalization : Se normalizar os latentes de referência codificados.

**Retorna:**

Tupla de `(latents, image_latents)` em que `latents` tem forma `(B, 1, C, T, H', W')` e `image_latents` tem forma `(B, N_ref, C, T, H', W')` ou `None` quando nenhuma imagem de referência é fornecida.

**Exceções:** `ValueError`

- `ValueError` -- Se `generator` for uma lista cujo comprimento difere de `batch_size`.

Prepare o tensor latente inicial com ruído para o loop de desruidamento.

## JoyImageEditPipelineOutput[[diffusers.JoyImageEditPipelineOutput]]

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

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

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

Classe de saída para pipelines de geração do JoyImageEdit.

