Pular para o conteúdo
🧠Inteligência em Código
🐍 Exemplos de Código8 min de leitura

Gerando Imagens com Stable Diffusion via Python

Exemplo completo de geração de imagens com Stable Diffusion usando Python: instalação, prompts, parâmetros, img2img e otimizações.

#stable-diffusion#geração-imagens#python#ia-generativa#deep-learning

O que vamos construir

Um gerador de imagens com IA que:

  • Gera imagens a partir de descrições textuais (text-to-image)
  • Modifica imagens existentes (image-to-image)
  • Suporta estilos artísticos variados
  • Funciona com GPU ou CPU (com otimizações)
  • Inclui interface de linha de comando

Pré-requisitos

# Instalar dependências
pip install diffusers transformers accelerate torch
pip install Pillow safetensors

Código Completo

1. Gerador Básico (Text-to-Image)

"""
gerador_imagens.py - Geração de imagens com Stable Diffusion
"""

import torch
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
from PIL import Image
from pathlib import Path
from datetime import datetime
from dataclasses import dataclass
from typing import Optional


@dataclass
class ImageConfig:
    """Configuração para geração de imagem."""
    prompt: str
    negative_prompt: str = (
        "blurry, bad quality, distorted, deformed, ugly, "
        "low resolution, pixelated, watermark, text"
    )
    width: int = 512
    height: int = 512
    num_steps: int = 30
    guidance_scale: float = 7.5
    seed: Optional[int] = None
    num_images: int = 1


class ImageGenerator:
    """Gerador de imagens com Stable Diffusion."""

    def __init__(
        self,
        model_id: str = "stabilityai/stable-diffusion-2-1",
        device: str = "auto",
        use_fp16: bool = True,
    ):
        # Detectar dispositivo
        if device == "auto":
            self.device = "cuda" if torch.cuda.is_available() else "cpu"
        else:
            self.device = device

        print(f"🖥️ Dispositivo: {self.device}")
        print(f"📥 Carregando modelo {model_id}...")

        # Configurar precisão
        dtype = torch.float16 if (use_fp16 and self.device == "cuda") else torch.float32

        # Carregar pipeline
        self.pipe = StableDiffusionPipeline.from_pretrained(
            model_id,
            torch_dtype=dtype,
            safety_checker=None,  # Desabilitar para uso local
        )

        # Otimizações
        self.pipe.to(self.device)

        if self.device == "cuda":
            # Attention slicing para reduzir uso de VRAM
            self.pipe.enable_attention_slicing()
            # xformers se disponível
            try:
                self.pipe.enable_xformers_memory_efficient_attention()
                print("✅ xformers ativado")
            except Exception:
                print("ℹ️ xformers não disponível")

        # Scheduler mais rápido
        self.pipe.scheduler = DPMSolverMultistepScheduler.from_config(
            self.pipe.scheduler.config
        )

        print("✅ Modelo carregado!")

    def gerar(self, config: ImageConfig) -> list[Image.Image]:
        """Gera imagens a partir de uma configuração."""
        print(f"\n🎨 Gerando {config.num_images} imagem(ns)...")
        print(f"   Prompt: {config.prompt[:80]}...")
        print(f"   Tamanho: {config.width}x{config.height}")
        print(f"   Steps: {config.num_steps}")

        # Configurar seed para reprodutibilidade
        generator = None
        if config.seed is not None:
            generator = torch.Generator(device=self.device).manual_seed(config.seed)
            print(f"   Seed: {config.seed}")

        # Gerar
        start = datetime.now()

        result = self.pipe(
            prompt=config.prompt,
            negative_prompt=config.negative_prompt,
            width=config.width,
            height=config.height,
            num_inference_steps=config.num_steps,
            guidance_scale=config.guidance_scale,
            generator=generator,
            num_images_per_prompt=config.num_images,
        )

        elapsed = (datetime.now() - start).total_seconds()
        print(f"   ⏱️ Tempo: {elapsed:.1f}s")

        return result.images

    def gerar_e_salvar(
        self,
        config: ImageConfig,
        output_dir: str = "imagens_geradas",
        prefix: str = "img",
    ) -> list[str]:
        """Gera e salva imagens em disco."""
        output_path = Path(output_dir)
        output_path.mkdir(parents=True, exist_ok=True)

        images = self.gerar(config)
        paths = []

        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        for i, img in enumerate(images):
            filename = f"{prefix}_{timestamp}_{i}.png"
            filepath = output_path / filename
            img.save(filepath)
            paths.append(str(filepath))
            print(f"   💾 Salvo: {filepath}")

        return paths

2. Image-to-Image (Transformação)

"""
Transformação de imagens existentes com Stable Diffusion
"""

from diffusers import StableDiffusionImg2ImgPipeline


