FLUX.1 Kontext представляет собой передовую модель редактирования изображений на основе инструкций. Эта модель демонстрирует высочайшую точность при редактировании по текстовым командам на естественном языке:[1][2]
https://huggingface.co/black-forest-labs/FLUX.1-dev
Ключевые возможности:
Преимущества:
Три модели в линейке FLUX:
Версия PRO генерирует изображения самого высокого качества, в то время как версии dev и schnell могут быть использованы бесплатно на своих серверах. Из этих версий версия schnell оптимизирована для создания высококачественных изображений за меньшее количество шагов, что делает ее более быстрой.
Модель FLUX.1 [dev] является 12-миллиардным трансформером, способным генерировать изображения по текстовым описаниям. Модель поддерживает возможности генерации «текст-в-изображение», «изображение-в-изображение» и inpainting.
Inpainting — это процесс заполнения или восстановления определённых областей изображения, которые были удалены или замаскированы, с использованием искусственного интеллекта. Цель inpainting — создать визуально согласованный и реалистичный результат, чтобы удалённый объект (например, руки, держащие товар) был заменён фоном или другим содержимым, органично вписанным в общую композицию изображения. Как работает inpainting в контексте FLUX.1 [dev] и других моделей:
https://huggingface.co/alimama-creative/FLUX.1-dev-Controlnet-Inpainting-Beta
Пример
from diffusers import DiffusionPipeline
from diffusers.utils import load_image
pipe = DiffusionPipeline.from_pretrained("alimama-creative/FLUX.1-dev-Controlnet-Inpainting-Beta")
prompt = "Turn this cat into a dog"
input_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/cat.png")
image = pipe(image=input_image, prompt=prompt).images[0]
Также некоторые модели могут поддерживать и outpainting. Outpainting — это процесс расширения изображения за его исходные границы с генерацией нового, визуально согласованного содержимого, которое логично продолжает оригинальную сцену. В отличие от inpainting (заполнение внутри изображения), outpainting работает вне границ изображения — добавляет новые области вокруг него.
Последняя модель Google для редактирования изображений привлекла большое внимание благодаря своей точности:[6][1][5]
Ключевые особенности:
Специализированная модель для редактирования изображений от Alibaba, сочетающая семантическое и визуальное редактирование:[7]
Возможности:
Модели: SD 1.5, SDXL, SD 3.5 Large[8][9]
Варианты реализации:
Пример рабочего процесса для удаления объекта на примере задачи «удалить руки, держащие предмет, оставить только предмет и установить нейтральный фон».
Рекомендации по использованию:[11]
Комбинированный подход:[12][13][14]
Рабочий процесс:
Реализации на GitHub:
Рис 1. Что можно делать с инструментом EditAnything
InfEdit (CVPR 2024)[16]
Learnable Regions (CVPR 2024)[17]
Модели: DALL-E 2 (редактирование), DALL-E 3 (только генерация)[18][19][20]
Текущие ограничения:
Пример:
# Пример редактирования с помощью DALL-E 2
response = openai.Image.create_edit(
image=open("image.png", "rb"),
mask=open("mask.png", "rb"),
prompt="нейтральный фон, только продукт",
n=1,
size="1024x1024"
)
Комплексный набор инструментов для редактирования:[24][25][26][27]
Ключевые возможности:
Пример:
// Firefly Fill API для удаления объекта
const response = await firefly.fill({
image: uploadedImageId,
mask: maskImageId,
prompt: "нейтральный фон, незаметное заполнение"
});
PhotoRoom API[29]
Remove.bg API
PicWish API[30]
Пример программного кода. Потребует достаточно большое количество видеопамяти для работы, в маленькую карту (16Гб и менее не уберется).
# controlnet_inpaint_pipeline.py
# Удаление рук с помощью ControlNet + SAM + SDXL Inpainting
import os
import torch
import numpy as np
from PIL import Image
from transformers import AutoModelForZeroShotObjectDetection, AutoProcessor
from segment_anything import sam_model_registry, SamPredictor
from diffusers import StableDiffusionXLInpaintPipeline, ControlNetModel, StableDiffusionInpaintPipeline
import cv2
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
DTYPE = torch.float16 if torch.cuda.is_available() else torch.float32
# Пути к файлам входа и выхода
IMAGE_PATH = "product_with_hands.jpg"
OUTPUT_PATH = "final_controlnet_no_hands.png"
# Параметры
TEXT_PROMPT = "hand, person, finger, arm"
BOX_THRESHOLD = 0.25
MASK_DILATION_KERNEL = 15
GUIDANCE_SCALE = 7.5
NUM_STEPS = 30
SEED = 42
RESIZE_TO = 1024 # SDXL лучше работает на 1024x1024
# ========================================
# Загрузка моделей
# ========================================
print("🚀 Загрузка моделей...")
# 1. Grounding DINO — для поиска рук
print("🔍 Загрузка Grounding DINO...")
dino_model = AutoModelForZeroShotObjectDetection.from_pretrained("IDEA-Research/grounding-dino-tiny").to(DEVICE)
dino_processor = AutoProcessor.from_pretrained("IDEA-Research/grounding-dino-tiny")
# 2. SAM — для сегментации
print("🧠 Загрузка Segment Anything (SAM)...")
SAM_CHECKPOINT = "https://huggingface.co/HCMUE-Research/SAM-vit-h/resolve/main/sam_vit_h_4b8939.pth" # https://github.com/facebookresearch/segment-anything
sam = sam_model_registry["vit_h"](checkpoint=SAM_CHECKPOINT)
sam.to(DEVICE)
sam_predictor = SamPredictor(sam)
# 3. ControlNet + SDXL Inpainting
print("🎨 Загрузка ControlNet + SDXL Inpainting...")
controlnet = ControlNetModel.from_pretrained(
"diffusers/controlnet-depth-sdxl-1.0",
torch_dtype=DTYPE
)
# 4. StableDiffusion XL-1.0
pipe = StableDiffusionXLInpaintPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
controlnet=controlnet,
torch_dtype=DTYPE,
variant="fp16",
use_safetensors=True
).to(DEVICE)
# Оптимизация (если мало VRAM)
pipe.enable_xformers_memory_efficient_attention() # если установлено
pipe.enable_model_cpu_offload() # для слабых GPU
# ========================================
# Вспомогательные функции
# ========================================
def load_image(path):
image = Image.open(path).convert("RGB")
return np.array(image)
def detect_boxes(image, text, threshold):
inputs = dino_processor(images=image, text=text, return_tensors="pt").to(DEVICE)
with torch.no_grad():
outputs = dino_model(**inputs)
results = dino_processor.post_process_object_detection(
outputs, threshold=threshold, target_sizes=[image.shape[:2]]
)[0]
return results["boxes"].cpu().numpy()
def get_sam_mask(image, boxes):
sam_predictor.set_image(image)
combined_mask = np.zeros(image.shape[:2], dtype=bool)
for box in boxes:
mask, _, _ = sam_predictor.predict(box=box, multimask_output=False)
mask = cv2.dilate(mask[0].astype(np.uint8), np.ones((MASK_DILATION_KERNEL, MASK_DILATION_KERNEL)))
combined_mask = np.logical_or(combined_mask, mask.astype(bool))
return combined_mask
# ========================================
# Основной пайплайн
# ========================================
print(f"🖼️ Загрузка изображения: {IMAGE_PATH}")
image_rgb = load_image(IMAGE_PATH)
# 1. Найти руки
boxes = detect_boxes(image_rgb, TEXT_PROMPT, BOX_THRESHOLD)
print(f"🔍 Найдено {len(boxes)} объектов")
# 2. Получить маску рук через SAM
mask_bool = get_sam_mask(image_rgb, boxes)
mask_image = Image.fromarray(mask_bool.astype(np.uint8) * 255, mode="L")
# 3. Подготовка изображения и маски
def resize_image(img, size=RESIZE_TO):
w, h = img.size if hasattr(img, 'size') else img.shape[1::-1]
scale = size / max(w, h)
new_w, new_h = int(w * scale), int(h * scale)
return img.resize((new_w, new_h), Image.LANCZOS)
# Изменяем размер
init_image = Image.fromarray(image_rgb)
init_image = resize_image(init_image)
mask_image = resize_image(mask_image)
# Дополняем до квадрата 1024x1024 (обязательно для SDXL)
def pad_to_square(img, target=1024, pad_color=255):
w, h = img.size
left = (target - w) // 2
top = (target - h) // 2
out = Image.new(img.mode, (target, target), pad_color)
out.paste(img, (left, top))
return out, (left, top, w, h) # возвращаем смещение
init_image_padded, bbox_crop = pad_to_square(init_image, target=1024)
mask_padded, _ = pad_to_square(mask_image, target=1024)
# 4. Создаём "conditioning image" — оригинальное + маска (как в Inpainting)
def make_inpaint_condition(image, mask):
image = np.array(image) / 255.0
mask = np.array(mask) / 255.0
return Image.fromarray(np.clip(image * (1 - mask), 0, 1) * 255).convert("RGB")
control_image = make_inpaint_condition(init_image_padded, mask_padded)
# 5. Генерация с ControlNet
prompt = (
"a professional product photo on clean white background, studio lighting, "
"no hands, no people, high detail, e-commerce, sharp focus"
)
negative_prompt = (
"hands, fingers, people, blurry, text, logo, shadow, dark, low quality"
)
generator = torch.Generator(DEVICE).manual_seed(SEED)
print("🖌️ Генерация с ControlNet...")
result = pipe(
prompt=prompt,
negative_prompt=negative_prompt,
image=init_image_padded,
mask_image=mask_padded,
control_image=control_image,
strength=0.78,
guidance_scale=GUIDANCE_SCALE,
num_inference_steps=NUM_STEPS,
generator=generator,
controlnet_conditioning_scale=1.0,
).images[0]
# 6. Обрезаем обратно
left, top, w, h = bbox_crop
result_cropped = result.crop((left, top, left + w, top + h))
# 7. Сохранение
result_cropped.save(OUTPUT_PATH)
print(f"✅ Результат сохранён: {OUTPUT_PATH}")
Лучшее решение с открытым исходным кодом:
Лучшее коммерческое API-решение:
Условный рабочий процесс:
# 1. Использовать SAM для выявления и маскирования рук
mask = sam_model.segment(image, prompt="руки, держащие объект")
# 2. Использовать FLUX.1 или Stable Diffusion для inpainting
result = inpaint_model.edit(
image=original_image,
mask=hand_mask,
instruction="удалить руки, оставить только предмет, нейтральный белый фон"
)
# 3. Дополнительная обработка для согласованности
final_image = enhance_product_photo(result)
Рекомендации по производительности:
Выбор зависит от ваших конкретных требований к качеству, стоимости, скорости обработки и сложности интеграции. Для промышленного использования с высокими требованиями к качеству рекомендуются API FLUX.1 Kontext или Adobe Firefly. Для разработки и экспериментов комбинация Stable Diffusion + SAM предлагает максимальную гибкость и возможности для обучения.
Ссылки