Processamento de Imagens com Python

Aprenda processamento de imagens com Python e Pillow. Redimensione, aplique filtros, adicione textos e automatize manipulacoes em lote.

5 min de leitura Equipe Python Brasil

Processamento de imagens e uma habilidade valiosa para desenvolvedores Python. Desde redimensionar fotos para um site ate criar thumbnails em lote ou aplicar marcas dagua, a biblioteca Pillow oferece tudo o que voce precisa. Neste artigo, vamos explorar as operacoes mais uteis com exemplos praticos e prontos para usar.

Instalacao e Conceitos Basicos

Instale o Pillow, o fork mantido da classica PIL (Python Imaging Library):

pip install Pillow

O Pillow trabalha com o conceito de objetos Image. Cada imagem tem modo (RGB, RGBA, L para escala de cinza), tamanho e pixels:

from PIL import Image

# Abrir uma imagem
img = Image.open("foto.jpg")

# Informacoes basicas
print(f"Formato: {img.format}")
print(f"Tamanho: {img.size}")      # (largura, altura)
print(f"Modo: {img.mode}")          # RGB, RGBA, L, etc.
print(f"Resolucao: {img.info.get('dpi', 'N/A')}")

# Mostrar a imagem (abre no visualizador padrao)
img.show()

Redimensionamento e Recorte

As operacoes mais comuns envolvem alterar o tamanho das imagens:

from PIL import Image

def redimensionar(caminho: str, largura: int, altura: int, saida: str):
    """Redimensiona mantendo ou nao a proporcao."""
    img = Image.open(caminho)
    img_redimensionada = img.resize((largura, altura), Image.Resampling.LANCZOS)
    img_redimensionada.save(saida)
    print(f"Redimensionada: {img.size} -> {img_redimensionada.size}")

def thumbnail(caminho: str, tamanho_max: tuple, saida: str):
    """Cria thumbnail mantendo proporcao."""
    img = Image.open(caminho)
    img.thumbnail(tamanho_max, Image.Resampling.LANCZOS)
    img.save(saida)
    print(f"Thumbnail criado: {img.size}")

def recortar(caminho: str, caixa: tuple, saida: str):
    """Recorta uma regiao da imagem (esquerda, cima, direita, baixo)."""
    img = Image.open(caminho)
    img_recortada = img.crop(caixa)
    img_recortada.save(saida)
    print(f"Recortada: {img_recortada.size}")

# Exemplos de uso
redimensionar("foto.jpg", 800, 600, "foto_800x600.jpg")
thumbnail("foto.jpg", (300, 300), "foto_thumb.jpg")
recortar("foto.jpg", (100, 100, 500, 400), "foto_recortada.jpg")

Aplicando Filtros e Efeitos

O Pillow oferece diversos filtros prontos e permite criar efeitos personalizados:

from PIL import Image, ImageFilter, ImageEnhance

def aplicar_filtros(caminho: str):
    """Demonstra varios filtros disponiveis."""
    img = Image.open(caminho)

    # Filtros prontos
    desfocada = img.filter(ImageFilter.GaussianBlur(radius=5))
    desfocada.save("desfocada.jpg")

    nitida = img.filter(ImageFilter.SHARPEN)
    nitida.save("nitida.jpg")

    bordas = img.filter(ImageFilter.FIND_EDGES)
    bordas.save("bordas.jpg")

    relevo = img.filter(ImageFilter.EMBOSS)
    relevo.save("relevo.jpg")

    contorno = img.filter(ImageFilter.CONTOUR)
    contorno.save("contorno.jpg")

def ajustar_imagem(caminho: str):
    """Ajusta brilho, contraste e saturacao."""
    img = Image.open(caminho)

    # Aumentar brilho em 30%
    brilho = ImageEnhance.Brightness(img)
    img_brilho = brilho.enhance(1.3)
    img_brilho.save("brilho_aumentado.jpg")

    # Aumentar contraste em 50%
    contraste = ImageEnhance.Contrast(img)
    img_contraste = contraste.enhance(1.5)
    img_contraste.save("contraste_aumentado.jpg")

    # Saturacao
    saturacao = ImageEnhance.Color(img)
    img_saturada = saturacao.enhance(1.4)
    img_saturada.save("saturada.jpg")

    # Preto e branco
    img_pb = img.convert("L")
    img_pb.save("preto_branco.jpg")

aplicar_filtros("foto.jpg")
ajustar_imagem("foto.jpg")

Marca Dagua e Texto

Adicionar textos e marcas dagua e essencial para proteger imagens:

from PIL import Image, ImageDraw, ImageFont

def adicionar_marca_dagua(caminho: str, texto: str, saida: str):
    """Adiciona marca dagua de texto a imagem."""
    img = Image.open(caminho).convert("RGBA")
    largura, altura = img.size

    # Criar camada transparente
    overlay = Image.new("RGBA", img.size, (255, 255, 255, 0))
    draw = ImageDraw.Draw(overlay)

    # Fonte (use uma fonte do sistema ou baixe uma)
    try:
        fonte = ImageFont.truetype("arial.ttf", 40)
    except OSError:
        fonte = ImageFont.load_default()

    # Calcular posicao centralizada
    bbox = draw.textbbox((0, 0), texto, font=fonte)
    texto_largura = bbox[2] - bbox[0]
    texto_altura = bbox[3] - bbox[1]
    x = (largura - texto_largura) // 2
    y = (altura - texto_altura) // 2

    # Desenhar texto semi-transparente
    draw.text((x, y), texto, font=fonte, fill=(255, 255, 255, 100))

    # Combinar camadas
    resultado = Image.alpha_composite(img, overlay)
    resultado.convert("RGB").save(saida)
    print(f"Marca dagua adicionada: {saida}")