class ImageTransformer:
    """Transforma imagens existentes usando Stable Diffusion."""

    def __init__(self, model_id: str = "stabilityai/stable-diffusion-2-1"):
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        dtype = torch.float16 if self.device == "cuda" else torch.float32

        self.pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
            model_id,
            torch_dtype=dtype,
            safety_checker=None,
        )
        self.pipe.to(self.device)

        if self.device == "cuda":
            self.pipe.enable_attention_slicing()

    def transformar(
        self,
        image: Image.Image,
        prompt: str,
        strength: float = 0.75,
        guidance_scale: float = 7.5,
        num_steps: int = 30,
    ) -> Image.Image:
        """
        Transforma uma imagem existente.
        
        strength: 0.0 = sem mudança, 1.0 = completamente nova
        """
        # Redimensionar para múltiplo de 8
        w, h = image.size
        w = (w // 8) * 8
        h = (h // 8) * 8
        image = image.resize((w, h))

        result = self.pipe(
            prompt=prompt,
            image=image,
            strength=strength,
            guidance_scale=guidance_scale,
            num_inference_steps=num_steps,
        )

        return result.images[0]


# Exemplo de uso
def exemplo_img2img():
    """Transforma uma foto em pintura."""
    transformer = ImageTransformer()

    # Carregar imagem original
    original = Image.open("foto_paisagem.jpg")

    # Transformar em diferentes estilos
    estilos = [
        ("Pintura a óleo impressionista, cores vibrantes, Monet", 0.6),
        ("Anime japonês, estilo studio ghibli, colorido", 0.7),
        ("Pixel art retro, 16-bit, colorido", 0.8),
    ]

    for prompt, strength in estilos:
        resultado = transformer.transformar(
            image=original,
            prompt=prompt,
            strength=strength,
        )
        nome = prompt.split(",")[0].replace(" ", "_").lower()
        resultado.save(f"resultado_{nome}.png")
        print(f"✅ Salvo: resultado_{nome}.png")

3. Gerador com Estilos Predefinidos

class StylePresets:
    """Presets de estilos artísticos para geração de imagens."""

    ESTILOS = {
        "fotorrealista": {
            "suffix": ", photorealistic, 8k resolution, highly detailed, professional photography, sharp focus, natural lighting",
            "negative": "cartoon, anime, painting, drawing, illustration, cgi",
            "steps": 40,
            "guidance": 8.0,
        },
        "anime": {
            "suffix": ", anime style, studio ghibli, vibrant colors, detailed, beautiful, masterpiece",
            "negative": "realistic, photo, 3d render, ugly, bad anatomy",
            "steps": 30,
            "guidance": 7.0,
        },
        "oleo": {
            "suffix": ", oil painting, classical art, detailed brushstrokes, rich colors, masterpiece, museum quality",
            "negative": "photo, digital, modern, cartoon",
            "steps": 35,
            "guidance": 7.5,
        },
        "cyberpunk": {
            "suffix": ", cyberpunk style, neon lights, futuristic, dark atmosphere, rain, detailed, cinematic",
            "negative": "nature, bright, sunny, cartoon",
            "steps": 30,
            "guidance": 8.0,
        },
        "aquarela": {
            "suffix": ", watercolor painting, soft colors, gentle brushstrokes, artistic, delicate, beautiful",
            "negative": "photo, digital, sharp, 3d",
            "steps": 25,
            "guidance": 6.5,
        },
        "pixel_art": {
            "suffix": ", pixel art, 16-bit, retro game style, colorful, nostalgic",
            "negative": "realistic, 3d, blurry, smooth",
            "steps": 25,
            "guidance": 7.0,
        },
        "minimalista": {
            "suffix": ", minimalist illustration, clean lines, simple shapes, modern design, flat colors",
            "negative": "complex, detailed, realistic, noisy",
            "steps": 25,
            "guidance": 7.0,
        },
    }

    @classmethod
    def aplicar(cls, prompt: str, estilo: str) -> ImageConfig:
        """Aplica um estilo predefinido ao prompt."""
        if estilo not in cls.ESTILOS:
            estilos_disponiveis = ", ".join(cls.ESTILOS.keys())
            raise ValueError(f"Estilo '{estilo}' não encontrado. Disponíveis: {estilos_disponiveis}")

        preset = cls.ESTILOS[estilo]
        return ImageConfig(
            prompt=prompt + preset["suffix"],
            negative_prompt=preset["negative"],
            num_steps=preset["steps"],
            guidance_scale=preset["guidance"],
        )

    @classmethod
    def listar(cls):
        """Lista estilos disponíveis."""
        print("\n🎨 Estilos disponíveis:")
        for nome, config in cls.ESTILOS.items():
            print(f"  • {nome}: steps={config['steps']}, guidance={config['guidance']}")

4. CLI Interativo

def cli_interativo():
    """Interface de linha de comando para geração de imagens."""
    print("=" * 60)
    print("🎨 GERADOR DE IMAGENS COM IA")
    print("=" * 60)

    generator = ImageGenerator()

    StylePresets.listar()

    while True:
        print("\n" + "-" * 40)
        prompt = input("📝 Descreva a imagem (ou 'sair'): ").strip()

        if prompt.lower() in ('sair', 'exit', 'quit'):
            print("👋 Até mais!")
            break

        if not prompt:
            continue

        # Escolher estilo
        estilo = input("🎨 Estilo (enter para fotorrealista): ").strip() or "fotorrealista"

        # Configurar
        try:
            config = StylePresets.aplicar(prompt, estilo)
        except ValueError as e:
            print(f"❌ {e}")
            continue

        # Seed opcional
        seed_input = input("🎲 Seed (enter para aleatório): ").strip()
        if seed_input:
            config.seed = int(seed_input)

        # Gerar
        paths = generator.gerar_e_salvar(config)
        print(f"\n✅ {len(paths)} imagem(ns) gerada(s)!")

        for p in paths:
            print(f"   📁 {p}")

5. Geração via API

"""
Alternativa: usar API para geração sem GPU local
"""

import requests
import base64
from io import BytesIO


class APIImageGenerator:
    """Gera imagens via API (Stability AI, DALL-E, etc.)."""

    def __init__(self, api_key: str, provider: str = "stability"):
        self.api_key = api_key
        self.provider = provider

    def gerar_stability(self, prompt: str, **kwargs) -> Image.Image:
        """Gera imagem via Stability AI API."""
        response = requests.post(
            "https://api.stability.ai/v1/generation/stable-diffusion-xl-1024-v1-0/text-to-image",
            headers={
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json",
            },
            json={
                "text_prompts": [{"text": prompt, "weight": 1.0}],
                "cfg_scale": kwargs.get("guidance", 7),
                "height": kwargs.get("height", 1024),
                "width": kwargs.get("width", 1024),
                "steps": kwargs.get("steps", 30),
                "samples": 1,
            },
        )

        if response.status_code != 200:
            raise Exception(f"Erro na API: {response.text}")

        data = response.json()
        img_data = base64.b64decode(data["artifacts"][0]["base64"])
        return Image.open(BytesIO(img_data))

    def gerar_openai(self, prompt: str, **kwargs) -> Image.Image:
        """Gera imagem via OpenAI DALL-E API."""
        from openai import OpenAI
        client = OpenAI(api_key=self.api_key)

        response = client.images.generate(
            model="dall-e-3",
            prompt=prompt,
            size=kwargs.get("size", "1024x1024"),
            quality=kwargs.get("quality", "standard"),
            n=1,
        )

        # Baixar imagem
        img_url = response.data[0].url
        img_response = requests.get(img_url)
        return Image.open(BytesIO(img_response.content))

6. Exemplo Principal

def main():
    """Demonstração completa do gerador de imagens."""
    print("🎨 Gerador de Imagens com Stable Diffusion\n")

    generator = ImageGenerator()

    # Exemplo 1: Paisagem fotorrealista
    config1 = StylePresets.aplicar(
        "A beautiful tropical beach in Brazil with palm trees and crystal clear water",
        "fotorrealista"
    )
    config1.seed = 42
    generator.gerar_e_salvar(config1, prefix="praia")

    # Exemplo 2: Personagem anime
    config2 = StylePresets.aplicar(
        "A young programmer coding on a laptop in a cozy room",
        "anime"
    )
    generator.gerar_e_salvar(config2, prefix="programador")

    # Exemplo 3: Cidade cyberpunk
    config3 = StylePresets.aplicar(
        "A futuristic São Paulo skyline with flying cars and neon signs",
        "cyberpunk"
    )
    generator.gerar_e_salvar(config3, prefix="sp_futuro")

    print("\n✅ Todas as imagens foram geradas!")
    print("📁 Verifique a pasta 'imagens_geradas/'")


if __name__ == "__main__":
    # CLI interativo ou exemplos
    import sys
    if "--cli" in sys.argv:
        cli_interativo()
    else:
        main()

Como Rodar

# Com GPU NVIDIA (recomendado)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
pip install diffusers transformers accelerate

# Apenas CPU (mais lento)
pip install torch torchvision
pip install diffusers transformers accelerate

# Executar exemplos
python gerador_imagens.py

# Modo interativo
python gerador_imagens.py --cli

Dicas de Prompts

| Objetivo | Prompt | |----------|--------| | Mais detalhe | Adicione "highly detailed, 8k, sharp focus" | | Iluminação | "golden hour lighting", "studio lighting", "dramatic shadows" | | Composição | "rule of thirds", "centered composition", "wide angle" | | Qualidade | "masterpiece, best quality, professional" |

Requisitos de Hardware

| Configuração | VRAM | Tempo por imagem | |--------------|------|------------------| | RTX 4090 | 24GB | ~3s (512x512) | | RTX 3060 | 12GB | ~10s (512x512) | | CPU (i7) | RAM 16GB+ | ~3-5min (512x512) |

Expansões Possíveis

  • ControlNet: controlar pose, bordas e profundidade da imagem
  • Inpainting: editar partes específicas de uma imagem
  • LoRA: usar modelos fine-tunados para estilos específicos
  • Upscaling: aumentar resolução com Real-ESRGAN
  • Batch: gerar múltiplas variações de um mesmo prompt
  • Web UI: interface gráfica com Gradio ou Streamlit

Geração de imagens com IA é uma das aplicações mais impressionantes de deep learning — e com Stable Diffusion, tudo isso roda na sua própria máquina! 🎨