Patu

Um número de qualidade é uma mentira: o que o ssimulacra2 mede de verdade

Todo codificador de imagem tem um botão de qualidade: -q 80, -quality 90, um cq-level. Parece uma promessa: gire para 80 e toda imagem sai “80% boa”. Não sai. O número define um parâmetro de compressão, não um resultado, e o resultado depende inteiramente da imagem.

Podemos mostrar exatamente o quanto isso mente.

O mesmo ajuste, qualidades bem diferentes

Codificamos 1.998 fotografias reais em JPEG com um -q 80 fixo (libjpeg-turbo) e avaliamos cada uma com ssimulacra2, uma métrica perceptual em que quanto maior, mais próximo do original.

vips -q 80 em 1.998 fotos ssimulacra2
pior imagem 58
percentil 10 74
mediana 77
percentil 90 80
melhor imagem 87

Um único ajuste. Uma variação de 29 pontos na qualidade real. Em -q 80, uma foto sai em 58 (visivelmente degradada, com blocos e borrões) enquanto outra passa tranquila em 87, indistinguível da fonte e carregando bytes que não precisava. O número no mostrador não dizia nada sobre nenhuma das duas.

E piora entre codificadores. -q 80 em JPEG não é -q 80 em WebP, não é cq-level 30 em AVIF: cada escala é definida pelo próprio codificador, então os mesmos dígitos significam coisas diferentes. Um número de qualidade nem sequer é comparável a si mesmo em outra ferramenta.

Por que o conteúdo da foto decide a qualidade dela

Um ajuste de qualidade escolhe o quão agressivamente descartar detalhe. Um céu liso ou um retrato suave têm pouco detalhe a perder, então ajustes agressivos quase não machucam: a pontuação sai alta. Uma foto de folhagem, cascalho ou tecido é só detalhe fino, então o mesmo ajuste a destrói: a pontuação sai baixa. O codificador aplicou a regra idêntica; as imagens tinham quantidades de perda completamente diferentes.

É por isso que “simplesmente use qualidade 80” entrega duas falhas de uma vez, sem que você perceba: algumas imagens degradadas além do ponto que um usuário nota, e outras 30% maiores do que precisavam ser. Você não vê isso no ajuste, só na saída.

O que mirar em vez disso

Mire o resultado, não o parâmetro. O ssimulacra2 foi feito para isso: é calibrado em unidades de diferença percebida (a grosso modo, “diferenças perceptíveis” em relação ao original), então uma pontuação alvo significa a mesma coisa em qualquer imagem e em qualquer formato.

Escolha um alvo e deixe a qualidade do codificador ser buscada por imagem para atingi-lo. A foto de folhagem recebe um ajuste de qualidade maior porque precisa; o céu liso recebe um menor porque pode. Toda imagem chega à mesma qualidade percebida, cada uma com os menores bytes que alcançam esse nível. Nenhuma imagem é arruinada sem que você perceba, nenhuma fica inchada sem que você perceba.

É isso que o Patu faz em cada imagem: uma busca por imagem na qualidade de codificação para atingir um alvo ssimulacra2, em vez de um -q fixo que significa uma coisa diferente em cada foto.

curl -X POST "https://patu.dev/v1/compress?target=85" \
  -H "X-Api-Key: $PATU_KEY" \
  --data-binary @photo.jpg -o photo.avif

A métrica faz o trabalho que um número de qualidade finge fazer: descrever a imagem que você de fato recebe.


Método e dados: o harness de benchmark do Patu sobre a categoria de fotos (1.998 fotografias reais); libjpeg-turbo via vips; avaliado com ssimulacra2 via a implementação rust-av. Os percentis são sobre todas as imagens avaliadas no ajuste fixo.