# JoyAI-Image-Edit

[JoyAI-Image](https://github.com/jd-opensource/JoyAI-Image) es un modelo de base multimodal unificado para la comprensión de imágenes, la generación de imágenes a partir de texto y la edición de imágenes guiada por instrucciones. Combina un Modelo de Lenguaje Grande Multimodal (MLLM) de 8B con un Transformer de Difusión Multimodal (MMDiT) de 16B. Un principio central de JoyAI-Image es la colaboración en bucle cerrado entre la comprensión, la generación y la edición.

JoyAI-Image-Edit admite la edición general de imágenes, así como capacidades de edición espacial, que incluyen el movimiento de objetos, la rotación de objetos y el control de la cámara.

| Modelo | Descripción | Descargar |
|:-----:|:-----------:|:--------:|
| JoyAI-Image-Edit | Edición de imágenes guiada por instrucciones con manipulación espacial precisa y controlable | [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")
```

## Edición espacial

JoyAI-Image admite tres patrones de edición espacial: **Object Move**, **Object Rotation** y **Camera Control**. Para obtener los mejores resultados, siga las plantillas de indicaciones a continuación con la mayor fidelidad posible. Para obtener más información, consulte [SpatialEdit](https://github.com/EasonXiao-888/SpatialEdit).

### Mover objeto

Mover un objeto de destino a una región especificada marcada con un recuadro rojo en la imagen de entrada.

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

### Rotación de objetos

Gire un objeto a una vista canónica específica. Valores de `<view>` admitidos: `front`, `right`, `left`, `rear`, `front right`, `front left`, `rear right`, `rear left`.

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

### Control de cámara

Cambia el punto de vista de la cámara manteniendo la escena 3D sin cambios.

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

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

Pipeline de difusión para la edición de imágenes que utiliza la arquitectura JoyImage.

El pipeline codifica el condicionamiento de texto e imagen mediante un codificador de texto Qwen3-VL, desruidiza los latentes con un transformador 3-D y decodifica el resultado con un VAE de WAN.

Orden de descarga de modelos: 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)
```

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

**Parámetros:**

prompt (*str* o *List[str]*) : El prompt o los prompts para guiar la generación.

height (*int*) : Altura de la salida generada en píxeles.

width (*int*) : Ancho de la salida generada en píxeles.

image (*PipelineImageInput*, *opcional*) : Imagen de referencia utilizada para el condicionamiento. Cuando se proporciona, la pipeline opera en modo de edición de imagen con `num_items=2`.

num_inference_steps (*int*, *optional*, por defecto 40) : Número de pasos de desruido. Más pasos generalmente mejoran la calidad a costa de una inferencia más lenta.

timesteps (*List[int]*, *opcional*) : Pasos de tiempo personalizados para el proceso de desruido. Cuando se proporcionan, `num_inference_steps` se infiere a partir de la longitud de la lista.

sigmas (*List[float]*, *opcional*) : Sigmas personalizados para el proceso de desruido. Mutuamente excluyente con `timesteps`.

guidance_scale (*float*, *optional*, por defecto 4.0) : Escala de guía sin clasificador.

negative_prompt (*str* o *List[str]*, *opcional*) : Prompt(s) negativo(s) utilizado(s) para suprimir contenido no deseado.

num_images_per_prompt (*int*, *optional*, por defecto 1) : Número de muestras generadas por prompt.

generator (*torch.Generator* o *List[torch.Generator]*, *opcional*) : Generador(es) de RNG para muestreo determinista.

latents (*torch.Tensor*, *opcional*) : Latentes ruidosos pregenerados para el slot objetivo. Se muestrean de una distribución gaussiana cuando no se proporcionan. Se pueden usar para iniciar la generación desde un tensor de ruido inicial específico.

prompt_embeds (*torch.Tensor*, *opcional*) : Embeddings de prompt precalculados. Si se proporcionan, `prompt` puede omitirse.

prompt_embeds_mask (*torch.Tensor*, *opcional*) : Máscara de atención para `prompt_embeds`.

negative_prompt_embeds (*torch.Tensor*, *opcional*) : Incrustaciones de prompt negativo precalculadas.

negative_prompt_embeds_mask (*torch.Tensor*, *opcional*) : Máscara de atención para `negative_prompt_embeds`.

output_type (*str*, *opcional*, por defecto `"pil"`) : Formato de salida. Pasa `"latent"` para devolver los latentes crudos.

return_dict (*bool*, *opcional*, por defecto *True*) : Si se debe devolver un [JoyImageEditPipelineOutput](/docs/diffusers/v0.43.0/es/api/pipelines/joyimage_edit#diffusers.JoyImageEditPipelineOutput) o un tensor simple.

callback_on_step_end (*Callable*, *PipelineCallback*, *MultiPipelineCallbacks*, *optional*) : Callback que se invoca al final de cada paso de desruido con la firma `(self, step: int, timestep: int, callback_kwargs: Dict)`.

callback_on_step_end_tensor_inputs (*List[str]*, *opcional*, por defecto `["latents"]`) : Claves de tensor incluidas en `callback_kwargs` para `callback_on_step_end`.

max_sequence_length (*int*, *optional*, por defecto 4096) : Longitud máxima de la secuencia para la codificación del prompt.

enable_denormalization (*bool*, *opcional*, valor predeterminado *True*) : Desnormalizar los latentes antes de la decodificación VAE.

**Devuelve:** [*~pipelines.joyimage.JoyImageEditPipelineOutput*] o *torch.Tensor*

Si `return_dict` es `True`, devuelve un objeto de salida de pipeline que contiene la(s) imagen(es) generada(s). En caso contrario, devuelve el tensor de imagen directamente.

Genere una imagen editada condicionada a una imagen de referencia y un prompt de texto.

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

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

**Excepciones:** ``ValueError``

- ``ValueError`` -- En cualquier combinación inválida de argumentos.

Validar las entradas de la pipeline antes de la pasada hacia adelante.

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

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

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

**Parámetros:**

latent : Tensor latente normalizado.

**Devuelve:**

Tensor latente en la escala esperada por `vae.decode`.

Invierte `normalize_latents` para recuperar la 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')
```

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

**Parámetros:**

prompt : Cadena de texto de entrada o lista de cadenas de texto de entrada.

device : Dispositivo de destino.

num_images_per_prompt : Número de salidas a generar por indicación.

prompt_embeds : Embeddings de prompt precalculados.

prompt_embeds_mask : Máscara de atención para incrustaciones precalculadas.

max_sequence_length : Longitud máxima de la secuencia de salida.

template_type : Clave de la plantilla de prompt (`"image"` o `"multiple_images"`).

**Devuelve:**

Tupla de (prompt_embeds, prompt_embeds_mask).

Codifica un prompt de texto en embeddings (ruta solo de texto).

Los `prompt_embeds` precalculados omiten por completo la codificación.

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

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

**Parámetros:**

prompt : Cadena(s) de prompt, que opcionalmente contienen tokens `&amp;lt;image>\n`.

device : Dispositivo de destino.

num_images_per_prompt : Número de salidas a generar por indicación.

images : Tensores de píxeles correspondientes a los tokens de imagen en línea.

prompt_embeds : Embeddings de prompt precalculados.

prompt_embeds_mask : Máscara de atención para incrustaciones precalculadas.

template_type : Debe ser `"multiple_images"`.

max_sequence_length : Si se establece, trunca la salida a esta longitud (conservando los últimos `max_sequence_length` tokens).

**Devuelve:**

Tupla de (prompt_embeds, prompt_embeds_mask).

Codifica los prompts que contienen tokens de imagen en línea mediante el procesador de Qwen.

Los marcadores de posición `&amp;lt;image>\n` en cada cadena de indicación se reemplazan por los tokens especiales de visión de Qwen antes de ser enviados al codificador multimodal.

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

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

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

**Parámetros:**

latent : Tensor latente sin procesar de `vae.encode`.

**Devuelve:**

Tensor latente normalizado.

Normaliza los latentes usando estadísticas por canal de la configuración del VAE.

Uses (latent - mean) / std cuando el VAE expone `latents_mean` y `latents_std`; de lo contrario, se escala mediante `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)
```

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

**Parámetros:**

batch_size : Número de muestras en el lote.

num_channels_latents : Dimensión del canal latente de la configuración del transformer.

height : Altura espacial en píxeles.

width : Ancho espacial en píxeles.

video_length : Número de fotogramas (1 para inferencia de imagen).

dtype : dtype de punto flotante para el tensor latente.

device : Dispositivo de destino.

generator : Generador(es) de RNG para muestreo reproducible.

latents : Ruido inicial opcional proporcionado por el usuario para el slot objetivo. Cuando `None`, se muestrea ruido aleatorio.

image : Lista opcional de imágenes de referencia de PIL para codificar con VAE como ranuras de condicionamiento.

enable_denormalization : Si se deben normalizar los latentes de referencia codificados.

**Devuelve:**

Tupla de `(latents, image_latents)` donde `latents` tiene forma `(B, 1, C, T, H', W')` y `image_latents` tiene forma `(B, N_ref, C, T, H', W')` o `None` cuando no se proporcionan imágenes de referencia.

**Excepciones:** `ValueError`

- `ValueError` -- Si `generator` es una lista cuya longitud difiere de `batch_size`.

Prepara el tensor latente inicial con ruido para el bucle de desruido.

## JoyImageEditPipelineOutput[[diffusers.JoyImageEditPipelineOutput]]

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

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

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

Clase de salida para las tuberías de generación de JoyImageEdit.