def adicionar_texto(caminho: str, texto: str, posicao: tuple, saida: str):
    """Adiciona texto simples a imagem."""
    img = Image.open(caminho)
    draw = ImageDraw.Draw(img)

    try:
        fonte = ImageFont.truetype("arial.ttf", 30)
    except OSError:
        fonte = ImageFont.load_default()

    # Sombra do texto
    draw.text((posicao[0] + 2, posicao[1] + 2), texto, font=fonte, fill="black")
    # Texto principal
    draw.text(posicao, texto, font=fonte, fill="white")

    img.save(saida)

adicionar_marca_dagua("foto.jpg", "Python Brasil", "foto_marca.jpg")
adicionar_texto("foto.jpg", "Julho 2025", (20, 20), "foto_texto.jpg")

Processamento em Lote

A automacao brilha quando voce precisa processar centenas de imagens:

import os
from pathlib import Path
from PIL import Image

def processar_lote(
    pasta_entrada: str,
    pasta_saida: str,
    largura_max: int = 1200,
    qualidade: int = 85,
):
    """Processa todas as imagens de uma pasta."""
    pasta_saida_path = Path(pasta_saida)
    pasta_saida_path.mkdir(parents=True, exist_ok=True)

    extensoes = {".jpg", ".jpeg", ".png", ".webp", ".bmp"}
    processadas = 0
    erros = 0

    for arquivo in Path(pasta_entrada).iterdir():
        if arquivo.suffix.lower() not in extensoes:
            continue

        try:
            img = Image.open(arquivo)

            # Redimensionar se necessario
            if img.width > largura_max:
                proporcao = largura_max / img.width
                nova_altura = int(img.height * proporcao)
                img = img.resize(
                    (largura_max, nova_altura), Image.Resampling.LANCZOS
                )

            # Converter RGBA para RGB (necessario para JPEG)
            if img.mode == "RGBA":
                fundo = Image.new("RGB", img.size, (255, 255, 255))
                fundo.paste(img, mask=img.split()[3])
                img = fundo

            # Salvar otimizada
            saida = pasta_saida_path / f"{arquivo.stem}.jpg"
            img.save(saida, "JPEG", quality=qualidade, optimize=True)
            processadas += 1

            tamanho_original = arquivo.stat().st_size / 1024
            tamanho_novo = saida.stat().st_size / 1024
            economia = (1 - tamanho_novo / tamanho_original) * 100
            print(f"  {arquivo.name}: {tamanho_original:.0f}KB -> {tamanho_novo:.0f}KB ({economia:.0f}% menor)")

        except Exception as e:
            print(f"  Erro em {arquivo.name}: {e}")
            erros += 1

    print(f"\nProcessadas: {processadas} | Erros: {erros}")

processar_lote("fotos_originais/", "fotos_otimizadas/", largura_max=1200)

Criando Colagens e Composicoes

Combine multiplas imagens em uma unica composicao:

from PIL import Image

def criar_colagem(caminhos: list[str], colunas: int, saida: str):
    """Cria uma colagem com as imagens fornecidas."""
    tamanho_celula = (300, 300)
    imagens = []

    for caminho in caminhos:
        img = Image.open(caminho)
        img.thumbnail(tamanho_celula, Image.Resampling.LANCZOS)
        imagens.append(img)

    linhas = (len(imagens) + colunas - 1) // colunas
    largura_total = colunas * tamanho_celula[0]
    altura_total = linhas * tamanho_celula[1]

    colagem = Image.new("RGB", (largura_total, altura_total), (255, 255, 255))

    for i, img in enumerate(imagens):
        col = i % colunas
        lin = i // colunas
        x = col * tamanho_celula[0] + (tamanho_celula[0] - img.width) // 2
        y = lin * tamanho_celula[1] + (tamanho_celula[1] - img.height) // 2
        colagem.paste(img, (x, y))

    colagem.save(saida)
    print(f"Colagem criada: {largura_total}x{altura_total}")

fotos = ["foto1.jpg", "foto2.jpg", "foto3.jpg", "foto4.jpg", "foto5.jpg", "foto6.jpg"]
criar_colagem(fotos, colunas=3, saida="colagem.jpg")

Boas Praticas

Sempre trabalhe com copias das imagens originais para evitar perda de dados. Use o formato JPEG para fotos e PNG para imagens com transparencia. Ao salvar JPEGs, ajuste a qualidade entre 80 e 90 para um bom equilibrio entre tamanho e qualidade visual. Para processamento em lote, trate excecoes individualmente para que um erro em uma imagem nao interrompa todo o processo. E libere memoria explicitamente com img.close() ao processar muitas imagens.

Conclusao

O Pillow e uma biblioteca completa e acessivel para processamento de imagens em Python. Desde operacoes simples como redimensionamento ate composicoes complexas com filtros e marcas dagua, ele cobre praticamente todas as necessidades. Combine-o com automacao em lote e voce tera uma ferramenta indispensavel no seu kit de desenvolvimento.

E

Equipe Python Brasil

Contribuidor do Python Brasil — Aprenda Python em Português