JPEG XL e a fronteira de Pareto
(cloudinary.com)- O gargalo da codificação JPEG XL que processava imagens grandes de uma só vez foi reduzido no libjxl 0.10 com a API de codificação em streaming, melhorando bastante o uso de memória e a velocidade da compressão sem perdas
- A codificação sem perdas da imagem noturna da Terra da NASA em 13500×6750 caiu de cerca de 8GB de RAM e mais de 2 minutos no libjxl 0.9 para 0,7GB de RAM, 30 segundos em thread única e 5 segundos com 8 threads no libjxl 0.10
- Comparar métodos de compressão apenas pelo tamanho do arquivo não basta; a fronteira de Pareto, que considera velocidade de codificação e densidade de compressão, vira o critério para definir a melhor configuração conforme o orçamento de tempo
- Na compressão com perdas, é preciso observar ao mesmo tempo taxa de compressão, velocidade e qualidade de imagem; na faixa SSIMULACRA2 de 60 a 90, o JPEG XL mostra resultados especialmente fortes na região de alta qualidade a perda visualmente imperceptível
- Novos codificadores JPEG, como o jpegli, ainda seguem competitivos nas faixas de codificação extremamente rápida, mas o JPEG XL se consolida como uma opção central tanto para compressão sem perdas quanto com perdas em uma ampla faixa de velocidades
Principais mudanças no libjxl 0.10
- O libjxl 0.10 é a nova versão da implementação de referência do JPEG XL, e a maior mudança é a implementação completa da API de codificação em streaming
- Essa API codifica imagens grandes em blocos em vez de processá-las de uma vez só
- Isso reduz a carga de RAM causada por manter a imagem inteira na memória
- A velocidade de codificação também melhora
- O efeito é especialmente visível na compressão sem perdas de imagens grandes
Menos memória e tempo na compressão sem perdas
- Antes do libjxl 0.10, a codificação JPEG XL sem perdas podia ter como problema o alto consumo de memória e o longo tempo de processamento
- A imagem de exemplo é a imagem noturna da Terra da NASA em 13500×6750
- O arquivo TIFF tem 64MB
- O tamanho antes da compressão é 273MB
- Resultado da compressão da mesma imagem com a configuração padrão de effort e7:
- O libjxl 0.9 usou cerca de 8GB de RAM e levou mais de 2 minutos, com arquivo final de 33,7MB
- Em thread única levou 2 minutos e 40 segundos, e com 8 threads 2 minutos e 6 segundos, mostrando pouco ganho com mais threads
- O ambiente de medição foi um MacBook Pro de novembro de 2023 com CPU Apple M3 Pro de 12 núcleos e 36GB de RAM
- No libjxl 0.10, a compressão da mesma imagem precisa de apenas 0,7GB de RAM
- 30 segundos em thread única
- 5 segundos com 8 threads
- O arquivo final ficou em 33,2MB
- Ao aumentar o valor de effort, a taxa de compressão melhora, mas o ganho por tempo de CPU vai diminuindo
- De e1 para e2, usar 1 segundo em vez de 0,1 segundo reduziu 22MB
- De e2 para e7, usar 5 segundos em vez de 1 segundo reduziu mais 11MB
- De e7 para e9, para reduzir mais 1MB era preciso esperar quase 2 minutos
O compromisso prático da configuração de effort
- A configuração de compressão é um problema de compromisso entre tempo e tamanho de arquivo
- Em fluxos de trabalho de criação com salvamento local durante a edição, uma compressão muito forte pode não ser necessária, então um effort baixo pode ser a escolha mais racional
- Em cenários de distribuição para muitos destinos ou arquivamento de longo prazo, pode valer a pena gastar mais tempo de CPU para economizar alguns MB
Comparando métodos de compressão com a fronteira de Pareto
- Ao comparar técnicas de compressão, olhar só para o tamanho do arquivo faz com que seja fácil perder informações importantes para a escolha real
-
Eixos de comparação e leitura do gráfico
- Os eixos principais são densidade de compressão e velocidade de codificação
- Dizer que um método é ótimo de Pareto significa que não existe outro método que alcance a mesma ou melhor densidade de compressão em menos tempo
- O conjunto desses métodos ótimos de Pareto é a fronteira de Pareto
- No gráfico, o eixo vertical é a velocidade de codificação e o horizontal é a média de bits por pixel da imagem comprimida
- O eixo vertical usa a unidade megapixels por segundo e escala logarítmica para cobrir uma faixa ampla de velocidades
- Antes da compressão, RGB de 8 bits corresponde a 24bpp
- Quanto mais alto, mais rápido; quanto mais à esquerda, melhor a compressão
Resultado da comparação em compressão sem perdas
- O libjxl anterior já entregava resultados ótimos de Pareto em toda a faixa de velocidades e gerava arquivos menores que PNG, AVIF sem perdas e WebP sem perdas
- O libjxl 0.10 mostra resultados bem melhores que a versão anterior
- O QOI não apareceu no gráfico, mas registrou 17bpp a 154Mpx/s
- A configuração de effort mais baixa do libjxl comprimiu até 11,5bpp a 427Mpx/s
- O libjxl foi 2,7 vezes mais rápido e gerou arquivos 32,5% menores
Compressão sem perdas em imagens não fotográficas
- Fotos costumam ter muito ruído natural, o que torna a compressão sem perdas mais difícil; em imagens não fotográficas os resultados mudam
- Em um teste com 41 imagens de quadrinhos com estilos variados, o tamanho médio foi de 7,3 megapixels
- Esse tipo de imagem foi comprimido até cerca de 4bpp, muito melhor que as imagens fotográficas, que ficam por volta de 10bpp
- O AVIF sem perdas não foi útil para esse tipo de imagem
- A compressão foi pior que PNG
- Chegou a uma densidade parecida com a do QOI, mas foi muito mais lento
- O WebP sem perdas mostrou ótima taxa de compressão nessas imagens
- O QOI é aceitável considerando velocidade e simplicidade, mas está longe de ser ótimo de Pareto
- A codificação JPEG XL com effort baixo foi 2 vezes mais rápida que o QOI e gerou arquivos 31% menores
- O libjxl 0.10 também melhorou muito em imagens não fotográficas em relação ao 0.9
- WebP com effort padrão: 4.30bpp, 2.3Mpx/s
- libjxl 0.9 effort 5: 4.27bpp, 2.6Mpx/s
- libjxl 0.10 effort 5: 4.25bpp, 12.2Mpx/s
- libjxl 0.10 effort 7: 4.04bpp, 5.9Mpx/s
Na compressão com perdas, entra o eixo de qualidade
- Na compressão sem perdas, basta olhar tamanho e velocidade, mas na compressão com perdas entra também a qualidade de imagem
- Codecs e codificadores de imagem com perdas podem ter desempenho diferente dependendo do ponto de qualidade
- Um codificador bom em alta qualidade não necessariamente será bom também em baixa qualidade
- O contrário também vale
- Gráficos bitrate-distortion que olham só para taxa de compressão e qualidade dificultam avaliar o compromisso entre effort de codificação e desempenho de compressão
- Para observar a fronteira de Pareto da compressão com perdas, é preciso cortar o espaço tridimensional de compressão, velocidade e qualidade em vários pontos de qualidade
Medição de qualidade e forma de agregação
- Qualidade de imagem é subjetiva e pode variar de pessoa para pessoa
- A melhor forma de medição é um experimento com dezenas de pessoas ou mais comparando ou avaliando imagens com um protocolo rigoroso
- Como esse tipo de experimento custa tempo e dinheiro, dificultando testar todas as configurações dos codificadores, usam-se métricas objetivas
- Entre as métricas públicas consideradas boas estão SSIMULACRA2, Butteraugli e DSSIM
- Elas tentam modelar o sistema visual humano e têm boa correlação com avaliações subjetivas
- Métricas antigas e simples como PSNR e SSIM não acompanham bem o julgamento humano de qualidade
- Avaliar com a mesma métrica que o codificador otimiza internamente pode distorcer o resultado em favor dele
- O libjxl em effort alto otimiza Butteraugli
- O libavif pode otimizar PSNR ou SSIM
- O SSIMULACRA2 é tratado como métrica segura porque os codificadores testados não o usam na otimização interna
- No teste, foram escolhidas configurações dos codificadores para que, ao serem aplicadas ao conjunto todo de imagens, a pontuação média de SSIMULACRA2 ficasse próxima de um valor específico
- Ordenar pela média favorece WebP e AVIF
- Em estudos anteriores, AVIF e WebP foram menos consistentes que JPEG e HEIC, enquanto o JPEG XL foi o codificador mais consistente
- No uso real, pode ser desejável ajustar pelo pior resultado ou pela pior qualidade visual real
Faixa de qualidade mais próxima do uso real
- A compressão com perdas permite taxas muito altas, como 50:1 ou 200:1, mas surgem artefatos de compressão
- A faixa mais relevante no uso real é SSIMULACRA2 60 a 90
- Características por ponto de qualidade:
- SSIMULACRA2 90: qualidade visualmente sem perdas; codecs modernos como AVIF e JPEG XL podem chegar lá com taxa de compressão de cerca de 8:1, ou 3bpp
- SSIMULACRA2 80: alta qualidade; chega-se a cerca de 16:1, ou 1.5bpp
- SSIMULACRA2 70: qualidade intermediária-alta; cerca de 30:1, ou 0.8bpp
- SSIMULACRA2 60: qualidade intermediária; cerca de 40:1, ou 0.6bpp
- Qualidade abaixo de SSIMULACRA2 60 pode reduzir ainda mais a largura de banda, mas traz risco de estragar a imagem
- Na web de 2024, a faixa de qualidade intermediária a alta é a mais relevante
- Segundo o HTTP Archive, a mediana do AVIF na web é 1bpp, correspondente a qualidade intermediária-alta
- A mediana do JPEG é 2.1bpp, correspondente a alta qualidade
- Em usos fora da web, como câmeras, a faixa de alta qualidade a visualmente sem perdas é ainda mais relevante
Resultado da fronteira de Pareto na compressão com perdas
- O teste de compressão com perdas foi feito com as versões mais recentes de cada codificador até o fim de fevereiro de 2024
- A velocidade de codificação foi medida com 8 threads em um MacBook Pro de novembro de 2023 com Apple M3 Pro
- No AVIF, foram testadas configurações com tiles e sem tiles
- As configurações com tiles aproveitam melhor o multithreading e são mais rápidas
- Em troca, perdem densidade de compressão
Qualidade intermediária: SSIMULACRA2 60
- Mesmo dentro do mesmo formato, houve grande diferença de resultado conforme o codificador e a configuração de effort
- A configuração padrão do libjpeg-turbo, historicamente muito usada como codificador JPEG, aparece como a mais rápida no gráfico, mas com baixa densidade de compressão
- O WebP teve densidade de compressão melhor que o libjpeg-turbo
- O mozjpeg é mais lento que o libjpeg-turbo, mas entrega melhor compressão e, nesse conjunto de imagens e ponto de qualidade, foi mais eficiente em Pareto que o WebP
- O jpegli, criado pela equipe do JPEG XL no Google, foi mais rápido que o mozjpeg e também comprimiu melhor
- Ele se baseia em lições aprendidas com o guetzli e o libjxl
- Comprime melhor que WebP e AVIF rápido, mas continua gerando arquivos JPEG tradicionais
- AVIF e HEIC conseguem densidade de compressão melhor que JPEG e WebP, mas codificam mais lentamente
- O JPEG XL alcançou densidade de compressão semelhante com codificação muito mais rápida
- A fronteira de Pareto nesse ponto de qualidade é formada por JPEG XL e vários codificadores JPEG nas faixas de velocidade razoáveis, e por AVIF nas faixas mais lentas
Resultados em qualidade intermediária-alta e alta
- Em qualidade intermediária-alta, SSIMULACRA2 70, o quadro geral foi parecido com o da qualidade intermediária
- Foi usado SSIMULACRA2 médio de 85 como o ponto de qualidade mais alto relevante para a web, com configuração para que a maioria das imagens ficasse em 80 ou mais
- Nesse ponto de alta qualidade, as diferenças ficam mais nítidas
- O mozjpeg deixou de superar o WebP
- O jpegli continuou melhor que o WebP
- A fronteira de Pareto passou a ser ocupada principalmente pelo JPEG XL
- Em codificação extremamente rápida, o JPEG tradicional ainda foi bom
- Nesse ponto de qualidade, o AVIF não apareceu na fronteira de Pareto
- Em sua configuração mais lenta, igualou a densidade de compressão da segunda configuração mais rápida do libjxl com velocidade inferior a 0.5Mpx/s
- Essa configuração do libjxl rodou a 52Mpx/s, mais de 100 vezes mais rápido
Velocidade de decodificação
- Até aqui, a comparação se concentrou em densidade de compressão e velocidade de codificação
- Em computadores modernos, a velocidade de decodificação não é um grande problema, mas as medições também foram comparadas
- O JPEG sequencial é o mais forte em velocidade de decodificação
- O JPEG progressivo gerado por mozjpeg e pelo jpegli padrão é mais lento, mas ainda rápido o bastante para carregar imagens de tamanho razoável com muita agilidade
- O JPEG XL fica entre o JPEG sequencial e o JPEG progressivo
- A velocidade de decodificação do AVIF varia conforme a forma de codificação
- Se usar codificação multi-tile, que é mais rápida mas um pouco pior, a decodificação também fica mais rápida
- A codificação padrão single-tile é mais lenta
- Mesmo a menor velocidade de decodificação medida ainda é suficientemente rápida em comparação com a velocidade de codificação
Perda visualmente imperceptível e imagens grandes
- O gráfico de qualidade visualmente sem perdas não incluiu WebP
- Em modo com perdas, ele não consegue atingir esse ponto de qualidade
- Isso acontece porque o WebP exige subamostragem de crominância 4:2:0
- O mozjpeg também não foi projetado para esse ponto de qualidade e ficou pior que o libjpeg-turbo tanto em compressão quanto em velocidade
- Na configuração de velocidade padrão, o libavif gerou arquivos 20% menores que o libjpeg-turbo, mas levou uma ordem de grandeza a mais no tempo de codificação
- No mesmo ponto de qualidade, o libjxl foi 20% menor que o libavif e 2,5 vezes mais rápido
- A fronteira de Pareto em qualidade visualmente sem perdas foi ocupada majoritariamente pelo JPEG XL, com JPEG também presente na faixa mais rápida
- Diferentemente do teste com imagens de cerca de 1 megapixel em tamanho web, os resultados mudaram bastante no teste com imagens maiores
- Em alta qualidade, WebP, mozjpeg e AVIF foram piores que o libjpeg-turbo
- O HEIC ofereceu uma economia significativa em relação ao libjpeg-turbo
- O jpegli também ofereceu uma redução significativa com velocidade melhor
- O JPEG XL comprimiu a imagem para menos de 1.3bpp, enquanto AVIF, libjpeg-turbo e WebP precisaram de mais de 2bpp
Posição final do libjxl 0.10
- O libjxl 0.10 reduziu o uso de memória em uma ordem de grandeza tanto na compressão sem perdas quanto com perdas
- A velocidade também melhorou, especialmente na codificação sem perdas multithread com o effort padrão, que ficou uma ordem de grandeza mais rápida
- O JPEG XL se firma como um codec de imagem forte tanto em compressão sem perdas quanto com perdas, especialmente na faixa de alta qualidade a perda visualmente imperceptível
- Em uma ampla faixa de configurações de velocidade, o JPEG XL continua sendo uma opção próxima do ótimo de Pareto
- O JPEG tradicional também segue atraente graças aos novos codificadores
- O jpegli melhora bastante em velocidade e compressão em relação ao mozjpeg
- Quando é necessário codificar de forma extremamente rápida, o JPEG tradicional ainda pode ser a melhor escolha
2 comentários
O encoder jpegli está mais uma vez prolongando a vida do jpg, depois do mozjpeg...
Embora tenha sido criado pelo lado do JXL, ironicamente pode acabar atrapalhando a disseminação do próprio JXL...
Comentários do Hacker News
Vale notar também o quão bom é o WebP sem perdas
Isso acaba ficando muito ofuscado pelas discussões de que o WebP tem pouca vantagem clara ou até é pior que a codificação com MozJPEG, mas o WebP sem perdas é realmente excelente em desempenho e velocidade
É muito melhor que PNG ou OptiPNG, o suporte online já ficou suficiente, e naturalmente fica bem à frente do péssimo AVIF sem perdas
Para imagens SDR ele serve, mas para HDR isso vira uma limitação fundamental, tão séria quanto o GIF ser limitado a 256 cores
Se a ideia é comprimir quadrinhos inteiros, PNG ainda continua sendo a escolha certa, e nesse caso é melhor usar oxipng em vez do optipng, que na prática já foi abandonado
Outro ponto que faltou aqui é que o JPEG2000 sem perdas pode ser surpreendentemente bom e rápido para conteúdo fotográfico
Na maioria dos usos ele tende a ser preferível ao realmente sem perdas, e muitas vezes ainda reduz o tamanho pela metade sem perda visível adicional
Em configurações de qualidade muito baixa, é surpreendente que o JPEG mantenha uma aproximação nítida dos detalhes que preserva melhor a qualidade geral da imagem, mesmo que de perto ela vire uma bagunça cheia de artefatos visíveis, parecendo uma pintura cubista
Na prática, ele transforma a imagem em algum estilo de arte abstrata, enquanto JXL e AVIF só ficam borrados
Essas imagens não estão tentando igualar a mesma taxa de compressão, mas o mesmo nível de distorção, e os bits por pixel estão mostrados ao lado das imagens
Na internet real, usar qualidade 65 é raro e só aparece em sites de qualidade mínima; qualidade 75 é um nível baixo comum, e qualidade 85 é mais próxima da média
Quando é preciso compressão, usa-se qualidade 94 yuv444 ou superior
Os bitrates estão na coluna da esquerda, e o JPG de baixa qualidade tem o mesmo tamanho que 0.4bpp, uma qualidade média-baixa de JXL/AVIF, então a comparação correta é entre a imagem inferior esquerda e as imagens superior central e superior direita
Não dá para se deixar levar por uma comparação errada; se der o dobro do tamanho de arquivo a JXL e AVIF, eles também vão parecer muito melhores
O SSIMULACRA2 parece punir fortemente artefatos de bloco, mas não se importar muito com borrão, e concordo que, com a mesma pontuação de SSIMULACRA2, a versão JPEG parece melhor
Não entendo por que este texto dá tanto foco à velocidade de codificação, enquanto trata de forma tão superficial a decodificação, que eu diria representar 99% do uso em um ambiente de conexão web
Fica só em algo como “a velocidade de decodificação não é um grande problema em computadores modernos, mas é interessante olhar os números rapidamente”
A partir desse ponto, o gargalo deixa de ser a decodificação
A maioria dos algoritmos modernos de compressão é assimétrica, então pode gastar muito mais tempo para comprimir sem afetar muito o desempenho da descompressão; uma vez atingido um desempenho básico, isso passa a importar menos
Se isso for possível, pode ser um forte motivo para preferi-los ao JPEG XL, que no hardware atual precisa ser decodificado inteiramente por software
A decodificação H264 está em todo lugar, e a de AV1 também vem se tornando gradualmente um recurso padrão
Se o cliente consegue decodificar as poucas imagens de uma página rápido o bastante para uma pessoa não perceber, isso já basta; por outro lado, qualquer melhoria de alguns por cento na codificação pode reduzir custos reais
Na prática, eles gastam milhões de dólares com codificação de imagens
Ri ao ver QOI incluído no benchmark sem perdas
É interessante que um formato praticamente irrelevante, sem suporte padrão em software voltado ao grande público e que mira ser apenas aceitável em vez de realmente bom, tenha ocupado um lugar no gráfico de codificação não fotográfica
Então o GameMaker Studio e os jogos feitos nos últimos 2 anos mais ou menos de fato usam QOI internamente
O consumidor não usa isso de forma consciente, mas também não dá para dizer que seja totalmente irrelevante
Olhando em retrospecto, era esperado, porque a decodificação de QOI é essencialmente sequencial e não pode ser paralelizada com facilidade
Fico me perguntando se o quão bom o JXL é se deve ao formato em si ou ao codificador
A capacidade de gerar imagens pequenas e de alta qualidade só com
-d 1.0é quase estranha; em outros codecs, para obter resultados parecidos, era preciso ajustar a configuração de qualidade de forma diferente conforme o tipo de imagemNesse ritmo de desenvolvimento, não seria surpresa se o libjxl se tornasse o x264 dos codificadores de imagem
Em contrapartida, o libvpx sempre foi um codificador mediano, e acho que isso pode explicar o desempenho decepcionante do formato vp8/vp9, não só em velocidade, mas no desempenho geral
Isso inevitavelmente também afetou o desempenho do WebP com perdas, e o Dark Shikari já comparou o desempenho em imagens estáticas do x264 e do vp8 [0]
[0] https://web.archive.org/web/20150419071902/http://x264dev.mu...
O foco permaneceu fortemente em perda visualmente imperceptível, e não se queria incluir recursos de formato que só aumentassem a complexidade sem ajudar nas configurações de alta qualidade
Além dos recursos de modelagem, a modelagem de contexto e a eficiência da codificação por entropia são muito importantes em alta qualidade
Acho que a codificação por entropia do AVIF não combina bem com fotos em alta qualidade ou sem perdas
-d 1.0Vale mencionar que do trabalho no JPEG XL também surgiu uma excelente nova biblioteca de paralelização chamada Highway
Essa biblioteca está sendo usada não só no JPEG XL, mas também no modelo de IA Gemma mais recente do Google
Também é abordado em [1], que começa assim: “Hoje estamos compartilhando código open source que ordena vetores numéricos em C++ cerca de 10 vezes mais rápido que
std::sort, mantendo portabilidade em todas as arquiteturas modernas de CPU e ainda superando algoritmos modernos específicos de arquitetura. Abaixo discutimos como conseguimos isso.”[0] https://github.com/google/highway
[1] https://opensource.googleblog.com/2022/06/Vectorized%20and%2..., o artigo relacionado está em https://arxiv.org/pdf/2205.05982.pdf
Parece ser a melhor forma de obter SIMD portável em C++
Independentemente de o JPEG XL brilhar por si só, só o fato de conseguir fazer o seguinte já é impressionante
a.jpgtem 615504 bytes e o SHA-1 é716744d950ecf9e5757c565041143775a810e10fAo executar
cjxl a.jpg a.jxl, ele lê o JPEG de 615504 bytes e o comprime para 537339 bytes, incluindo o contêinerMas ao executar
djxl a.jxl b.jpg, ele lê os 537339 bytes de dados comprimidos e reconstrói o JPEG, eb.jpgtambém tem 615504 bytes e um SHA-1 exatamente igualConsiderando que existem bilhões de arquivos JPEG no mundo que alguém pode querer preservar, recomprimir JPEGs existentes em um formato com perdas reduz a qualidade
Mas o JPEG XL consegue economizar de 15% a 30% e ainda, se você quiser, restaurar o JPG original com 100% de identidade bit a bit
Muito legal
Infelizmente uso o Debian stable 12 Bookworm, então estou no ImageMagick 6.9, e pelo que sei o Emacs provavelmente usa o ImageMagick para exibir imagens
O suporte a JPEG XL só foi adicionado no ImageMagick 7, e ainda não fui investigar mais a fundo
Acho que isso vai ajudar a preservar integralmente o patrimônio digital sem reencodificação com perdas
É muito impressionante que a nova versão do libjxl tenha reduzido o uso de memória em uma ordem de grandeza de um dígito tanto na compressão com perdas quanto sem perdas, além de melhorar a velocidade
Gosto especialmente da parte em que a configuração de esforço padrão para codificação sem perdas com múltiplas threads agora ficou uma ordem de grandeza de um dígito mais rápida, e o texto também foi muito bem escrito
Fico curioso se existe algum site que explique em detalhes cada etapa do formato JPEG XL
Diferentemente do JPEG tradicional, foi difícil encontrar um documento que guiasse claramente pelas etapas relevantes, e é uma pena, porque esse formato claramente reúne muitas inovações interessantes
Os componentes individuais também parecem úteis por si só
O essencial é DCT de tamanho variável de até 128x128, predição de entropia ANS e predição de crominância baseada em luminância
https://github.com/libjxl/libjxl/blob/main/doc/encode_effort... também mostra bem a divisão de recursos por nível de esforço
O texto deixou de fora o rav1e, que codifica AV1 e, portanto, AVIF
O rav1e é muito mais rápido que a implementação de referência aom, e houve casos em que o aom não conseguiu terminar a conversão da imagem nem esperando 1 minuto, enquanto o rav1e levou menos de 10 segundos
Também queria saber se o rav1e rápido parece melhor que o jpegli em altas velocidades de codificação
Em velocidades semelhantes, não vi uma grande diferença no desempenho de compressão entre os dois